diff --git a/Documentation/Changes.txt b/Documentation/Changes.txt index 349dc1ab8..6d42e58d0 100644 --- a/Documentation/Changes.txt +++ b/Documentation/Changes.txt @@ -14,11 +14,14 @@ Version 1.1.1 * Fix volume change in settings not affecting voice track. * Fix several lighting bugs. * Fix savegame count not properly increasing. -* Overhaul look mode: - - Allow for consistent and wider viewing angles while crawling, crouching, and hanging. - - Improve movement and control. +* Fix regeneration of non-ammo pickups with OCB 128. +* Overhaul look-around feature: + - Allow for more consistent and wider viewing angles while crawling, crouching, and hanging. + - Improve look camera movement and control. - Re-enable looking while performing up jump, backward jump, or backward crawl. - Add functionality to rotate slowly when holding Walk while using binoculars or lasersight. +* Add target highlighter system with toggle in Sound and Gameplay settings. +* Add sprint slide state 191. * Add swinging blade. * Add crumbling platform and add new OCBs for behaviour: - OCB 0: Default behaviour. When the player steps on the platform, it will shake and crumble after 1.2 seconds. @@ -27,12 +30,13 @@ Version 1.1.1 - A negative value requires a trigger to activate. Lua API changes: +* Add DisplaySprite object. * Add Flow::EnableLoadSave() function to disable savegames. * Add Flow::EnablePointFilter() function to disable bilinear filtering. * Add Lara::GetAmmoType() function to read the ammo that Lara is using. * Add Lara::GetControlLock() and Lara::SetControlLock() functions to handle controls locking. * Add Logic.HandleEvent() function to call node events. -* Add functions to load, save, and delete savegames. +* Add functions to load, save, delete and check existence of savegames. * Add DisplayStringOption.RIGHT and DisplayStringOption.BLINK flags for DisplayString. * Make Vec2 object float-based instead of integer-based. * Add Vec2 arithmetic for division with a number and multiplication with another Vec2. diff --git a/Scripts/SystemStrings.lua b/Scripts/SystemStrings.lua index 1755825e5..4e8d11070 100644 --- a/Scripts/SystemStrings.lua +++ b/Scripts/SystemStrings.lua @@ -50,7 +50,7 @@ local strings = ammo_used = { "Ammo Used" }, antialiasing = { "Antialiasing" }, apply = { "Apply" }, - auto_target = { "Automatic Targeting" }, + automatic_targeting = { "Automatic Targeting" }, back = { "Back" }, cancel = { "Cancel" }, caustics = { "Underwater Caustics" }, @@ -71,13 +71,15 @@ local strings = examine = { "Examine" }, exit_game = { "Exit Game" }, exit_to_title = { "Exit to Title" }, - general_actions = { "General Actions"}, + general_actions = { "General Actions" }, high = { "High" }, level_secrets_found = { "Secrets Found in Level" }, load_game = { "Load Game" }, low = { "Low" }, medium = { "Medium" }, menu_actions = { "Menu Actions" }, + mouse_sensitivity = { "Mouse Sensitivity" }, + mouse_smoothing = { "Mouse Smoothing" }, music_volume = { "Music Volume" }, new_game = { "New Game" }, none = { "None" }, @@ -101,6 +103,7 @@ local strings = sound = { "Sound" }, statistics = { "Statistics" }, subtitles = { "Subtitles" }, + target_highlighter = { "Target Highlighter" }, thumbstick_camera = { "Thumbstick Camera" }, time_taken = { "Time Taken" }, total_secrets_found = { "Secrets Found Total" }, @@ -112,6 +115,7 @@ local strings = waiting_for_input = { "Waiting For Input" }, window_title = { "TombEngine" }, windowed = { "Windowed" }, + unlimited = { "Unlimited %s" }, } TEN.Flow.SetStrings(strings) diff --git a/TombEngine/Game/Hud/Hud.cpp b/TombEngine/Game/Hud/Hud.cpp index 490bd55ff..4a1d12e31 100644 --- a/TombEngine/Game/Hud/Hud.cpp +++ b/TombEngine/Game/Hud/Hud.cpp @@ -11,20 +11,23 @@ namespace TEN::Hud { HudController g_Hud = {}; - void HudController::Update(const ItemInfo& item) + void HudController::Update(const ItemInfo& playerItem) { + TargetHighlighter.Update(playerItem); PickupSummary.Update(); - StatusBars.Update(item); + StatusBars.Update(playerItem); } - void HudController::Draw(const ItemInfo& item) const + void HudController::Draw(const ItemInfo& playerItem) const { + TargetHighlighter.Draw(); PickupSummary.Draw(); - StatusBars.Draw(item); + StatusBars.Draw(playerItem); } void HudController::Clear() { + TargetHighlighter.Clear(); PickupSummary.Clear(); StatusBars.Clear(); } diff --git a/TombEngine/Game/Hud/Hud.h b/TombEngine/Game/Hud/Hud.h index a07fc0660..9001f782d 100644 --- a/TombEngine/Game/Hud/Hud.h +++ b/TombEngine/Game/Hud/Hud.h @@ -1,6 +1,7 @@ #pragma once #include "Game/Hud/PickupSummary.h" #include "Game/Hud/StatusBars.h" +#include "Game/Hud/TargetHighlighter.h" struct ItemInfo; @@ -10,12 +11,13 @@ namespace TEN::Hud { public: // Members - StatusBarsController StatusBars = {}; - PickupSummaryController PickupSummary = {}; + StatusBarsController StatusBars = {}; + PickupSummaryController PickupSummary = {}; + TargetHighlighterController TargetHighlighter = {}; // Utilities - void Update(const ItemInfo& item); - void Draw(const ItemInfo& item) const; + void Update(const ItemInfo& playerItem); + void Draw(const ItemInfo& playerItem) const; void Clear(); }; diff --git a/TombEngine/Game/Hud/PickupSummary.h b/TombEngine/Game/Hud/PickupSummary.h index e2968216a..0d1232b14 100644 --- a/TombEngine/Game/Hud/PickupSummary.h +++ b/TombEngine/Game/Hud/PickupSummary.h @@ -20,7 +20,7 @@ namespace TEN::Hud float Life = 0.0f; float Scale = 0.0f; - float Opacity = 0.0f; // BIG TODO: Object transparency in renderer. + float Opacity = 0.0f; float HideVelocity = 0.0f; float StringScale = 0.0f; float StringScalar = 0.0f; diff --git a/TombEngine/Game/Hud/TargetHighlighter.cpp b/TombEngine/Game/Hud/TargetHighlighter.cpp new file mode 100644 index 000000000..a78114393 --- /dev/null +++ b/TombEngine/Game/Hud/TargetHighlighter.cpp @@ -0,0 +1,379 @@ +#include "framework.h" +#include "Game/Hud/TargetHighlighter.h" + +#include "Game/camera.h" +#include "Game/effects/DisplaySprite.h" +#include "Game/items.h" +#include "Game/lara/lara_fire.h" +#include "Game/lara/lara_helpers.h" +#include "Math/Math.h" +#include "Renderer/Renderer11.h" +#include "Specific/configuration.h" +#include "Specific/trutils.h" + +using namespace TEN::Effects::DisplaySprite; +using namespace TEN::Math; +using namespace TEN::Utils; +using TEN::Renderer::g_Renderer; + +namespace TEN::Hud +{ + float CrosshairData::GetScale(float cameraDist) const + { + constexpr auto RANGE = BLOCK(10); + constexpr auto CROSSHAIR_SCALE_MAX = 0.15f; + constexpr auto CROSSHAIR_SCALE_MIN = CROSSHAIR_SCALE_MAX / 3; + + auto alpha = cameraDist / RANGE; + return Lerp(CROSSHAIR_SCALE_MAX, CROSSHAIR_SCALE_MIN, alpha); + } + + float CrosshairData::GetRadius() const + { + // Get screen aspect ratio. + auto screenRes = g_Renderer.GetScreenResolution().ToVector2(); + float screenResAspect = screenRes.x / screenRes.y; + + return ((((SCREEN_SPACE_RES.x * Scale) / 2) * (RadiusScale * PulseScale)) * screenResAspect); + } + + Vector2 CrosshairData::GetPositionOffset(short orientOffset) const + { + constexpr auto ANGLE_OFFSET = ANGLE(-360.0f / (SEGMENT_COUNT * 2)); + + float offsetDist = GetRadius(); + auto relPosOffset = Vector2(offsetDist, 0.0f); + auto rotMatrix = Matrix::CreateRotationZ(TO_RAD((Orientation + orientOffset) + ANGLE_OFFSET)); + + auto posOffset = Vector2::Transform(relPosOffset, rotMatrix); + return GetAspectCorrect2DPosition(posOffset); + } + + void CrosshairData::SetPrimary() + { + IsPrimary = true; + ColorTarget = COLOR_RED; + } + + void CrosshairData::SetPeripheral() + { + IsPrimary = false; + ColorTarget = COLOR_GRAY; + } + + bool CrosshairData::IsOffscreen() const + { + if (!Position.has_value()) + return true; + + // TODO: Not working? + float screenEdgeThreshold = GetRadius(); + return (Position->x <= -screenEdgeThreshold || + Position->y <= -screenEdgeThreshold || + Position->x >= (SCREEN_SPACE_RES.x + screenEdgeThreshold) || + Position->y >= (SCREEN_SPACE_RES.y + screenEdgeThreshold)); + } + + void CrosshairData::Update(const Vector3& targetPos, bool isActive, bool doPulse) + { + constexpr auto ROT = ANGLE(2.0f); + constexpr auto ALIGN_ANGLE_STEP = ANGLE(360.0f / SEGMENT_COUNT); + constexpr auto SCALE_PRIMARY = 0.75f; + constexpr auto SCALE_PERIPHERAL = 0.5f; + constexpr auto RADIUS_SCALE_PRIMARY = 0.5f; + constexpr auto RADIUS_SCALE_PERIPHERAL = 0.25f; + constexpr auto PULSE_SCALE_MAX = 1.3f; + constexpr auto MORPH_LERP_ALPHA = 0.3f; + constexpr auto ORIENT_LERP_ALPHA = 0.1f; + constexpr auto RADIUS_LERP_ALPHA = 0.2f; + + // Update active status. + IsActive = isActive; + + // Update position. + Position = g_Renderer.Get2DPosition(targetPos); + + // Update orientation. + if (IsPrimary) + { + Orientation += ROT; + } + else + { + short closestAlignAngle = round(Orientation / ALIGN_ANGLE_STEP) * ALIGN_ANGLE_STEP; + Orientation = (short)round(Lerp(Orientation, closestAlignAngle, ORIENT_LERP_ALPHA)); + } + + // Update scale. + if (IsActive) + { + float cameraDist = Vector3::Distance(Camera.pos.ToVector3(), targetPos); + float scaleTarget = GetScale(cameraDist) * (IsPrimary ? SCALE_PRIMARY : SCALE_PERIPHERAL); + + Scale = Lerp(Scale, scaleTarget, MORPH_LERP_ALPHA); + } + else + { + Scale = Lerp(Scale, 0.0f, MORPH_LERP_ALPHA / 2); + } + + // Update color. + if (!IsActive) + { + ColorTarget = CrosshairData::COLOR_GRAY; + ColorTarget.w = 0.0f; + } + Color = Vector4::Lerp(Color, ColorTarget, MORPH_LERP_ALPHA); + + float radiusScaleTarget = IsPrimary ? RADIUS_SCALE_PRIMARY : RADIUS_SCALE_PERIPHERAL; + if (!IsActive) + radiusScaleTarget = RADIUS_SCALE_PERIPHERAL; + + // Update radius scale. + RadiusScale = Lerp(RadiusScale, radiusScaleTarget, RADIUS_LERP_ALPHA); + + // Update pulse scale. + PulseScale = doPulse ? PULSE_SCALE_MAX : Lerp(PulseScale, 1.0f, MORPH_LERP_ALPHA); + + // Update segments. + for (auto& segment : Segments) + segment.PosOffset = GetPositionOffset(segment.OrientOffset); + } + + void CrosshairData::Draw() const + { + constexpr auto SPRITE_SEQUENCE_OBJECT_ID = ID_CROSSHAIR; + constexpr auto STATIC_ELEMENT_SPRITE_ID = 0; + constexpr auto SEGMENT_ELEMENT_SPRITE_ID = 1; + constexpr auto PRIORITY = 0; // TODO: Check later. May interfere with Lua display sprites. -- Sezz 2023.10.06 + constexpr auto ALIGN_MODE = DisplaySpriteAlignMode::Center; + constexpr auto SCALE_MODE = DisplaySpriteScaleMode::Fill; + constexpr auto BLEND_MODE = BLEND_MODES::BLENDMODE_ALPHABLEND; + + if (IsOffscreen()) + return; + + // Draw main static element. + AddDisplaySprite( + SPRITE_SEQUENCE_OBJECT_ID, STATIC_ELEMENT_SPRITE_ID, + *Position, Orientation, Vector2(Scale), Color, + PRIORITY, ALIGN_MODE, SCALE_MODE, BLEND_MODE); + + // Draw animated outer segment elements. + for (const auto& segment : Segments) + { + auto pos = *Position + segment.PosOffset; + short orient = Orientation + segment.OrientOffset; + auto scale = Vector2(Scale / 2); + + AddDisplaySprite( + SPRITE_SEQUENCE_OBJECT_ID, SEGMENT_ELEMENT_SPRITE_ID, + pos, orient, scale, Color, + PRIORITY, ALIGN_MODE, SCALE_MODE, BLEND_MODE); + } + } + + void TargetHighlighterController::Update(const ItemInfo& playerItem) + { + // Check if target highlighter is enabled. + if (!g_Configuration.EnableTargetHighlighter) + { + if (!Crosshairs.empty()) + Crosshairs.clear(); + + return; + } + + const auto& player = GetLaraInfo(playerItem); + + // Loop over player targets. + auto itemNumbers = std::vector{}; + for (const auto* itemPtr : player.TargetList) + { + if (itemPtr == nullptr) + continue; + + // Collect item number. + itemNumbers.push_back(itemPtr->Index); + + // Find crosshair at item number key. + auto it = Crosshairs.find(itemPtr->Index); + if (it == Crosshairs.end()) + continue; + + // Set crosshair as primary or peripheral. + auto& crosshair = it->second; + if (player.TargetEntity != nullptr && + itemPtr->Index == player.TargetEntity->Index) + { + crosshair.SetPrimary(); + } + else + { + crosshair.SetPeripheral(); + } + } + + // Update crosshairs. + Update(itemNumbers); + } + + void TargetHighlighterController::Draw() const + { + //DrawDebug(); + + if (Crosshairs.empty()) + return; + + for (const auto& [itemNumber, crosshair] : Crosshairs) + crosshair.Draw(); + } + + void TargetHighlighterController::Clear() + { + *this = {}; + } + + void TargetHighlighterController::Update(const std::vector& itemNumbers) + { + constexpr auto TARGET_BONE_ID = 0; + + // No crosshairs to update; return early. + if (Crosshairs.empty() && itemNumbers.empty()) + return; + + // Update active crosshairs. + for (int itemNumber : itemNumbers) + { + const auto& item = g_Level.Items[itemNumber]; + auto targetPos = GetJointPosition(item, TARGET_BONE_ID).ToVector3(); + + // Update existing active crosshair. + auto it = Crosshairs.find(itemNumber); + if (it != Crosshairs.end()) + { + auto& crosshair = it->second; + if (crosshair.IsActive) + { + crosshair.Update(targetPos, true, item.HitStatus); + continue; + } + } + + // Add new active crosshair. + AddCrosshair(itemNumber, targetPos); + } + + // Update inactive crosshairs. + for (auto& [itemNumber, crosshair] : Crosshairs) + { + // Find crosshairs at absent item number keys. + if (Contains(itemNumbers, itemNumber)) + continue; + + const auto& item = g_Level.Items[itemNumber]; + auto targetPos = GetJointPosition(item, 0).ToVector3(); + + // Update inactive crosshair. + crosshair.Update(targetPos, false, item.HitStatus); + } + + ClearInactiveCrosshairs(); + } + + CrosshairData& TargetHighlighterController::GetNewCrosshair(int itemNumber) + { + constexpr auto CROSSHAIR_COUNT_MAX = 16; + + // Map is full; clear smallest crosshair. + if (Crosshairs.size() >= CROSSHAIR_COUNT_MAX) + { + int key = 0; + float smallestScale = INFINITY; + + for (auto& [itemNumber, crosshair] : Crosshairs) + { + if (crosshair.Scale < smallestScale) + { + key = itemNumber; + smallestScale = crosshair.Scale; + } + } + + Crosshairs.erase(key); + } + + // Return new crosshair. + Crosshairs.insert({ itemNumber, {} }); + auto& crosshair = Crosshairs.at(itemNumber); + crosshair = {}; + return crosshair; + } + + // TODO: If crosshair happens to be in view upon spawn, first frame is sometimes garbage. + void TargetHighlighterController::AddCrosshair(int itemNumber, const Vector3& targetPos) + { + constexpr auto SCALE_START = 0.75f; + constexpr auto RADIUS_SCALE_START = 1.5f * SQRT_2; + constexpr auto ANGLE_STEP = ANGLE(360.0f / CrosshairData::SEGMENT_COUNT); + + auto pos = g_Renderer.Get2DPosition(targetPos); + if (!pos.has_value()) + return; + + // Create new crosshair. + auto& crosshair = GetNewCrosshair(itemNumber); + + crosshair.IsActive = true; + crosshair.IsPrimary = false; + crosshair.Position = *pos; + crosshair.Orientation = 0; + crosshair.Scale = SCALE_START; + crosshair.Color = CrosshairData::COLOR_GRAY; + crosshair.Color.w = 0.0f; + crosshair.ColorTarget = CrosshairData::COLOR_GRAY; + crosshair.RadiusScale = RADIUS_SCALE_START; + crosshair.PulseScale = 1.0f; + + // Initialize segments. + short angleOffset = 0; + for (auto& segment : crosshair.Segments) + { + segment.PosOffset = crosshair.GetPositionOffset(segment.OrientOffset); + segment.OrientOffset = angleOffset; + + angleOffset += ANGLE_STEP; + } + } + + void TargetHighlighterController::ClearInactiveCrosshairs() + { + for (auto it = Crosshairs.begin(); it != Crosshairs.end();) + { + const auto& crosshair = it->second; + (!crosshair.IsActive && crosshair.Scale <= EPSILON) ? + (it = Crosshairs.erase(it)) : ++it; + } + } + + void TargetHighlighterController::DrawDebug() const + { + unsigned int visibleCount = 0; + unsigned int primaryCount = 0; + unsigned int peripheralCount = 0; + + for (const auto& [itemNumber, crosshair] : Crosshairs) + { + crosshair.IsPrimary ? primaryCount++ : peripheralCount++; + + if (!crosshair.IsOffscreen()) + visibleCount++; + } + + g_Renderer.PrintDebugMessage("TARGET HIGHLIGHTER DEBUG"); + g_Renderer.PrintDebugMessage(g_Configuration.EnableTargetHighlighter ? "Enabled" : "Disabled"); + g_Renderer.PrintDebugMessage("Visible crosshairs: %d", visibleCount); + g_Renderer.PrintDebugMessage("Primary crosshairs: %d", primaryCount); + g_Renderer.PrintDebugMessage("Peripheral crosshairs: %d", peripheralCount); + } +} diff --git a/TombEngine/Game/Hud/TargetHighlighter.h b/TombEngine/Game/Hud/TargetHighlighter.h new file mode 100644 index 000000000..fe2fac326 --- /dev/null +++ b/TombEngine/Game/Hud/TargetHighlighter.h @@ -0,0 +1,77 @@ +#pragma once + +struct ItemInfo; + +namespace TEN::Hud +{ + class CrosshairData + { + private: + struct SegmentData + { + Vector2 PosOffset = Vector2::Zero; + short OrientOffset = 0; + }; + + public: + // Constants + static constexpr auto COLOR_RED = Vector4(1.0f, 0.2f, 0.2f, 0.9f); + static constexpr auto COLOR_GRAY = Vector4(0.5f, 0.5f, 0.5f, 0.5f); + static constexpr auto SEGMENT_COUNT = 4; + + // Members + bool IsActive = false; + bool IsPrimary = false; + + std::optional Position = std::nullopt; + short Orientation = 0; + float Scale = 0.0f; + Vector4 Color = Vector4::Zero; + Vector4 ColorTarget = Vector4::Zero; + + float RadiusScale = 0.0f; + float PulseScale = 0.0f; + + std::array Segments = {}; + + // Getters + float GetScale(float cameraDist) const; + float GetRadius() const; + Vector2 GetPositionOffset(short orientOffset) const; + + // Setters + void SetPrimary(); + void SetPeripheral(); + + // Inquirers + bool IsOffscreen() const; + + // Utilities + void Update(const Vector3& targetPos, bool isActive, bool doPulse); + void Draw() const; + }; + + class TargetHighlighterController + { + private: + // Members + std::unordered_map Crosshairs = {}; // Key = item number. + + public: + // Utilities + void Update(const ItemInfo& playerItem); + void Draw() const; + void Clear(); + + private: + // Update helpers + void Update(const std::vector& itemNumbers); + + // Object helpers + CrosshairData& GetNewCrosshair(int itemNumber); + void AddCrosshair(int itemNumber, const Vector3& targetPos); + void ClearInactiveCrosshairs(); + + void DrawDebug() const; + }; +} diff --git a/TombEngine/Game/Lara/lara.cpp b/TombEngine/Game/Lara/lara.cpp index 0f95a18df..d77b01f83 100644 --- a/TombEngine/Game/Lara/lara.cpp +++ b/TombEngine/Game/Lara/lara.cpp @@ -245,6 +245,8 @@ std::function lara_control_routines[NUM_LARA_STATES + 1] = lara_as_null, lara_as_null, lara_as_use_puzzle,//189 + lara_as_null,//190 + lara_as_sprint_slide,//191 }; std::function lara_collision_routines[NUM_LARA_STATES + 1] = @@ -439,6 +441,8 @@ std::function lara_collision_routines[NUM_LARA_STATES + 1] lara_void_func, lara_void_func, lara_default_col,//189 + lara_void_func,//190 + lara_col_sprint_slide,//191 }; void LaraControl(ItemInfo* item, CollisionInfo* coll) diff --git a/TombEngine/Game/Lara/lara_basic.cpp b/TombEngine/Game/Lara/lara_basic.cpp index f6cedb497..858cbccba 100644 --- a/TombEngine/Game/Lara/lara_basic.cpp +++ b/TombEngine/Game/Lara/lara_basic.cpp @@ -2426,7 +2426,7 @@ void lara_as_sprint_dive(ItemInfo* item, CollisionInfo* coll) } // State: LS_SPRINT_DIVE (74) -// Control: lara_col_sprint_dive() +// Control: lara_as_sprint_dive() void lara_col_sprint_dive(ItemInfo* item, CollisionInfo* coll) { auto* lara = GetLaraInfo(item); @@ -2458,3 +2458,77 @@ void lara_col_sprint_dive(ItemInfo* item, CollisionInfo* coll) return; } } + +// TODO: Useful for having the player sweep under a gate. No default animation is currently included, +// but later one will be added to avoid making this an "insider feature". -- Sezz 2023.10.12 +// State: LS_SPRINT_SLIDE (191) +// Collision: lara_col_sprint_slide() +void lara_as_sprint_slide(ItemInfo* item, CollisionInfo* coll) +{ + auto& player = GetLaraInfo(*item); + + player.Control.Look.Mode = LookMode::Horizontal; + + player.Control.Count.Run++; + if (player.Control.Count.Run > LARA_RUN_JUMP_TIME) + player.Control.Count.Run = LARA_RUN_JUMP_TIME; + + if (IsHeld(In::Left) || IsHeld(In::Right)) + { + ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_SLOW_TURN_RATE_MAX); + ModulateLaraLean(item, coll, LARA_LEAN_RATE, LARA_LEAN_MAX * 0.6f); + } + + if ((player.Control.KeepLow || IsHeld(In::Crouch)) && HasStateDispatch(item, LS_CROUCH_IDLE) && + TestLaraCrouch(item)) + { + item->Animation.TargetState = LS_CROUCH_IDLE; + return; + } + + item->Animation.TargetState = LS_RUN_FORWARD; +} + +// State: LS_SPRINT_SLIDE (191) +// Control: lara_as_sprint_slide() +void lara_col_sprint_slide(ItemInfo* item, CollisionInfo* coll) +{ + auto& player = GetLaraInfo(*item); + + player.Control.MoveAngle = item->Pose.Orientation.y; + player.Control.KeepLow = TestLaraKeepLow(item, coll); + player.Control.IsLow = true; + coll->Setup.Height = LARA_HEIGHT_CRAWL; + coll->Setup.LowerFloorBound = NO_LOWER_BOUND; + coll->Setup.UpperFloorBound = -(CLICK(1) - 1); + coll->Setup.LowerCeilingBound = 0; + coll->Setup.BlockFloorSlopeUp = true; + coll->Setup.ForwardAngle = player.Control.MoveAngle; + GetCollisionInfo(coll, item); + + LaraDeflectEdge(item, coll); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallAnimation(item); + return; + } + + if (TestLaraSlide(item, coll)) + { + SetLaraSlideAnimation(item, coll); + return; + } + + if (TestLaraStep(item, coll) && coll->CollisionType != CT_FRONT) + { + DoLaraStep(item, coll); + return; + } +} diff --git a/TombEngine/Game/Lara/lara_basic.h b/TombEngine/Game/Lara/lara_basic.h index fd36cee6b..4613deeb1 100644 --- a/TombEngine/Game/Lara/lara_basic.h +++ b/TombEngine/Game/Lara/lara_basic.h @@ -73,3 +73,5 @@ void lara_as_sprint(ItemInfo* item, CollisionInfo* coll); void lara_col_sprint(ItemInfo* item, CollisionInfo* coll); void lara_as_sprint_dive(ItemInfo* item, CollisionInfo* coll); void lara_col_sprint_dive(ItemInfo* item, CollisionInfo* coll); +void lara_as_sprint_slide(ItemInfo* item, CollisionInfo* coll); +void lara_col_sprint_slide(ItemInfo* item, CollisionInfo* coll); diff --git a/TombEngine/Game/Lara/lara_fire.cpp b/TombEngine/Game/Lara/lara_fire.cpp index 89f40fd0b..d57a3d459 100644 --- a/TombEngine/Game/Lara/lara_fire.cpp +++ b/TombEngine/Game/Lara/lara_fire.cpp @@ -282,6 +282,15 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] = } }; +// TODO: Use map like in GetWeaponAnimData(); +const WeaponInfo& GetWeaponInfo(LaraWeaponType weaponType) +{ + if ((int)weaponType < 0 || (int)weaponType >= (int)LaraWeaponType::NumWeapons) + return Weapons[0]; + + return (Weapons[(int)weaponType]); +} + void InitializeNewWeapon(ItemInfo& laraItem) { auto& player = *GetLaraInfo(&laraItem); @@ -469,6 +478,15 @@ GAME_OBJECT_ID GetWeaponObjectMeshID(ItemInfo& laraItem, LaraWeaponType weaponTy } } +static void ClearPlayerTargets(ItemInfo& playerItem) +{ + auto& player = GetLaraInfo(playerItem); + + player.TargetEntity = nullptr; + player.TargetList.fill(nullptr); + player.LastTargets.fill(nullptr); +} + void HandleWeapon(ItemInfo& laraItem) { auto& player = *GetLaraInfo(&laraItem); @@ -545,7 +563,7 @@ void HandleWeapon(ItemInfo& laraItem) (player.Control.Weapon.RequestGunType == LaraWeaponType::HarpoonGun || player.Control.WaterStatus == WaterStatus::Dry || (player.Control.WaterStatus == WaterStatus::Wade && - player.Context.WaterSurfaceDist > -Weapons[(int)player.Control.Weapon.GunType].GunHeight)))) + player.Context.WaterSurfaceDist > -GetWeaponInfo(player.Control.Weapon.GunType).GunHeight)))) { if (player.Control.Weapon.GunType == LaraWeaponType::Flare) { @@ -586,7 +604,7 @@ void HandleWeapon(ItemInfo& laraItem) else if (player.Control.Weapon.GunType != LaraWeaponType::HarpoonGun && player.Control.WaterStatus != WaterStatus::Dry && (player.Control.WaterStatus != WaterStatus::Wade || - player.Context.WaterSurfaceDist < -Weapons[(int)player.Control.Weapon.GunType].GunHeight)) + player.Context.WaterSurfaceDist < -GetWeaponInfo(player.Control.Weapon.GunType).GunHeight)) { player.Control.HandStatus = HandStatus::WeaponUndraw; } @@ -647,6 +665,7 @@ void HandleWeapon(ItemInfo& laraItem) break; case HandStatus::WeaponUndraw: + ClearPlayerTargets(laraItem); laraItem.Model.MeshIndex[LM_HEAD] = laraItem.Model.BaseMesh + LM_HEAD; switch (player.Control.Weapon.GunType) @@ -791,7 +810,7 @@ FireWeaponType FireWeapon(LaraWeaponType weaponType, ItemInfo& targetEntity, Ite if (!ammo.HasInfinite()) ammo--; - const auto& weapon = Weapons[(int)weaponType]; + const auto& weapon = GetWeaponInfo(weaponType); auto wobbledArmOrient = EulerAngles( armOrient.x + (Random::GenerateAngle(0, ANGLE(180.0f)) - ANGLE(90.0f)) * weapon.ShotAccuracy / 65536, diff --git a/TombEngine/Game/Lara/lara_fire.h b/TombEngine/Game/Lara/lara_fire.h index 8f9877b40..ceeb66975 100644 --- a/TombEngine/Game/Lara/lara_fire.h +++ b/TombEngine/Game/Lara/lara_fire.h @@ -48,11 +48,12 @@ extern WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons]; void InitializeNewWeapon(ItemInfo& laraItem); -Ammo& GetAmmo(LaraInfo& lara, LaraWeaponType weaponType); -GameVector GetTargetPoint(ItemInfo& targetEntity); -HolsterSlot GetWeaponHolsterSlot(LaraWeaponType weaponType); -GAME_OBJECT_ID GetWeaponObjectID(LaraWeaponType weaponType); -GAME_OBJECT_ID GetWeaponObjectMeshID(ItemInfo& laraItem, LaraWeaponType weaponType); +const WeaponInfo& GetWeaponInfo(LaraWeaponType weaponType); +Ammo& GetAmmo(LaraInfo& lara, LaraWeaponType weaponType); +GameVector GetTargetPoint(ItemInfo& targetEntity); +HolsterSlot GetWeaponHolsterSlot(LaraWeaponType weaponType); +GAME_OBJECT_ID GetWeaponObjectID(LaraWeaponType weaponType); +GAME_OBJECT_ID GetWeaponObjectMeshID(ItemInfo& laraItem, LaraWeaponType weaponType); void HandleWeapon(ItemInfo& laraItem); void AimWeapon(ItemInfo& laraItem, ArmInfo& arm, const WeaponInfo& weaponInfo); diff --git a/TombEngine/Game/Lara/lara_struct.h b/TombEngine/Game/Lara/lara_struct.h index 39bbaa34d..4ec20f47f 100644 --- a/TombEngine/Game/Lara/lara_struct.h +++ b/TombEngine/Game/Lara/lara_struct.h @@ -211,6 +211,8 @@ enum LaraState // 174-188 reserved for "true" ladders. -- Sezz 2023.04.16 LS_REMOVE_PUZZLE = 189, + LS_RESERVED_PUSHABLE_STATE = 190, + LS_SPRINT_SLIDE = 191, NUM_LARA_STATES }; diff --git a/TombEngine/Game/Lara/lara_two_guns.cpp b/TombEngine/Game/Lara/lara_two_guns.cpp index 90932744d..0f38ac88d 100644 --- a/TombEngine/Game/Lara/lara_two_guns.cpp +++ b/TombEngine/Game/Lara/lara_two_guns.cpp @@ -33,17 +33,16 @@ struct WeaponAnimData static WeaponAnimData GetWeaponAnimData(LaraWeaponType weaponType) { - static const auto DEFAULT_WEAPON_ANIM_DATA = WeaponAnimData{ ID_LARA, 0, 0, 0, 0 }; - static const auto ANIM_DATA_MAP = std::unordered_map + static const auto ANIM_DATA_MAP = std::unordered_map { { LaraWeaponType::None, WeaponAnimData{ ID_LARA, 0, 0, 0, 0 } }, { LaraWeaponType::Pistol, WeaponAnimData{ ID_PISTOLS_ANIM, 4, 5, 13, 24 } }, { LaraWeaponType::Revolver, WeaponAnimData{ ID_REVOLVER_ANIM , 7, 8, 15, 29 } }, { LaraWeaponType::Uzi, WeaponAnimData{ ID_UZI_ANIM, 4, 5, 13, 24 } } }; - + auto it = ANIM_DATA_MAP.find(weaponType); - return ((it != ANIM_DATA_MAP.end()) ? it->second : DEFAULT_WEAPON_ANIM_DATA); + return ((it != ANIM_DATA_MAP.end()) ? it->second : ANIM_DATA_MAP.at(LaraWeaponType::None)); } static Vector3i GetWeaponSmokeRelOffset(LaraWeaponType weaponType, bool isRightWeapon) diff --git a/TombEngine/Game/control/control.cpp b/TombEngine/Game/control/control.cpp index 75bef8aad..04acd4685 100644 --- a/TombEngine/Game/control/control.cpp +++ b/TombEngine/Game/control/control.cpp @@ -13,6 +13,7 @@ #include "Game/effects/debris.h" #include "Game/effects/Blood.h" #include "Game/effects/Bubble.h" +#include "Game/effects/DisplaySprite.h" #include "Game/effects/Drip.h" #include "Game/effects/effects.h" #include "Game/effects/Electricity.h" @@ -62,6 +63,7 @@ using namespace std::chrono; using namespace TEN::Effects; using namespace TEN::Effects::Blood; using namespace TEN::Effects::Bubble; +using namespace TEN::Effects::DisplaySprite; using namespace TEN::Effects::Drip; using namespace TEN::Effects::Electricity; using namespace TEN::Effects::Environment; @@ -118,6 +120,9 @@ int DrawPhase(bool isTitle) g_Renderer.Render(); } + // Clear display sprites. + ClearDisplaySprites(); + Camera.numberFrames = g_Renderer.Synchronize(); return Camera.numberFrames; } @@ -416,6 +421,7 @@ void CleanUp() StreamerEffect.Clear(); ClearUnderwaterBloodParticles(); ClearBubbles(); + ClearDisplaySprites(); ClearFootprints(); ClearDrips(); ClearRipples(); diff --git a/TombEngine/Game/effects/DisplaySprite.cpp b/TombEngine/Game/effects/DisplaySprite.cpp new file mode 100644 index 000000000..c3c962909 --- /dev/null +++ b/TombEngine/Game/effects/DisplaySprite.cpp @@ -0,0 +1,38 @@ +#include "framework.h" +#include "Game/effects/DisplaySprite.h" + +#include "Game/effects/effects.h" +#include "Game/Setup.h" +#include "Math/Math.h" +#include "Objects/objectslist.h" +#include "Renderer/Renderer11.h" + +using namespace TEN::Math; + +namespace TEN::Effects::DisplaySprite +{ + std::vector DisplaySprites = {}; + + void AddDisplaySprite(GAME_OBJECT_ID objectID, int spriteID, const Vector2& pos, short orient, const Vector2& scale, const Vector4& color, + int priority, DisplaySpriteAlignMode alignMode, DisplaySpriteScaleMode scaleMode, BLEND_MODES blendMode) + { + auto displaySprite = DisplaySprite{}; + displaySprite.ObjectID = objectID; + displaySprite.SpriteID = spriteID; + displaySprite.Position = pos; + displaySprite.Orientation = orient; + displaySprite.Scale = scale; + displaySprite.Color = color; + displaySprite.Priority = priority; + displaySprite.AlignMode = alignMode; + displaySprite.ScaleMode = scaleMode; + displaySprite.BlendMode = blendMode; + + DisplaySprites.push_back(displaySprite); + } + + void ClearDisplaySprites() + { + DisplaySprites.clear(); + } +} diff --git a/TombEngine/Game/effects/DisplaySprite.h b/TombEngine/Game/effects/DisplaySprite.h new file mode 100644 index 000000000..9ae284bc1 --- /dev/null +++ b/TombEngine/Game/effects/DisplaySprite.h @@ -0,0 +1,48 @@ +#pragma once +#include "Objects/game_object_ids.h" +#include "Renderer/Renderer11Enums.h" + +namespace TEN::Effects::DisplaySprite +{ + enum class DisplaySpriteAlignMode + { + Center, + CenterTop, + CenterBottom, + CenterLeft, + CenterRight, + TopLeft, + TopRight, + BottomLeft, + BottomRight + }; + + enum class DisplaySpriteScaleMode + { + Fit, + Fill, + Stretch + }; + + struct DisplaySprite + { + GAME_OBJECT_ID ObjectID = ID_DEFAULT_SPRITES; + int SpriteID = 0; + + Vector2 Position = Vector2::Zero; + short Orientation = 0; + Vector2 Scale = Vector2::One; + Vector4 Color = Vector4::One; + + int Priority = 0; + DisplaySpriteAlignMode AlignMode = DisplaySpriteAlignMode::Center; + DisplaySpriteScaleMode ScaleMode = DisplaySpriteScaleMode::Fit; + BLEND_MODES BlendMode = BLENDMODE_ALPHABLEND; + }; + + extern std::vector DisplaySprites; + + void AddDisplaySprite(GAME_OBJECT_ID objectID, int spriteID, const Vector2& pos, short orient, const Vector2& scale, const Vector4& color, + int priority, DisplaySpriteAlignMode alignMode, DisplaySpriteScaleMode scaleMode, BLEND_MODES blendMode); + void ClearDisplaySprites(); +} diff --git a/TombEngine/Game/gui.cpp b/TombEngine/Game/gui.cpp index e14d26c25..690f01f95 100644 --- a/TombEngine/Game/gui.cpp +++ b/TombEngine/Game/gui.cpp @@ -181,7 +181,7 @@ namespace TEN::Gui return false; // Avoid Select or Action release interference when entering inventory. - if (GetActionTimeActive(In::Select) < TimeInMenu || GetActionTimeActive(In::Action) < TimeInMenu) + if (GetActionTimeActive(In::Select) < TimeInMenu && GetActionTimeActive(In::Action) < TimeInMenu) return true; return false; @@ -871,14 +871,16 @@ namespace TEN::Gui MusicVolume, SfxVolume, Subtitles, - AutoTarget, + AutoTargeting, + TargetHighlighter, ToggleRumble, ThumbstickCameraControl, + Apply, Cancel }; - static const int numOtherSettingsOptions = 8; + static const int numOtherSettingsOptions = 9; OptionCount = numOtherSettingsOptions; @@ -903,11 +905,21 @@ namespace TEN::Gui CurrentSettings.Configuration.EnableReverb = !CurrentSettings.Configuration.EnableReverb; break; - case OtherSettingsOption::AutoTarget: + case OtherSettingsOption::Subtitles: + SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always); + CurrentSettings.Configuration.EnableSubtitles = !CurrentSettings.Configuration.EnableSubtitles; + break; + + case OtherSettingsOption::AutoTargeting: SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always); CurrentSettings.Configuration.EnableAutoTargeting = !CurrentSettings.Configuration.EnableAutoTargeting; break; + case OtherSettingsOption::TargetHighlighter: + SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always); + CurrentSettings.Configuration.EnableTargetHighlighter = !CurrentSettings.Configuration.EnableTargetHighlighter; + break; + case OtherSettingsOption::ToggleRumble: SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always); CurrentSettings.Configuration.EnableRumble = !CurrentSettings.Configuration.EnableRumble; @@ -917,11 +929,6 @@ namespace TEN::Gui SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always); CurrentSettings.Configuration.EnableThumbstickCamera = !CurrentSettings.Configuration.EnableThumbstickCamera; break; - - case OtherSettingsOption::Subtitles: - SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always); - CurrentSettings.Configuration.EnableSubtitles = !CurrentSettings.Configuration.EnableSubtitles; - break; } } @@ -2710,7 +2717,7 @@ namespace TEN::Gui if (AmmoObjectList[n].Amount == -1) { - sprintf(&invTextBuffer[0], "Unlimited %s", g_GameFlow->GetString(InventoryObjectTable[AmmoObjectList[n].InventoryItem].ObjectName)); + sprintf(&invTextBuffer[0], g_GameFlow->GetString(STRING_UNLIMITED), g_GameFlow->GetString(InventoryObjectTable[AmmoObjectList[n].InventoryItem].ObjectName)); } else { @@ -3033,7 +3040,7 @@ namespace TEN::Gui { if (numItems == -1) { - sprintf(textBuffer, "Unlimited %s", g_GameFlow->GetString(invObject.ObjectName)); + sprintf(textBuffer, g_GameFlow->GetString(STRING_UNLIMITED), g_GameFlow->GetString(invObject.ObjectName)); } else { diff --git a/TombEngine/Game/pickup/pickup.cpp b/TombEngine/Game/pickup/pickup.cpp index 226b2ab22..b264f5777 100644 --- a/TombEngine/Game/pickup/pickup.cpp +++ b/TombEngine/Game/pickup/pickup.cpp @@ -827,6 +827,9 @@ void RegeneratePickups() case ID_SHOTGUN_AMMO2_ITEM: ammo = lara->Weapons[(int)LaraWeaponType::Shotgun].Ammo[(int)WeaponAmmoType::Ammo2]; break; + + default: + continue; // Don't regenerate anything but ammo. } if (ammo == 0) diff --git a/TombEngine/Game/savegame.cpp b/TombEngine/Game/savegame.cpp index 1931af56c..fe70aa559 100644 --- a/TombEngine/Game/savegame.cpp +++ b/TombEngine/Game/savegame.cpp @@ -70,7 +70,7 @@ void SaveGame::LoadSavegameInfos() // Try loading savegame. for (int i = 0; i < SAVEGAME_MAX; i++) { - if (!DoesSaveGameExist(i)) + if (!DoesSaveGameExist(i, true)) continue; SavegameInfos[i].Present = true; @@ -175,11 +175,13 @@ bool SaveGame::IsSaveGameSlotValid(int slot) return true; } -bool SaveGame::DoesSaveGameExist(int slot) +bool SaveGame::DoesSaveGameExist(int slot, bool silent) { if (!std::filesystem::is_regular_file(GetSavegameFilename(slot))) { - TENLog("Attempted to access missing savegame slot " + std::to_string(slot), LogLevel::Warning); + if (!silent) + TENLog("Attempted to access missing savegame slot " + std::to_string(slot), LogLevel::Warning); + return false; } diff --git a/TombEngine/Game/savegame.h b/TombEngine/Game/savegame.h index 5209c1220..60e5e8c62 100644 --- a/TombEngine/Game/savegame.h +++ b/TombEngine/Game/savegame.h @@ -60,5 +60,5 @@ public: static void LoadSavegameInfos(); static void Delete(int slot); - static bool DoesSaveGameExist(int slot); + static bool DoesSaveGameExist(int slot, bool silent = false); }; diff --git a/TombEngine/Objects/TR2/Entity/tr2_skidman.cpp b/TombEngine/Objects/TR2/Entity/tr2_skidman.cpp index 1f3dcc11d..6f3a2f029 100644 --- a/TombEngine/Objects/TR2/Entity/tr2_skidman.cpp +++ b/TombEngine/Objects/TR2/Entity/tr2_skidman.cpp @@ -72,7 +72,7 @@ namespace TEN::Entities::Creatures::TR2 InitializeItem(skidooItemNumber); g_Level.NumItems++; // Register snowmobile gun for driver to control. - riderItem.Data = skidooItemNumber; + riderItem.ItemFlags[0] = skidooItemNumber; } void InitializeSkidooMan(short itemNumber) @@ -118,17 +118,17 @@ namespace TEN::Entities::Creatures::TR2 void SkidooManControl(short riderItemNumber) { auto& riderItem = g_Level.Items[riderItemNumber]; - if (!riderItem.Data) + if (!riderItem.ItemFlags[0]) { // Create snowmobile. CreateSkidooGun(riderItem); - if (!riderItem.Data) + if (!riderItem.ItemFlags[0]) TENLog("Skidoo rider data does not contain skidoo item ID.", LogLevel::Error); return; } - int skidooItemNumber = (short)riderItem.Data; + int skidooItemNumber = (short)riderItem.ItemFlags[0]; auto* skidooItem = &g_Level.Items[skidooItemNumber]; if (!skidooItem->Data) diff --git a/TombEngine/Objects/game_object_ids.h b/TombEngine/Objects/game_object_ids.h index 11bf2c66d..eafb5314b 100644 --- a/TombEngine/Objects/game_object_ids.h +++ b/TombEngine/Objects/game_object_ids.h @@ -994,6 +994,8 @@ enum GAME_OBJECT_ID : short ID_AIR_BAR_TEXTURE, ID_DASH_BAR_TEXTURE, ID_SFX_BAR_TEXTURE, + // NOTE: 1378 - 1379 reserved for blood effects. -- Sezz 2023.05.29 + ID_CROSSHAIR = 1380, ID_PANEL_BORDER = 1400, ID_PANEL_MIDDLE, diff --git a/TombEngine/Renderer/RenderView/RenderView.cpp b/TombEngine/Renderer/RenderView/RenderView.cpp index 67e44fc21..b65b32f0d 100644 --- a/TombEngine/Renderer/RenderView/RenderView.cpp +++ b/TombEngine/Renderer/RenderView/RenderView.cpp @@ -1,5 +1,5 @@ #include "framework.h" -#include "RenderView.h" +#include "Renderer/RenderView/RenderView.h" namespace TEN::Renderer { @@ -46,6 +46,7 @@ namespace TEN::Renderer RoomsToDraw.clear(); LightsToDraw.clear(); SpritesToDraw.clear(); + DisplaySpritesToDraw.clear(); SortedStaticsToDraw.clear(); FogBulbsToDraw.clear(); } diff --git a/TombEngine/Renderer/RenderView/RenderView.h b/TombEngine/Renderer/RenderView/RenderView.h index f0631ec77..bf1957f58 100644 --- a/TombEngine/Renderer/RenderView/RenderView.h +++ b/TombEngine/Renderer/RenderView/RenderView.h @@ -1,15 +1,12 @@ #pragma once -#include -#include -#include - #include "Game/camera.h" -#include "Renderer/Frustum.h" #include "Renderer/ConstantBuffers/CameraMatrixBuffer.h" +#include "Renderer/Frustum.h" +#include "Specific/memory/LinearArrayBuffer.h" +#include "Renderer/RendererSprite2D.h" #include "Renderer/RendererSprites.h" #include "Renderer/RendererTransparentFace.h" #include "Renderer/Structures/RendererFogBulb.h" -#include "Specific/memory/LinearArrayBuffer.h" namespace TEN::Renderer { @@ -19,6 +16,7 @@ namespace TEN::Renderer struct RendererEffect; struct RendererRoom; struct RendererTransparentFace; + constexpr auto MAX_ROOMS_DRAW = 256; constexpr auto MAX_STATICS_DRAW = 128; constexpr auto MAX_EFFECTS_DRAW = 16; @@ -26,9 +24,6 @@ namespace TEN::Renderer constexpr auto MAX_LIGHTS_DRAW = 48; constexpr auto MAX_FOG_BULBS_DRAW = 32; constexpr auto MAX_SPRITES_DRAW = 512; - using DirectX::SimpleMath::Vector3; - using DirectX::SimpleMath::Vector2; - using DirectX::SimpleMath::Matrix; struct RenderViewCamera { @@ -51,15 +46,18 @@ namespace TEN::Renderer struct RenderView { RenderViewCamera Camera; - D3D11_VIEWPORT Viewport; - std::vector RoomsToDraw; - std::vector LightsToDraw; - std::vector FogBulbsToDraw; - std::vector SpritesToDraw; - std::map> SortedStaticsToDraw; + D3D11_VIEWPORT Viewport; + + std::vector RoomsToDraw = {}; + std::vector LightsToDraw = {}; + std::vector FogBulbsToDraw = {}; + std::vector SpritesToDraw = {}; + std::vector DisplaySpritesToDraw = {}; + std::map> SortedStaticsToDraw = {}; RenderView(CAMERA_INFO* cam, float roll, float fov, float nearPlane, float farPlane, int w, int h); RenderView(const Vector3& pos, const Vector3& dir, const Vector3& up, int w, int h, int room, float nearPlane, float farPlane, float fov); + void fillConstantBuffer(CCameraMatrixBuffer& bufferToFill); void clear(); }; diff --git a/TombEngine/Renderer/Renderer11.h b/TombEngine/Renderer/Renderer11.h index a135d8edc..2429c5a5f 100644 --- a/TombEngine/Renderer/Renderer11.h +++ b/TombEngine/Renderer/Renderer11.h @@ -555,9 +555,10 @@ namespace TEN::Renderer void DrawEffect(RenderView& view, RendererEffect* effect, RendererPass rendererPass); void DrawSplashes(RenderView& view); void DrawSprites(RenderView& view); + void DrawDisplaySprites(RenderView& view); void DrawSortedFaces(RenderView& view); void DrawLines3D(RenderView& view); - void DrawLines2D(); + void DrawLinesIn2DSpace(); void DrawOverlays(RenderView& view); void DrawRopes(RenderView& view); void DrawBats(RenderView& view); @@ -745,8 +746,9 @@ namespace TEN::Renderer std::optional Get2DPosition(const Vector3& pos) const; Vector3 GetAbsEntityBonePosition(int itemNumber, int jointIndex, const Vector3& relOffset = Vector3::Zero); - void DrawSpriteIn2DSpace(GAME_OBJECT_ID spriteID, unsigned int spriteIndex, const Vector2& pos2D, short orient2D, - const Vector4& color, const Vector2& size); + void AddDisplaySprite(const RendererSprite& sprite, const Vector2& pos2D, short orient, const Vector2& size, const Vector4& color, + int priority, BLEND_MODES blendMode, const Vector2& aspectCorrection, RenderView& renderView); + void CollectDisplaySprites(RenderView& renderView); }; extern Renderer11 g_Renderer; diff --git a/TombEngine/Renderer/Renderer11Compatibility.cpp b/TombEngine/Renderer/Renderer11Compatibility.cpp index 8f0e1a75a..c77b4a2d5 100644 --- a/TombEngine/Renderer/Renderer11Compatibility.cpp +++ b/TombEngine/Renderer/Renderer11Compatibility.cpp @@ -164,8 +164,8 @@ namespace TEN::Renderer m_spritesTextures.resize(g_Level.SpritesTextures.size()); for (int i = 0; i < g_Level.SpritesTextures.size(); i++) { - TEXTURE *texture = &g_Level.SpritesTextures[i]; - m_spritesTextures[i] = Texture2D(m_device.Get(), texture->colorMapData.data(), (int)texture->colorMapData.size()); + auto& texture = g_Level.SpritesTextures[i]; + m_spritesTextures[i] = Texture2D(m_device.Get(), texture.colorMapData.data(), (int)texture.colorMapData.size()); } if (m_spritesTextures.size() > 0) diff --git a/TombEngine/Renderer/Renderer11Draw.cpp b/TombEngine/Renderer/Renderer11Draw.cpp index cb1936c34..173fa39ef 100644 --- a/TombEngine/Renderer/Renderer11Draw.cpp +++ b/TombEngine/Renderer/Renderer11Draw.cpp @@ -372,7 +372,7 @@ namespace TEN::Renderer } } - void Renderer11::DrawLines2D() + void Renderer11::DrawLinesIn2DSpace() { SetBlendMode(BLENDMODE_OPAQUE); SetDepthState(DEPTH_STATE_READ_ONLY_ZBUFFER); @@ -539,9 +539,7 @@ namespace TEN::Renderer void Renderer11::DrawBats(RenderView& view) { if (!Objects[ID_BATS_EMITTER].loaded) - { return; - } RendererMesh* mesh = GetMesh(Objects[ID_BATS_EMITTER].meshIndex + (GlobalCounter & 3)); @@ -607,47 +605,43 @@ namespace TEN::Renderer } } } - void Renderer11::DrawScarabs(RenderView& view) { if (!Objects[ID_LITTLE_BEETLE].loaded) - { return; - } - RendererMesh* mesh = GetMesh(Objects[ID_LITTLE_BEETLE].meshIndex + ((Wibble >> 2) % 2)); - - int littleBeetlesCount = 0; + const auto& mesh = *GetMesh(Objects[ID_LITTLE_BEETLE].meshIndex + ((Wibble >> 2) % 2)); + unsigned int beetleCount = 0; for (int i = 0; i < TEN::Entities::TR4::NUM_BEETLES; i++) { - auto* beetle = &TEN::Entities::TR4::BeetleSwarm[i]; + const auto& beetle = TEN::Entities::TR4::BeetleSwarm[i]; - if (beetle->On) + if (beetle.On) { - RendererRoom& room = m_rooms[beetle->RoomNumber]; + auto& room = m_rooms[beetle.RoomNumber]; - Matrix translation = Matrix::CreateTranslation(beetle->Pose.Position.x, beetle->Pose.Position.y, beetle->Pose.Position.z); - Matrix rotation = beetle->Pose.Orientation.ToRotationMatrix(); - Matrix world = rotation * translation; + auto tMatrix = Matrix::CreateTranslation(beetle.Pose.Position.x, beetle.Pose.Position.y, beetle.Pose.Position.z); + auto rotMatrix = beetle.Pose.Orientation.ToRotationMatrix(); + auto worldMatrix = rotMatrix * tMatrix; - m_stInstancedStaticMeshBuffer.StaticMeshes[littleBeetlesCount].World = world; - m_stInstancedStaticMeshBuffer.StaticMeshes[littleBeetlesCount].Ambient = room.AmbientLight; - m_stInstancedStaticMeshBuffer.StaticMeshes[littleBeetlesCount].Color = Vector4::One; - m_stInstancedStaticMeshBuffer.StaticMeshes[littleBeetlesCount].LightMode = mesh->LightMode; - BindInstancedStaticLights(room.LightsToDraw, littleBeetlesCount); + m_stInstancedStaticMeshBuffer.StaticMeshes[beetleCount].World = worldMatrix; + m_stInstancedStaticMeshBuffer.StaticMeshes[beetleCount].Ambient = room.AmbientLight; + m_stInstancedStaticMeshBuffer.StaticMeshes[beetleCount].Color = Vector4::One; + m_stInstancedStaticMeshBuffer.StaticMeshes[beetleCount].LightMode = mesh.LightMode; + BindInstancedStaticLights(room.LightsToDraw, beetleCount); - littleBeetlesCount++; + beetleCount++; } } - if (littleBeetlesCount > 0) + if (beetleCount > 0) { m_context->VSSetShader(m_vsInstancedStaticMeshes.Get(), nullptr, 0); m_context->PSSetShader(m_psInstancedStaticMeshes.Get(), nullptr, 0); - UINT stride = sizeof(RendererVertex); - UINT offset = 0; + unsigned int stride = sizeof(RendererVertex); + unsigned int offset = 0; m_context->IASetVertexBuffers(0, 1, m_moveablesVertexBuffer.Buffer.GetAddressOf(), &stride, &offset); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -661,19 +655,17 @@ namespace TEN::Renderer BindConstantBufferVS(CB_INSTANCED_STATICS, m_cbInstancedStaticMeshBuffer.get()); BindConstantBufferPS(CB_INSTANCED_STATICS, m_cbInstancedStaticMeshBuffer.get()); - for (auto& bucket : mesh->Buckets) + for (const auto& bucket : mesh.Buckets) { if (bucket.NumVertices == 0 && bucket.BlendMode == BLEND_MODES::BLENDMODE_OPAQUE) - { continue; - } SetBlendMode(bucket.BlendMode); BindTexture(TEXTURE_COLOR_MAP, &std::get<0>(m_moveablesTextures[bucket.Texture]), SAMPLER_ANISOTROPIC_CLAMP); BindTexture(TEXTURE_NORMAL_MAP, &std::get<1>(m_moveablesTextures[bucket.Texture]), SAMPLER_NONE); - DrawIndexedInstancedTriangles(bucket.NumIndices, littleBeetlesCount, bucket.StartIndex, 0); + DrawIndexedInstancedTriangles(bucket.NumIndices, beetleCount, bucket.StartIndex, 0); m_numStaticsDrawCalls++; } @@ -1418,15 +1410,15 @@ namespace TEN::Renderer void Renderer11::RenderScene(ID3D11RenderTargetView* target, ID3D11DepthStencilView* depthTarget, RenderView& view) { - ResetDebugVariables(); - m_Locked = false; - using ns = std::chrono::nanoseconds; using get_time = std::chrono::steady_clock; - ScriptInterfaceLevel* level = g_GameFlow->GetLevel(CurrentLevel); + ResetDebugVariables(); + m_Locked = false; + + auto& level = *g_GameFlow->GetLevel(CurrentLevel); - // Prepare the scene to draw + // Prepare scene to draw. auto time1 = std::chrono::high_resolution_clock::now(); CollectRooms(view, false); auto timeRoomsCollector = std::chrono::high_resolution_clock::now(); @@ -1446,39 +1438,38 @@ namespace TEN::Renderer m_timeUpdate = (std::chrono::duration_cast(time2 - time1)).count() / 1000000; time1 = time2; - // Reset GPU state + // Reset GPU state. SetBlendMode(BLENDMODE_OPAQUE, true); SetDepthState(DEPTH_STATE_WRITE_ZBUFFER, true); SetCullMode(CULL_MODE_CCW, true); - // Bind and clear render target + // Bind and clear render target. m_context->ClearRenderTargetView(m_renderTarget.RenderTargetView.Get(), Colors::Black); m_context->ClearDepthStencilView(m_renderTarget.DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); m_context->ClearRenderTargetView(m_depthMap.RenderTargetView.Get(), Colors::White); m_context->ClearDepthStencilView(m_depthMap.DepthStencilView.Get(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); - ID3D11RenderTargetView* m_pRenderViews[2]; - m_pRenderViews[0] = m_renderTarget.RenderTargetView.Get(); - m_pRenderViews[1] = m_depthMap.RenderTargetView.Get(); - m_context->OMSetRenderTargets(2, &m_pRenderViews[0], m_renderTarget.DepthStencilView.Get()); + ID3D11RenderTargetView* pRenderViewPtrs[2]; + pRenderViewPtrs[0] = m_renderTarget.RenderTargetView.Get(); + pRenderViewPtrs[1] = m_depthMap.RenderTargetView.Get(); + m_context->OMSetRenderTargets(2, &pRenderViewPtrs[0], m_renderTarget.DepthStencilView.Get()); m_context->RSSetViewports(1, &view.Viewport); ResetScissor(); - // The camera constant buffer contains matrices, camera position, fog values and other - // things that are shared for all shaders + // Camera constant buffer contains matrices, camera position, fog values, and other things that are shared for all shaders. CCameraMatrixBuffer cameraConstantBuffer; view.fillConstantBuffer(cameraConstantBuffer); cameraConstantBuffer.Frame = GlobalCounter; cameraConstantBuffer.CameraUnderwater = g_Level.Rooms[cameraConstantBuffer.RoomNumber].flags & ENV_FLAG_WATER; - if (level->GetFogEnabled()) + if (level.GetFogEnabled()) { - auto fogCol = level->GetFogColor(); - cameraConstantBuffer.FogColor = Vector4(fogCol.GetR() / 255.0f, fogCol.GetG() / 255.0f, fogCol.GetB() / 255.0f, 1.0f); - cameraConstantBuffer.FogMinDistance = level->GetFogMinDistance(); - cameraConstantBuffer.FogMaxDistance = level->GetFogMaxDistance(); + auto fogColor = level.GetFogColor(); + cameraConstantBuffer.FogColor = Vector4(fogColor.GetR() / 255.0f, fogColor.GetG() / 255.0f, fogColor.GetB() / 255.0f, 1.0f); + cameraConstantBuffer.FogMinDistance = level.GetFogMinDistance(); + cameraConstantBuffer.FogMaxDistance = level.GetFogMaxDistance(); } else { @@ -1502,10 +1493,10 @@ namespace TEN::Renderer BindConstantBufferVS(CB_CAMERA, m_cbCameraMatrices.get()); BindConstantBufferPS(CB_CAMERA, m_cbCameraMatrices.get()); - // Draw the horizon and the sky + // Draw horizon and sky. DrawHorizonAndSky(view, m_renderTarget.DepthStencilView.Get()); - // Draw opaque and alpha test faces + // Draw opaque and alpha faces. DrawRooms(view, RendererPass::Opaque); DrawItems(view, RendererPass::Opaque); DrawStatics(view, RendererPass::Opaque); @@ -1518,11 +1509,10 @@ namespace TEN::Renderer DrawLocusts(view); DrawDebris(view, RendererPass::Opaque); - m_context->OMSetRenderTargets(1, m_renderTarget.RenderTargetView.GetAddressOf(), - m_renderTarget.DepthStencilView.Get()); + m_context->OMSetRenderTargets(1, m_renderTarget.RenderTargetView.GetAddressOf(), m_renderTarget.DepthStencilView.Get()); - // Do special effects and weather - // NOTE: functions here just fill the sprites to draw array + // Prepare special effects and weather. + // NOTE: Functions here merely fill array of sprites to draw. DrawFires(view); DrawSmokes(view); DrawSmokeParticles(view); @@ -1545,11 +1535,19 @@ namespace TEN::Renderer DrawStreamers(view); DrawLaserBarriers(view); - // Here is where we actually output sprites + // Output sprites. DrawSprites(view); DrawLines3D(view); - // Draw immediately additive and unsorted blended faces, and collect all sorted blend modes faces for later + // Collect all sorted blend modes faces for later. + DrawRooms(view, RendererPass::CollectSortedFaces); + DrawItems(view, RendererPass::CollectSortedFaces); + DrawStatics(view, RendererPass::CollectSortedFaces); + + // Draw all sorted blend mode faces collected in previous steps. + DrawSortedFaces(view); + + // Draw immediate transparent faces (i.e. additive) DrawRooms(view, RendererPass::Transparent); DrawItems(view, RendererPass::Transparent); DrawStatics(view, RendererPass::Transparent); @@ -1558,18 +1556,20 @@ namespace TEN::Renderer DrawGunFlashes(view); DrawBaddyGunflashes(view); - // Draw all sorted blend mode faces collected in the previous steps - DrawSortedFaces(view); - + // Draw post-process effects (cinematic bars, fade, flash, HDR, tone mapping, etc.). DrawPostprocess(target, depthTarget, view); - // Draw GUI stuff at the end - DrawLines2D(); + // Draw GUI elements at end. + DrawLinesIn2DSpace(); // Draw HUD. g_Hud.Draw(*LaraItem); - // Draw binoculars or lasersight + // Draw display sprites sorted by priority. + CollectDisplaySprites(view); + DrawDisplaySprites(view); + + // Draw binoculars or lasersight. DrawOverlays(view); time2 = std::chrono::high_resolution_clock::now(); @@ -1876,7 +1876,8 @@ namespace TEN::Renderer for (auto& bucket : refMesh->Buckets) { - if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ (rendererPass == RendererPass::Transparent))) + if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ + (rendererPass == RendererPass::Transparent))) { continue; } @@ -1898,9 +1899,8 @@ namespace TEN::Renderer { SetBlendMode(bucket.BlendMode); SetAlphaTest( - bucket.BlendMode == BLENDMODE_ALPHATEST ? ALPHA_TEST_GREATER_THAN : ALPHA_TEST_NONE, - ALPHA_TEST_THRESHOLD - ); + (bucket.BlendMode == BLENDMODE_ALPHATEST) ? ALPHA_TEST_GREATER_THAN : ALPHA_TEST_NONE, + ALPHA_TEST_THRESHOLD); } else { @@ -1924,7 +1924,7 @@ namespace TEN::Renderer } // Collect sorted blend modes faces ordered by room, if transparent pass - if (rendererPass == RendererPass::Transparent) + if (rendererPass == RendererPass::CollectSortedFaces) { Vector3 cameraPosition = Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z); @@ -1940,11 +1940,6 @@ namespace TEN::Renderer for (auto& bucket : mesh->Buckets) { - if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ (rendererPass == RendererPass::Transparent))) - { - continue; - } - if (bucket.NumVertices == 0) { continue; @@ -1989,19 +1984,19 @@ namespace TEN::Renderer UINT stride = sizeof(RendererVertex); UINT offset = 0; - // Bind vertex and index buffer + // Bind vertex and index buffer. m_context->IASetVertexBuffers(0, 1, m_roomsVertexBuffer.Buffer.GetAddressOf(), &stride, &offset); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetInputLayout(m_inputLayout.Get()); m_context->IASetIndexBuffer(m_roomsIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); - // Bind pixel shaders + // Bind pixel shaders. m_context->PSSetShader(m_psRooms.Get(), nullptr, 0); BindConstantBufferVS(CB_ROOM, m_cbRoom.get()); BindConstantBufferPS(CB_ROOM, m_cbRoom.get()); - // Bind caustics texture + // Bind caustics texture. if (!m_sprites.empty()) { int nmeshes = -Objects[ID_CAUSTICS_TEXTURES].nmeshes; @@ -2009,13 +2004,13 @@ namespace TEN::Renderer int causticsFrame = std::min(nmeshes ? meshIndex + ((GlobalCounter) % nmeshes) : meshIndex, (int)m_sprites.size()); BindTexture(TEXTURE_CAUSTICS, m_sprites[causticsFrame].Texture, SAMPLER_ANISOTROPIC_CLAMP); - // Strange packing due to particular HLSL 16 bytes alignment requirements + // NOTE: Strange packing due to particular HLSL 16 bytes alignment requirements. RendererSprite* causticsSprite = &m_sprites[causticsFrame]; m_stRoom.CausticsStartUV = causticsSprite->UV[0]; m_stRoom.CausticsScale = Vector2(causticsSprite->Width / (float)causticsSprite->Texture->Width, causticsSprite->Height / (float)causticsSprite->Texture->Height); } - // Set shadow map data and bind shadow map texture + // Set shadow map data and bind shadow map texture. if (m_shadowLight != nullptr) { memcpy(&m_stShadowMap.Light, m_shadowLight, sizeof(ShaderLight)); @@ -2071,14 +2066,15 @@ namespace TEN::Renderer continue; } - if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ (rendererPass == RendererPass::Transparent))) + if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ + (rendererPass == RendererPass::Transparent || rendererPass == RendererPass::CollectSortedFaces))) { continue; } - if (DoesBlendModeRequireSorting(bucket.BlendMode)) + if (rendererPass == RendererPass::CollectSortedFaces && DoesBlendModeRequireSorting(bucket.BlendMode)) { - // Collect transparent faces + // Collect transparent faces. for (int j = 0; j < bucket.Polygons.size(); j++) { RendererPolygon* p = &bucket.Polygons[j]; @@ -2178,20 +2174,20 @@ namespace TEN::Renderer void Renderer11::DrawHorizonAndSky(RenderView& renderView, ID3D11DepthStencilView* depthTarget) { - ScriptInterfaceLevel* level = g_GameFlow->GetLevel(CurrentLevel); + auto* levelPtr = g_GameFlow->GetLevel(CurrentLevel); bool anyOutsideRooms = false; for (int k = 0; k < renderView.RoomsToDraw.size(); k++) { - ROOM_INFO* nativeRoom = &g_Level.Rooms[renderView.RoomsToDraw[k]->RoomNumber]; - if (nativeRoom->flags & ENV_FLAG_OUTSIDE) + const auto& nativeRoom = g_Level.Rooms[renderView.RoomsToDraw[k]->RoomNumber]; + if (nativeRoom.flags & ENV_FLAG_OUTSIDE) { anyOutsideRooms = true; break; } } - if (!level->Horizon || !anyOutsideRooms) + if (!levelPtr->Horizon || !anyOutsideRooms) return; if (Lara.Control.Look.OpticRange != 0) @@ -2201,7 +2197,7 @@ namespace TEN::Renderer UINT offset = 0; // Draw sky. - Matrix rotation = Matrix::CreateRotationX(PI); + auto rotation = Matrix::CreateRotationX(PI); m_context->VSSetShader(m_vsSky.Get(), nullptr, 0); m_context->PSSetShader(m_psSky.Get(), nullptr, 0); @@ -2221,9 +2217,9 @@ namespace TEN::Renderer { auto weather = TEN::Effects::Environment::Weather; - Matrix translation = Matrix::CreateTranslation(Camera.pos.x + weather.SkyPosition(s) - i * SKY_SIZE, + auto translation = Matrix::CreateTranslation(Camera.pos.x + weather.SkyPosition(s) - i * SKY_SIZE, Camera.pos.y - 1536.0f, Camera.pos.z); - Matrix world = rotation * translation; + auto world = rotation * translation; m_stSky.World = (rotation * translation); m_stSky.Color = weather.SkyColor(s); @@ -2239,7 +2235,7 @@ namespace TEN::Renderer m_context->ClearDepthStencilView(depthTarget, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1, 0); - // Draw horizon + // Draw horizon. if (m_moveableObjects[ID_HORIZON].has_value()) { m_context->IASetVertexBuffers(0, 1, m_moveablesVertexBuffer.Buffer.GetAddressOf(), &stride, &offset); @@ -2247,7 +2243,7 @@ namespace TEN::Renderer m_context->IASetInputLayout(m_inputLayout.Get()); m_context->IASetIndexBuffer(m_moveablesIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); - RendererObject& moveableObj = *m_moveableObjects[ID_HORIZON]; + auto& moveableObj = *m_moveableObjects[ID_HORIZON]; m_stSky.World = Matrix::CreateTranslation(Camera.pos.x, Camera.pos.y, Camera.pos.z); m_stSky.Color = Vector4::One; @@ -2259,9 +2255,9 @@ namespace TEN::Renderer for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++) { - RendererMesh* mesh = moveableObj.ObjectMeshes[k]; + auto* meshPtr = moveableObj.ObjectMeshes[k]; - for (auto& bucket : mesh->Buckets) + for (auto& bucket : meshPtr->Buckets) { if (bucket.NumVertices == 0) continue; @@ -2271,11 +2267,11 @@ namespace TEN::Renderer BindTexture(TEXTURE_NORMAL_MAP, &std::get<1>(m_moveablesTextures[bucket.Texture]), SAMPLER_ANISOTROPIC_CLAMP); - // Always render horizon as alpha-blended surface + // Always render horizon as alpha-blended surface. SetBlendMode(bucket.BlendMode == BLEND_MODES::BLENDMODE_ALPHATEST ? BLEND_MODES::BLENDMODE_ALPHABLEND : bucket.BlendMode); SetAlphaTest(ALPHA_TEST_NONE, ALPHA_TEST_THRESHOLD); - // Draw vertices + // Draw vertices. DrawIndexedTriangles(bucket.NumIndices, bucket.StartIndex, 0); m_numMoveablesDrawCalls++; @@ -2283,7 +2279,7 @@ namespace TEN::Renderer } } - // Clear just the Z-buffer so we can start drawing on top of the horizon + // Clear just the Z-buffer to start drawing on top of horizon. m_context->ClearDepthStencilView(depthTarget, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); } @@ -2297,19 +2293,18 @@ namespace TEN::Renderer void Renderer11::DrawMoveableMesh(RendererItem* itemToDraw, RendererMesh* mesh, RendererRoom* room, int boneIndex, RendererPass rendererPass) { - Vector3 cameraPosition = Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z); + auto cameraPos = Camera.pos.ToVector3(); for (auto& bucket : mesh->Buckets) { - if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ (rendererPass == RendererPass::Transparent))) + if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ + (rendererPass == RendererPass::Transparent || rendererPass == RendererPass::CollectSortedFaces))) { continue; } if (bucket.NumVertices == 0) - { continue; - } if (rendererPass == RendererPass::ShadowMap) { @@ -2320,21 +2315,21 @@ namespace TEN::Renderer m_numMoveablesDrawCalls++; } - else if (DoesBlendModeRequireSorting(bucket.BlendMode)) + else if (rendererPass == RendererPass::CollectSortedFaces && DoesBlendModeRequireSorting(bucket.BlendMode)) { // Collect transparent faces for (int j = 0; j < bucket.Polygons.size(); j++) { - RendererPolygon* p = &bucket.Polygons[j]; + auto* polygonPtr = &bucket.Polygons[j]; - // As polygon distance, for moveables, we use the averaged distance - Vector3 centre = Vector3::Transform( - p->centre, itemToDraw->AnimationTransforms[boneIndex] * itemToDraw->World); - int distance = (centre - cameraPosition).Length(); + // Use averaged distance as polygon distance for moveables. + auto centre = Vector3::Transform( + polygonPtr->centre, itemToDraw->AnimationTransforms[boneIndex] * itemToDraw->World); + int distance = (centre - cameraPos).Length(); RendererTransparentFace face; face.type = RendererTransparentFaceType::TRANSPARENT_FACE_MOVEABLE; - face.info.polygon = p; + face.info.polygon = polygonPtr; face.distance = distance; face.info.animated = bucket.Animated; face.info.texture = bucket.Texture; @@ -2362,8 +2357,7 @@ namespace TEN::Renderer SetBlendMode(bucket.BlendMode); SetAlphaTest( bucket.BlendMode == BLENDMODE_ALPHATEST ? ALPHA_TEST_GREATER_THAN : ALPHA_TEST_NONE, - ALPHA_TEST_THRESHOLD - ); + ALPHA_TEST_THRESHOLD); } else { diff --git a/TombEngine/Renderer/Renderer11Draw2D.cpp b/TombEngine/Renderer/Renderer11Draw2D.cpp index 22fea528f..157d1384d 100644 --- a/TombEngine/Renderer/Renderer11Draw2D.cpp +++ b/TombEngine/Renderer/Renderer11Draw2D.cpp @@ -4,6 +4,7 @@ #include "Game/camera.h" #include "Game/control/control.h" #include "Game/spotcam.h" +#include "Game/effects/DisplaySprite.h" #include "Game/effects/weather.h" #include "Game/Lara/lara.h" #include "Game/Setup.h" @@ -12,6 +13,7 @@ #include "Objects/Utils/object_helper.h" #include "Specific/trutils.h" +using namespace TEN::Effects::DisplaySprite; using namespace TEN::Effects::Environment; using namespace TEN::Math; @@ -379,67 +381,77 @@ namespace TEN::Renderer DrawFullScreenQuad(texture, Vector3(fade), true); } - void Renderer11::DrawSpriteIn2DSpace(GAME_OBJECT_ID spriteID, unsigned int spriteIndex, const Vector2& pos2D, short orient2D, - const Vector4& color, const Vector2& size) + void Renderer11::DrawDisplaySprites(RenderView& renderView) { - constexpr auto VERTEX_COUNT = 4; - constexpr auto UV_CONSTRAINTS = std::array - { - Vector2(0.0f), - Vector2(1.0f, 0.0f), - Vector2(1.0f), - Vector2(0.0f, 1.0f) - }; + constexpr auto VERTEX_COUNT = 4; - // Calculate vertex base. - auto halfSize = size / 2; - auto vertexPoints = std::array - { - halfSize, - Vector2(-halfSize.x, halfSize.y), - -halfSize, - Vector2(halfSize.x, -halfSize.y) - }; - - // Transform vertices. - auto rotMatrix = Matrix::CreateRotationZ(TO_RAD(orient2D + ANGLE(180.0f))); // NOTE: +Y is down. - for (auto& vertexPoint : vertexPoints) - { - // Rotate. - vertexPoint = Vector2::Transform(vertexPoint, rotMatrix); - - // Adjust for aspect ratio and convert to NDC. - vertexPoint = TEN::Utils::GetAspectCorrect2DPosition(vertexPoint); - vertexPoint += pos2D; - vertexPoint = TEN::Utils::Convert2DPositionToNDC(vertexPoint); - } - - // Define renderer vertices. - auto vertices = std::array{}; - for (int i = 0; i < vertices.size(); i++) - { - vertices[i].Position = Vector3(vertexPoints[i]); - vertices[i].UV = UV_CONSTRAINTS[i]; - vertices[i].Color = color; - } - - SetBlendMode(BLENDMODE_ALPHABLEND); + if (renderView.DisplaySpritesToDraw.empty()) + return; m_context->VSSetShader(m_vsFullScreenQuad.Get(), nullptr, 0); m_context->PSSetShader(m_psFullScreenQuad.Get(), nullptr, 0); - const auto& spritePtr = m_sprites[Objects[spriteID].meshIndex + spriteIndex]; - auto* texturePtr = spritePtr.Texture->ShaderResourceView.Get(); - m_context->PSSetShaderResources(0, 1, &texturePtr); - - auto* sampler = m_states->AnisotropicClamp(); - m_context->PSSetSamplers(0, 1, &sampler); - m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetInputLayout(m_inputLayout.Get()); - m_primitiveBatch->Begin(); - m_primitiveBatch->DrawQuad(vertices[0], vertices[1], vertices[2], vertices[3]); + Texture2D* texture2DPtr = nullptr; + for (const auto& spriteToDraw : renderView.DisplaySpritesToDraw) + { + if (texture2DPtr == nullptr) + { + m_primitiveBatch->Begin(); + + BindTexture(TEXTURE_COLOR_MAP, spriteToDraw.SpritePtr->Texture, SAMPLER_ANISOTROPIC_CLAMP); + SetBlendMode(spriteToDraw.BlendMode); + } + else if (texture2DPtr != spriteToDraw.SpritePtr->Texture || lastBlendMode != spriteToDraw.BlendMode) + { + m_primitiveBatch->End(); + m_primitiveBatch->Begin(); + + BindTexture(TEXTURE_COLOR_MAP, spriteToDraw.SpritePtr->Texture, SAMPLER_ANISOTROPIC_CLAMP); + SetBlendMode(spriteToDraw.BlendMode); + } + + // Calculate vertex base. + auto vertices = std::array + { + spriteToDraw.Size / 2, + Vector2(-spriteToDraw.Size.x, spriteToDraw.Size.y) / 2, + -spriteToDraw.Size / 2, + Vector2(spriteToDraw.Size.x, -spriteToDraw.Size.y) / 2 + }; + + // Transform vertices. + // NOTE: Must rotate 180 degrees to account for +Y being down. + auto rotMatrix = Matrix::CreateRotationZ(TO_RAD(spriteToDraw.Orientation + ANGLE(180.0f))); + for (auto& vertex : vertices) + { + // Rotate. + vertex = Vector2::Transform(vertex, rotMatrix); + + // Apply aspect correction. + vertex *= spriteToDraw.AspectCorrection; + + // Offset to position and convert to NDC. + vertex += spriteToDraw.Position; + vertex = TEN::Utils::Convert2DPositionToNDC(vertex); + } + + // Define renderer vertices. + auto rVertices = std::array{}; + for (int i = 0; i < rVertices.size(); i++) + { + rVertices[i].Position = Vector3(vertices[i]); + rVertices[i].UV = spriteToDraw.SpritePtr->UV[i]; + rVertices[i].Color = Vector4(spriteToDraw.Color.x, spriteToDraw.Color.y, spriteToDraw.Color.z, spriteToDraw.Color.w); + } + + m_primitiveBatch->DrawQuad(rVertices[0], rVertices[1], rVertices[2], rVertices[3]); + + texture2DPtr = spriteToDraw.SpritePtr->Texture; + } + m_primitiveBatch->End(); } @@ -453,11 +465,11 @@ namespace TEN::Renderer if (fit) { - ID3D11Texture2D* texture2D; - texture->GetResource(reinterpret_cast(&texture2D)); + ID3D11Texture2D* texture2DPtr; + texture->GetResource(reinterpret_cast(&texture2DPtr)); auto desc = D3D11_TEXTURE2D_DESC(); - texture2D->GetDesc(&desc); + texture2DPtr->GetDesc(&desc); float screenAspect = float(m_screenWidth) / float(m_screenHeight); float imageAspect = float(desc.Width) / float(desc.Height); @@ -541,7 +553,7 @@ namespace TEN::Renderer } } - Vector2 scale = Vector2(sprite->Width / (float)sprite->Texture->Width, sprite->Height / (float)sprite->Texture->Height); + auto scale = Vector2(sprite->Width / (float)sprite->Texture->Width, sprite->Height / (float)sprite->Texture->Height); uvStart.x = uvStart.x * scale.x + sprite->UV[0].x; uvStart.y = uvStart.y * scale.y + sprite->UV[0].y; uvEnd.x = uvEnd.x * scale.x + sprite->UV[0].x; @@ -581,7 +593,7 @@ namespace TEN::Renderer m_context->PSSetShader(m_psFullScreenQuad.Get(), nullptr, 0); m_context->PSSetShaderResources(0, 1, &texture); - ID3D11SamplerState* sampler = m_states->AnisotropicClamp(); + auto* sampler = m_states->AnisotropicClamp(); m_context->PSSetSamplers(0, 1, &sampler); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); @@ -591,4 +603,165 @@ namespace TEN::Renderer m_primitiveBatch->DrawQuad(vertices[0], vertices[1], vertices[2], vertices[3]); m_primitiveBatch->End(); } + + void Renderer11::AddDisplaySprite(const RendererSprite& sprite, const Vector2& pos2D, short orient, const Vector2& size, const Vector4& color, + int priority, BLEND_MODES blendMode, const Vector2& aspectCorrection, RenderView& renderView) + { + auto spriteToDraw = RendererDisplaySpriteToDraw{}; + + spriteToDraw.SpritePtr = &sprite; + spriteToDraw.Position = pos2D; + spriteToDraw.Orientation = orient; + spriteToDraw.Size = size; + spriteToDraw.Color = color; + spriteToDraw.Priority = priority; + spriteToDraw.BlendMode = blendMode; + spriteToDraw.AspectCorrection = aspectCorrection; + + renderView.DisplaySpritesToDraw.push_back(spriteToDraw); + } + + void Renderer11::CollectDisplaySprites(RenderView& renderView) + { + constexpr auto DISPLAY_SPACE_ASPECT = SCREEN_SPACE_RES.x / SCREEN_SPACE_RES.y; + + // Calculate screen aspect ratio. + auto screenRes = GetScreenResolution().ToVector2(); + float screenResAspect = screenRes.x / screenRes.y; + + // Calculate aspect ratio correction base. + auto aspectCorrectionBase = screenResAspect / DISPLAY_SPACE_ASPECT; + + for (const auto& displaySprite : DisplaySprites) + { + const auto& sprite = m_sprites[Objects[displaySprite.ObjectID].meshIndex + displaySprite.SpriteID]; + + // Calculate sprite aspect ratio. + float spriteAspect = (float)sprite.Width / (float)sprite.Height; + + auto halfSize = Vector2::Zero; + auto aspectCorrection = Vector2::One; + + // Calculate size and aspect correction. + switch (displaySprite.ScaleMode) + { + default: + case DisplaySpriteScaleMode::Fit: + if (screenResAspect >= spriteAspect) + { + halfSize = (Vector2(SCREEN_SPACE_RES.y) * displaySprite.Scale) / 2; + halfSize.x *= (spriteAspect >= 1.0f) ? spriteAspect : (1.0f / spriteAspect); + + aspectCorrection.x = 1.0f / aspectCorrectionBase; + } + else + { + halfSize = (Vector2(SCREEN_SPACE_RES.x) * displaySprite.Scale) / 2; + halfSize.y *= (spriteAspect >= 1.0f) ? (1.0f / spriteAspect) : spriteAspect; + + aspectCorrection.y = aspectCorrectionBase; + } + break; + + case DisplaySpriteScaleMode::Fill: + if (screenResAspect >= spriteAspect) + { + halfSize = (Vector2(SCREEN_SPACE_RES.x) * displaySprite.Scale) / 2; + halfSize.y *= (spriteAspect >= 1.0f) ? (1.0f / spriteAspect) : spriteAspect; + + aspectCorrection.y = aspectCorrectionBase; + } + else + { + halfSize = (Vector2(SCREEN_SPACE_RES.y) * displaySprite.Scale) / 2; + halfSize.x *= (spriteAspect >= 1.0f) ? spriteAspect : (1.0f / spriteAspect); + + aspectCorrection.x = 1.0f / aspectCorrectionBase; + } + break; + + case DisplaySpriteScaleMode::Stretch: + if (screenResAspect >= 1.0f) + { + halfSize = (SCREEN_SPACE_RES.x * displaySprite.Scale) / 2; + halfSize.y *= (screenResAspect >= 1.0f) ? (1.0f / screenResAspect) : screenResAspect; + + aspectCorrection.y = aspectCorrectionBase; + } + else + { + halfSize = (Vector2(SCREEN_SPACE_RES.y) * displaySprite.Scale) / 2; + halfSize.x *= (screenResAspect >= 1.0f) ? (1.0f / screenResAspect) : screenResAspect; + + aspectCorrection.x = 1.0f / aspectCorrectionBase; + } + break; + } + + // Calculate position offset. + auto offset = Vector2::Zero; + switch (displaySprite.AlignMode) + { + default: + case DisplaySpriteAlignMode::Center: + break; + + case DisplaySpriteAlignMode::CenterTop: + offset = Vector2(0.0f, halfSize.y); + break; + + case DisplaySpriteAlignMode::CenterBottom: + offset = Vector2(0.0f, -halfSize.y); + break; + + case DisplaySpriteAlignMode::CenterLeft: + offset = Vector2(halfSize.x, 0.0f); + break; + + case DisplaySpriteAlignMode::CenterRight: + offset = Vector2(-halfSize.x, 0.0f); + break; + + case DisplaySpriteAlignMode::TopLeft: + offset = Vector2(halfSize.x, halfSize.y); + break; + + case DisplaySpriteAlignMode::TopRight: + offset = Vector2(-halfSize.x, halfSize.y); + break; + + case DisplaySpriteAlignMode::BottomLeft: + offset = Vector2(halfSize.x, -halfSize.y); + break; + + case DisplaySpriteAlignMode::BottomRight: + offset = Vector2(-halfSize.x, -halfSize.y); + break; + } + offset *= aspectCorrection; + + AddDisplaySprite( + sprite, + displaySprite.Position + offset, + displaySprite.Orientation, + halfSize * 2, + displaySprite.Color, + displaySprite.Priority, + displaySprite.BlendMode, + aspectCorrection, + renderView); + } + + std::sort( + renderView.DisplaySpritesToDraw.begin(), renderView.DisplaySpritesToDraw.end(), + [](const RendererDisplaySpriteToDraw& spriteToDraw0, const RendererDisplaySpriteToDraw& spriteToDraw1) + { + // Same priority; sort by blend mode. + if (spriteToDraw0.Priority == spriteToDraw1.Priority) + return (spriteToDraw0.BlendMode < spriteToDraw1.BlendMode); + + // Sort by priority. + return (spriteToDraw0.Priority < spriteToDraw1.Priority); + }); + } } diff --git a/TombEngine/Renderer/Renderer11DrawEffect.cpp b/TombEngine/Renderer/Renderer11DrawEffect.cpp index dcf9d342b..4d5bf5824 100644 --- a/TombEngine/Renderer/Renderer11DrawEffect.cpp +++ b/TombEngine/Renderer/Renderer11DrawEffect.cpp @@ -28,6 +28,7 @@ #include "Math/Math.h" #include "Objects/TR5/Trap/LaserBarrier.h" #include "Objects/Utils/object_helper.h" +#include "Renderer/RendererSprite2D.h" #include "Renderer/RendererSprites.h" #include "Renderer/Quad/RenderQuad.h" #include "Specific/level.h" @@ -1191,7 +1192,7 @@ namespace TEN::Renderer currentSpriteBucket.SpritesToDraw.clear(); } - //HACK: prevent sprites like Explosionsmoke which have blendmode_subtractive from having laser effects + // HACK: Prevent sprites like Explosionsmoke which have blendmode_subtractive from having laser effects. if (DoesBlendModeRequireSorting(rDrawSprite.BlendMode) && currentSpriteBucket.RenderType) { // If blend mode requires sorting, save sprite for later. @@ -1205,7 +1206,7 @@ namespace TEN::Renderer for (int j = 0; j < view.RoomsToDraw.size(); j++) { - short roomNumber = view.RoomsToDraw[j]->RoomNumber; + int roomNumber = view.RoomsToDraw[j]->RoomNumber; if (g_Level.Rooms[roomNumber].Active() && IsPointInRoom(Vector3i(rDrawSprite.pos), roomNumber)) { view.RoomsToDraw[j]->TransparentFacesToDraw.push_back(face); @@ -1362,8 +1363,8 @@ namespace TEN::Renderer UINT stride = sizeof(RendererVertex); UINT offset = 0; - m_context->VSSetShader(m_vsSprites.Get(), NULL, 0); - m_context->PSSetShader(m_psSprites.Get(), NULL, 0); + m_context->VSSetShader(m_vsSprites.Get(), nullptr, 0); + m_context->PSSetShader(m_psSprites.Get(), nullptr, 0); m_transparentFacesVertexBuffer.Update(m_context.Get(), m_transparentFacesVertices, 0, (int)m_transparentFacesVertices.size()); @@ -1398,7 +1399,7 @@ namespace TEN::Renderer void Renderer11::DrawEffect(RenderView& view, RendererEffect* effect, RendererPass rendererPass) { - RendererRoom const& room = m_rooms[effect->RoomNumber]; + const auto& room = m_rooms[effect->RoomNumber]; m_stStatic.World = effect->World; m_stStatic.Color = effect->Color; @@ -1418,16 +1419,19 @@ namespace TEN::Renderer SetAlphaTest(ALPHA_TEST_GREATER_THAN, ALPHA_TEST_THRESHOLD); } - RendererMesh* mesh = effect->Mesh; - BLEND_MODES lastBlendMode = BLEND_MODES::BLENDMODE_UNSET; + auto* meshPtr = effect->Mesh; + auto lastBlendMode = BLEND_MODES::BLENDMODE_UNSET; - for (auto& bucket : mesh->Buckets) + for (auto& bucket : meshPtr->Buckets) { if (bucket.NumVertices == 0) continue; - if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ (rendererPass == RendererPass::Transparent))) + if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ + (rendererPass == RendererPass::Transparent))) + { continue; + } BindTexture(TEXTURE_COLOR_MAP, &std::get<0>(m_moveablesTextures[bucket.Texture]), SAMPLER_ANISOTROPIC_CLAMP); BindTexture(TEXTURE_NORMAL_MAP, &std::get<1>(m_moveablesTextures[bucket.Texture]), SAMPLER_ANISOTROPIC_CLAMP); @@ -1436,13 +1440,12 @@ namespace TEN::Renderer DrawIndexedTriangles(bucket.NumIndices, bucket.StartIndex, 0); } - } void Renderer11::DrawEffects(RenderView& view, RendererPass rendererPass) { - m_context->VSSetShader(m_vsStatics.Get(), NULL, 0); - m_context->PSSetShader(m_psStatics.Get(), NULL, 0); + m_context->VSSetShader(m_vsStatics.Get(), nullptr, 0); + m_context->PSSetShader(m_psStatics.Get(), nullptr, 0); BindConstantBufferVS(CB_STATIC, m_cbStatic.get()); BindConstantBufferPS(CB_STATIC, m_cbStatic.get()); @@ -1455,23 +1458,23 @@ namespace TEN::Renderer m_context->IASetInputLayout(m_inputLayout.Get()); m_context->IASetIndexBuffer(m_moveablesIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); - for (auto room : view.RoomsToDraw) + for (auto* roomPtr : view.RoomsToDraw) { - for (auto effect : room->EffectsToDraw) + for (auto* effectPtr : roomPtr->EffectsToDraw) { - RendererRoom const& room = m_rooms[effect->RoomNumber]; - ObjectInfo* obj = &Objects[effect->ObjectNumber]; + const auto& room = m_rooms[effectPtr->RoomNumber]; + const auto& object = Objects[effectPtr->ObjectNumber]; - if (obj->drawRoutine && obj->loaded) - DrawEffect(view, effect, rendererPass); + if (object.drawRoutine && object.loaded) + DrawEffect(view, effectPtr, rendererPass); } } } void Renderer11::DrawDebris(RenderView& view, RendererPass rendererPass) { - m_context->VSSetShader(m_vsStatics.Get(), NULL, 0); - m_context->PSSetShader(m_psStatics.Get(), NULL, 0); + m_context->VSSetShader(m_vsStatics.Get(), nullptr, 0); + m_context->PSSetShader(m_psStatics.Get(), nullptr, 0); BindConstantBufferVS(CB_STATIC, m_cbStatic.get()); BindConstantBufferPS(CB_STATIC, m_cbStatic.get()); @@ -1479,18 +1482,21 @@ namespace TEN::Renderer extern std::vector DebrisFragments; std::vector vertices; - BLEND_MODES lastBlendMode = BLEND_MODES::BLENDMODE_UNSET; + auto lastBlendMode = BLEND_MODES::BLENDMODE_UNSET; for (auto deb = DebrisFragments.begin(); deb != DebrisFragments.end(); deb++) { if (deb->active) { - if (!((deb->mesh.blendMode == BLENDMODE_OPAQUE || deb->mesh.blendMode == BLENDMODE_ALPHATEST) ^ (rendererPass == RendererPass::Transparent))) + if (!((deb->mesh.blendMode == BLENDMODE_OPAQUE || deb->mesh.blendMode == BLENDMODE_ALPHATEST) ^ + (rendererPass == RendererPass::Transparent))) + { continue; + } - Matrix translation = Matrix::CreateTranslation(deb->worldPosition.x, deb->worldPosition.y, deb->worldPosition.z); - Matrix rotation = Matrix::CreateFromQuaternion(deb->rotation); - Matrix world = rotation * translation; + auto translation = Matrix::CreateTranslation(deb->worldPosition.x, deb->worldPosition.y, deb->worldPosition.z); + auto rotation = Matrix::CreateFromQuaternion(deb->rotation); + auto world = rotation * translation; m_primitiveBatch->Begin(); diff --git a/TombEngine/Renderer/Renderer11DrawMenu.cpp b/TombEngine/Renderer/Renderer11DrawMenu.cpp index 420ffef9f..08fda4530 100644 --- a/TombEngine/Renderer/Renderer11DrawMenu.cpp +++ b/TombEngine/Renderer/Renderer11DrawMenu.cpp @@ -227,26 +227,31 @@ namespace TEN::Renderer GetNextLinePosition(&y); // Auto targeting - AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTO_TARGET), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 4)); + AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_AUTOMATIC_TARGETING), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 4)); AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableAutoTargeting), PRINTSTRING_COLOR_WHITE, SF(titleOption == 4)); GetNextLinePosition(&y); + // Target highlighter + AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_TARGET_HIGHLIGHTER), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 5)); + AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableTargetHighlighter), PRINTSTRING_COLOR_WHITE, SF(titleOption == 5)); + GetNextLinePosition(&y); + // Vibration - AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_RUMBLE), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 5)); - AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableRumble), PRINTSTRING_COLOR_WHITE, SF(titleOption == 5)); + AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_RUMBLE), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 6)); + AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableRumble), PRINTSTRING_COLOR_WHITE, SF(titleOption == 6)); GetNextLinePosition(&y); // Thumbstick camera - AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_THUMBSTICK_CAMERA), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 6)); - AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableThumbstickCamera), PRINTSTRING_COLOR_WHITE, SF(titleOption == 6)); + AddString(MenuLeftSideEntry, y, g_GameFlow->GetString(STRING_THUMBSTICK_CAMERA), PRINTSTRING_COLOR_ORANGE, SF(titleOption == 7)); + AddString(MenuRightSideEntry, y, Str_Enabled(g_Gui.GetCurrentSettings().Configuration.EnableThumbstickCamera), PRINTSTRING_COLOR_WHITE, SF(titleOption == 7)); GetNextBlockPosition(&y); // Apply - AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_APPLY), PRINTSTRING_COLOR_ORANGE, SF_Center(titleOption == 7)); + AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_APPLY), PRINTSTRING_COLOR_ORANGE, SF_Center(titleOption == 8)); GetNextLinePosition(&y); // Cancel - AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_CANCEL), PRINTSTRING_COLOR_ORANGE, SF_Center(titleOption == 8)); + AddString(MenuCenterEntry, y, g_GameFlow->GetString(STRING_CANCEL), PRINTSTRING_COLOR_ORANGE, SF_Center(titleOption == 9)); break; case Menu::GeneralActions: @@ -562,7 +567,7 @@ namespace TEN::Renderer break; } - DrawLines2D(); + DrawLinesIn2DSpace(); DrawAllStrings(); } diff --git a/TombEngine/Renderer/Renderer11Enums.h b/TombEngine/Renderer/Renderer11Enums.h index e05c36a63..9d1d9fd9b 100644 --- a/TombEngine/Renderer/Renderer11Enums.h +++ b/TombEngine/Renderer/Renderer11Enums.h @@ -42,6 +42,8 @@ enum LIGHT_TYPES enum BLEND_MODES { + BLENDMODE_UNSET = -1, + BLENDMODE_OPAQUE = 0, BLENDMODE_ALPHATEST = 1, BLENDMODE_ADDITIVE = 2, @@ -51,8 +53,7 @@ enum BLEND_MODES BLENDMODE_EXCLUDE = 8, BLENDMODE_SCREEN = 9, BLENDMODE_LIGHTEN = 10, - BLENDMODE_ALPHABLEND = 11, - BLENDMODE_UNSET = -1 + BLENDMODE_ALPHABLEND = 11 }; enum CULL_MODES @@ -205,7 +206,8 @@ enum RendererPass { ShadowMap, Opaque, - Transparent + Transparent, + CollectSortedFaces }; constexpr auto TEXTURE_HEIGHT = 256; diff --git a/TombEngine/Renderer/Renderer11Frame.cpp b/TombEngine/Renderer/Renderer11Frame.cpp index 566ea32fd..fae57bf16 100644 --- a/TombEngine/Renderer/Renderer11Frame.cpp +++ b/TombEngine/Renderer/Renderer11Frame.cpp @@ -19,47 +19,48 @@ using namespace TEN::Math; namespace TEN::Renderer { using TEN::Memory::LinearArrayBuffer; - using std::vector; void Renderer11::CollectRooms(RenderView& renderView, bool onlyRooms) { + constexpr auto VIEW_PORT = Vector4(-1.0f, -1.0f, 1.0f, 1.0f); + m_visitedRoomsStack.clear(); for (int i = 0; i < g_Level.Rooms.size(); i++) { - RendererRoom* room = &m_rooms[i]; + auto& room = m_rooms[i]; - room->ItemsToDraw.clear(); - room->EffectsToDraw.clear(); - room->TransparentFacesToDraw.clear(); - room->StaticsToDraw.clear(); - room->LightsToDraw.clear(); - room->Visited = false; - room->ViewPort = Vector4(-1.0f, -1.0f, 1.0f, 1.0f); + room.ItemsToDraw.clear(); + room.EffectsToDraw.clear(); + room.TransparentFacesToDraw.clear(); + room.StaticsToDraw.clear(); + room.LightsToDraw.clear(); + room.Visited = false; + room.ViewPort = VIEW_PORT; - for (int j = 0; j < room->Doors.size(); j++) + for (auto& door : room.Doors) { - room->Doors[j].Visited = false; - room->Doors[j].InvisibleFromCamera = false; - room->Doors[j].DotProduct = FLT_MAX; + door.Visited = false; + door.InvisibleFromCamera = false; + door.DotProduct = FLT_MAX; } } - GetVisibleRooms(NO_ROOM, renderView.Camera.RoomNumber, Vector4(-1.0f, -1.0f, 1.0f, 1.0f), false, 0, onlyRooms, renderView); + GetVisibleRooms(NO_ROOM, renderView.Camera.RoomNumber, VIEW_PORT, false, 0, onlyRooms, renderView); m_invalidateCache = false; - // Prepare the real DX scissor test rectangle - for (auto room : renderView.RoomsToDraw) + // Prepare real DX scissor test rectangle. + for (auto* roomPtr : renderView.RoomsToDraw) { - room->ClipBounds.left = (room->ViewPort.x + 1.0f) * m_screenWidth * 0.5f; - room->ClipBounds.bottom = (1.0f - room->ViewPort.y) * m_screenHeight * 0.5f; - room->ClipBounds.right = (room->ViewPort.z + 1.0f) * m_screenWidth * 0.5f; - room->ClipBounds.top = (1.0f - room->ViewPort.w) * m_screenHeight * 0.5f; + roomPtr->ClipBounds.left = (roomPtr->ViewPort.x + 1.0f) * m_screenWidth * 0.5f; + roomPtr->ClipBounds.bottom = (1.0f - roomPtr->ViewPort.y) * m_screenHeight * 0.5f; + roomPtr->ClipBounds.right = (roomPtr->ViewPort.z + 1.0f) * m_screenWidth * 0.5f; + roomPtr->ClipBounds.top = (1.0f - roomPtr->ViewPort.w) * m_screenHeight * 0.5f; } - // Collect fog bulbs - vector tempFogBulbs; + // Collect fog bulbs. + std::vector tempFogBulbs; tempFogBulbs.reserve(MAX_FOG_BULBS_DRAW); for (auto& room : m_rooms) @@ -67,12 +68,13 @@ namespace TEN::Renderer if (!g_Level.Rooms[room.RoomNumber].Active()) continue; - for (auto& light : room.Lights) + for (const auto& light : room.Lights) { if (light.Type != LIGHT_TYPE_FOG_BULB) continue; - if (renderView.Camera.Frustum.SphereInFrustum(light.Position, light.Out * 1.2f)) /* Test a bigger radius for avoiding bad clipping */ + // Test bigger radius to avoid bad clipping. + if (renderView.Camera.Frustum.SphereInFrustum(light.Position, light.Out * 1.2f)) { RendererFogBulb bulb; @@ -88,19 +90,17 @@ namespace TEN::Renderer } } + // Sort fog bulbs. std::sort( tempFogBulbs.begin(), tempFogBulbs.end(), - [](RendererFogBulb a, RendererFogBulb b) + [](const RendererFogBulb& bulb0, const RendererFogBulb& bulb1) { - return a.Distance < b.Distance; - } - ); + return bulb0.Distance < bulb1.Distance; + }); for (int i = 0; i < std::min(MAX_FOG_BULBS_DRAW, (int)tempFogBulbs.size()); i++) - { renderView.FogBulbsToDraw.push_back(tempFogBulbs[i]); - } } bool Renderer11::CheckPortal(short parentRoomNumber, RendererDoor* door, Vector4 viewPort, Vector4* clipPort, RenderView& renderView) @@ -296,7 +296,7 @@ namespace TEN::Renderer m_dotProducts++; } - if (door->DotProduct <= 0) + if (door->DotProduct < 0) { door->InvisibleFromCamera = true; continue; diff --git a/TombEngine/Renderer/Renderer11Helper.cpp b/TombEngine/Renderer/Renderer11Helper.cpp index f78061caa..43c71cffb 100644 --- a/TombEngine/Renderer/Renderer11Helper.cpp +++ b/TombEngine/Renderer/Renderer11Helper.cpp @@ -529,14 +529,14 @@ namespace TEN::Renderer gameCamera.Camera.WorldPosition.y, gameCamera.Camera.WorldPosition.z, 1.0f); - auto cameraDirection = Vector4( + auto cameraDir = Vector4( gameCamera.Camera.WorldDirection.x, gameCamera.Camera.WorldDirection.y, gameCamera.Camera.WorldDirection.z, 1.0f); // Point is behind camera; return nullopt. - if ((point - cameraPos).Dot(cameraDirection) < 0.0f) + if ((point - cameraPos).Dot(cameraDir) < 0.0f) return std::nullopt; // Calculate clip space coords. diff --git a/TombEngine/Renderer/RendererSprite2D.h b/TombEngine/Renderer/RendererSprite2D.h new file mode 100644 index 000000000..3dbfbd550 --- /dev/null +++ b/TombEngine/Renderer/RendererSprite2D.h @@ -0,0 +1,22 @@ +#pragma once +#include "Renderer/Renderer11Enums.h" + +namespace TEN::Renderer +{ + struct RendererSprite; + + struct RendererDisplaySpriteToDraw + { + const RendererSprite* SpritePtr = nullptr; + + Vector2 Position = Vector2::Zero; + short Orientation = 0; + Vector2 Size = Vector2::Zero; + Vector4 Color = Vector4::Zero; + + int Priority = 0; + BLEND_MODES BlendMode = BLENDMODE_ALPHABLEND; + + Vector2 AspectCorrection = Vector2::One; + }; +} diff --git a/TombEngine/Scripting/Include/Strings/StringsCommon.h b/TombEngine/Scripting/Include/Strings/StringsCommon.h index cec3f6ced..bbe361cb8 100644 --- a/TombEngine/Scripting/Include/Strings/StringsCommon.h +++ b/TombEngine/Scripting/Include/Strings/StringsCommon.h @@ -1,8 +1,9 @@ -using CallbackDrawString = std::function; + +using CallbackDrawString = std::function< + void( + const std::string&, + D3DCOLOR, + int, // X + int, // X + float, // Scale + int)>; // Flags diff --git a/TombEngine/Scripting/Internal/LanguageScript.h b/TombEngine/Scripting/Internal/LanguageScript.h index 87ed32654..735f796a9 100644 --- a/TombEngine/Scripting/Internal/LanguageScript.h +++ b/TombEngine/Scripting/Internal/LanguageScript.h @@ -79,7 +79,8 @@ #define STRING_SOUND "sound" #define STRING_ENABLE_SOUND "enable_sound" #define STRING_REVERB "reverb" -#define STRING_AUTO_TARGET "auto_target" +#define STRING_AUTOMATIC_TARGETING "automatic_targeting" +#define STRING_TARGET_HIGHLIGHTER "target_highlighter" #define STRING_RUMBLE "rumble" #define STRING_THUMBSTICK_CAMERA "thumbstick_camera" #define STRING_SUBTITLES "subtitles" @@ -167,3 +168,4 @@ #define STRING_MECHANICAL_SCARAB_1 "mechanical_scarab_1" #define STRING_MECHANICAL_SCARAB_2 "mechanical_scarab_2" #define STRING_VEHICLE_ACTIONS "vehicle_actions" +#define STRING_UNLIMITED "unlimited" diff --git a/TombEngine/Scripting/Internal/ReservedScriptNames.h b/TombEngine/Scripting/Internal/ReservedScriptNames.h index a0445137b..c39ffa28d 100644 --- a/TombEngine/Scripting/Internal/ReservedScriptNames.h +++ b/TombEngine/Scripting/Internal/ReservedScriptNames.h @@ -27,6 +27,25 @@ static constexpr char ScriptReserved_Vec3[] = "Vec3"; static constexpr char ScriptReserved_Rotation[] = "Rotation"; static constexpr char ScriptReserved_LevelFunc[] = "LevelFunc"; +// DisplaySprite object +static constexpr char ScriptReserved_DisplaySprite[] = "DisplaySprite"; +static constexpr char ScriptReserved_DisplayStringGetObjectID[] = "GetObjectID"; +static constexpr char ScriptReserved_DisplayStringGetSpriteID[] = "GetSpriteID"; +static constexpr char ScriptReserved_DisplayStringGetPosition[] = "GetPosition"; +static constexpr char ScriptReserved_DisplayStringGetRotation[] = "GetRotation"; +static constexpr char ScriptReserved_DisplayStringGetScale[] = "GetScale"; +static constexpr char ScriptReserved_DisplayStringGetColor[] = "GetColor"; +static constexpr char ScriptReserved_DisplayStringSetObjectID[] = "SetObjectID"; +static constexpr char ScriptReserved_DisplayStringSetSpriteID[] = "SetSpriteID"; +static constexpr char ScriptReserved_DisplayStringSetPosition[] = "SetPosition"; +static constexpr char ScriptReserved_DisplayStringSetRotation[] = "SetRotation"; +static constexpr char ScriptReserved_DisplayStringSetScale[] = "SetScale"; +static constexpr char ScriptReserved_DisplayStringSetColor[] = "SetColor"; +static constexpr char ScriptReserved_DisplaySpriteDraw[] = "Draw"; +static constexpr char ScriptReserved_DisplaySpriteEnum[] = "DisplaySpriteEnum"; +static constexpr char ScriptReserved_DisplaySpriteEnumAlignMode[] = "AlignMode"; +static constexpr char ScriptReserved_DisplaySpriteEnumScaleMode[] = "ScaleMode"; + // Built-in LevelFuncs static constexpr char ScriptReserved_OnStart[] = "OnStart"; static constexpr char ScriptReserved_OnLoad[] = "OnLoad"; @@ -177,6 +196,7 @@ static constexpr char ScriptReserved_EndLevel[] = "EndLevel"; static constexpr char ScriptReserved_SaveGame[] = "SaveGame"; static constexpr char ScriptReserved_LoadGame[] = "LoadGame"; static constexpr char ScriptReserved_DeleteSaveGame[] = "DeleteSaveGame"; +static constexpr char ScriptReserved_DoesSaveGameExist[] = "DoesSaveGameExist"; static constexpr char ScriptReserved_GetSecretCount[] = "GetSecretCount"; static constexpr char ScriptReserved_SetSecretCount[] = "SetSecretCount"; static constexpr char ScriptReserved_SetTotalSecretCount[] = "SetTotalSecretCount"; @@ -234,8 +254,8 @@ static constexpr char ScriptReserved_GetRoomsByTag[] = "GetRoomsByTag"; static constexpr char ScriptReserved_GetRoomByName[] = "GetRoomByName"; static constexpr char ScriptReserved_CalculateDistance[] = "CalculateDistance"; static constexpr char ScriptReserved_CalculateHorizontalDistance[] = "CalculateHorizontalDistance"; -static constexpr char ScriptReserved_ScreenToPercent[] = "ScreenToPercent"; static constexpr char ScriptReserved_PercentToScreen[] = "PercentToScreen"; +static constexpr char ScriptReserved_ScreenToPercent[] = "ScreenToPercent"; static constexpr char ScriptReserved_HasLineOfSight[] = "HasLineOfSight"; static constexpr char ScriptReserved_AddCallback[] = "AddCallback"; diff --git a/TombEngine/Scripting/Internal/ScriptInterfaceState.cpp b/TombEngine/Scripting/Internal/ScriptInterfaceState.cpp index 2a70d7613..0550d5d7c 100644 --- a/TombEngine/Scripting/Internal/ScriptInterfaceState.cpp +++ b/TombEngine/Scripting/Internal/ScriptInterfaceState.cpp @@ -2,6 +2,7 @@ #include "Scripting/Include/ScriptInterfaceState.h" #include "Scripting/Internal/ReservedScriptNames.h" +#include "Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.h" #include "Scripting/Internal/TEN/Effects/EffectsFunctions.h" #include "Scripting/Internal/TEN/Flow/FlowHandler.h" #include "Scripting/Internal/TEN/Inventory/InventoryHandler.h" @@ -10,8 +11,10 @@ #include "Scripting/Internal/TEN/Objects/ObjectsHandler.h" #include "Scripting/Internal/TEN/Strings/StringsHandler.h" -static sol::state s_solState; -static sol::table s_rootTable; +using namespace TEN::Scripting::DisplaySprite; + +static sol::state SolState; +static sol::table RootTable; int lua_exception_handler(lua_State* luaStatePtr, sol::optional exception, sol::string_view description) { @@ -20,36 +23,38 @@ int lua_exception_handler(lua_State* luaStatePtr, sol::optional using TypeOrNil = std::variant; -// To be used with TypeOrNil to fill arguments with default values if said arguments weren't given by the script. -#define USE_IF_HAVE(Type, ifThere, ifNotThere) \ -(std::holds_alternative(ifThere) ? std::get(ifThere) : ifNotThere) +// Used with TypeOrNil to fill arguments with default values if arguments in script not provided. +#define USE_IF_HAVE(Type, valueIfExists, valueIfMissing) \ +(std::holds_alternative(valueIfExists) ? std::get(valueIfExists) : valueIfMissing) template bool IsValidOptionalArg(const TypeOrNil & arg) { diff --git a/TombEngine/Scripting/Internal/TEN/DisplaySprite/AlignModes.h b/TombEngine/Scripting/Internal/TEN/DisplaySprite/AlignModes.h new file mode 100644 index 000000000..62a07187f --- /dev/null +++ b/TombEngine/Scripting/Internal/TEN/DisplaySprite/AlignModes.h @@ -0,0 +1,50 @@ +#pragma once +#include +#include + +#include "Game/Effects/DisplaySprite.h" + +using namespace TEN::Effects::DisplaySprite; + +namespace TEN::Scripting::DisplaySprite +{ + /*** + Constants for display sprite align modes. + @enum DisplaySprite.AlignMode + @pragma nostrip + */ + + /*** DisplaySprite.AlignMode constants. + + The following constants are inside AlignMode. + + CENTER + CENTER_TOP + CENTER_BOTTOM + CENTER_LEFT + CENTER_RIGHT + TOP_LEFT + TOP_RIGHT + BOTTOM_LEFT + BOTTOM_RIGHT + + @section DisplaySprite.AlignMode + */ + + /*** Table of display sprite align modes. + @table CONSTANT_STRING_HERE + */ + + static const std::unordered_map DISPLAY_SPRITE_ALIGN_MODES + { + { "CENTER", DisplaySpriteAlignMode::Center }, + { "CENTER_TOP", DisplaySpriteAlignMode::CenterTop }, + { "CENTER_BOTTOM", DisplaySpriteAlignMode::CenterBottom }, + { "CENTER_LEFT", DisplaySpriteAlignMode::CenterLeft }, + { "CENTER_RIGHT", DisplaySpriteAlignMode::CenterRight }, + { "TOP_LEFT", DisplaySpriteAlignMode::TopLeft }, + { "TOP_RIGHT", DisplaySpriteAlignMode::TopRight }, + { "BOTTOM_LEFT", DisplaySpriteAlignMode::BottomLeft }, + { "BOTTOM_RIGHT", DisplaySpriteAlignMode::BottomRight } + }; +} diff --git a/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScaleModes.h b/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScaleModes.h new file mode 100644 index 000000000..2d758a4c2 --- /dev/null +++ b/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScaleModes.h @@ -0,0 +1,38 @@ +#pragma once +#include +#include + +#include "Game/effects/DisplaySprite.h" + +using namespace TEN::Effects::DisplaySprite; + +namespace TEN::Scripting::DisplaySprite +{ + /*** + Constants for display sprite scale modes. + @enum DisplaySprite.ScaleMode + @pragma nostrip + */ + + /*** DisplaySprite.ScaleMode constants. + + The following constants are inside DisplaySprite.ScaleMode. + + FIT + FILL + STRETCH + + @section DisplaySprite.ScaleMode + */ + + /*** Table of display sprite scale modes. + @table CONSTANT_STRING_HERE + */ + + static const std::unordered_map DISPLAY_SPRITE_SCALE_MODES + { + { "FIT", DisplaySpriteScaleMode::Fit }, + { "FILL", DisplaySpriteScaleMode::Fill }, + { "STRETCH", DisplaySpriteScaleMode::Stretch } + }; +} diff --git a/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.cpp b/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.cpp new file mode 100644 index 000000000..7ffe81984 --- /dev/null +++ b/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.cpp @@ -0,0 +1,254 @@ +#include "framework.h" +#include "Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.h" + +#include "Game/effects/DisplaySprite.h" +#include "Game/Setup.h" +#include "Objects/game_object_ids.h" +#include "Renderer/Renderer11.h" +#include "Scripting/Internal/LuaHandler.h" +#include "Scripting/Internal/ReservedScriptNames.h" +#include "Scripting/Internal/TEN/Color/Color.h" +#include "Scripting/Internal/TEN/DisplaySprite/AlignModes.h" +#include "Scripting/Internal/TEN/DisplaySprite/ScaleModes.h" +#include "Scripting/Internal/TEN/Vec2/Vec2.h" + +using namespace TEN::Effects::DisplaySprite; +using TEN::Renderer::g_Renderer; + +namespace TEN::Scripting::DisplaySprite +{ + void ScriptDisplaySprite::Register(sol::state& state, sol::table& parent) + { + using ctors = sol::constructors< + ScriptDisplaySprite(GAME_OBJECT_ID, int, const Vec2&, float, const Vec2&, const ScriptColor&), + ScriptDisplaySprite(GAME_OBJECT_ID, int, const Vec2&, float, const Vec2&)>; + + // Register type. + parent.new_usertype( + ScriptReserved_DisplaySprite, + ctors(), + sol::call_constructor, ctors(), + + /*** Get the object ID of the sprite sequence object used by the display sprite. + @function DisplaySprite:GetObjectID() + @treturn Objects.ObjID Sprite sequence object ID. + */ + ScriptReserved_DisplayStringGetObjectID, &ScriptDisplaySprite::GetObjectID, + + /*** Get the sprite ID in the sprite sequence object used by the display sprite. + @function DisplaySprite:GetSpriteID() + @treturn int Sprite ID in the sprite sequence object. + */ + ScriptReserved_DisplayStringGetSpriteID, &ScriptDisplaySprite::GetSpriteID, + + /*** Get the display position of the display sprite in percent. + @function DisplaySprite:GetPosition() + @treturn Vec2 Display position in percent. + */ + ScriptReserved_DisplayStringGetPosition, &ScriptDisplaySprite::GetPosition, + + /*** Get the rotation of the display sprite in degrees. + @function DisplaySprite:GetRotation() + @treturn float Rotation in degrees. + */ + ScriptReserved_DisplayStringGetRotation, &ScriptDisplaySprite::GetRotation, + + /*** Get the horizontal and vertical scale of the display sprite in percent. + @function DisplaySprite:GetScale() + @treturn Vec2 Horizontal and vertical scale in percent. + */ + ScriptReserved_DisplayStringGetScale, &ScriptDisplaySprite::GetScale, + + /*** Get the color of the display sprite. + @function DisplaySprite:GetColor() + @treturn Color Color. + */ + ScriptReserved_DisplayStringGetColor, &ScriptDisplaySprite::GetColor, + + /*** Set the sprite sequence object ID used by the display sprite. + @function DisplaySprite:SetObjectID(Objects.ObjID) + @tparam Objects.ObjID New sprite sequence object ID. + */ + ScriptReserved_DisplayStringSetObjectID, &ScriptDisplaySprite::SetObjectID, + + /*** Set the sprite ID in the sprite sequence object used by the display sprite. + @function DisplaySprite:SetSpriteID(int) + @tparam int New sprite ID in the sprite sequence object. + */ + ScriptReserved_DisplayStringSetSpriteID, &ScriptDisplaySprite::SetSpriteID, + + /*** Set the display position of the display sprite in percent. + @function DisplaySprite:SetPosition(Vec2) + @tparam Vec2 New display position in percent. + */ + ScriptReserved_DisplayStringSetPosition, &ScriptDisplaySprite::SetPosition, + + /*** Set the rotation of the display sprite in degrees. + @function DisplaySprite:SetRotation(float) + @tparam float New rotation in degrees. + */ + ScriptReserved_DisplayStringSetRotation, &ScriptDisplaySprite::SetRotation, + + /*** Set the horizontal and vertical scale of the display sprite in percent. + @function DisplaySprite:SetScale(Vec2) + @tparam float New horizontal and vertical scale in percent. + */ + ScriptReserved_DisplayStringSetScale, &ScriptDisplaySprite::SetScale, + + /*** Set the color of the display sprite. + @function DisplaySprite:SetColor(Color) + @tparam float New color. + */ + ScriptReserved_DisplayStringSetColor, &ScriptDisplaySprite::SetColor, + + /*** Draw the display sprite in display space for the current frame. + @function DisplaySprite:Draw + @tparam Objects.ObjID[opt] priority Draw priority. Can be thought of as a layer, with higher values having precedence. __Default: 0__ + @tparam DisplaySprite.AlignMode[opt] alignMode Align mode interpreting an offset from the sprite's position. __Default: DisplaySprite.AlignMode.CENTER__ + @tparam DisplaySprite.ScaleMode[opt] scaleMode Scale mode interpreting the display sprite's horizontal and vertical scale. __Default: DisplaySprite.ScaleMode.FIT__ + @tparam Effects.BlendID[opt] blendMode Blend mode. __Default: Effects.BlendID.ALPHABLEND__ + */ + ScriptReserved_DisplaySpriteDraw, &ScriptDisplaySprite::Draw); + + auto table = sol::table(state.lua_state(), sol::create); + parent.set(ScriptReserved_DisplaySpriteEnum, table); + + // Register enums. + auto handler = LuaHandler(&state); + handler.MakeReadOnlyTable(table, ScriptReserved_DisplaySpriteEnumAlignMode, DISPLAY_SPRITE_ALIGN_MODES); + handler.MakeReadOnlyTable(table, ScriptReserved_DisplaySpriteEnumScaleMode, DISPLAY_SPRITE_SCALE_MODES); + } + + /*** Create a DisplaySprite. + @function DisplaySprite + @tparam Objects.ObjID ID of the sprite sequence object. + @tparam int int spriteID ID of the sprite in the sequence. + @tparam Vec2 pos Display position in percent. + @tparam float rot Rotation in degrees. + @tparam Vec2 scale Horizontal and vertical scale in percent. Scaling is interpreted by the DisplaySpriteEnum.ScaleMode passed to the Draw() function call. + @tparam Color color[opt] Color. __Default: Color(255, 255, 255, 255)__ + @treturn DisplaySprite A new DisplaySprite object. + */ + ScriptDisplaySprite::ScriptDisplaySprite(GAME_OBJECT_ID objectID, int spriteID, const Vec2& pos, float rot, const Vec2& scale, const ScriptColor& color) + { + ObjectID = objectID; + SpriteID = spriteID; + Position = pos; + Rotation = rot; + Scale = scale; + Color = color; + } + + ScriptDisplaySprite::ScriptDisplaySprite(GAME_OBJECT_ID objectID, int spriteID, const Vec2& pos, float rot, const Vec2& scale) + { + static const auto DEFAULT_COLOR = ScriptColor(255, 255, 255, 255); + + *this = ScriptDisplaySprite(objectID, spriteID, pos, rot, scale, DEFAULT_COLOR); + } + + GAME_OBJECT_ID ScriptDisplaySprite::GetObjectID() const + { + return ObjectID; + } + + int ScriptDisplaySprite::GetSpriteID() const + { + return SpriteID; + } + + Vec2 ScriptDisplaySprite::GetPosition() const + { + return Position; + } + + float ScriptDisplaySprite::GetRotation() const + { + return Rotation; + } + + Vec2 ScriptDisplaySprite::GetScale() const + { + return Scale; + } + + ScriptColor ScriptDisplaySprite::GetColor() const + { + return Color; + } + + void ScriptDisplaySprite::SetObjectID(GAME_OBJECT_ID objectID) + { + ObjectID = objectID; + } + + void ScriptDisplaySprite::SetSpriteID(int spriteID) + { + SpriteID = spriteID; + } + + void ScriptDisplaySprite::SetPosition(const Vec2& pos) + { + Position = pos; + } + + void ScriptDisplaySprite::SetRotation(float rot) + { + Rotation = rot; + } + + void ScriptDisplaySprite::SetScale(const Vec2& scale) + { + Scale = scale; + } + + void ScriptDisplaySprite::SetColor(const ScriptColor& color) + { + Color = color; + } + + void ScriptDisplaySprite::Draw(sol::optional priority, sol::optional alignMode, + sol::optional scaleMode, sol::optional blendMode) + { + // NOTE: Conversion from more intuitive 100x100 screen space resolution to internal 800x600 is required. + // In a future refactor, everything will use 100x100 natively. -- Sezz 2023.08.31 + constexpr auto POS_CONVERSION_COEFF = Vector2(SCREEN_SPACE_RES.x / 100, SCREEN_SPACE_RES.y / 100); + constexpr auto SCALE_CONVERSION_COEFF = 0.01f; + + constexpr auto DEFAULT_PRIORITY = 0; + constexpr auto DEFAULT_ALIGN_MODE = DisplaySpriteAlignMode::Center; + constexpr auto DEFAULT_SCALE_MODE = DisplaySpriteScaleMode::Fit; + constexpr auto DEFAULT_BLEND_MODE = BLENDMODE_ALPHABLEND; + + // Object is not a sprite sequence object; return early. + if (ObjectID < GAME_OBJECT_ID::ID_HORIZON || ObjectID >= GAME_OBJECT_ID::ID_NUMBER_OBJECTS) + { + TENLog("Attempted to draw display sprite from non-sprite sequence object " + std::to_string(ObjectID), LogLevel::Warning); + return; + } + + // Sprite missing or sequence not found; return early. + const auto& object = Objects[ObjectID]; + if (!object.loaded || SpriteID >= abs(object.nmeshes)) + { + TENLog( + "Attempted to draw missing sprite " + std::to_string(SpriteID) + + " from sprite sequence object " + std::to_string(ObjectID) + + " as display sprite.", + LogLevel::Warning); + return; + } + + auto convertedPos = Vector2(Position.x, Position.y) * POS_CONVERSION_COEFF; + short convertedRot = ANGLE(Rotation); + auto convertedScale = Vector2(Scale.x, Scale.y) * SCALE_CONVERSION_COEFF; + auto convertedColor = Vector4(Color.GetR(), Color.GetG(), Color.GetB(), Color.GetA()) / UCHAR_MAX; + + AddDisplaySprite( + ObjectID, SpriteID, + convertedPos, convertedRot, convertedScale, convertedColor, + priority.value_or(DEFAULT_PRIORITY), + alignMode.value_or(DEFAULT_ALIGN_MODE), + scaleMode.value_or(DEFAULT_SCALE_MODE), + blendMode.value_or(DEFAULT_BLEND_MODE)); + } +} diff --git a/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.h b/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.h new file mode 100644 index 000000000..79b6eecaf --- /dev/null +++ b/TombEngine/Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.h @@ -0,0 +1,53 @@ +#pragma once +#include "Game/effects/DisplaySprite.h" +#include "Objects/game_object_ids.h" +#include "Scripting/Internal/TEN/Color/Color.h" +#include "Scripting/Internal/TEN/Vec2/Vec2.h" + +using namespace TEN::Effects::DisplaySprite; + +enum BLEND_MODE; + +namespace TEN::Scripting::DisplaySprite +{ + class ScriptDisplaySprite + { + public: + static void Register(sol::state& state, sol::table& parent); + + private: + // Members + GAME_OBJECT_ID ObjectID = GAME_OBJECT_ID::ID_DEFAULT_SPRITES; + int SpriteID = 0; + + Vec2 Position = Vec2(0.0f, 0.0f); + float Rotation = 0.0f; + Vec2 Scale = Vec2(0.0f, 0.0f); + ScriptColor Color = ScriptColor(255, 255, 255, 255); + + public: + // Constructors + ScriptDisplaySprite(GAME_OBJECT_ID objectID, int spriteID, const Vec2& pos, float rot, const Vec2& scale, const ScriptColor& color); + ScriptDisplaySprite(GAME_OBJECT_ID objectID, int spriteID, const Vec2& pos, float rot, const Vec2& scale); + + // Getters + GAME_OBJECT_ID GetObjectID() const; + int GetSpriteID() const; + Vec2 GetPosition() const; + float GetRotation() const; + Vec2 GetScale() const; + ScriptColor GetColor() const; + + // Setters + void SetObjectID(GAME_OBJECT_ID objectID); + void SetSpriteID(int spriteID); + void SetPosition(const Vec2& pos); + void SetRotation(float rot); + void SetScale(const Vec2& scale); + void SetColor(const ScriptColor& color); + + // Utilities + void Draw(sol::optional priority, sol::optional alignMode, + sol::optional scaleMode, sol::optional blendMode); + }; +} diff --git a/TombEngine/Scripting/Internal/TEN/Effects/BlendIDs.h b/TombEngine/Scripting/Internal/TEN/Effects/BlendIDs.h index 3c5a91726..d362a54b1 100644 --- a/TombEngine/Scripting/Internal/TEN/Effects/BlendIDs.h +++ b/TombEngine/Scripting/Internal/TEN/Effects/BlendIDs.h @@ -1,10 +1,8 @@ #pragma once - -// Last generated on 31/7/2022. +#include +#include #include "Renderer/Renderer11Enums.h" -#include -#include /*** Constants for blend mode IDs. @@ -34,17 +32,16 @@ The following constants are inside BlendID. @table CONSTANT_STRING_HERE */ - static const std::unordered_map BLEND_IDS { - {"OPAQUE", BLENDMODE_OPAQUE}, - {"ALPHATEST", BLENDMODE_ALPHATEST}, - {"ADDITIVE", BLENDMODE_ADDITIVE}, - {"NOZTEST", BLENDMODE_NOZTEST}, - {"SUBTRACTIVE", BLENDMODE_SUBTRACTIVE}, - {"WIREFRAME", BLENDMODE_WIREFRAME}, - {"EXCLUDE", BLENDMODE_EXCLUDE}, - {"SCREEN", BLENDMODE_SCREEN}, - {"LIGHTEN", BLENDMODE_LIGHTEN}, - {"ALPHABLEND", BLENDMODE_ALPHABLEND} + { "OPAQUE", BLENDMODE_OPAQUE }, + { "ALPHATEST", BLENDMODE_ALPHATEST }, + { "ADDITIVE", BLENDMODE_ADDITIVE }, + { "NOZTEST", BLENDMODE_NOZTEST }, + { "SUBTRACTIVE", BLENDMODE_SUBTRACTIVE }, + { "WIREFRAME", BLENDMODE_WIREFRAME }, + { "EXCLUDE", BLENDMODE_EXCLUDE }, + { "SCREEN", BLENDMODE_SCREEN }, + { "LIGHTEN", BLENDMODE_LIGHTEN }, + { "ALPHABLEND", BLENDMODE_ALPHABLEND } }; diff --git a/TombEngine/Scripting/Internal/TEN/Effects/EffectIDs.h b/TombEngine/Scripting/Internal/TEN/Effects/EffectIDs.h index 478c60f85..48cbc89b2 100644 --- a/TombEngine/Scripting/Internal/TEN/Effects/EffectIDs.h +++ b/TombEngine/Scripting/Internal/TEN/Effects/EffectIDs.h @@ -32,11 +32,11 @@ The following constants are inside EffectID. static const std::unordered_map EFFECT_IDS { - {"NONE", EffectType::None}, - {"FIRE", EffectType::Fire}, - {"SPARKS", EffectType::Sparks}, - {"SMOKE", EffectType::Smoke}, - {"ELECTRICIGNITE", EffectType::ElectricIgnite}, - {"REDIGNITE", EffectType::RedIgnite}, - {"CUSTOM", EffectType::Custom} + { "NONE", EffectType::None }, + { "FIRE", EffectType::Fire }, + { "SPARKS", EffectType::Sparks }, + { "SMOKE", EffectType::Smoke}, + { "ELECTRICIGNITE", EffectType::ElectricIgnite }, + { "REDIGNITE", EffectType::RedIgnite }, + { "CUSTOM", EffectType::Custom } }; diff --git a/TombEngine/Scripting/Internal/TEN/Effects/EffectsFunctions.cpp b/TombEngine/Scripting/Internal/TEN/Effects/EffectsFunctions.cpp index 435313898..cb7d3ff98 100644 --- a/TombEngine/Scripting/Internal/TEN/Effects/EffectsFunctions.cpp +++ b/TombEngine/Scripting/Internal/TEN/Effects/EffectsFunctions.cpp @@ -3,9 +3,10 @@ #include "Game/camera.h" #include "Game/collision/collide_room.h" +#include "Game/control/los.h" +#include "Game/effects/DisplaySprite.h" #include "Game/effects/effects.h" #include "Game/effects/Electricity.h" -#include "Game/control/los.h" #include "Game/effects/explosion.h" #include "Game/effects/spark.h" #include "Game/effects/tomb4fx.h" @@ -19,6 +20,7 @@ #include "Scripting/Internal/TEN/Effects/BlendIDs.h" #include "Scripting/Internal/TEN/Effects/EffectIDs.h" #include "Scripting/Internal/TEN/Vec3/Vec3.h" +#include "Scripting/Internal/TEN/Vec2/Vec2.h" #include "Sound/sound.h" #include "Specific/clock.h" @@ -28,6 +30,7 @@ Functions to generate effects. @pragma nostrip */ +using namespace TEN::Effects::DisplaySprite; using namespace TEN::Effects::Electricity; using namespace TEN::Effects::Environment; using namespace TEN::Effects::Explosion; @@ -318,9 +321,9 @@ namespace Effects Weather.Flash(color.GetR(), color.GetG(), color.GetB(), (USE_IF_HAVE(float, speed, 1.0)) / (float)FPS); } - void Register(sol::state* state, sol::table& parent) + void Register(sol::state* state, sol::table& parent) { - sol::table tableEffects = { state->lua_state(), sol::create }; + auto tableEffects = sol::table(state->lua_state(), sol::create); parent.set(ScriptReserved_Effects, tableEffects); tableEffects.set_function(ScriptReserved_EmitLightningArc, &EmitLightningArc); @@ -333,7 +336,7 @@ namespace Effects tableEffects.set_function(ScriptReserved_FlashScreen, &FlashScreen); tableEffects.set_function(ScriptReserved_MakeEarthquake, &Earthquake); - LuaHandler handler{ state }; + auto handler = LuaHandler{ state }; handler.MakeReadOnlyTable(tableEffects, ScriptReserved_BlendID, BLEND_IDS); handler.MakeReadOnlyTable(tableEffects, ScriptReserved_EffectID, EFFECT_IDS); } diff --git a/TombEngine/Scripting/Internal/TEN/Flow/Animations/Animations.h b/TombEngine/Scripting/Internal/TEN/Flow/Animations/Animations.h index 82a9e5ad6..763fc789c 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/Animations/Animations.h +++ b/TombEngine/Scripting/Internal/TEN/Flow/Animations/Animations.h @@ -20,5 +20,5 @@ struct Animations bool HasOverhangClimb; // Overhang functionality. bool HasLedgeJumps; // Jump up or back from a ledge. - static void Register(sol::table &); + static void Register(sol::table&); }; diff --git a/TombEngine/Scripting/Internal/TEN/Flow/FlowHandler.cpp b/TombEngine/Scripting/Internal/TEN/Flow/FlowHandler.cpp index d8da1558b..6013e290a 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/FlowHandler.cpp +++ b/TombEngine/Scripting/Internal/TEN/Flow/FlowHandler.cpp @@ -8,6 +8,9 @@ #include "Scripting/Include/Objects/ScriptInterfaceObjectsHandler.h" #include "Scripting/Include/Strings/ScriptInterfaceStringsHandler.h" #include "Scripting/Internal/ReservedScriptNames.h" +#include "Scripting/Internal/TEN/DisplaySprite/AlignModes.h" +#include "Scripting/Internal/TEN/DisplaySprite/ScaleModes.h" +#include "Scripting/Internal/TEN/DisplaySprite/ScriptDisplaySprite.h" #include "Scripting/Internal/TEN/Flow/InventoryItem/InventoryItem.h" #include "Scripting/Internal/TEN/Logic/LevelFunc.h" #include "Scripting/Internal/TEN/Vec2/Vec2.h" @@ -15,6 +18,8 @@ #include "Sound/sound.h" #include "Specific/trutils.h" +using namespace TEN::Scripting::DisplaySprite; + /*** Functions that (mostly) don't directly impact in-game mechanics. Used for setup in gameflow.lua, settings.lua and strings.lua; some can be used in level @@ -28,7 +33,8 @@ ScriptInterfaceObjectsHandler* g_GameScriptEntities; ScriptInterfaceStringsHandler* g_GameStringsHandler; ScriptInterfaceFlowHandler* g_GameFlow; -FlowHandler::FlowHandler(sol::state* lua, sol::table& parent) : m_handler(lua) +FlowHandler::FlowHandler(sol::state* lua, sol::table& parent) : + m_handler(lua) { /*** gameflow.lua. These functions are called in gameflow.lua, a file loosely equivalent to winroomedit's SCRIPT.DAT. @@ -151,6 +157,14 @@ level count, jumps to title. */ tableFlow.set_function(ScriptReserved_DeleteSaveGame, &FlowHandler::DeleteSaveGame, this); + /*** + Check if a savegame exists. + @function DoesSaveGameExist + @tparam int slotID ID of the savegame slot to check. + @treturn bool true if the savegame exists, false if not. + */ + tableFlow.set_function(ScriptReserved_DoesSaveGameExist, &FlowHandler::DoesSaveGameExist, this); + /*** Returns the player's current per-game secret count. @function GetSecretCount @@ -222,6 +236,7 @@ Specify which translations in the strings table correspond to which languages. tableFlow.set_function(ScriptReserved_SetLanguageNames, &FlowHandler::SetLanguageNames, this); ScriptColor::Register(parent); + ScriptDisplaySprite::Register(*lua, parent); Rotation::Register(parent); Vec2::Register(parent); Vec3::Register(parent); @@ -233,11 +248,11 @@ Specify which translations in the strings table correspond to which languages. Settings::Register(tableFlow); Fog::Register(tableFlow); - m_handler.MakeReadOnlyTable(tableFlow, ScriptReserved_WeatherType, kWeatherTypes); - m_handler.MakeReadOnlyTable(tableFlow, ScriptReserved_LaraType, kLaraTypes); + m_handler.MakeReadOnlyTable(tableFlow, ScriptReserved_WeatherType, WEATHER_TYPES); + m_handler.MakeReadOnlyTable(tableFlow, ScriptReserved_LaraType, PLAYER_TYPES); m_handler.MakeReadOnlyTable(tableFlow, ScriptReserved_RotationAxis, ROTATION_AXES); m_handler.MakeReadOnlyTable(tableFlow, ScriptReserved_ItemAction, ITEM_MENU_ACTIONS); - m_handler.MakeReadOnlyTable(tableFlow, ScriptReserved_ErrorMode, kErrorModes); + m_handler.MakeReadOnlyTable(tableFlow, ScriptReserved_ErrorMode, ERROR_MODES); } FlowHandler::~FlowHandler() @@ -430,6 +445,11 @@ void FlowHandler::DeleteSaveGame(int slot) SaveGame::Delete(slot); } +bool FlowHandler::DoesSaveGameExist(int slot) +{ + return SaveGame::DoesSaveGameExist(slot, true); +} + int FlowHandler::GetSecretCount() const { return Statistics.Game.Secrets; diff --git a/TombEngine/Scripting/Internal/TEN/Flow/FlowHandler.h b/TombEngine/Scripting/Internal/TEN/Flow/FlowHandler.h index 9a17a17f6..1925c1b03 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/FlowHandler.h +++ b/TombEngine/Scripting/Internal/TEN/Flow/FlowHandler.h @@ -63,6 +63,7 @@ public: void SaveGame(int slot); void LoadGame(int slot); void DeleteSaveGame(int slot); + bool DoesSaveGameExist(int slot); int GetSecretCount() const; void SetSecretCount(int secretsNum); void AddSecret(int levelSecretIndex); diff --git a/TombEngine/Scripting/Internal/TEN/Flow/Fog/Fog.cpp b/TombEngine/Scripting/Internal/TEN/Flow/Fog/Fog.cpp index c100c517b..7b3dfde50 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/Fog/Fog.cpp +++ b/TombEngine/Scripting/Internal/TEN/Flow/Fog/Fog.cpp @@ -8,7 +8,7 @@ Fog @pragma nostrip */ -void Fog::Register(sol::table & parent) +void Fog::Register(sol::table& parent) { using ctors = sol::constructors; parent.new_usertype("Fog", diff --git a/TombEngine/Scripting/Internal/TEN/Flow/Fog/Fog.h b/TombEngine/Scripting/Internal/TEN/Flow/Fog/Fog.h index a61cba58d..ecee5b9c6 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/Fog/Fog.h +++ b/TombEngine/Scripting/Internal/TEN/Flow/Fog/Fog.h @@ -20,5 +20,5 @@ struct Fog void SetColor(ScriptColor const& col); ScriptColor GetColor() const; - static void Register(sol::table &); + static void Register(sol::table&); }; diff --git a/TombEngine/Scripting/Internal/TEN/Flow/Level/FlowLevel.cpp b/TombEngine/Scripting/Internal/TEN/Flow/Level/FlowLevel.cpp index d8a5d46b7..0214dfd58 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/Level/FlowLevel.cpp +++ b/TombEngine/Scripting/Internal/TEN/Flow/Level/FlowLevel.cpp @@ -14,7 +14,7 @@ These are things things which aren't present in the compiled level file itself. @function Level @treturn Level a Level object */ -void Level::Register(sol::table & parent) +void Level::Register(sol::table& parent) { parent.new_usertype("Level", sol::constructors(), diff --git a/TombEngine/Scripting/Internal/TEN/Flow/Level/FlowLevel.h b/TombEngine/Scripting/Internal/TEN/Flow/Level/FlowLevel.h index 75335d7b6..5e26fabd3 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/Level/FlowLevel.h +++ b/TombEngine/Scripting/Internal/TEN/Flow/Level/FlowLevel.h @@ -6,7 +6,7 @@ #include "Scripting/Include/ScriptInterfaceLevel.h" #include "Scripting/Internal/TEN/Flow/InventoryItem/InventoryItem.h" -static const std::unordered_map kWeatherTypes +static const std::unordered_map WEATHER_TYPES { {"None", WeatherType::None}, {"Rain", WeatherType::Rain}, @@ -14,7 +14,7 @@ static const std::unordered_map kWeatherTypes }; -static const std::unordered_map kLaraTypes +static const std::unordered_map PLAYER_TYPES { {"Normal", LaraType::Normal}, {"Young", LaraType::Young}, @@ -50,7 +50,7 @@ struct Level : public ScriptInterfaceLevel LaraType GetLaraType() const override; void SetWeatherStrength(float val); void SetLevelFarView(short val); - static void Register(sol::table & parent); + static void Register(sol::table& parent); WeatherType GetWeatherType() const override; short GetMirrorRoom() const override; short GetFogMinDistance() const override; diff --git a/TombEngine/Scripting/Internal/TEN/Flow/Mirror/Mirror.h b/TombEngine/Scripting/Internal/TEN/Flow/Mirror/Mirror.h index 40854c961..51e05cda4 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/Mirror/Mirror.h +++ b/TombEngine/Scripting/Internal/TEN/Flow/Mirror/Mirror.h @@ -12,7 +12,7 @@ struct Mirror int StartZ{ 0 }; int EndZ{ 0 }; - static void Register(sol::table & parent); + static void Register(sol::table& parent); Mirror() = default; Mirror(short room, int startX, int endX, int startZ, int endZ); diff --git a/TombEngine/Scripting/Internal/TEN/Flow/Settings/Settings.h b/TombEngine/Scripting/Internal/TEN/Flow/Settings/Settings.h index 9c1d27d27..e1988f09f 100644 --- a/TombEngine/Scripting/Internal/TEN/Flow/Settings/Settings.h +++ b/TombEngine/Scripting/Internal/TEN/Flow/Settings/Settings.h @@ -3,7 +3,7 @@ #include "Scripting/Internal/ScriptAssert.h" #include -static const std::unordered_map kErrorModes { +static const std::unordered_map ERROR_MODES { {"SILENT", ErrorMode::Silent}, {"WARN", ErrorMode::Warn}, {"TERMINATE", ErrorMode::Terminate} diff --git a/TombEngine/Scripting/Internal/TEN/Inventory/InventoryHandler.cpp b/TombEngine/Scripting/Internal/TEN/Inventory/InventoryHandler.cpp index 3a3908477..a7f543c23 100644 --- a/TombEngine/Scripting/Internal/TEN/Inventory/InventoryHandler.cpp +++ b/TombEngine/Scripting/Internal/TEN/Inventory/InventoryHandler.cpp @@ -61,12 +61,12 @@ namespace InventoryHandler void Register(sol::state* state, sol::table& parent) { - sol::table table_inventory{ state->lua_state(), sol::create }; - parent.set(ScriptReserved_Inventory, table_inventory); + auto tableInventory = sol::table{ state->lua_state(), sol::create }; + parent.set(ScriptReserved_Inventory, tableInventory); - table_inventory.set_function(ScriptReserved_GiveInvItem, &GiveItem); - table_inventory.set_function(ScriptReserved_TakeInvItem, &TakeItem); - table_inventory.set_function(ScriptReserved_GetInvItemCount, &GetItemCount); - table_inventory.set_function(ScriptReserved_SetInvItemCount, &SetItemCount); + tableInventory.set_function(ScriptReserved_GiveInvItem, &GiveItem); + tableInventory.set_function(ScriptReserved_TakeInvItem, &TakeItem); + tableInventory.set_function(ScriptReserved_GetInvItemCount, &GetItemCount); + tableInventory.set_function(ScriptReserved_SetInvItemCount, &SetItemCount); } } diff --git a/TombEngine/Scripting/Internal/TEN/Misc/Miscellaneous.cpp b/TombEngine/Scripting/Internal/TEN/Misc/Miscellaneous.cpp index 39713eb80..68e478801 100644 --- a/TombEngine/Scripting/Internal/TEN/Misc/Miscellaneous.cpp +++ b/TombEngine/Scripting/Internal/TEN/Misc/Miscellaneous.cpp @@ -14,10 +14,12 @@ #include "Scripting/Internal/ReservedScriptNames.h" #include "Scripting/Internal/ScriptAssert.h" #include "Scripting/Internal/ScriptUtil.h" +#include "Scripting/Internal/TEN/Color/Color.h" #include "Scripting/Internal/TEN/Misc/ActionIDs.h" #include "Scripting/Internal/TEN/Misc/CameraTypes.h" #include "Scripting/Internal/TEN/Misc/LevelLog.h" #include "Scripting/Internal/TEN/Misc/SoundTrackTypes.h" +#include "Scripting/Internal/TEN/Vec2/Vec2.h" #include "Scripting/Internal/TEN/Vec3/Vec3.h" #include "Sound/sound.h" #include "Specific/clock.h" @@ -308,11 +310,12 @@ namespace Misc return (int)round(Vector3::Distance(p1, p2)); } + // TODO: Deprecated. Also should not use int! ///Calculate the horizontal distance between two positions. //@function CalculateHorizontalDistance //@tparam Vec3 posA first position //@tparam Vec3 posB second position - //@treturn int the direct distance on the XZ plane from one position to the other + //@treturn float the direct distance on the XZ plane from one position to the other static int CalculateHorizontalDistance(const Vec3& pos1, const Vec3& pos2) { auto p1 = Vector2(pos1.x, pos1.z); @@ -320,49 +323,49 @@ namespace Misc return (int)round(Vector2::Distance(p1, p2)); } - ///Translate a pair of percentages to screen-space pixel coordinates. - //To be used with @{Strings.DisplayString:SetPosition} and @{Strings.DisplayString}. + /// Translate a pair display position coordinates to pixel coordinates. + //To be used with @{ Strings.DisplayString:SetPosition } and @{ Strings.DisplayString }. //@function PercentToScreen - //@tparam float x percent value to translate to x-coordinate - //@tparam float y percent value to translate to y-coordinate - //@treturn int x coordinate in pixels - //@treturn int y coordinate in pixels + //@tparam float x X component of the display position. + //@tparam float y Y component of the display position. + //@treturn int x X coordinate in pixels. + //@treturn int y Y coordinate in pixels. //@usage //local halfwayX, halfwayY = PercentToScreen(50, 50) //local baddy //local spawnLocationNullmesh = GetMoveableByName("position_behind_left_pillar") - //local str1 = DisplayString("You spawned a baddy!", halfwayX, halfwayY, Color(255, 100, 100), false, {DisplayStringOption.SHADOW, DisplayStringOption.CENTER}) + //local str1 = DisplayString("You spawned an enemy!", halfwayX, halfwayY, Color(255, 100, 100), false, { DisplayStringOption.SHADOW, DisplayStringOption.CENTER }) // //LevelFuncs.triggerOne = function(obj) // ShowString(str1, 4) //end - static std::tuple PercentToScreen(double x, double y) + static std::tuple PercentToScreen(float x, float y) { - auto fWidth = static_cast(g_Configuration.ScreenWidth); - auto fHeight = static_cast(g_Configuration.ScreenHeight); - int resX = static_cast(std::round(fWidth / 100.0 * x)); - int resY = static_cast(std::round(fHeight / 100.0 * y)); - //todo this still assumes a resolution of 800/600. account for this somehow + float fWidth = g_Configuration.ScreenWidth; + float fHeight = g_Configuration.ScreenHeight; + int resX = (int)std::round(fWidth / 100.0f * x); + int resY = (int)std::round(fHeight / 100.0f * y); + return std::make_tuple(resX, resY); } - ///Translate a pair of coordinates to percentages of window dimensions. - //To be used with @{Strings.DisplayString:GetPosition}. + /// Translate a pair of pixel coordinates to display position coordinates. + //To be used with @{ Strings.DisplayString:GetPosition }. //@function ScreenToPercent - //@tparam int x pixel value to translate to a percentage of the window width - //@tparam int y pixel value to translate to a percentage of the window height - //@treturn float x coordinate as percentage - //@treturn float y coordinate as percentage - static std::tuple ScreenToPercent(int x, int y) + //@tparam int x X pixel coordinate to translate to display position. + //@tparam int y Y pixel coordinate to translate to display position. + //@treturn float x X component of display position. + //@treturn float y Y component of display position. + static std::tuple ScreenToPercent(int x, int y) { - auto fWidth = static_cast(g_Configuration.ScreenWidth); - auto fHeight = static_cast(g_Configuration.ScreenHeight); - double resX = x / fWidth * 100.0; - double resY = y / fHeight * 100.0; + float fWidth = g_Configuration.ScreenWidth; + float fHeight = g_Configuration.ScreenHeight; + float resX = x / fWidth * 100.0f; + float resY = y / fHeight * 100.0f; return std::make_tuple(resX, resY); } - /// Reset object camera back to Lara and deactivate object camera. + /// Reset object camera back to the player and deactivate object camera. //@function ResetObjCamera static void ResetObjCamera() { diff --git a/TombEngine/Scripting/Internal/TEN/Objects/AIObject/AIObject.cpp b/TombEngine/Scripting/Internal/TEN/Objects/AIObject/AIObject.cpp index 40f7de16c..5deda997d 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/AIObject/AIObject.cpp +++ b/TombEngine/Scripting/Internal/TEN/Objects/AIObject/AIObject.cpp @@ -19,7 +19,7 @@ static auto newindex_error = newindex_error_maker(AIObject, ScriptReserved_AIObj AIObject::AIObject(AI_OBJECT & ref) : m_aiObject{ref} {}; -void AIObject::Register(sol::table & parent) +void AIObject::Register(sol::table& parent) { parent.new_usertype(ScriptReserved_AIObject, sol::no_constructor, // ability to spawn new ones could be added later diff --git a/TombEngine/Scripting/Internal/TEN/Objects/AIObject/AIObject.h b/TombEngine/Scripting/Internal/TEN/Objects/AIObject/AIObject.h index aa62124fd..660b81bd4 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/AIObject/AIObject.h +++ b/TombEngine/Scripting/Internal/TEN/Objects/AIObject/AIObject.h @@ -20,7 +20,7 @@ public: AIObject& operator=(AIObject const& other) = delete; AIObject(AIObject const& other) = delete; - static void Register(sol::table & parent); + static void Register(sol::table& parent); Vec3 GetPos() const; void SetPos(Vec3 const& pos); diff --git a/TombEngine/Scripting/Internal/TEN/Objects/Camera/CameraObject.cpp b/TombEngine/Scripting/Internal/TEN/Objects/Camera/CameraObject.cpp index 6d5e7e9d3..387f42907 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/Camera/CameraObject.cpp +++ b/TombEngine/Scripting/Internal/TEN/Objects/Camera/CameraObject.cpp @@ -22,7 +22,7 @@ static auto newindex_error = newindex_error_maker(CameraObject, ScriptReserved_C CameraObject::CameraObject(LevelCameraInfo & ref) : m_camera{ref} {}; -void CameraObject::Register(sol::table & parent) +void CameraObject::Register(sol::table& parent) { parent.new_usertype(ScriptReserved_Camera, sol::no_constructor, // ability to spawn new ones could be added later diff --git a/TombEngine/Scripting/Internal/TEN/Objects/Camera/CameraObject.h b/TombEngine/Scripting/Internal/TEN/Objects/Camera/CameraObject.h index 7fc6f3468..671650d0e 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/Camera/CameraObject.h +++ b/TombEngine/Scripting/Internal/TEN/Objects/Camera/CameraObject.h @@ -22,7 +22,7 @@ public: CameraObject& operator=(CameraObject const& other) = delete; CameraObject(CameraObject const& other) = delete; - static void Register(sol::table &); + static void Register(sol::table&); Vec3 GetPos() const; void SetPos(Vec3 const& pos); diff --git a/TombEngine/Scripting/Internal/TEN/Objects/Lara/LaraObject.h b/TombEngine/Scripting/Internal/TEN/Objects/Lara/LaraObject.h index fc7baa2b8..f15752a0b 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/Lara/LaraObject.h +++ b/TombEngine/Scripting/Internal/TEN/Objects/Lara/LaraObject.h @@ -56,7 +56,7 @@ public: void UndrawWeapon(); void ThrowAwayTorch(); bool TorchIsLit() const; - static void Register(sol::table & parent); + static void Register(sol::table& parent); using Moveable::Moveable; }; diff --git a/TombEngine/Scripting/Internal/TEN/Objects/Moveable/MoveableObject.cpp b/TombEngine/Scripting/Internal/TEN/Objects/Moveable/MoveableObject.cpp index bce78b3cd..de3e05c54 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/Moveable/MoveableObject.cpp +++ b/TombEngine/Scripting/Internal/TEN/Objects/Moveable/MoveableObject.cpp @@ -76,19 +76,18 @@ most can just be ignored (see usage). @tparam string name Lua name of the item @tparam Vec3 position position in level @tparam[opt] Rotation rotation rotation about x, y, and z axes (default Rotation(0, 0, 0)) - @int[opt] room room ID item is in (default: calculated automatically) + @int[opt] roomID room ID item is in (default: calculated automatically) @int[opt=0] animNumber anim number @int[opt=0] frameNumber frame number @int[opt=10] hp HP of item @int[opt=0] OCB ocb of item (default 0) - @tparam[opt] table AIBits table with AI bits (default {0,0,0,0,0,0}) + @tparam[opt] table AIBits table with AI bits (default { 0, 0, 0, 0, 0, 0 }) @treturn Moveable A new Moveable object (a wrapper around the new object) @usage local item = Moveable( TEN.Objects.ObjID.PISTOLS_ITEM, -- object id "test", -- name - Vec3(18907, 0, 21201) - ) + Vec3(18907, 0, 21201)) */ static std::unique_ptr Create( GAME_OBJECT_ID objID, diff --git a/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h b/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h index 4e363c4cc..2c17fc672 100644 --- a/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h +++ b/TombEngine/Scripting/Internal/TEN/Objects/ObjectIDs.h @@ -2157,6 +2157,7 @@ static const std::unordered_map kObjIDs { { "AIR_BAR_TEXTURE", ID_AIR_BAR_TEXTURE }, { "DASH_BAR_TEXTURE", ID_DASH_BAR_TEXTURE }, { "SFX_BAR_TEXTURE", ID_SFX_BAR_TEXTURE }, + { "CROSSHAIR", ID_CROSSHAIR }, { "PANEL_BORDER", ID_PANEL_BORDER }, { "PANEL_MIDDLE", ID_PANEL_MIDDLE }, { "PANEL_CORNER", ID_PANEL_CORNER }, diff --git a/TombEngine/Scripting/Internal/TEN/Strings/DisplayString/DisplayString.cpp b/TombEngine/Scripting/Internal/TEN/Strings/DisplayString/DisplayString.cpp index cdb5a0146..f4db9da87 100644 --- a/TombEngine/Scripting/Internal/TEN/Strings/DisplayString/DisplayString.cpp +++ b/TombEngine/Scripting/Internal/TEN/Strings/DisplayString/DisplayString.cpp @@ -19,14 +19,14 @@ when you need to use screen-space coordinates. @pragma nostrip */ -UserDisplayString::UserDisplayString(const std::string& key, int x, int y, float scale, D3DCOLOR color, const FlagArray& flags, bool translated) : - m_key{ key }, - m_x{ x }, - m_y{ y }, - m_scale{ scale }, - m_color{ color }, - m_flags{ flags }, - m_isTranslated{ translated } +UserDisplayString::UserDisplayString(const std::string& key, int x, int y, float scale, D3DCOLOR color, const FlagArray& flags, bool isTranslated) : + m_key(key), + m_x(x), + m_y(y), + m_scale(scale), + m_color(color), + m_flags(flags), + m_isTranslated(isTranslated) { } @@ -120,21 +120,21 @@ void DisplayString::Register(sol::table& parent) /// Get the display string's color // @function DisplayString:GetColor // @treturn Color a copy of the display string's color - ScriptReserved_GetColor, &DisplayString::GetCol, + ScriptReserved_GetColor, &DisplayString::GetColor, /// Set the display string's color // @function DisplayString:SetColor // @tparam Color color the new color of the display string - ScriptReserved_SetColor, &DisplayString::SetCol, + ScriptReserved_SetColor, &DisplayString::SetColor, - /// Get the string key to use. If `translated` is true when @{DisplayString} + /// Get the string key to use. If `isTranslated` is true when @{ DisplayString } // is called, this will be the string key for the translation that will be displayed. // If false or omitted, this will be the string that's displayed. // @function DisplayString:GetKey // @treturn string the string to use ScriptReserved_GetKey, &DisplayString::GetKey, - /// Set the string key to use. If `translated` is true when @{DisplayString} + /// Set the string key to use. If `isTranslated` is true when @{ DisplayString } // is called, this will be the string key for the translation that will be displayed. // If false or omitted, this will be the string that's displayed. // @function DisplayString:SetKey @@ -154,15 +154,15 @@ void DisplayString::Register(sol::table& parent) /// Set the position of the string. // Screen-space coordinates are expected. // @function DisplayString:SetPosition - // @tparam int x x-coordinate of the string - // @tparam int y y-coordinate of the string + // @tparam int x X component. + // @tparam int y Y component. ScriptReserved_SetPosition, &DisplayString::SetPos, /// Get the position of the string. // Screen-space coordinates are returned. // @function DisplayString:GetPosition - // @treturn int x-coordinate of the string - // @treturn int y-coordinate of the string + // @treturn int x X component. + // @treturn int y Y component. ScriptReserved_GetPosition, &DisplayString::GetPos, /// Set the display string's flags @@ -183,8 +183,7 @@ void DisplayString::Register(sol::table& parent) // @function DisplayString:SetTranslated // @tparam bool shouldTranslate if true, the string's key will be used as the key for the translation that will be displayed. // If false, the key itself will be displayed - ScriptReserved_SetTranslated, &DisplayString::SetTranslated - ); + ScriptReserved_SetTranslated, &DisplayString::SetTranslated); } DisplayStringIDType DisplayString::GetID() const @@ -217,7 +216,7 @@ std::tuple DisplayString::GetPos() const return std::make_tuple(displayString.m_x, displayString.m_y); } -void DisplayString::SetCol(const ScriptColor& color) +void DisplayString::SetColor(const ScriptColor& color) { UserDisplayString& displayString = s_getItemCallback(m_id).value(); displayString.m_color = color; @@ -226,10 +225,10 @@ void DisplayString::SetCol(const ScriptColor& color) //s_addItemCallback(m_id, s); } -ScriptColor DisplayString::GetCol() +ScriptColor DisplayString::GetColor() { - UserDisplayString& s = s_getItemCallback(m_id).value(); - return s.m_color; + UserDisplayString& displayString = s_getItemCallback(m_id).value(); + return displayString.m_color; } void DisplayString::SetKey(const std::string& key) diff --git a/TombEngine/Scripting/Internal/TEN/Strings/DisplayString/DisplayString.h b/TombEngine/Scripting/Internal/TEN/Strings/DisplayString/DisplayString.h index a0d54f2aa..67602eb84 100644 --- a/TombEngine/Scripting/Internal/TEN/Strings/DisplayString/DisplayString.h +++ b/TombEngine/Scripting/Internal/TEN/Strings/DisplayString/DisplayString.h @@ -4,24 +4,25 @@ #include "Scripting/Internal/TEN/Color/Color.h" -enum class DisplayStringOptions : size_t +enum class DisplayStringOptions { - CENTER, - OUTLINE, - RIGHT, - BLINK, - NUM_OPTIONS + Center, + Outline, + Right, + Blink, + + Count }; -static const std::unordered_map kDisplayStringOptionNames +static const std::unordered_map DISPLAY_STRING_OPTION_NAMES { - {"CENTER", DisplayStringOptions::CENTER}, - {"SHADOW", DisplayStringOptions::OUTLINE}, - {"RIGHT", DisplayStringOptions::RIGHT}, - {"BLINK", DisplayStringOptions::BLINK} + { "CENTER", DisplayStringOptions::Center }, + { "SHADOW", DisplayStringOptions::Outline }, + { "RIGHT", DisplayStringOptions::Right }, + { "BLINK", DisplayStringOptions::Blink } }; -using FlagArray = std::array(DisplayStringOptions::NUM_OPTIONS)>; +using FlagArray = std::array; // Used to store data used to render the string. // This is separate from DisplayString because the lifetimes of the classes differ slightly. @@ -69,8 +70,8 @@ public: void SetPos(int x, int y); std::tuple GetPos() const; - void SetCol(const ScriptColor&); - ScriptColor GetCol(); + void SetColor(const ScriptColor&); + ScriptColor GetColor(); void SetKey(const std::string&); std::string GetKey() const; diff --git a/TombEngine/Scripting/Internal/TEN/Strings/StringsHandler.cpp b/TombEngine/Scripting/Internal/TEN/Strings/StringsHandler.cpp index 49583a648..16daab99e 100644 --- a/TombEngine/Scripting/Internal/TEN/Strings/StringsHandler.cpp +++ b/TombEngine/Scripting/Internal/TEN/Strings/StringsHandler.cpp @@ -12,7 +12,8 @@ On-screen strings. @pragma nostrip */ -StringsHandler::StringsHandler(sol::state* lua, sol::table & parent) : LuaHandler{ lua } +StringsHandler::StringsHandler(sol::state* lua, sol::table& parent) : + LuaHandler{ lua } { sol::table table_strings{ m_lua->lua_state(), sol::create }; parent.set(ScriptReserved_Strings, table_strings); @@ -46,12 +47,11 @@ Checks if the string is shown DisplayString::Register(table_strings); DisplayString::SetCallbacks( - [this](auto && ... param) {return SetDisplayString(std::forward(param)...); }, - [this](auto && ... param) {return ScheduleRemoveDisplayString(std::forward(param)...); }, - [this](auto && ... param) {return GetDisplayString(std::forward(param)...); } - ); + [this](auto && ... param) { return SetDisplayString(std::forward(param)...); }, + [this](auto && ... param) { return ScheduleRemoveDisplayString(std::forward(param)...); }, + [this](auto && ... param) { return GetDisplayString(std::forward(param)...); }); - MakeReadOnlyTable(table_strings, ScriptReserved_DisplayStringOption, kDisplayStringOptionNames); + MakeReadOnlyTable(table_strings, ScriptReserved_DisplayStringOption, DISPLAY_STRING_OPTION_NAMES); } std::optional> StringsHandler::GetDisplayString(DisplayStringIDType id) @@ -116,16 +116,16 @@ void StringsHandler::ProcessDisplayStrings(float deltaTime) auto cstr = str.m_isTranslated ? g_GameFlow->GetString(str.m_key.c_str()) : str.m_key.c_str(); int flags = 0; - if (str.m_flags[static_cast(DisplayStringOptions::CENTER)]) + if (str.m_flags[(size_t)DisplayStringOptions::Center]) flags |= PRINTSTRING_CENTER; - if (str.m_flags[static_cast(DisplayStringOptions::RIGHT)]) + if (str.m_flags[(size_t)DisplayStringOptions::Right]) flags |= PRINTSTRING_RIGHT; - if (str.m_flags[static_cast(DisplayStringOptions::OUTLINE)]) + if (str.m_flags[(size_t)DisplayStringOptions::Outline]) flags |= PRINTSTRING_OUTLINE; - if (str.m_flags[static_cast(DisplayStringOptions::BLINK)]) + if (str.m_flags[(size_t)DisplayStringOptions::Blink]) flags |= PRINTSTRING_BLINK; m_callbackDrawSring(cstr, str.m_color, str.m_x, str.m_y, str.m_scale, flags); diff --git a/TombEngine/Shaders/DX11_FullscreenQuad.fx b/TombEngine/Shaders/DX11_FullscreenQuad.fx index 8e845a8fd..6f59a855b 100644 --- a/TombEngine/Shaders/DX11_FullscreenQuad.fx +++ b/TombEngine/Shaders/DX11_FullscreenQuad.fx @@ -1,32 +1,31 @@ -#include "./VertexInput.hlsli" - -struct PixelShaderInput -{ - float4 Position: SV_POSITION; - float2 UV: TEXCOORD; - float4 Color: COLOR; -}; - -Texture2D Texture : register(t0); -SamplerState Sampler : register(s0); - -PixelShaderInput VS(VertexShaderInput input) -{ - PixelShaderInput output; - - output.Position = float4(input.Position, 1.0f); - output.Color = input.Color; - output.UV = input.UV; - - return output; -} - -float4 PS(PixelShaderInput input) : SV_TARGET -{ - float4 output = Texture.Sample(Sampler, input.UV); - float3 colorMul = min(input.Color.xyz, 1.0f); - output.xyz = output.xyz * colorMul.xyz; - //output.w = 1.0f; - - return output; -} \ No newline at end of file +#include "./VertexInput.hlsli" + +struct PixelShaderInput +{ + float4 Position: SV_POSITION; + float2 UV: TEXCOORD; + float4 Color: COLOR; +}; + +Texture2D Texture : register(t0); +SamplerState Sampler : register(s0); + +PixelShaderInput VS(VertexShaderInput input) +{ + PixelShaderInput output; + + output.Position = float4(input.Position, 1.0f); + output.Color = input.Color; + output.UV = input.UV; + + return output; +} + +float4 PS(PixelShaderInput input) : SV_TARGET +{ + float4 output = Texture.Sample(Sampler, input.UV); + float4 colorMul = min(input.Color, 1.0f); + output = output * colorMul; + + return output; +} diff --git a/TombEngine/Specific/configuration.cpp b/TombEngine/Specific/configuration.cpp index 623126154..e5dd047e4 100644 --- a/TombEngine/Specific/configuration.cpp +++ b/TombEngine/Specific/configuration.cpp @@ -230,6 +230,7 @@ bool SaveConfiguration() // Set Gameplay keys. if (SetBoolRegKey(gameplayKey, REGKEY_ENABLE_SUBTITLES, g_Configuration.EnableSubtitles) != ERROR_SUCCESS || SetBoolRegKey(gameplayKey, REGKEY_ENABLE_AUTO_TARGETING, g_Configuration.EnableAutoTargeting) != ERROR_SUCCESS || + SetBoolRegKey(gameplayKey, REGKEY_ENABLE_TARGET_HIGHLIGHTER, g_Configuration.EnableTargetHighlighter) != ERROR_SUCCESS || SetBoolRegKey(gameplayKey, REGKEY_ENABLE_RUMBLE, g_Configuration.EnableRumble) != ERROR_SUCCESS || SetBoolRegKey(gameplayKey, REGKEY_ENABLE_THUMBSTICK_CAMERA, g_Configuration.EnableThumbstickCamera) != ERROR_SUCCESS) { @@ -308,6 +309,7 @@ void InitDefaultConfiguration() g_Configuration.EnableSubtitles = true; g_Configuration.EnableAutoTargeting = true; + g_Configuration.EnableTargetHighlighter = false; g_Configuration.EnableRumble = true; g_Configuration.EnableThumbstickCamera = false; @@ -400,12 +402,14 @@ bool LoadConfiguration() bool enableSubtitles = true; bool enableAutoTargeting = true; + bool enableTargetHighlighter = true; bool enableRumble = true; bool enableThumbstickCamera = true; // Load Gameplay keys. if (GetBoolRegKey(gameplayKey, REGKEY_ENABLE_SUBTITLES, &enableSubtitles, true) != ERROR_SUCCESS || GetBoolRegKey(gameplayKey, REGKEY_ENABLE_AUTO_TARGETING, &enableAutoTargeting, true) != ERROR_SUCCESS || + GetBoolRegKey(gameplayKey, REGKEY_ENABLE_TARGET_HIGHLIGHTER, &enableTargetHighlighter, true) != ERROR_SUCCESS || GetBoolRegKey(gameplayKey, REGKEY_ENABLE_RUMBLE, &enableRumble, true) != ERROR_SUCCESS || GetBoolRegKey(gameplayKey, REGKEY_ENABLE_THUMBSTICK_CAMERA, &enableThumbstickCamera, true) != ERROR_SUCCESS) { @@ -470,6 +474,7 @@ bool LoadConfiguration() g_Configuration.SoundDevice = soundDevice; g_Configuration.EnableAutoTargeting = enableAutoTargeting; + g_Configuration.EnableTargetHighlighter = enableTargetHighlighter; g_Configuration.EnableRumble = enableRumble; g_Configuration.EnableThumbstickCamera = enableThumbstickCamera; g_Configuration.EnableSubtitles = enableSubtitles; diff --git a/TombEngine/Specific/configuration.h b/TombEngine/Specific/configuration.h index 386054973..8ae778999 100644 --- a/TombEngine/Specific/configuration.h +++ b/TombEngine/Specific/configuration.h @@ -31,10 +31,11 @@ constexpr auto REGKEY_MUSIC_VOLUME = "MusicVolume"; constexpr auto REGKEY_SFX_VOLUME = "SfxVolume"; // Gameplay keys -constexpr auto REGKEY_ENABLE_SUBTITLES = "EnableSubtitles"; -constexpr auto REGKEY_ENABLE_AUTO_TARGETING = "EnableAutoTargeting"; -constexpr auto REGKEY_ENABLE_RUMBLE = "EnableRumble"; -constexpr auto REGKEY_ENABLE_THUMBSTICK_CAMERA = "EnableThumbstickCamera"; +constexpr auto REGKEY_ENABLE_SUBTITLES = "EnableSubtitles"; +constexpr auto REGKEY_ENABLE_AUTO_TARGETING = "EnableAutoTargeting"; +constexpr auto REGKEY_ENABLE_TARGET_HIGHLIGHTER = "EnableTargetHighlighter"; +constexpr auto REGKEY_ENABLE_RUMBLE = "EnableRumble"; +constexpr auto REGKEY_ENABLE_THUMBSTICK_CAMERA = "EnableThumbstickCamera"; struct GameConfiguration { @@ -56,10 +57,11 @@ struct GameConfiguration int SfxVolume = 0; // Gameplay - bool EnableSubtitles = false; - bool EnableAutoTargeting = false; - bool EnableRumble = false; - bool EnableThumbstickCamera = false; + bool EnableSubtitles = false; + bool EnableAutoTargeting = false; + bool EnableTargetHighlighter = false; + bool EnableRumble = false; + bool EnableThumbstickCamera = false; // Input std::vector Bindings = {}; diff --git a/TombEngine/Specific/trutils.cpp b/TombEngine/Specific/trutils.cpp index 407f98164..13aa86dcf 100644 --- a/TombEngine/Specific/trutils.cpp +++ b/TombEngine/Specific/trutils.cpp @@ -155,31 +155,32 @@ namespace TEN::Utils return strings; } - Vector2 GetAspectCorrect2DPosition(Vector2 pos2D) + Vector2 GetAspectCorrect2DPosition(const Vector2& pos) { - constexpr auto SCREEN_SPACE_ASPECT_RATIO = SCREEN_SPACE_RES.x / SCREEN_SPACE_RES.y; + constexpr auto DISPLAY_SPACE_ASPECT = SCREEN_SPACE_RES.x / SCREEN_SPACE_RES.y; auto screenRes = g_Renderer.GetScreenResolution().ToVector2(); - float screenResAspectRatio = screenRes.x / screenRes.y; - float aspectRatioDelta = screenResAspectRatio - SCREEN_SPACE_ASPECT_RATIO; + float screenResAspect = screenRes.x / screenRes.y; + float aspectDelta = screenResAspect - DISPLAY_SPACE_ASPECT; - if (aspectRatioDelta > EPSILON) + auto correctedPos = pos; + if (aspectDelta > EPSILON) { - pos2D.x *= 1.0f - (aspectRatioDelta / 2); + correctedPos.x *= 1.0f - (aspectDelta / 2); } - else if (aspectRatioDelta < -EPSILON) + else if (aspectDelta < -EPSILON) { - pos2D.y *= 1.0f - (aspectRatioDelta / 2); + correctedPos.y *= 1.0f - (aspectDelta / 2); } - return pos2D; + return correctedPos; } - Vector2 Convert2DPositionToNDC(const Vector2& pos2D) + Vector2 Convert2DPositionToNDC(const Vector2& pos) { return Vector2( - ((pos2D.x * 2) / SCREEN_SPACE_RES.x) - 1.0f, - 1.0f - ((pos2D.y * 2) / SCREEN_SPACE_RES.y)); + ((pos.x * 2) / SCREEN_SPACE_RES.x) - 1.0f, + 1.0f - ((pos.y * 2) / SCREEN_SPACE_RES.y)); } Vector2 ConvertNDCTo2DPosition(const Vector2& ndc) diff --git a/TombEngine/Specific/trutils.h b/TombEngine/Specific/trutils.h index 83922b78c..f24acd617 100644 --- a/TombEngine/Specific/trutils.h +++ b/TombEngine/Specific/trutils.h @@ -14,8 +14,8 @@ namespace TEN::Utils std::vector SplitString(const std::string& string); // 2D space utilities - Vector2 GetAspectCorrect2DPosition(Vector2 pos2D); - Vector2 Convert2DPositionToNDC(const Vector2& pos2D); + Vector2 GetAspectCorrect2DPosition(const Vector2& pos); + Vector2 Convert2DPositionToNDC(const Vector2& pos); Vector2 ConvertNDCTo2DPosition(const Vector2& ndc); std::vector GetProductOrFileVersion(bool productVersion); diff --git a/TombEngine/Specific/winmain.cpp b/TombEngine/Specific/winmain.cpp index fb583004a..7316a1992 100644 --- a/TombEngine/Specific/winmain.cpp +++ b/TombEngine/Specific/winmain.cpp @@ -62,14 +62,14 @@ Vector2i GetScreenResolution() std::vector GetAllSupportedScreenResolutions() { - std::vector result; + auto resList = std::vector{}; DEVMODE dm = { 0 }; dm.dmSize = sizeof(dm); for (int iModeNum = 0; EnumDisplaySettings(NULL, iModeNum, &dm) != 0; iModeNum++) { bool add = true; - for (auto m : result) + for (auto m : resList) { if (m.x == dm.dmPelsWidth && m.y == dm.dmPelsHeight) { @@ -79,30 +79,19 @@ std::vector GetAllSupportedScreenResolutions() } if (add) { - Vector2i resolution; - resolution.x = dm.dmPelsWidth; - resolution.y = dm.dmPelsHeight; - result.push_back(resolution); + auto res = Vector2i(dm.dmPelsWidth, dm.dmPelsHeight); + resList.push_back(res); } } std::sort( - result.begin(), - result.end(), + resList.begin(), resList.end(), [](Vector2i& a, Vector2i& b) { - if (a.x == b.x) - { - return (a.y < b.y); - } - else - { - return (a.x < b.x); - } - } - ); + return ((a.x == b.x) ? (a.y < b.y) : (a.x < b.x)); + }); - return result; + return resList; } void DisableDpiAwareness() diff --git a/TombEngine/TombEngine.vcxproj b/TombEngine/TombEngine.vcxproj index 59721b937..01e6f8ce5 100644 --- a/TombEngine/TombEngine.vcxproj +++ b/TombEngine/TombEngine.vcxproj @@ -324,10 +324,12 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" + + @@ -671,6 +673,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" + @@ -711,6 +714,9 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" + + + @@ -802,6 +808,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" + @@ -821,6 +828,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" + @@ -1128,6 +1136,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)" + diff --git a/TombEngine/TombEngine.vcxproj.user b/TombEngine/TombEngine.vcxproj.user index e6fdc4543..376f694fc 100644 --- a/TombEngine/TombEngine.vcxproj.user +++ b/TombEngine/TombEngine.vcxproj.user @@ -6,8 +6,7 @@ $(SolutionDir)Build\$(Configuration)\ WindowsLocalDebugger - -gameDir "P:\Projects\TombEngineAssets" -debug - -gameDir "P:\Projects\TombEngineAssets" -debug + /debug $(SolutionDir)Build\$(Configuration)\