Merge remote-tracking branch 'origin/DisplayString_Scale' into DisplayString_Scale

This commit is contained in:
hispidence 2023-10-13 09:23:34 +01:00
commit 0a3c0beaca
76 changed files with 1857 additions and 527 deletions

View file

@ -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.

View file

@ -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)

View file

@ -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();
}

View file

@ -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();
};

View file

@ -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;

View file

@ -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<int>{};
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<int>& 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);
}
}

View file

@ -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<Vector2> 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<SegmentData, SEGMENT_COUNT> 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<int, CrosshairData> Crosshairs = {}; // Key = item number.
public:
// Utilities
void Update(const ItemInfo& playerItem);
void Draw() const;
void Clear();
private:
// Update helpers
void Update(const std::vector<int>& itemNumbers);
// Object helpers
CrosshairData& GetNewCrosshair(int itemNumber);
void AddCrosshair(int itemNumber, const Vector3& targetPos);
void ClearInactiveCrosshairs();
void DrawDebug() const;
};
}

View file

@ -245,6 +245,8 @@ std::function<LaraRoutineFunction> 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<LaraRoutineFunction> lara_collision_routines[NUM_LARA_STATES + 1] =
@ -439,6 +441,8 @@ std::function<LaraRoutineFunction> 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)

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -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
};

View file

@ -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<LaraWeaponType, WeaponAnimData>
static const auto ANIM_DATA_MAP = std::unordered_map<LaraWeaponType, WeaponAnimData>
{
{ 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)

View file

@ -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();

View file

@ -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<DisplaySprite> 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();
}
}

View file

@ -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<DisplaySprite> 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();
}

View file

@ -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
{

View file

@ -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)

View file

@ -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;
}

View file

@ -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);
};

View file

@ -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)

View file

@ -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,

View file

@ -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();
}

View file

@ -1,15 +1,12 @@
#pragma once
#include <vector>
#include <d3d11.h>
#include <SimpleMath.h>
#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<RendererRoom*> RoomsToDraw;
std::vector<RendererLight*> LightsToDraw;
std::vector<RendererFogBulb> FogBulbsToDraw;
std::vector<RendererSpriteToDraw> SpritesToDraw;
std::map<int, std::vector<RendererStatic*>> SortedStaticsToDraw;
D3D11_VIEWPORT Viewport;
std::vector<RendererRoom*> RoomsToDraw = {};
std::vector<RendererLight*> LightsToDraw = {};
std::vector<RendererFogBulb> FogBulbsToDraw = {};
std::vector<RendererSpriteToDraw> SpritesToDraw = {};
std::vector<RendererDisplaySpriteToDraw> DisplaySpritesToDraw = {};
std::map<int, std::vector<RendererStatic*>> 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();
};

View file

@ -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<Vector2> 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;

View file

@ -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)

View file

@ -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<ns>(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
{

View file

@ -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, VERTEX_COUNT>
{
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<Vector2, VERTEX_COUNT>
{
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<RendererVertex, VERTEX_COUNT>{};
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<Vector2, VERTEX_COUNT>
{
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<RendererVertex, VERTEX_COUNT>{};
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<ID3D11Resource**>(&texture2D));
ID3D11Texture2D* texture2DPtr;
texture->GetResource(reinterpret_cast<ID3D11Resource**>(&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);
});
}
}

View file

@ -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<DebrisFragment> DebrisFragments;
std::vector<RendererVertex> 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();

View file

@ -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();
}

View file

@ -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;

View file

@ -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<RendererFogBulb> tempFogBulbs;
// Collect fog bulbs.
std::vector<RendererFogBulb> 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;

View file

@ -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.

View file

@ -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;
};
}

View file

@ -1,8 +1,9 @@
using CallbackDrawString = std::function<void(
const std::string&,
D3DCOLOR,
int, //x
int, //y
float, //scale
int //flags
)>;
using CallbackDrawString = std::function<
void(
const std::string&,
D3DCOLOR,
int, // X
int, // X
float, // Scale
int)>; // Flags

View file

@ -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"

View file

@ -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";

View file

@ -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<const std::exception&> exception, sol::string_view description)
{
@ -20,36 +23,38 @@ int lua_exception_handler(lua_State* luaStatePtr, sol::optional<const std::excep
ScriptInterfaceGame* ScriptInterfaceState::CreateGame()
{
return new LogicHandler(&s_solState, s_rootTable);
return new LogicHandler(&SolState, RootTable);
}
ScriptInterfaceFlowHandler* ScriptInterfaceState::CreateFlow()
{
return new FlowHandler(&s_solState, s_rootTable);
return new FlowHandler(&SolState, RootTable);
}
ScriptInterfaceObjectsHandler* ScriptInterfaceState::CreateObjectsHandler()
{
return new ObjectsHandler(&s_solState, s_rootTable);
return new ObjectsHandler(&SolState, RootTable);
}
ScriptInterfaceStringsHandler* ScriptInterfaceState::CreateStringsHandler()
{
return new StringsHandler(&s_solState, s_rootTable);
return new StringsHandler(&SolState, RootTable);
}
void ScriptInterfaceState::Init(const std::string& assetsDir)
{
s_solState.open_libraries(sol::lib::base, sol::lib::math, sol::lib::package, sol::lib::coroutine, sol::lib::table, sol::lib::string, sol::lib::debug);
SolState.open_libraries(
sol::lib::base, sol::lib::math, sol::lib::package, sol::lib::coroutine,
sol::lib::table, sol::lib::string, sol::lib::debug);
s_solState.script("package.path=\"" + assetsDir + "Scripts/?.lua\"");
s_solState.set_exception_handler(lua_exception_handler);
SolState.script("package.path=\"" + assetsDir + "Scripts/?.lua\"");
SolState.set_exception_handler(lua_exception_handler);
s_rootTable = sol::table{ s_solState.lua_state(), sol::create };
s_solState.set(ScriptReserved_TEN, s_rootTable);
RootTable = sol::table(SolState.lua_state(), sol::create);
SolState.set(ScriptReserved_TEN, RootTable);
// Misc. handlers not assigned above.
InventoryHandler::Register(&s_solState, s_rootTable);
Misc::Register(&s_solState, s_rootTable);
Effects::Register(&s_solState, s_rootTable);
InventoryHandler::Register(&SolState, RootTable);
Misc::Register(&SolState, RootTable);
Effects::Register(&SolState, RootTable);
}

View file

@ -28,9 +28,9 @@
// This alias is an effort to avoid the above problems.
template <typename ... Ts> using TypeOrNil = std::variant<Ts..., sol::nil_t, sol::object>;
// 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<Type>(ifThere) ? std::get<Type>(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<Type>(valueIfExists) ? std::get<Type>(valueIfExists) : valueIfMissing)
template<typename T> bool IsValidOptionalArg(const TypeOrNil<T> & arg)
{

View file

@ -0,0 +1,50 @@
#pragma once
#include <string>
#include <unordered_map>
#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<std::string, DisplaySpriteAlignMode> 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 }
};
}

View file

@ -0,0 +1,38 @@
#pragma once
#include <string>
#include <unordered_map>
#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<std::string, DisplaySpriteScaleMode> DISPLAY_SPRITE_SCALE_MODES
{
{ "FIT", DisplaySpriteScaleMode::Fit },
{ "FILL", DisplaySpriteScaleMode::Fill },
{ "STRETCH", DisplaySpriteScaleMode::Stretch }
};
}

View file

@ -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<ScriptDisplaySprite>(
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<int> priority, sol::optional<DisplaySpriteAlignMode> alignMode,
sol::optional<DisplaySpriteScaleMode> scaleMode, sol::optional<BLEND_MODES> 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));
}
}

View file

@ -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<int> priority, sol::optional<DisplaySpriteAlignMode> alignMode,
sol::optional<DisplaySpriteScaleMode> scaleMode, sol::optional<BLEND_MODES> blendMode);
};
}

View file

@ -1,10 +1,8 @@
#pragma once
// Last generated on 31/7/2022.
#include <string>
#include <unordered_map>
#include "Renderer/Renderer11Enums.h"
#include <unordered_map>
#include <string>
/***
Constants for blend mode IDs.
@ -34,17 +32,16 @@ The following constants are inside BlendID.
@table CONSTANT_STRING_HERE
*/
static const std::unordered_map<std::string, BLEND_MODES> 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 }
};

View file

@ -32,11 +32,11 @@ The following constants are inside EffectID.
static const std::unordered_map<std::string, EffectType> 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 }
};

View file

@ -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);
}

View file

@ -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&);
};

View file

@ -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;

View file

@ -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);

View file

@ -8,7 +8,7 @@ Fog
@pragma nostrip
*/
void Fog::Register(sol::table & parent)
void Fog::Register(sol::table& parent)
{
using ctors = sol::constructors<Fog(ScriptColor const&, short, short)>;
parent.new_usertype<Fog>("Fog",

View file

@ -20,5 +20,5 @@ struct Fog
void SetColor(ScriptColor const& col);
ScriptColor GetColor() const;
static void Register(sol::table &);
static void Register(sol::table&);
};

View file

@ -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>("Level",
sol::constructors<Level()>(),

View file

@ -6,7 +6,7 @@
#include "Scripting/Include/ScriptInterfaceLevel.h"
#include "Scripting/Internal/TEN/Flow/InventoryItem/InventoryItem.h"
static const std::unordered_map<std::string, WeatherType> kWeatherTypes
static const std::unordered_map<std::string, WeatherType> WEATHER_TYPES
{
{"None", WeatherType::None},
{"Rain", WeatherType::Rain},
@ -14,7 +14,7 @@ static const std::unordered_map<std::string, WeatherType> kWeatherTypes
};
static const std::unordered_map<std::string, LaraType> kLaraTypes
static const std::unordered_map<std::string, LaraType> 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;

View file

@ -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);

View file

@ -3,7 +3,7 @@
#include "Scripting/Internal/ScriptAssert.h"
#include <string>
static const std::unordered_map<std::string, ErrorMode> kErrorModes {
static const std::unordered_map<std::string, ErrorMode> ERROR_MODES {
{"SILENT", ErrorMode::Silent},
{"WARN", ErrorMode::Warn},
{"TERMINATE", ErrorMode::Terminate}

View file

@ -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);
}
}

View file

@ -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<int, int> PercentToScreen(double x, double y)
static std::tuple<int, int> PercentToScreen(float x, float y)
{
auto fWidth = static_cast<double>(g_Configuration.ScreenWidth);
auto fHeight = static_cast<double>(g_Configuration.ScreenHeight);
int resX = static_cast<int>(std::round(fWidth / 100.0 * x));
int resY = static_cast<int>(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<double, double> 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<float, float> ScreenToPercent(int x, int y)
{
auto fWidth = static_cast<double>(g_Configuration.ScreenWidth);
auto fHeight = static_cast<double>(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()
{

View file

@ -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<AIObject>(ScriptReserved_AIObject,
sol::no_constructor, // ability to spawn new ones could be added later

View file

@ -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);

View file

@ -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<CameraObject>(ScriptReserved_Camera,
sol::no_constructor, // ability to spawn new ones could be added later

View file

@ -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);

View file

@ -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;
};

View file

@ -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<Moveable> Create(
GAME_OBJECT_ID objID,

View file

@ -2157,6 +2157,7 @@ static const std::unordered_map<std::string, GAME_OBJECT_ID> 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 },

View file

@ -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<int, int> 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)

View file

@ -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<std::string, DisplayStringOptions> kDisplayStringOptionNames
static const std::unordered_map<std::string, DisplayStringOptions> 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<bool, static_cast<size_t>(DisplayStringOptions::NUM_OPTIONS)>;
using FlagArray = std::array<bool, (int)DisplayStringOptions::Count>;
// 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<int, int> GetPos() const;
void SetCol(const ScriptColor&);
ScriptColor GetCol();
void SetColor(const ScriptColor&);
ScriptColor GetColor();
void SetKey(const std::string&);
std::string GetKey() const;

View file

@ -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<decltype(param)>(param)...); },
[this](auto && ... param) {return ScheduleRemoveDisplayString(std::forward<decltype(param)>(param)...); },
[this](auto && ... param) {return GetDisplayString(std::forward<decltype(param)>(param)...); }
);
[this](auto && ... param) { return SetDisplayString(std::forward<decltype(param)>(param)...); },
[this](auto && ... param) { return ScheduleRemoveDisplayString(std::forward<decltype(param)>(param)...); },
[this](auto && ... param) { return GetDisplayString(std::forward<decltype(param)>(param)...); });
MakeReadOnlyTable(table_strings, ScriptReserved_DisplayStringOption, kDisplayStringOptionNames);
MakeReadOnlyTable(table_strings, ScriptReserved_DisplayStringOption, DISPLAY_STRING_OPTION_NAMES);
}
std::optional<std::reference_wrapper<UserDisplayString>> 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<size_t>(DisplayStringOptions::CENTER)])
if (str.m_flags[(size_t)DisplayStringOptions::Center])
flags |= PRINTSTRING_CENTER;
if (str.m_flags[static_cast<size_t>(DisplayStringOptions::RIGHT)])
if (str.m_flags[(size_t)DisplayStringOptions::Right])
flags |= PRINTSTRING_RIGHT;
if (str.m_flags[static_cast<size_t>(DisplayStringOptions::OUTLINE)])
if (str.m_flags[(size_t)DisplayStringOptions::Outline])
flags |= PRINTSTRING_OUTLINE;
if (str.m_flags[static_cast<size_t>(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);

View file

@ -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;
}
#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;
}

View file

@ -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;

View file

@ -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<int> Bindings = {};

View file

@ -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)

View file

@ -14,8 +14,8 @@ namespace TEN::Utils
std::vector<std::string> 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<unsigned short> GetProductOrFileVersion(bool productVersion);

View file

@ -62,14 +62,14 @@ Vector2i GetScreenResolution()
std::vector<Vector2i> GetAllSupportedScreenResolutions()
{
std::vector<Vector2i> result;
auto resList = std::vector<Vector2i>{};
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<Vector2i> 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()

View file

@ -324,10 +324,12 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Game\effects\Bubble.h" />
<ClInclude Include="Game\effects\DisplaySprite.h" />
<ClInclude Include="Game\GuiObjects.h" />
<ClInclude Include="Game\Hud\Hud.h" />
<ClInclude Include="Game\Hud\PickupSummary.h" />
<ClInclude Include="Game\Hud\StatusBars.h" />
<ClInclude Include="Game\Hud\TargetHighlighter.h" />
<ClInclude Include="Game\Lara\lara.h" />
<ClInclude Include="Game\Lara\lara_basic.h" />
<ClInclude Include="Game\Lara\lara_cheat.h" />
@ -671,6 +673,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
<ClInclude Include="Renderer\Frustum.h" />
<ClInclude Include="Renderer\IndexBuffer\IndexBuffer.h" />
<ClInclude Include="Renderer\Quad\RenderQuad.h" />
<ClInclude Include="Renderer\RendererSprite2D.h" />
<ClInclude Include="Renderer\RenderTarget2D\RenderTarget2D.h" />
<ClInclude Include="Renderer\RenderTargetCubeArray\RenderTargetCubeArray.h" />
<ClInclude Include="Renderer\RenderTargetCube\RenderTargetCube.h" />
@ -711,6 +714,9 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
<ClInclude Include="Scripting\Internal\ScriptAssert.h" />
<ClInclude Include="Scripting\Internal\ScriptUtil.h" />
<ClInclude Include="Scripting\Internal\TEN\Color\Color.h" />
<ClInclude Include="Scripting\Internal\TEN\DisplaySprite\AlignModes.h" />
<ClInclude Include="Scripting\Internal\TEN\DisplaySprite\ScaleModes.h" />
<ClInclude Include="Scripting\Internal\TEN\DisplaySprite\ScriptDisplaySprite.h" />
<ClInclude Include="Scripting\Internal\TEN\Effects\BlendIDs.h" />
<ClInclude Include="Scripting\Internal\TEN\Effects\EffectIDs.h" />
<ClInclude Include="Scripting\Internal\TEN\Effects\EffectsFunctions.h" />
@ -802,6 +808,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
<ClCompile Include="Game\effects\Bubble.cpp" />
<ClCompile Include="Game\effects\chaffFX.cpp" />
<ClCompile Include="Game\effects\debris.cpp" />
<ClCompile Include="Game\effects\DisplaySprite.cpp" />
<ClCompile Include="Game\effects\Drip.cpp" />
<ClCompile Include="Game\effects\effects.cpp" />
<ClCompile Include="Game\effects\Electricity.cpp" />
@ -821,6 +828,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
<ClCompile Include="Game\Hud\Hud.cpp" />
<ClCompile Include="Game\Hud\PickupSummary.cpp" />
<ClCompile Include="Game\Hud\StatusBars.cpp" />
<ClCompile Include="Game\Hud\TargetHighlighter.cpp" />
<ClCompile Include="Game\itemdata\creature_info.cpp" />
<ClCompile Include="Game\itemdata\itemdata.cpp" />
<ClCompile Include="Game\items.cpp" />
@ -1128,6 +1136,7 @@ xcopy /Y "$(SolutionDir)Libs\zlib\x64\*.dll" "$(TargetDir)"</Command>
<ClCompile Include="Scripting\Internal\ScriptInterfaceState.cpp" />
<ClCompile Include="Scripting\Internal\ScriptUtil.cpp" />
<ClCompile Include="Scripting\Internal\TEN\Color\Color.cpp" />
<ClCompile Include="Scripting\Internal\TEN\DisplaySprite\ScriptDisplaySprite.cpp" />
<ClCompile Include="Scripting\Internal\TEN\Effects\EffectsFunctions.cpp" />
<ClCompile Include="Scripting\Internal\TEN\Flow\Animations\Animations.cpp" />
<ClCompile Include="Scripting\Internal\TEN\Flow\FlowHandler.cpp" />

View file

@ -6,8 +6,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)Build\$(Configuration)\</LocalDebuggerWorkingDirectory>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
<LocalDebuggerCommandArguments>-gameDir "P:\Projects\TombEngineAssets" -debug</LocalDebuggerCommandArguments>
<RemoteDebuggerCommandArguments>-gameDir "P:\Projects\TombEngineAssets" -debug</RemoteDebuggerCommandArguments>
<LocalDebuggerCommandArguments>/debug</LocalDebuggerCommandArguments>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerWorkingDirectory>$(SolutionDir)Build\$(Configuration)\</LocalDebuggerWorkingDirectory>