Merge branch 'develop' into test

This commit is contained in:
Kubsy 2023-02-12 12:34:17 +00:00
commit 034ef1dd1b
35 changed files with 882 additions and 654 deletions

View file

@ -21,6 +21,8 @@ Version 1.0.7
- ItemFlags[6] = Distance to use the switch. (example: MySwitch:SetItemFlags(Distance Position, 6) - ItemFlags[6] = Distance to use the switch. (example: MySwitch:SetItemFlags(Distance Position, 6)
* Implement squash and stretch water bubbles. * Implement squash and stretch water bubbles.
* Prevent Lara from drawing weapons during parallel bar swinging. * Prevent Lara from drawing weapons during parallel bar swinging.
* Implement squash and stretch water bubbles.
* Implement a new pickup display inspired by OpenLara.
Lua API Changes Lua API Changes
* Fix Camera:SetPosition not updating camera position when it is played simultaneously. * Fix Camera:SetPosition not updating camera position when it is played simultaneously.

215
TombEngine/Game/Hud/Hud.cpp Normal file
View file

@ -0,0 +1,215 @@
#include "framework.h"
#include "Game/Hud/Hud.h"
#include "Game/control/control.h"
#include "Game/Hud/PickupSummary.h"
#include "Game/items.h"
#include "Game/Lara/lara.h"
#include "Game/Lara/lara_helpers.h"
#include "Renderer/Renderer11.h"
using namespace TEN::Math;
using namespace TEN::Renderer;
extern RendererHUDBar* g_HealthBar;
extern RendererHUDBar* g_DashBar;
extern RendererHUDBar* g_AirBar;
namespace TEN::Hud
{
HudController g_Hud = HudController();
void HudController::Update()
{
this->PickupSummary.Update();
}
void HudController::Draw() const
{
this->PickupSummary.Draw();
}
void HudController::Clear()
{
this->PickupSummary.Clear();
}
constexpr auto HEALTH_BAR_TIMER_MAX = 40.0f;
struct HealthBarData
{
float Value = LARA_HEALTH_MAX;
float PrevValue = LARA_HEALTH_MAX;
float MutateAmount = 0.0f;
float Timer = HEALTH_BAR_TIMER_MAX;
};
auto HealthBar = HealthBarData();
static void DrawHealthBarOverlay(ItemInfo* item, float value)
{
const auto& player = *GetLaraInfo(item);
if (CurrentLevel != 0)
g_Renderer.DrawBar(value, g_HealthBar, ID_HEALTH_BAR_TEXTURE, GlobalCounter, player.PoisonPotency != 0);
}
static void DrawHealthBar(ItemInfo* item, float value)
{
const auto& player = *GetLaraInfo(item);
g_Renderer.DrawBar(value, g_HealthBar, ID_HEALTH_BAR_TEXTURE, GlobalCounter, player.PoisonPotency != 0);
}
static void DrawHealthBar(ItemInfo* item, bool doFlash)
{
const auto& player = *GetLaraInfo(item);
// Flash when at critical capacity and bar is not transitioning.
if (HealthBar.Value <= LARA_HEALTH_CRITICAL)
{
if (!BinocularRange)
{
if (doFlash || HealthBar.MutateAmount)
DrawHealthBar(item, HealthBar.Value / LARA_HEALTH_MAX);
else
DrawHealthBar(item, 0.0f);
}
else
{
if (doFlash || HealthBar.MutateAmount)
DrawHealthBarOverlay(item, HealthBar.Value / LARA_HEALTH_MAX);
else
DrawHealthBarOverlay(item, 0.0f);
}
}
else if (HealthBar.Timer > 0.0f || HealthBar.Value <= 0.0f ||
player.Control.HandStatus == HandStatus::WeaponReady &&
player.Control.Weapon.GunType != LaraWeaponType::Torch ||
player.PoisonPotency)
{
if (!BinocularRange)
DrawHealthBar(item, HealthBar.Value / LARA_HEALTH_MAX);
else
DrawHealthBarOverlay(item, HealthBar.Value / LARA_HEALTH_MAX);
}
}
static void DrawAirBar(float value)
{
g_Renderer.DrawBar(value, g_AirBar, ID_AIR_BAR_TEXTURE, 0, false);
}
static void DrawAirBar(ItemInfo* item, bool doFlash)
{
const auto& player = *GetLaraInfo(item);
if (player.Air == LARA_AIR_MAX || item->HitPoints <= 0)
return;
if (player.Vehicle == NO_ITEM ||
g_Level.Items[player.Vehicle].ObjectNumber != ID_UPV)
{
if (player.Control.WaterStatus != WaterStatus::Underwater &&
player.Control.WaterStatus != WaterStatus::TreadWater &&
!(TestEnvironment(ENV_FLAG_SWAMP, item) && player.WaterSurfaceDist < -(CLICK(3) - 1)))
{
return;
}
}
float air = player.Air;
if (air < 0.0f)
{
air = 0.0f;
}
else if (air > LARA_AIR_MAX)
{
air = LARA_AIR_MAX;
}
if (air <= LARA_AIR_CRITICAL)
{
if (doFlash)
DrawAirBar(air / LARA_AIR_MAX);
else
DrawAirBar(0.0f);
}
else
{
DrawAirBar(air / LARA_AIR_MAX);
}
}
static void DrawSprintBar(float value)
{
g_Renderer.DrawBar(value, g_DashBar, ID_DASH_BAR_TEXTURE, 0, false);
}
static void DrawSprintBar(ItemInfo* item)
{
const auto& player = *GetLaraInfo(item);
if (player.SprintEnergy < LARA_SPRINT_ENERGY_MAX)
DrawSprintBar(player.SprintEnergy / LARA_SPRINT_ENERGY_MAX);
}
void UpdateBars(ItemInfo* item)
{
const auto& player = *GetLaraInfo(item);
if (HealthBar.Timer > 0.0f)
HealthBar.Timer -= 1.0f;
float hitPoints = item->HitPoints;
if (hitPoints < 0.0f)
{
hitPoints = 0.0f;
}
else if (hitPoints > LARA_HEALTH_MAX)
{
hitPoints = LARA_HEALTH_MAX;
}
// Smoothly transition health bar display.
if (HealthBar.PrevValue != hitPoints)
{
HealthBar.MutateAmount += HealthBar.PrevValue - hitPoints;
HealthBar.PrevValue = hitPoints;
HealthBar.Timer = HEALTH_BAR_TIMER_MAX;
}
if ((HealthBar.Value - HealthBar.MutateAmount) < 0.0f)
{
HealthBar.MutateAmount = HealthBar.Value;
}
else if ((HealthBar.Value - HealthBar.MutateAmount) > LARA_HEALTH_MAX)
{
HealthBar.MutateAmount = HealthBar.Value - LARA_HEALTH_MAX;
}
HealthBar.Value -= HealthBar.MutateAmount / 3;
HealthBar.MutateAmount -= HealthBar.MutateAmount / 3;
if (abs(HealthBar.MutateAmount) < 0.5f)
{
HealthBar.MutateAmount = 0.0f;
HealthBar.Value = hitPoints;
}
}
void DrawHud(ItemInfo* item)
{
static bool doFlash = false;
if ((GameTimer & 0x07) == 0x07)
doFlash = !doFlash;
if (CurrentLevel == 0 || CinematicBarsHeight > 0)
return;
DrawSprintBar(item);
DrawHealthBar(item, doFlash);
DrawAirBar(item, doFlash);
}
}

24
TombEngine/Game/Hud/Hud.h Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include "Game/Hud/PickupSummary.h"
struct ItemInfo;
namespace TEN::Hud
{
class HudController
{
public:
// Components
PickupSummaryController PickupSummary = {};
// Utilities
void Update();
void Draw() const;
void Clear();
};
extern HudController g_Hud;
void UpdateBars(ItemInfo* item);
void DrawHud(ItemInfo* item);
}

View file

@ -0,0 +1,212 @@
#include "framework.h"
#include "Game/Hud/PickupSummary.h"
#include "Game/pickup/pickup.h"
#include "Math/Math.h"
#include "Renderer/Renderer11.h"
#include "Specific/clock.h"
#include "Specific/setup.h"
using namespace TEN::Math;
using TEN::Renderer::g_Renderer;
namespace TEN::Hud
{
constexpr auto DISPLAY_PICKUP_COUNT_MAX = 64;
bool DisplayPickup::IsOffscreen() const
{
constexpr auto SCREEN_THRESHOLD_COEFF = 0.1f;
constexpr auto SCREEN_THRESHOLD = Vector2(SCREEN_SPACE_RES.x * SCREEN_THRESHOLD_COEFF, SCREEN_SPACE_RES.y * SCREEN_THRESHOLD_COEFF);
return (Position.x <= -SCREEN_THRESHOLD.x ||
Position.y <= -SCREEN_THRESHOLD.y ||
Position.x >= (SCREEN_SPACE_RES.x + SCREEN_THRESHOLD.x) ||
Position.y >= (SCREEN_SPACE_RES.y + SCREEN_THRESHOLD.y));
}
void DisplayPickup::Update(bool isHead)
{
constexpr auto LIFE_BUFFER = 0.2f;
constexpr auto SCALE_MAX = 0.4f;
constexpr auto SCALE_MIN = 0.2f;
constexpr auto HIDE_VELOCITY_COEFF = 3 / 100.0f;
constexpr auto POSITION_LERP_ALPHA = 0.2f;
constexpr auto STRING_SCALAR_ALPHA = 0.25f;
constexpr auto ROTATION = EulerAngles(0, ANGLE(3.0f), 0);
// Move offscreen.
if (Life <= 0.0f && isHead)
{
auto vel = Vector2(SCREEN_SPACE_RES.x * HIDE_VELOCITY_COEFF, 0.0f);
this->Position += vel;
}
// Update position, scale, and opacity.
else if (Life > 0.0f)
{
float totalDist = Vector2::Distance(Origin, Target);
float coveredDist = Vector2::Distance(Origin, Position);
// Handle edge case when stack shifts.
if (coveredDist > totalDist)
{
this->Origin = Position;
totalDist = Vector2::Distance(Origin, Target);
coveredDist = Vector2::Distance(Origin, Position);
}
float alpha = coveredDist / totalDist;
this->Position = Vector2::Lerp(Position, Target, POSITION_LERP_ALPHA);
this->Scale = std::max(Lerp(SCALE_MIN, SCALE_MAX, alpha), Scale);
this->Opacity = std::max(Lerp(0.0f, 1.0f, alpha), Opacity);
}
// Update orientation.
this->Orientation += ROTATION;
// Update string scale.
float alpha = Scale / SCALE_MAX;
this->StringScale = Lerp(0.0f, 1.0f, alpha) * (1.0f + StringScalar);
this->StringScalar = Lerp(StringScalar, 0.0f, STRING_SCALAR_ALPHA);
// Update life.
this->Life -= 1.0f;
if (!isHead)
this->Life = std::max(Life, round(LIFE_BUFFER * FPS));
}
void PickupSummaryController::AddDisplayPickup(GAME_OBJECT_ID objectID, const Vector3& pos)
{
constexpr auto DEFAULT_POSITION = Vector2(0.0f, 0.0f);
constexpr auto LIFE_MAX = 2.5f;
constexpr auto STRING_SCALAR_MAX = 0.6f;
// TODO: Call this elsewhere, maybe in pickup.cpp. -- Sezz 2023.02.06
PickedUpObject(objectID);
// Increment count of existing display pickup if it exists.
for (auto& pickup : this->DisplayPickups)
{
// Ignore already disappearing display pickups.
if (pickup.Life <= 0.0f)
continue;
if (pickup.ObjectID == objectID)
{
pickup.Count++;
pickup.Life = round(LIFE_MAX * FPS);
pickup.StringScalar = STRING_SCALAR_MAX;
return;
}
}
// Create new display pickup.
auto& pickup = this->GetNewDisplayPickup();
auto screenPos = g_Renderer.GetScreenSpacePosition(pos);
if (screenPos == INVALID_SCREEN_SPACE_POSITION)
screenPos = DEFAULT_POSITION;
pickup.ObjectID = objectID;
pickup.Count = 1;
pickup.Position =
pickup.Origin = screenPos;
pickup.Target = Vector2::Zero;
pickup.Life = round(LIFE_MAX * FPS);
pickup.Scale = 0.0f;
pickup.Opacity = 0.0f;
pickup.HideVelocity = 0.0f;
pickup.StringScale = 0.0f;
pickup.StringScalar = 0.0f;
}
void PickupSummaryController::Update()
{
if (DisplayPickups.empty())
return;
// Get and apply stack screen positions as targets.
auto stackPositions = this->GetStackPositions();
for (int i = 0; i < stackPositions.size(); i++)
this->DisplayPickups[i].Target = stackPositions[i];
// Update display pickups.
bool isHead = true;
for (auto& pickup : this->DisplayPickups)
{
pickup.Update(isHead);
isHead = false;
}
this->ClearInactiveDisplayPickups();
}
void PickupSummaryController::Draw() const
{
//this->DrawDebug();
if (DisplayPickups.empty())
return;
// Draw display pickups.
for (const auto& pickup : this->DisplayPickups)
{
if (pickup.IsOffscreen())
continue;
g_Renderer.DrawPickup(pickup);
}
}
void PickupSummaryController::Clear()
{
this->DisplayPickups.clear();
}
std::vector<Vector2> PickupSummaryController::GetStackPositions() const
{
constexpr auto STACK_HEIGHT_MAX = 6;
constexpr auto SCREEN_SCALE_COEFF = 1 / 7.0f;
constexpr auto SCREEN_OFFSET_COEFF = 1 / 7.0f;
constexpr auto SCREEN_SCALE = Vector2(SCREEN_SPACE_RES.x * SCREEN_SCALE_COEFF, SCREEN_SPACE_RES.y * SCREEN_SCALE_COEFF);
constexpr auto SCREEN_OFFSET = Vector2(SCREEN_SPACE_RES.y * SCREEN_OFFSET_COEFF);
// Calculate screen positions.
auto stackPositions = std::vector<Vector2>{};
for (int i = 0; i < DisplayPickups.size(); i++)
{
auto relPos = (i < STACK_HEIGHT_MAX) ? (Vector2(0.0f, i) * SCREEN_SCALE) : Vector2(0.0f, SCREEN_SPACE_RES.y);
auto pos = (SCREEN_SPACE_RES - relPos) - SCREEN_OFFSET;
stackPositions.push_back(pos);
}
return stackPositions;
}
DisplayPickup& PickupSummaryController::GetNewDisplayPickup()
{
// Add and return new display pickup.
if (DisplayPickups.size() < DISPLAY_PICKUP_COUNT_MAX)
return this->DisplayPickups.emplace_back();
// Clear and return most recent display pickup.
auto& pickup = this->DisplayPickups.back();
pickup = DisplayPickup();
return pickup;
}
void PickupSummaryController::ClearInactiveDisplayPickups()
{
this->DisplayPickups.erase(
std::remove_if(
this->DisplayPickups.begin(), this->DisplayPickups.end(),
[](const DisplayPickup& pickup) { return ((pickup.Life <= 0.0f) && pickup.IsOffscreen()); }),
this->DisplayPickups.end());
}
void PickupSummaryController::DrawDebug() const
{
g_Renderer.PrintDebugMessage("Num. display pickups: %d", DisplayPickups.size());
}
}

View file

@ -0,0 +1,52 @@
#pragma once
#include "Math/Math.h"
#include "Objects/game_object_ids.h"
using namespace TEN::Math;
namespace TEN::Hud
{
struct DisplayPickup
{
GAME_OBJECT_ID ObjectID = ID_NO_OBJECT;
unsigned int Count = 0;
Vector2 Position = Vector2::Zero;
Vector2 Origin = Vector2::Zero;
Vector2 Target = Vector2::Zero;
EulerAngles Orientation = EulerAngles::Zero;
float Life = 0.0f;
float Scale = 0.0f;
float Opacity = 0.0f; // BIG TODO: Object transparency in renderer.
float HideVelocity = 0.0f;
float StringScale = 0.0f;
float StringScalar = 0.0f;
bool IsOffscreen() const;
void Update(bool isHead);
};
class PickupSummaryController
{
private:
// Components
std::deque<DisplayPickup> DisplayPickups = {};
public:
// Utilities
void AddDisplayPickup(GAME_OBJECT_ID objectID, const Vector3& pos);
void Update();
void Draw() const;
void Clear();
private:
// Helpers
std::vector<Vector2> GetStackPositions() const;
DisplayPickup& GetNewDisplayPickup();
void ClearInactiveDisplayPickups();
void DrawDebug() const;
};
}

View file

@ -4,7 +4,7 @@
#include "Game/animation.h" #include "Game/animation.h"
#include "Game/camera.h" #include "Game/camera.h"
#include "Game/collision/collide_room.h" #include "Game/collision/collide_room.h"
#include "Game/health.h" #include "Game/Hud/Hud.h"
#include "Game/items.h" #include "Game/items.h"
#include "Game/Lara/lara.h" #include "Game/Lara/lara.h"
#include "Game/Lara/lara_tests.h" #include "Game/Lara/lara_tests.h"

View file

@ -1,7 +1,7 @@
#include "framework.h" #include "framework.h"
#include "Game/Lara/lara_initialise.h" #include "Game/Lara/lara_initialise.h"
#include "Game/health.h" #include "Game/Hud/Hud.h"
#include "Game/items.h" #include "Game/items.h"
#include "Game/Lara/lara.h" #include "Game/Lara/lara.h"
#include "Game/Lara/lara_flare.h" #include "Game/Lara/lara_flare.h"

View file

@ -545,8 +545,6 @@ void ClampRotation(Pose& outPose, short angle, short rotation)
Vector3i GetJointPosition(ItemInfo* item, int jointIndex, const Vector3i& relOffset) Vector3i GetJointPosition(ItemInfo* item, int jointIndex, const Vector3i& relOffset)
{ {
// Use matrices done in the renderer to transform the offset vector. // Use matrices done in renderer to transform relative offset.
auto pos = relOffset.ToVector3(); return Vector3i(g_Renderer.GetAbsEntityBonePosition(item->Index, jointIndex, relOffset.ToVector3()));
g_Renderer.GetItemAbsBonePosition(item->Index, pos, jointIndex);
return Vector3i(pos);
} }

View file

@ -24,11 +24,11 @@
#include "Game/effects/tomb4fx.h" #include "Game/effects/tomb4fx.h"
#include "Game/effects/weather.h" #include "Game/effects/weather.h"
#include "Game/Gui.h" #include "Game/Gui.h"
#include "Game/Hud/Hud.h"
#include "Game/Lara/lara.h" #include "Game/Lara/lara.h"
#include "Game/Lara/lara_cheat.h" #include "Game/Lara/lara_cheat.h"
#include "Game/Lara/lara_helpers.h" #include "Game/Lara/lara_helpers.h"
#include "Game/Lara/lara_one_gun.h" #include "Game/Lara/lara_one_gun.h"
#include "Game/health.h"
#include "Game/items.h" #include "Game/items.h"
#include "Game/pickup/pickup.h" #include "Game/pickup/pickup.h"
#include "Game/room.h" #include "Game/room.h"
@ -68,6 +68,7 @@ using namespace TEN::Entities::Generic;
using namespace TEN::Entities::Switches; using namespace TEN::Entities::Switches;
using namespace TEN::Entities::TR4; using namespace TEN::Entities::TR4;
using namespace TEN::Floordata; using namespace TEN::Floordata;
using namespace TEN::Hud;
using namespace TEN::Input; using namespace TEN::Input;
using namespace TEN::Math; using namespace TEN::Math;
using namespace TEN::Renderer; using namespace TEN::Renderer;
@ -213,9 +214,10 @@ GameStatus ControlPhase(int numFrames)
UpdateBeetleSwarm(); UpdateBeetleSwarm();
UpdateLocusts(); UpdateLocusts();
// Update screen UI and overlays. // Update HUD.
UpdateBars(LaraItem); UpdateBars(LaraItem);
UpdateFadeScreenAndCinematicBars(); UpdateFadeScreenAndCinematicBars();
g_Hud.Update();
// Rumble screen (like in submarine level of TRC). // Rumble screen (like in submarine level of TRC).
if (g_GameFlow->GetLevel(CurrentLevel)->Rumble) if (g_GameFlow->GetLevel(CurrentLevel)->Rumble)
@ -285,7 +287,6 @@ GameStatus DoLevel(int levelIndex, bool loadGame)
// Initialize items, effects, lots, and cameras. // Initialize items, effects, lots, and cameras.
InitialiseFXArray(true); InitialiseFXArray(true);
InitialisePickupDisplay();
InitialiseCamera(); InitialiseCamera();
InitialiseSpotCamSequences(isTitle); InitialiseSpotCamSequences(isTitle);
InitialiseHair(); InitialiseHair();
@ -411,6 +412,9 @@ void CleanUp()
// Clear swarm enemies. // Clear swarm enemies.
ClearSwarmEnemies(nullptr); ClearSwarmEnemies(nullptr);
// Clear HUD.
g_Hud.Clear();
// Clear soundtrack masks. // Clear soundtrack masks.
ClearSoundTrackMasks(); ClearSoundTrackMasks();
@ -434,9 +438,10 @@ void InitialiseScripting(int levelIndex, bool loadGame)
g_GameScript->InitCallbacks(); g_GameScript->InitCallbacks();
g_GameStringsHandler->SetCallbackDrawString([](std::string const key, D3DCOLOR col, int x, int y, int flags) g_GameStringsHandler->SetCallbackDrawString([](std::string const key, D3DCOLOR col, int x, int y, int flags)
{ {
g_Renderer.AddString(float(x) / float(g_Configuration.Width) * REFERENCE_RES_WIDTH, g_Renderer.AddString(
float(y) / float(g_Configuration.Height) * REFERENCE_RES_HEIGHT, float(x) / float(g_Configuration.Width) * SCREEN_SPACE_RES.x,
key.c_str(), col, flags); float(y) / float(g_Configuration.Height) * SCREEN_SPACE_RES.y,
key.c_str(), col, flags);
}); });
} }

View file

@ -33,8 +33,8 @@ using namespace TEN::Utils;
namespace TEN::Gui namespace TEN::Gui
{ {
constexpr int LINE_HEIGHT = 25; constexpr int LINE_HEIGHT = 25;
constexpr int PHD_CENTER_X = REFERENCE_RES_WIDTH / 2; constexpr int PHD_CENTER_X = SCREEN_SPACE_RES.x / 2;
constexpr int PHD_CENTER_Y = REFERENCE_RES_HEIGHT / 2; constexpr int PHD_CENTER_Y = SCREEN_SPACE_RES.y / 2;
constexpr int VOLUME_MAX = 100; constexpr int VOLUME_MAX = 100;
@ -2486,12 +2486,14 @@ namespace TEN::Gui
g_Renderer.AddString(PHD_CENTER_X, 380, &invTextBuffer[0], PRINTSTRING_COLOR_YELLOW, PRINTSTRING_CENTER | PRINTSTRING_OUTLINE); g_Renderer.AddString(PHD_CENTER_X, 380, &invTextBuffer[0], PRINTSTRING_COLOR_YELLOW, PRINTSTRING_CENTER | PRINTSTRING_OUTLINE);
if (n == *CurrentAmmoType) if (n == *CurrentAmmoType)
g_Renderer.DrawObjectOn2DPosition(x, y, objectNumber, AmmoObjectList[n].Orientation, scaler); g_Renderer.DrawObjectOn2DPosition(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
else else
g_Renderer.DrawObjectOn2DPosition(x, y, objectNumber, AmmoObjectList[n].Orientation, scaler); g_Renderer.DrawObjectOn2DPosition(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
} }
else else
g_Renderer.DrawObjectOn2DPosition(x, y, objectNumber, AmmoObjectList[n].Orientation, scaler); {
g_Renderer.DrawObjectOn2DPosition(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
}
xPos += OBJLIST_SPACING; xPos += OBJLIST_SPACING;
} }
@ -2775,9 +2777,9 @@ namespace TEN::Gui
int objectNumber; int objectNumber;
if (ringIndex == (int)RingTypes::Inventory) if (ringIndex == (int)RingTypes::Inventory)
objectNumber = int(PHD_CENTER_Y - (REFERENCE_RES_HEIGHT + 1) * 0.0625 * 2.5); objectNumber = int(PHD_CENTER_Y - (SCREEN_SPACE_RES.y + 1) * 0.0625 * 2.5);
else else
objectNumber = int(PHD_CENTER_Y + (REFERENCE_RES_HEIGHT + 1) * 0.0625 * 2.0); objectNumber = int(PHD_CENTER_Y + (SCREEN_SPACE_RES.y + 1) * 0.0625 * 2.0);
g_Renderer.AddString(PHD_CENTER_X, objectNumber, textBufferMe, PRINTSTRING_COLOR_YELLOW, PRINTSTRING_CENTER | PRINTSTRING_OUTLINE); g_Renderer.AddString(PHD_CENTER_X, objectNumber, textBufferMe, PRINTSTRING_COLOR_YELLOW, PRINTSTRING_CENTER | PRINTSTRING_OUTLINE);
} }
@ -2830,7 +2832,7 @@ namespace TEN::Gui
auto& orientation = Rings[ringIndex]->CurrentObjectList[n].Orientation; auto& orientation = Rings[ringIndex]->CurrentObjectList[n].Orientation;
int bits = InventoryObjectTable[Rings[ringIndex]->CurrentObjectList[n].InventoryItem].MeshBits; int bits = InventoryObjectTable[Rings[ringIndex]->CurrentObjectList[n].InventoryItem].MeshBits;
g_Renderer.DrawObjectOn2DPosition(x, ringIndex == (int)RingTypes::Inventory ? y : y2, objectNumber, orientation, scaler, bits); g_Renderer.DrawObjectOn2DPosition(objectNumber, Vector2(x, (ringIndex == (int)RingTypes::Inventory) ? y : y2), orientation, scaler, bits);
if (++n >= Rings[ringIndex]->NumObjectsInList) if (++n >= Rings[ringIndex]->NumObjectsInList)
n = 0; n = 0;
@ -3043,7 +3045,7 @@ namespace TEN::Gui
// TODO // TODO
return; return;
g_Renderer.DrawObjectOn2DPosition(130, 480, ID_COMPASS_ITEM, EulerAngles(ANGLE(90.0f), 0, ANGLE(180.0f)), InventoryObjectTable[INV_OBJECT_COMPASS].Scale1); g_Renderer.DrawObjectOn2DPosition(ID_COMPASS_ITEM, Vector2(130, 480), EulerAngles(ANGLE(90.0f), 0, ANGLE(180.0f)), InventoryObjectTable[INV_OBJECT_COMPASS].Scale1);
short compassSpeed = phd_sin(CompassNeedleAngle - item->Pose.Orientation.y); short compassSpeed = phd_sin(CompassNeedleAngle - item->Pose.Orientation.y);
short compassAngle = (item->Pose.Orientation.y + compassSpeed) - ANGLE(180.0f); short compassAngle = (item->Pose.Orientation.y + compassSpeed) - ANGLE(180.0f);
Matrix::CreateRotationY(compassAngle); Matrix::CreateRotationY(compassAngle);

View file

@ -1,285 +0,0 @@
#include "framework.h"
#include "Game/health.h"
#include "Game/animation.h"
#include "Game/camera.h"
#include "Game/control/control.h"
#include "Game/items.h"
#include "Game/Lara/lara.h"
#include "Game/Lara/lara_helpers.h"
#include "Game/Lara/lara_tests.h"
#include "Game/pickup/pickup.h"
#include "Renderer/Renderer11.h"
#include "Specific/level.h"
using namespace TEN::Renderer;
short PickupX;
short PickupY;
short PickupVel;
short CurrentPickup;
DisplayPickup Pickups[MAX_COLLECTED_PICKUPS];
float HealthBarOldValue = LARA_HEALTH_MAX;
float HealthBarValue = HealthBarOldValue;
float HealthBarMutateAmount = 0;
int HealthBarTimer = 40;
bool EnableSmoothHealthBar = true;
extern RendererHUDBar* g_HealthBar;
extern RendererHUDBar* g_DashBar;
extern RendererHUDBar* g_AirBar;
void DrawHUD(ItemInfo* item)
{
static bool doFlash = false;
if ((GameTimer & 0x07) == 0x07)
doFlash = !doFlash;
if (CurrentLevel == 0 || CinematicBarsHeight > 0)
return;
DrawSprintBar(LaraItem);
DrawHealthBar(LaraItem, doFlash);
DrawAirBar(LaraItem, doFlash);
DrawAllPickups();
}
void DrawHealthBarOverlay(ItemInfo* item, int value)
{
const auto& lara = *GetLaraInfo(item);
if (CurrentLevel)
g_Renderer.DrawBar(value, g_HealthBar, ID_HEALTH_BAR_TEXTURE, GlobalCounter, Lara.PoisonPotency);
}
void DrawHealthBar(ItemInfo* item, float value)
{
const auto& lara = *GetLaraInfo(item);
g_Renderer.DrawBar(value, g_HealthBar, ID_HEALTH_BAR_TEXTURE, GlobalCounter, lara.PoisonPotency);
}
void DrawHealthBar(ItemInfo* item, bool doFlash)
{
const auto& lara = *GetLaraInfo(item);
// Flash when at critical capacity and bar is not transitioning.
if (HealthBarValue <= LARA_HEALTH_CRITICAL)
{
if (!BinocularRange)
{
if (doFlash || HealthBarMutateAmount)
DrawHealthBar(item, HealthBarValue / LARA_HEALTH_MAX);
else
DrawHealthBar(item, 0.0f);
}
else
{
if (doFlash || HealthBarMutateAmount)
DrawHealthBarOverlay(item, HealthBarValue / LARA_HEALTH_MAX);
else
DrawHealthBarOverlay(item, 0);
}
}
else if (HealthBarTimer > 0 || HealthBarValue <= 0 ||
lara.Control.HandStatus == HandStatus::WeaponReady &&
lara.Control.Weapon.GunType != LaraWeaponType::Torch ||
lara.PoisonPotency)
{
if (!BinocularRange)
DrawHealthBar(item, HealthBarValue / LARA_HEALTH_MAX);
else
DrawHealthBarOverlay(item, HealthBarValue / LARA_HEALTH_MAX);
}
}
void DrawAirBar(float value)
{
g_Renderer.DrawBar(value, g_AirBar,ID_AIR_BAR_TEXTURE, 0, 0);
}
void DrawAirBar(ItemInfo* item, bool doFlash)
{
const auto& lara = *GetLaraInfo(item);
if (lara.Air == LARA_AIR_MAX || item->HitPoints <= 0)
return;
if (lara.Vehicle == NO_ITEM ||
g_Level.Items[lara.Vehicle].ObjectNumber != ID_UPV)
{
if (lara.Control.WaterStatus != WaterStatus::Underwater &&
lara.Control.WaterStatus != WaterStatus::TreadWater &&
!(TestEnvironment(ENV_FLAG_SWAMP, item) && lara.WaterSurfaceDist < -(CLICK(3) - 1)))
return;
}
float air = lara.Air;
if (air < 0.0f)
{
air = 0.0f;
}
else if (air > LARA_AIR_MAX)
{
air = LARA_AIR_MAX;
}
if (air <= LARA_AIR_CRITICAL)
{
if (doFlash)
DrawAirBar(air / LARA_AIR_MAX);
else
DrawAirBar(0.0f);
}
else
{
DrawAirBar(air / LARA_AIR_MAX);
}
}
void DrawSprintBar(float value)
{
g_Renderer.DrawBar(value, g_DashBar, ID_DASH_BAR_TEXTURE, 0, 0);
}
void DrawSprintBar(ItemInfo* item)
{
const auto& lara = *GetLaraInfo(item);
if (lara.SprintEnergy < LARA_SPRINT_ENERGY_MAX)
DrawSprintBar(lara.SprintEnergy / LARA_SPRINT_ENERGY_MAX);
}
void DrawAllPickups()
{
auto& pickup = Pickups[CurrentPickup];
if (pickup.Life > 0)
{
if (PickupX > 0)
PickupX += -PickupX >> 3;
else
pickup.Life--;
}
else if (pickup.Life == 0)
{
if (PickupX < 128)
{
if (PickupVel < 16)
PickupVel++;
PickupX += PickupVel;
}
else
{
pickup.Life = -1;
PickupVel = 0;
}
}
else
{
int i;
for (i = 0; i < MAX_COLLECTED_PICKUPS; i++)
{
if (Pickups[CurrentPickup].Life > 0)
break;
CurrentPickup++;
CurrentPickup &= (MAX_COLLECTED_PICKUPS - 1);
}
if (i == MAX_COLLECTED_PICKUPS)
{
CurrentPickup = 0;
return;
}
}
g_Renderer.DrawPickup(Pickups[CurrentPickup].ObjectNumber);
}
void AddDisplayPickup(GAME_OBJECT_ID objectNumber)
{
for (auto& pickup : Pickups)
{
if (pickup.Life < 0)
{
pickup.Life = 45;
pickup.ObjectNumber = objectNumber;
break;
}
}
// No free slot found; pickup the object without displaying it.
PickedUpObject(objectNumber);
}
void InitialisePickupDisplay()
{
for (auto& pickup : Pickups)
pickup.Life = -1;
PickupX = 128;
PickupY = 128;
PickupVel = 0;
CurrentPickup = 0;
}
void UpdateBars(ItemInfo* item)
{
if (HealthBarTimer)
HealthBarTimer--;
const auto& lara = *GetLaraInfo(item);
float hitPoints = item->HitPoints;
if (hitPoints < 0)
{
hitPoints = 0;
}
else if (hitPoints > LARA_HEALTH_MAX)
{
hitPoints = LARA_HEALTH_MAX;
}
// Smoothly transition health bar display.
if (EnableSmoothHealthBar)
{
if (HealthBarOldValue != hitPoints)
{
HealthBarMutateAmount += HealthBarOldValue - hitPoints;
HealthBarOldValue = hitPoints;
HealthBarTimer = 40;
}
if (HealthBarValue - HealthBarMutateAmount < 0)
{
HealthBarMutateAmount = HealthBarValue;
}
else if (HealthBarValue - HealthBarMutateAmount > LARA_HEALTH_MAX)
{
HealthBarMutateAmount = HealthBarValue - LARA_HEALTH_MAX;
}
HealthBarValue -= HealthBarMutateAmount / 3;
HealthBarMutateAmount -= HealthBarMutateAmount / 3;
if (HealthBarMutateAmount > -0.5f && HealthBarMutateAmount < 0.5f)
{
HealthBarMutateAmount = 0;
HealthBarValue = hitPoints;
}
}
// Discretely transition health bar display.
else
{
if (HealthBarOldValue != hitPoints)
{
HealthBarOldValue = hitPoints;
HealthBarValue = hitPoints;
HealthBarTimer = 40;
}
}
}

View file

@ -1,31 +0,0 @@
#pragma once
#include "Game/items.h"
#define MAX_COLLECTED_PICKUPS 32
enum GAME_OBJECT_ID : short;
struct DisplayPickup
{
int Life;
short ObjectNumber;
};
void DrawHUD(ItemInfo* item);
void DrawHealthBarOverlay(ItemInfo* item, int value);
void DrawHealthBar(ItemInfo* item, float value);
void DrawHealthBar(ItemInfo* item, bool doFlash);
void DrawAirBar(float value);
void DrawAirBar(ItemInfo* item, bool doFlash);
void DrawSprintBar(float value);
void DrawSprintBar(ItemInfo* item);
void UpdateBars(ItemInfo* item);
void AddDisplayPickup(GAME_OBJECT_ID objectNumber);
void DrawAllPickups();
void InitialisePickupDisplay();
extern short PickupX;
extern short PickupY;
extern DisplayPickup Pickups[MAX_COLLECTED_PICKUPS];
extern bool EnableSmoothHealthBar;

View file

@ -7,8 +7,8 @@
#include "Game/collision/collide_item.h" #include "Game/collision/collide_item.h"
#include "Game/effects/debris.h" #include "Game/effects/debris.h"
#include "Game/Gui.h" #include "Game/Gui.h"
#include "Game/Hud/Hud.h"
#include "Game/items.h" #include "Game/items.h"
#include "Game/health.h"
#include "Game/Lara/lara.h" #include "Game/Lara/lara.h"
#include "Game/Lara/lara_fire.h" #include "Game/Lara/lara_fire.h"
#include "Game/Lara/lara_flare.h" #include "Game/Lara/lara_flare.h"
@ -31,6 +31,7 @@
#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h"
using namespace TEN::Entities::Generic; using namespace TEN::Entities::Generic;
using namespace TEN::Hud;
using namespace TEN::Input; using namespace TEN::Input;
static auto PickUpPosition = Vector3i(0, 0, -100); static auto PickUpPosition = Vector3i(0, 0, -100);
@ -39,12 +40,10 @@ const ObjectCollisionBounds PickUpBounds =
GameBoundingBox( GameBoundingBox(
-CLICK(1), CLICK(1), -CLICK(1), CLICK(1),
-200, 200, -200, 200,
-CLICK(1), CLICK(1) -CLICK(1), CLICK(1)),
),
std::pair( std::pair(
EulerAngles(ANGLE(-45.0f), 0, ANGLE(-45.0f)), EulerAngles(ANGLE(-45.0f), 0, ANGLE(-45.0f)),
EulerAngles(ANGLE(45.0f), 0, ANGLE(45.0f)) EulerAngles(ANGLE(45.0f), 0, ANGLE(45.0f)))
)
}; };
static auto HiddenPickUpPosition = Vector3i(0, 0, -690); static auto HiddenPickUpPosition = Vector3i(0, 0, -690);
@ -53,12 +52,10 @@ const ObjectCollisionBounds HiddenPickUpBounds =
GameBoundingBox( GameBoundingBox(
-CLICK(1), CLICK(1), -CLICK(1), CLICK(1),
-100, 100, -100, 100,
-800, -CLICK(1) -800, -CLICK(1)),
),
std::pair( std::pair(
EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)), EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)),
EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)) EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)))
)
}; };
static auto CrowbarPickUpPosition = Vector3i(0, 0, 215); static auto CrowbarPickUpPosition = Vector3i(0, 0, 215);
@ -67,12 +64,10 @@ const ObjectCollisionBounds CrowbarPickUpBounds =
GameBoundingBox( GameBoundingBox(
-CLICK(1), CLICK(1), -CLICK(1), CLICK(1),
-100, 100, -100, 100,
200, CLICK(2) 200, CLICK(2) ),
),
std::pair( std::pair(
EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)), EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)),
EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)) EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)))
)
}; };
static auto JobyCrowPickUpPosition = Vector3i(-224, 0, 240); static auto JobyCrowPickUpPosition = Vector3i(-224, 0, 240);
@ -81,12 +76,10 @@ const ObjectCollisionBounds JobyCrowPickUpBounds =
GameBoundingBox( GameBoundingBox(
-CLICK(2), 0, -CLICK(2), 0,
-100, 100, -100, 100,
0, CLICK(2) 0, CLICK(2)),
),
std::pair( std::pair(
EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)), EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)),
EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)) EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)))
)
}; };
static auto PlinthPickUpPosition = Vector3i(0, 0, -460); static auto PlinthPickUpPosition = Vector3i(0, 0, -460);
@ -95,12 +88,10 @@ ObjectCollisionBounds PlinthPickUpBounds =
GameBoundingBox( GameBoundingBox(
-CLICK(1), CLICK(1), -CLICK(1), CLICK(1),
-640, 640, -640, 640,
-511, 0 -511, 0),
),
std::pair( std::pair(
EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)), EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)),
EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)) EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)))
)
}; };
static auto PickUpPositionUW = Vector3i(0, -200, -350); static auto PickUpPositionUW = Vector3i(0, -200, -350);
@ -109,12 +100,10 @@ const ObjectCollisionBounds PickUpBoundsUW =
GameBoundingBox( GameBoundingBox(
-CLICK(2), CLICK(2), -CLICK(2), CLICK(2),
-CLICK(2), CLICK(2), -CLICK(2), CLICK(2),
-CLICK(2), CLICK(2) -CLICK(2), CLICK(2)),
),
std::pair( std::pair(
EulerAngles(ANGLE(-45.0f), ANGLE(-45.0f), ANGLE(-45.0f)), EulerAngles(ANGLE(-45.0f), ANGLE(-45.0f), ANGLE(-45.0f)),
EulerAngles(ANGLE(45.0f), ANGLE(45.0f), ANGLE(45.0f)) EulerAngles(ANGLE(45.0f), ANGLE(45.0f), ANGLE(45.0f)))
)
}; };
static auto SOPos = Vector3i::Zero; static auto SOPos = Vector3i::Zero;
@ -123,8 +112,7 @@ ObjectCollisionBounds SOBounds =
GameBoundingBox::Zero, GameBoundingBox::Zero,
std::pair( std::pair(
EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)), EulerAngles(ANGLE(-45.0f), ANGLE(-30.0f), ANGLE(-45.0f)),
EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)) EulerAngles(ANGLE(45.0f), ANGLE(30.0f), ANGLE(45.0f)))
)
}; };
short SearchCollectFrames[4] = { 180, 100, 153, 83 }; short SearchCollectFrames[4] = { 180, 100, 153, 83 };
@ -136,8 +124,7 @@ const ObjectCollisionBounds MSBounds =
GameBoundingBox::Zero, GameBoundingBox::Zero,
std::pair( std::pair(
EulerAngles(ANGLE(-10.0f), ANGLE(-30.0f), ANGLE(-10.0f)), EulerAngles(ANGLE(-10.0f), ANGLE(-30.0f), ANGLE(-10.0f)),
EulerAngles(ANGLE(10.0f), ANGLE(30.0f), ANGLE(10.0f)) EulerAngles(ANGLE(10.0f), ANGLE(30.0f), ANGLE(10.0f)))
)
}; };
int NumRPickups; int NumRPickups;
@ -154,6 +141,7 @@ bool SetInventoryCount(GAME_OBJECT_ID objectID, int count)
{ {
return false; return false;
} }
return true; return true;
} }
@ -215,7 +203,7 @@ void CollectCarriedItems(ItemInfo* item)
{ {
auto* pickupItem = &g_Level.Items[pickupNumber]; auto* pickupItem = &g_Level.Items[pickupNumber];
AddDisplayPickup(pickupItem->ObjectNumber); g_Hud.PickupSummary.AddDisplayPickup(pickupItem->ObjectNumber, pickupItem->Pose.Position.ToVector3());
KillItem(pickupNumber); KillItem(pickupNumber);
pickupNumber = pickupItem->CarriedItem; pickupNumber = pickupItem->CarriedItem;
@ -239,7 +227,7 @@ void CollectMultiplePickups(int itemNumber)
if (!Objects[currentItem->ObjectNumber].isPickup) if (!Objects[currentItem->ObjectNumber].isPickup)
continue; continue;
AddDisplayPickup(currentItem->ObjectNumber); g_Hud.PickupSummary.AddDisplayPickup(currentItem->ObjectNumber, currentItem->Pose.Position.ToVector3());
if (currentItem->TriggerFlags & 0x100) if (currentItem->TriggerFlags & 0x100)
{ {
for (int i = 0; i < g_Level.NumItems; i++) for (int i = 0; i < g_Level.NumItems; i++)
@ -281,7 +269,7 @@ void DoPickup(ItemInfo* laraItem)
if (pickupItem->ObjectNumber == ID_BURNING_TORCH_ITEM) if (pickupItem->ObjectNumber == ID_BURNING_TORCH_ITEM)
{ {
AddDisplayPickup(ID_BURNING_TORCH_ITEM); g_Hud.PickupSummary.AddDisplayPickup(ID_BURNING_TORCH_ITEM, pickupItem->Pose.Position.ToVector3());
GetFlameTorch(); GetFlameTorch();
lara->Torch.IsLit = (pickupItem->ItemFlags[3] & 1); lara->Torch.IsLit = (pickupItem->ItemFlags[3] & 1);
@ -322,7 +310,7 @@ void DoPickup(ItemInfo* laraItem)
{ {
if (laraItem->Animation.AnimNumber == LA_UNDERWATER_PICKUP) //dirty but what can I do, it uses the same state if (laraItem->Animation.AnimNumber == LA_UNDERWATER_PICKUP) //dirty but what can I do, it uses the same state
{ {
AddDisplayPickup(pickupItem->ObjectNumber); g_Hud.PickupSummary.AddDisplayPickup(pickupItem->ObjectNumber, pickupItem->Pose.Position.ToVector3());
if (!(pickupItem->TriggerFlags & 0xC0)) if (!(pickupItem->TriggerFlags & 0xC0))
KillItem(pickupItemNumber); KillItem(pickupItemNumber);
else else
@ -340,7 +328,7 @@ void DoPickup(ItemInfo* laraItem)
{ {
if (laraItem->Animation.AnimNumber == LA_CROWBAR_PRY_WALL_SLOW) if (laraItem->Animation.AnimNumber == LA_CROWBAR_PRY_WALL_SLOW)
{ {
AddDisplayPickup(ID_CROWBAR_ITEM); g_Hud.PickupSummary.AddDisplayPickup(ID_CROWBAR_ITEM, pickupItem->Pose.Position.ToVector3());
lara->Inventory.HasCrowbar = true; lara->Inventory.HasCrowbar = true;
KillItem(pickupItemNumber); KillItem(pickupItemNumber);
} }
@ -355,7 +343,7 @@ void DoPickup(ItemInfo* laraItem)
return; return;
} }
AddDisplayPickup(pickupItem->ObjectNumber); g_Hud.PickupSummary.AddDisplayPickup(pickupItem->ObjectNumber, pickupItem->Pose.Position.ToVector3());
if (pickupItem->TriggerFlags & 0x100) if (pickupItem->TriggerFlags & 0x100)
{ {
for (int i = 0; i < g_Level.NumItems; i++) for (int i = 0; i < g_Level.NumItems; i++)
@ -1249,9 +1237,13 @@ void SearchObjectControl(short itemNumber)
else if (item->ObjectNumber == ID_SEARCH_OBJECT2) else if (item->ObjectNumber == ID_SEARCH_OBJECT2)
{ {
if (frameNumber == 18) if (frameNumber == 18)
{
item->MeshBits = 1; item->MeshBits = 1;
}
else if (frameNumber == 172) else if (frameNumber == 172)
{
item->MeshBits = 2; item->MeshBits = 2;
}
} }
else if (item->ObjectNumber == ID_SEARCH_OBJECT4) else if (item->ObjectNumber == ID_SEARCH_OBJECT4)
{ {
@ -1284,7 +1276,7 @@ void SearchObjectControl(short itemNumber)
if (Objects[item2->ObjectNumber].isPickup) if (Objects[item2->ObjectNumber].isPickup)
{ {
AddDisplayPickup(item2->ObjectNumber); g_Hud.PickupSummary.AddDisplayPickup(item2->ObjectNumber, item2->Pose.Position.ToVector3());
KillItem(item->ItemFlags[1]); KillItem(item->ItemFlags[1]);
} }
else else
@ -1299,7 +1291,9 @@ void SearchObjectControl(short itemNumber)
} }
} }
else else
{
CollectCarriedItems(item); CollectCarriedItems(item);
}
} }

View file

@ -12,17 +12,6 @@ using namespace TEN::Math;
//{ //{
const EulerAngles EulerAngles::Zero = EulerAngles(0, 0, 0); const EulerAngles EulerAngles::Zero = EulerAngles(0, 0, 0);
EulerAngles::EulerAngles()
{
}
EulerAngles::EulerAngles(short x, short y, short z)
{
this->x = x;
this->y = y;
this->z = z;
}
EulerAngles::EulerAngles(const Vector3& direction) EulerAngles::EulerAngles(const Vector3& direction)
{ {
auto directionNorm = direction; auto directionNorm = direction;
@ -40,11 +29,11 @@ using namespace TEN::Math;
EulerAngles::EulerAngles(const Quaternion& quat) EulerAngles::EulerAngles(const Quaternion& quat)
{ {
static constexpr auto singularityThreshold = 1.0f - EPSILON; constexpr auto SINGULARITY_THRESHOLD = 1.0f - EPSILON;
// Handle singularity case. // Handle singularity case.
float sinP = ((quat.w * quat.x) - (quat.y * quat.z)) * 2; float sinP = ((quat.w * quat.x) - (quat.y * quat.z)) * 2;
if (abs(sinP) > singularityThreshold) if (abs(sinP) > SINGULARITY_THRESHOLD)
{ {
if (sinP > 0.0f) if (sinP > 0.0f)
*this = EulerAngles(FROM_RAD(PI_DIV_2), 0, FROM_RAD(atan2(quat.z, quat.w) * 2.0f)); *this = EulerAngles(FROM_RAD(PI_DIV_2), 0, FROM_RAD(atan2(quat.z, quat.w) * 2.0f));

View file

@ -15,12 +15,12 @@
static const EulerAngles Zero; // TODO: Should be "Identity", not "Zero". static const EulerAngles Zero; // TODO: Should be "Identity", not "Zero".
// Constructors // Constructors
EulerAngles(); constexpr EulerAngles() {};
EulerAngles(short x, short y, short z); constexpr EulerAngles(short x, short y, short z) { this->x = x; this->y = y; this->z = z; };
EulerAngles(const Vector3& direction); EulerAngles(const Vector3& direction);
EulerAngles(const AxisAngle& axisAngle); EulerAngles(const AxisAngle& axisAngle);
EulerAngles(const Quaternion& quat); EulerAngles(const Quaternion& quat);
EulerAngles(const Matrix& rotMatrix); EulerAngles(const Matrix& rotMatrix);
// Utilities // Utilities
static bool Compare(const EulerAngles& eulers0, const EulerAngles& eulers1, short epsilon = 2); static bool Compare(const EulerAngles& eulers0, const EulerAngles& eulers1, short epsilon = 2);

View file

@ -5,6 +5,8 @@
#include "Game/items.h" #include "Game/items.h"
#include "Math/Objects/EulerAngles.h" #include "Math/Objects/EulerAngles.h"
#include "Math/Objects/Pose.h" #include "Math/Objects/Pose.h"
#include "Objects/game_object_ids.h"
#include "Specific/setup.h"
//namespace TEN::Math //namespace TEN::Math
//{ //{
@ -24,6 +26,11 @@
this->Z2 = (int)round(z2); this->Z2 = (int)round(z2);
} }
GameBoundingBox::GameBoundingBox(GAME_OBJECT_ID objectID, int animNumber, int frameNumber)
{
*this = GetFrame(objectID, animNumber, frameNumber)->boundingBox;
}
GameBoundingBox::GameBoundingBox(ItemInfo* item) GameBoundingBox::GameBoundingBox(ItemInfo* item)
{ {
int rate = 0; int rate = 0;
@ -53,15 +60,14 @@
Vector3 GameBoundingBox::GetCenter() const Vector3 GameBoundingBox::GetCenter() const
{ {
return ((Vector3(this->X1, this->Y1, this->Z1) + Vector3(this->X2, this->Y2, this->Z2)) / 2.0f); return ((Vector3(X1, Y1, Z1) + Vector3(X2, Y2, Z2)) / 2);
} }
Vector3 GameBoundingBox::GetExtents() const Vector3 GameBoundingBox::GetExtents() const
{ {
return ((Vector3(this->X2, this->Y2, this->Z2) - Vector3(this->X1, this->Y1, this->Z1)) / 2.0f); return ((Vector3(X2, Y2, Z2) - Vector3(X1, Y1, Z1)) / 2);
} }
// NOTE: Previously phd_RotBoundingBoxNoPersp().
void GameBoundingBox::RotateNoPersp(const EulerAngles& orient, const GameBoundingBox& bounds) void GameBoundingBox::RotateNoPersp(const EulerAngles& orient, const GameBoundingBox& bounds)
{ {
auto rotMatrix = orient.ToRotationMatrix(); auto rotMatrix = orient.ToRotationMatrix();

View file

@ -1,8 +1,10 @@
#pragma once #pragma once
enum GAME_OBJECT_ID : short;
class EulerAngles; class EulerAngles;
struct ItemInfo;
class Pose; class Pose;
struct ItemInfo;
struct ObjectInfo;
//namespace TEN::Math //namespace TEN::Math
//{ //{
@ -23,6 +25,7 @@ class Pose;
// Constructors // Constructors
GameBoundingBox(); GameBoundingBox();
GameBoundingBox(float x1, float x2, float y1, float y2, float z1, float z2); GameBoundingBox(float x1, float x2, float y1, float y2, float z1, float z2);
GameBoundingBox(GAME_OBJECT_ID objectID, int animNumber = 0, int frameNumber = 0);
GameBoundingBox(ItemInfo* item); GameBoundingBox(ItemInfo* item);
// Getters // Getters

View file

@ -7,7 +7,7 @@
#include "Game/items.h" #include "Game/items.h"
#include "Game/pickup/pickup.h" #include "Game/pickup/pickup.h"
#include "Specific/setup.h" #include "Specific/setup.h"
#include "Game/health.h" #include "Game/Hud/Hud.h"
#include "Game/collision/collide_item.h" #include "Game/collision/collide_item.h"
using namespace TEN::Input; using namespace TEN::Input;

View file

@ -13,7 +13,7 @@
#include "Game/effects/tomb4fx.h" #include "Game/effects/tomb4fx.h"
#include "Game/items.h" #include "Game/items.h"
#include "Game/effects/simple_particle.h" #include "Game/effects/simple_particle.h"
#include "Game/health.h" #include "Game/Hud/Hud.h"
#include "Game/camera.h" #include "Game/camera.h"
#include "Game/animation.h" #include "Game/animation.h"
#include "Math/Random.h" #include "Math/Random.h"

View file

@ -117,7 +117,7 @@ namespace TEN::Renderer
Vector3(x + w, HUD_ZERO_Y + y + h, 0.5), Vector3(x + w, HUD_ZERO_Y + y + h, 0.5),
}; };
const float HUD_BORDER_WIDTH = borderSize * (REFERENCE_RES_WIDTH / REFERENCE_RES_HEIGHT); const float HUD_BORDER_WIDTH = borderSize * (SCREEN_SPACE_RES.x / SCREEN_SPACE_RES.y);
const float HUD_BORDER_HEIGT = borderSize; const float HUD_BORDER_HEIGT = borderSize;
array<Vector3, 16> barBorderVertices = { array<Vector3, 16> barBorderVertices = {
//top left //top left
@ -377,35 +377,35 @@ namespace TEN::Renderer
switch (blendMode) switch (blendMode)
{ {
case BLENDMODE_ALPHABLEND: case BLENDMODE_ALPHABLEND:
m_context->OMSetBlendState(m_states->NonPremultiplied(), NULL, 0xFFFFFFFF); m_context->OMSetBlendState(m_states->NonPremultiplied(), nullptr, 0xFFFFFFFF);
break; break;
case BLENDMODE_ALPHATEST: case BLENDMODE_ALPHATEST:
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF); m_context->OMSetBlendState(m_states->Opaque(), nullptr, 0xFFFFFFFF);
break; break;
case BLENDMODE_OPAQUE: case BLENDMODE_OPAQUE:
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF); m_context->OMSetBlendState(m_states->Opaque(), nullptr, 0xFFFFFFFF);
break; break;
case BLENDMODE_SUBTRACTIVE: case BLENDMODE_SUBTRACTIVE:
m_context->OMSetBlendState(m_subtractiveBlendState.Get(), NULL, 0xFFFFFFFF); m_context->OMSetBlendState(m_subtractiveBlendState.Get(), nullptr, 0xFFFFFFFF);
break; break;
case BLENDMODE_ADDITIVE: case BLENDMODE_ADDITIVE:
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF); m_context->OMSetBlendState(m_states->Additive(), nullptr, 0xFFFFFFFF);
break; break;
case BLENDMODE_SCREEN: case BLENDMODE_SCREEN:
m_context->OMSetBlendState(m_screenBlendState.Get(), NULL, 0xFFFFFFFF); m_context->OMSetBlendState(m_screenBlendState.Get(), nullptr, 0xFFFFFFFF);
break; break;
case BLENDMODE_LIGHTEN: case BLENDMODE_LIGHTEN:
m_context->OMSetBlendState(m_lightenBlendState.Get(), NULL, 0xFFFFFFFF); m_context->OMSetBlendState(m_lightenBlendState.Get(), nullptr, 0xFFFFFFFF);
break; break;
case BLENDMODE_EXCLUDE: case BLENDMODE_EXCLUDE:
m_context->OMSetBlendState(m_excludeBlendState.Get(), NULL, 0xFFFFFFFF); m_context->OMSetBlendState(m_excludeBlendState.Get(), nullptr, 0xFFFFFFFF);
break; break;
} }
@ -426,7 +426,6 @@ namespace TEN::Renderer
default: default:
SetDepthState(DEPTH_STATE_READ_ONLY_ZBUFFER); SetDepthState(DEPTH_STATE_READ_ONLY_ZBUFFER);
break; break;
} }
} }

View file

@ -7,7 +7,9 @@
#include "Game/items.h" #include "Game/items.h"
#include "Game/animation.h" #include "Game/animation.h"
#include "Game/gui.h" #include "Game/Gui.h"
#include "Game/Hud/Hud.h"
#include "Game/Hud/PickupSummary.h"
#include "Game/effects/effects.h" #include "Game/effects/effects.h"
#include "Game/effects/Electricity.h" #include "Game/effects/Electricity.h"
#include "Specific/level.h" #include "Specific/level.h"
@ -53,6 +55,7 @@ struct RendererRectangle;
using namespace TEN::Effects::Electricity; using namespace TEN::Effects::Electricity;
using namespace TEN::Gui; using namespace TEN::Gui;
using namespace TEN::Hud;
namespace TEN::Renderer namespace TEN::Renderer
{ {
@ -244,8 +247,9 @@ namespace TEN::Renderer
struct RendererLine2D struct RendererLine2D
{ {
Vector2 Vertices[2]; Vector2 Origin = Vector2::Zero;
Vector4 Color; Vector2 Target = Vector2::Zero;
Vector4 Color = Vector4::Zero;
}; };
struct RendererRect2D struct RendererRect2D
@ -454,9 +458,6 @@ namespace TEN::Renderer
// A flag to prevent extra renderer object addition // A flag to prevent extra renderer object addition
bool m_Locked = false; bool m_Locked = false;
// Misc
int m_pickupRotation = 0;
// Caching state changes // Caching state changes
TextureBase* lastTexture; TextureBase* lastTexture;
@ -655,19 +656,19 @@ namespace TEN::Renderer
void PrintDebugMessage(LPCSTR message, ...); void PrintDebugMessage(LPCSTR message, ...);
void DrawDebugInfo(RenderView& view); void DrawDebugInfo(RenderView& view);
void SwitchDebugPage(bool back); void SwitchDebugPage(bool back);
void DrawPickup(short objectNum); void DrawPickup(const DisplayPickup& pickup);
int Synchronize(); int Synchronize();
void AddString(int x, int y, const char* string, D3DCOLOR color, int flags); void AddString(int x, int y, const char* string, D3DCOLOR color, int flags);
void AddString(const std::string& string, const Vector2& pos, const Color& color, float scale, int flags);
void FreeRendererData(); void FreeRendererData();
void AddDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b); void AddDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b);
void RenderLoadingScreen(float percentage); void RenderLoadingScreen(float percentage);
void UpdateProgress(float value); void UpdateProgress(float value);
void GetLaraBonePosition(Vector3* pos, int bone);
void ToggleFullScreen(bool force = false); void ToggleFullScreen(bool force = false);
void SetFullScreen(); void SetFullScreen();
bool IsFullsScreen(); bool IsFullsScreen();
void RenderTitleImage(); void RenderTitleImage();
void AddLine2D(int x1, int y1, int x2, int y2, byte r, byte g, byte b, byte a); void AddLine2D(const Vector2& origin, const Vector2& target, const Color& color);
void AddLine3D(Vector3 start, Vector3 end, Vector4 color); void AddLine3D(Vector3 start, Vector3 end, Vector4 color);
void AddBox(Vector3 min, Vector3 max, Vector4 color); void AddBox(Vector3 min, Vector3 max, Vector4 color);
void AddBox(Vector3* corners, Vector4 color); void AddBox(Vector3* corners, Vector4 color);
@ -679,13 +680,16 @@ namespace TEN::Renderer
void FlipRooms(short roomNumber1, short roomNumber2); void FlipRooms(short roomNumber1, short roomNumber2);
void UpdateLaraAnimations(bool force); void UpdateLaraAnimations(bool force);
void UpdateItemAnimations(int itemNumber, bool force); void UpdateItemAnimations(int itemNumber, bool force);
void GetItemAbsBonePosition(int itemNumber, Vector3& pos, int jointIndex);
int GetSpheres(short itemNumber, BoundingSphere* ptr, char worldSpace, Matrix local); int GetSpheres(short itemNumber, BoundingSphere* ptr, char worldSpace, Matrix local);
void GetBoneMatrix(short itemNumber, int jointIndex, Matrix* outMatrix); void GetBoneMatrix(short itemNumber, int jointIndex, Matrix* outMatrix);
void DrawObjectOn2DPosition(short x, short y, short objectNum, EulerAngles orient, float scale1, int meshBits = NO_JOINT_BITS); void DrawObjectOn2DPosition(int objectNumber, Vector2 pos, EulerAngles orient, float scale1, float opacity = 1.0f, int meshBits = NO_JOINT_BITS);
void SetLoadingScreen(std::wstring& fileName); void SetLoadingScreen(std::wstring& fileName);
void SetTextureOrDefault(Texture2D& texture, std::wstring path); void SetTextureOrDefault(Texture2D& texture, std::wstring path);
std::string GetDefaultAdapterName(); std::string GetDefaultAdapterName();
Vector2i GetScreenResolution() const;
Vector2 GetScreenSpacePosition(const Vector3& pos) const;
Vector3 GetAbsEntityBonePosition(int itemNumber, int jointIndex, const Vector3& relOffset = Vector3::Zero);
}; };
extern Renderer11 g_Renderer; extern Renderer11 g_Renderer;

View file

@ -14,7 +14,7 @@
#include "Game/effects/tomb4fx.h" #include "Game/effects/tomb4fx.h"
#include "Game/effects/weather.h" #include "Game/effects/weather.h"
#include "Game/Gui.h" #include "Game/Gui.h"
#include "Game/health.h" #include "Game/Hud/Hud.h"
#include "Game/items.h" #include "Game/items.h"
#include "Game/Lara/lara.h" #include "Game/Lara/lara.h"
#include "Game/savegame.h" #include "Game/savegame.h"
@ -31,6 +31,7 @@
#include "Specific/winmain.h" #include "Specific/winmain.h"
using namespace TEN::Entities::Generic; using namespace TEN::Entities::Generic;
using namespace TEN::Hud;
extern TEN::Renderer::RendererHUDBar* g_HealthBar; extern TEN::Renderer::RendererHUDBar* g_HealthBar;
extern TEN::Renderer::RendererHUDBar* g_AirBar; extern TEN::Renderer::RendererHUDBar* g_AirBar;
@ -355,38 +356,29 @@ namespace TEN::Renderer
m_context->VSSetShader(m_vsSolid.Get(), nullptr, 0); m_context->VSSetShader(m_vsSolid.Get(), nullptr, 0);
m_context->PSSetShader(m_psSolid.Get(), nullptr, 0); m_context->PSSetShader(m_psSolid.Get(), nullptr, 0);
Matrix world = Matrix::CreateOrthographicOffCenter(0, m_screenWidth, m_screenHeight, 0, m_viewport.MinDepth, auto worldMatrix = Matrix::CreateOrthographicOffCenter(0, m_screenWidth, m_screenHeight, 0, m_viewport.MinDepth, m_viewport.MaxDepth);
m_viewport.MaxDepth);
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST);
m_context->IASetInputLayout(m_inputLayout.Get()); m_context->IASetInputLayout(m_inputLayout.Get());
m_primitiveBatch->Begin(); m_primitiveBatch->Begin();
for (int i = 0; i < m_lines2DToDraw.size(); i++) for (const auto& line : m_lines2DToDraw)
{ {
RendererLine2D* line = &m_lines2DToDraw[i]; auto v1 = RendererVertex();
v1.Position.x = line.Origin.x;
RendererVertex v1; v1.Position.y = line.Origin.y;
v1.Position.x = line->Vertices[0].x;
v1.Position.y = line->Vertices[0].y;
v1.Position.z = 1.0f; v1.Position.z = 1.0f;
v1.Color.x = line->Color.x / 255.0f; v1.Color = line.Color;
v1.Color.y = line->Color.y / 255.0f;
v1.Color.z = line->Color.z / 255.0f;
v1.Color.w = line->Color.w / 255.0f;
RendererVertex v2; auto v2 = RendererVertex();
v2.Position.x = line->Vertices[1].x; v2.Position.x = line.Target.x;
v2.Position.y = line->Vertices[1].y; v2.Position.y = line.Target.y;
v2.Position.z = 1.0f; v2.Position.z = 1.0f;
v2.Color.x = line->Color.x / 255.0f; v2.Color = line.Color;
v2.Color.y = line->Color.y / 255.0f;
v2.Color.z = line->Color.z / 255.0f;
v2.Color.w = line->Color.w / 255.0f;
v1.Position = Vector3::Transform(v1.Position, world); v1.Position = Vector3::Transform(v1.Position, worldMatrix);
v2.Position = Vector3::Transform(v2.Position, world); v2.Position = Vector3::Transform(v2.Position, worldMatrix);
v1.Position.z = 0.5f; v1.Position.z = 0.5f;
v2.Position.z = 0.5f; v2.Position.z = 0.5f;
@ -1494,8 +1486,9 @@ namespace TEN::Renderer
// Draw GUI stuff at the end // Draw GUI stuff at the end
DrawLines2D(); DrawLines2D();
// Bars // Draw HUD.
DrawHUD(LaraItem); g_Hud.Draw();
DrawHud(LaraItem);
// Draw binoculars or lasersight // Draw binoculars or lasersight
DrawOverlays(view); DrawOverlays(view);

View file

@ -74,7 +74,7 @@ namespace TEN::Renderer
g_LoadingBar = new RendererHUDBar(m_device.Get(), 325, 550, 150, 8, 1, airColors); g_LoadingBar = new RendererHUDBar(m_device.Get(), 325, 550, 150, 8, 1, airColors);
} }
void Renderer11::DrawBar(float percent, const RendererHUDBar* const bar, GAME_OBJECT_ID textureSlot, int frame, bool poison) void Renderer11::DrawBar(float percent, const RendererHUDBar* const bar, GAME_OBJECT_ID textureSlot, int frame, bool isPoisoned)
{ {
UINT strides = sizeof(RendererVertex); UINT strides = sizeof(RendererVertex);
UINT offset = 0; UINT offset = 0;
@ -87,8 +87,8 @@ namespace TEN::Renderer
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetIndexBuffer(bar->IndexBufferBorder.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); m_context->IASetIndexBuffer(bar->IndexBufferBorder.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0);
m_context->VSSetShader(m_vsHUD.Get(), NULL, 0); m_context->VSSetShader(m_vsHUD.Get(), nullptr, 0);
m_context->PSSetShader(m_psHUDTexture.Get(), NULL, 0); m_context->PSSetShader(m_psHUDTexture.Get(), nullptr, 0);
SetBlendMode(BLENDMODE_OPAQUE); SetBlendMode(BLENDMODE_OPAQUE);
SetDepthState(DEPTH_STATE_NONE); SetDepthState(DEPTH_STATE_NONE);
@ -108,11 +108,11 @@ namespace TEN::Renderer
m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_context->IASetIndexBuffer(bar->InnerIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0); m_context->IASetIndexBuffer(bar->InnerIndexBuffer.Buffer.Get(), DXGI_FORMAT_R32_UINT, 0);
m_context->VSSetShader(m_vsHUD.Get(), NULL, 0); m_context->VSSetShader(m_vsHUD.Get(), nullptr, 0);
m_context->PSSetShader(m_psHUDBarColor.Get(), NULL, 0); m_context->PSSetShader(m_psHUDBarColor.Get(), nullptr, 0);
m_stHUDBar.Percent = percent; m_stHUDBar.Percent = percent;
m_stHUDBar.Poisoned = poison; m_stHUDBar.Poisoned = isPoisoned;
m_stHUDBar.Frame = frame; m_stHUDBar.Frame = frame;
m_cbHUDBar.updateData(m_stHUDBar, m_context.Get()); m_cbHUDBar.updateData(m_stHUDBar, m_context.Get());
BindConstantBufferVS(CB_HUD_BAR, m_cbHUDBar.get()); BindConstantBufferVS(CB_HUD_BAR, m_cbHUDBar.get());
@ -170,13 +170,9 @@ namespace TEN::Renderer
DrawIndexedTriangles(12, 0, 0); DrawIndexedTriangles(12, 0, 0);
} }
void Renderer11::AddLine2D(int x1, int y1, int x2, int y2, byte r, byte g, byte b, byte a) { void Renderer11::AddLine2D(const Vector2& origin, const Vector2& target, const Color& color)
RendererLine2D line; {
auto line = RendererLine2D{ origin, target, color };
line.Vertices[0] = Vector2(x1, y1);
line.Vertices[1] = Vector2(x2, y2);
line.Color = Vector4(r, g, b, a);
m_lines2DToDraw.push_back(line); m_lines2DToDraw.push_back(line);
} }

View file

@ -5,7 +5,7 @@
#include "Game/control/control.h" #include "Game/control/control.h"
#include "Game/control/volume.h" #include "Game/control/volume.h"
#include "Game/Gui.h" #include "Game/Gui.h"
#include "Game/health.h" #include "Game/Hud/Hud.h"
#include "Game/Lara/lara.h" #include "Game/Lara/lara.h"
#include "Game/savegame.h" #include "Game/savegame.h"
#include "Math/Math.h" #include "Math/Math.h"
@ -16,6 +16,7 @@
#include "Specific/trutils.h" #include "Specific/trutils.h"
#include "Specific/winmain.h" #include "Specific/winmain.h"
using namespace TEN::Hud;
using namespace TEN::Input; using namespace TEN::Input;
using namespace TEN::Math; using namespace TEN::Math;
@ -505,61 +506,67 @@ namespace TEN::Renderer
DrawAllStrings(); DrawAllStrings();
} }
void Renderer11::DrawPickup(short objectNum) void Renderer11::DrawPickup(const DisplayPickup& pickup)
{ {
// Clear just the Z-buffer so we can start drawing on top of the scene static const auto COUNT_STRING_PREFIX = std::string(" ");
// Clear only Z-buffer to draw on top of the scene.
ID3D11DepthStencilView* dsv; ID3D11DepthStencilView* dsv;
m_context->OMGetRenderTargets(1, nullptr, &dsv); m_context->OMGetRenderTargets(1, nullptr, &dsv);
m_context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); m_context->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
DrawObjectOn2DPosition(700 + PickupX, 450, objectNum, EulerAngles(0, m_pickupRotation, 0), 0.5f); // TODO: + PickupY // Draw display pickup.
m_pickupRotation += 45 * 360 / 30; DrawObjectOn2DPosition(pickup.ObjectID, pickup.Position, pickup.Orientation, pickup.Scale);
// Draw count string.
if (pickup.Count > 1)
{
AddString(
COUNT_STRING_PREFIX + std::to_string(pickup.Count),
pickup.Position, Color(PRINTSTRING_COLOR_WHITE), pickup.StringScale, SF());
}
} }
void Renderer11::DrawObjectOn2DPosition(short x, short y, short objectNum, EulerAngles orient, float scale1, int meshBits) // TODO: Handle opacity
void Renderer11::DrawObjectOn2DPosition(int objectNumber, Vector2 screenPos, EulerAngles orient, float scale, float opacity, int meshBits)
{ {
Matrix translation; constexpr auto AMBIENT_LIGHT_COLOR = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
Matrix rotation;
Matrix world;
Matrix view;
Matrix projection;
Matrix scale;
UINT stride = sizeof(RendererVertex); UINT stride = sizeof(RendererVertex);
UINT offset = 0; UINT offset = 0;
float factorX = m_screenWidth / REFERENCE_RES_WIDTH; auto screenRes = GetScreenResolution();
float factorY = m_screenHeight / REFERENCE_RES_HEIGHT; auto factor = Vector2(
screenRes.x / SCREEN_SPACE_RES.x,
screenRes.y / SCREEN_SPACE_RES.y);
x *= factorX; screenPos *= factor;
y *= factorY; scale *= (factor.x > factor.y) ? factor.y : factor.x;
scale1 *= factorX > factorY ? factorY : factorX;
auto index = g_Gui.ConvertObjectToInventoryItem(objectNum);
int index = g_Gui.ConvertObjectToInventoryItem(objectNumber);
if (index != -1) if (index != -1)
{ {
auto& invObject = InventoryObjectTable[index]; const auto& invObject = InventoryObjectTable[index];
y += invObject.YOffset;
screenPos.y += invObject.YOffset;
orient += invObject.Orientation; orient += invObject.Orientation;
} }
view = Matrix::CreateLookAt(Vector3(0.0f, 0.0f, 2048.0f), Vector3(0.0f, 0.0f, 0.0f), Vector3(0.0f, -1.0f, 0.0f)); auto viewMatrix = Matrix::CreateLookAt(Vector3(0.0f, 0.0f, BLOCK(2)), Vector3::Zero, Vector3::Down);
projection = Matrix::CreateOrthographic(m_screenWidth, m_screenHeight, -1024.0f, 1024.0f); auto projMatrix = Matrix::CreateOrthographic(m_screenWidth, m_screenHeight, -BLOCK(1), BLOCK(1));
auto& moveableObj = m_moveableObjects[objectNum]; auto& moveableObject = m_moveableObjects[objectNumber];
if (!moveableObj) if (!moveableObject)
return; return;
auto* obj = &Objects[objectNum]; const auto& object = Objects[objectNumber];
if (object.animIndex != -1)
if (obj->animIndex != -1)
{ {
AnimFrame* frame[] = { &g_Level.Frames[g_Level.Anims[obj->animIndex].FramePtr] }; AnimFrame* frame[] = { &g_Level.Frames[g_Level.Anims[object.animIndex].FramePtr] };
UpdateAnimation(nullptr, *moveableObj, frame, 0, 0, 0xFFFFFFFF); UpdateAnimation(nullptr, *moveableObject, frame, 0, 0, 0xFFFFFFFF);
} }
auto pos = m_viewportToolkit.Unproject(Vector3(x, y, 1), projection, view, Matrix::Identity); auto pos = m_viewportToolkit.Unproject(Vector3(screenPos.x, screenPos.y, 1.0f), projMatrix, viewMatrix, Matrix::Identity);
// Set vertex buffer. // Set vertex buffer.
m_context->IASetVertexBuffers(0, 1, m_moveablesVertexBuffer.Buffer.GetAddressOf(), &stride, &offset); m_context->IASetVertexBuffers(0, 1, m_moveablesVertexBuffer.Buffer.GetAddressOf(), &stride, &offset);
@ -572,41 +579,39 @@ namespace TEN::Renderer
m_context->PSSetShader(m_psInventory.Get(), nullptr, 0); m_context->PSSetShader(m_psInventory.Get(), nullptr, 0);
// Set matrices. // Set matrices.
CCameraMatrixBuffer HudCamera; CCameraMatrixBuffer hudCamera;
HudCamera.CamDirectionWS = -Vector4::UnitZ; hudCamera.CamDirectionWS = -Vector4::UnitZ;
HudCamera.ViewProjection = view * projection; hudCamera.ViewProjection = viewMatrix * projMatrix;
m_cbCameraMatrices.updateData(HudCamera, m_context.Get()); m_cbCameraMatrices.updateData(hudCamera, m_context.Get());
BindConstantBufferVS(CB_CAMERA, m_cbCameraMatrices.get()); BindConstantBufferVS(CB_CAMERA, m_cbCameraMatrices.get());
for (int n = 0; n < (*moveableObj).ObjectMeshes.size(); n++) for (int n = 0; n < (*moveableObject).ObjectMeshes.size(); n++)
{ {
if (meshBits && !(meshBits & (1 << n))) if (meshBits && !(meshBits & (1 << n)))
continue; continue;
auto* mesh = (*moveableObject).ObjectMeshes[n];
auto* mesh = (*moveableObj).ObjectMeshes[n]; // Construct world matrix.
auto tMatrix = Matrix::CreateTranslation(pos.x, pos.y, pos.z + BLOCK(1));
auto rotMatrix = orient.ToRotationMatrix();
auto scaleMatrix = Matrix::CreateScale(scale);
auto worldMatrix = scaleMatrix * rotMatrix * tMatrix;
// Finish the world matrix if (object.animIndex != -1)
translation = Matrix::CreateTranslation(pos.x, pos.y, pos.z + 1024.0f); m_stItem.World = (*moveableObject).AnimationTransforms[n] * worldMatrix;
rotation = orient.ToRotationMatrix();
scale = Matrix::CreateScale(scale1);
world = scale * rotation;
world = world * translation;
if (obj->animIndex != -1)
m_stItem.World = ((*moveableObj).AnimationTransforms[n] * world);
else else
m_stItem.World = ((*moveableObj).BindPoseTransforms[n] * world); m_stItem.World = (*moveableObject).BindPoseTransforms[n] * worldMatrix;
m_stItem.BoneLightModes[n] = LIGHT_MODES::LIGHT_MODE_DYNAMIC; m_stItem.BoneLightModes[n] = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
m_stItem.Color = Vector4::One; m_stItem.Color = Vector4::One;
m_stItem.AmbientLight = Vector4(0.5f, 0.5f, 0.5f, 1.0f); m_stItem.AmbientLight = AMBIENT_LIGHT_COLOR;
m_cbItem.updateData(m_stItem, m_context.Get()); m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get()); BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get()); BindConstantBufferPS(CB_ITEM, m_cbItem.get());
for (auto& bucket : mesh->Buckets) for (const auto& bucket : mesh->Buckets)
{ {
if (bucket.NumVertices == 0) if (bucket.NumVertices == 0)
continue; continue;
@ -619,12 +624,10 @@ namespace TEN::Renderer
BindTexture(TEXTURE_NORMAL_MAP, &std::get<1>(m_moveablesTextures[bucket.Texture]), SAMPLER_NONE); BindTexture(TEXTURE_NORMAL_MAP, &std::get<1>(m_moveablesTextures[bucket.Texture]), SAMPLER_NONE);
SetAlphaTest( SetAlphaTest(
bucket.BlendMode == BLENDMODE_ALPHATEST ? ALPHA_TEST_GREATER_THAN : ALPHA_TEST_NONE, (bucket.BlendMode == BLENDMODE_ALPHATEST) ? ALPHA_TEST_GREATER_THAN : ALPHA_TEST_NONE,
ALPHA_TEST_THRESHOLD ALPHA_TEST_THRESHOLD);
);
DrawIndexedTriangles(bucket.NumIndices, bucket.StartIndex, 0); DrawIndexedTriangles(bucket.NumIndices, bucket.StartIndex, 0);
m_numMoveablesDrawCalls++; m_numMoveablesDrawCalls++;
} }
} }
@ -633,7 +636,7 @@ namespace TEN::Renderer
void Renderer11::RenderTitleImage() void Renderer11::RenderTitleImage()
{ {
Texture2D texture; Texture2D texture;
SetTextureOrDefault(texture, TEN::Utils::FromChar(g_GameFlow->IntroImagePath.c_str())); SetTextureOrDefault(texture, TEN::Utils::ToWString(g_GameFlow->IntroImagePath.c_str()));
if (!texture.Texture) if (!texture.Texture)
return; return;
@ -651,7 +654,9 @@ namespace TEN::Renderer
timeout--; timeout--;
} }
else else
{
currentFade = std::clamp(currentFade -= FADE_FACTOR, 0.0f, 1.0f); currentFade = std::clamp(currentFade -= FADE_FACTOR, 0.0f, 1.0f);
}
DrawFullScreenImage(texture.ShaderResourceView.Get(), Smoothstep(currentFade), m_backBufferRTV, m_depthStencilView); DrawFullScreenImage(texture.ShaderResourceView.Get(), Smoothstep(currentFade), m_backBufferRTV, m_depthStencilView);
Synchronize(); Synchronize();
@ -662,6 +667,8 @@ namespace TEN::Renderer
void Renderer11::DrawExamines() void Renderer11::DrawExamines()
{ {
constexpr auto SCREEN_POS = Vector2(400.0f, 300.0f);
static EulerAngles orient = EulerAngles::Zero; static EulerAngles orient = EulerAngles::Zero;
static float scaler = 1.2f; static float scaler = 1.2f;
@ -695,23 +702,26 @@ namespace TEN::Renderer
float savedScale = object.Scale1; float savedScale = object.Scale1;
object.Scale1 = scaler; object.Scale1 = scaler;
DrawObjectOn2DPosition(400, 300, g_Gui.ConvertInventoryItemToObject(invItem), orient, object.Scale1); DrawObjectOn2DPosition(g_Gui.ConvertInventoryItemToObject(invItem), SCREEN_POS, orient, object.Scale1);
object.Scale1 = savedScale; object.Scale1 = savedScale;
} }
void Renderer11::DrawDiary() void Renderer11::DrawDiary()
{ {
unsigned int currentPage = Lara.Inventory.Diary.CurrentPage; constexpr auto SCREEN_POS = Vector2(400.0f, 300.0f);
const auto& object = InventoryObjectTable[INV_OBJECT_OPEN_DIARY]; const auto& object = InventoryObjectTable[INV_OBJECT_OPEN_DIARY];
unsigned int currentPage = Lara.Inventory.Diary.CurrentPage;
DrawObjectOn2DPosition(400, 300, g_Gui.ConvertInventoryItemToObject(INV_OBJECT_OPEN_DIARY), object.Orientation, object.Scale1); DrawObjectOn2DPosition(g_Gui.ConvertInventoryItemToObject(INV_OBJECT_OPEN_DIARY), SCREEN_POS, object.Orientation, object.Scale1);
for (size_t i = 0; i < MAX_DIARY_STRINGS_PER_PAGE; i++) for (int i = 0; i < MAX_DIARY_STRINGS_PER_PAGE; i++)
{ {
if (!Lara.Inventory.Diary.Pages[Lara.Inventory.Diary.CurrentPage].Strings[i].Position.x && !Lara.Inventory.Diary.Pages[Lara.Inventory.Diary.CurrentPage]. if (!Lara.Inventory.Diary.Pages[Lara.Inventory.Diary.CurrentPage].Strings[i].Position.x && !Lara.Inventory.Diary.Pages[Lara.Inventory.Diary.CurrentPage].
Strings[i].Position.y && !Lara.Inventory.Diary.Pages[Lara.Inventory.Diary.CurrentPage].Strings[i].StringID) Strings[i].Position.y && !Lara.Inventory.Diary.Pages[Lara.Inventory.Diary.CurrentPage].Strings[i].StringID)
{
break; break;
}
//AddString(Lara.Diary.Pages[currentPage].Strings[i].x, Lara.Diary.Pages[currentPage].Strings[i].y, g_GameFlow->GetString(Lara.Diary.Pages[currentPage].Strings[i].stringID), PRINTSTRING_COLOR_WHITE, 0); //AddString(Lara.Diary.Pages[currentPage].Strings[i].x, Lara.Diary.Pages[currentPage].Strings[i].y, g_GameFlow->GetString(Lara.Diary.Pages[currentPage].Strings[i].stringID), PRINTSTRING_COLOR_WHITE, 0);
} }
@ -719,8 +729,7 @@ namespace TEN::Renderer
DrawAllStrings(); DrawAllStrings();
} }
void Renderer11::RenderInventoryScene(ID3D11RenderTargetView* target, ID3D11DepthStencilView* depthTarget, void Renderer11::RenderInventoryScene(ID3D11RenderTargetView* target, ID3D11DepthStencilView* depthTarget, ID3D11ShaderResourceView* background)
ID3D11ShaderResourceView* background)
{ {
// Set basic render states // Set basic render states
SetBlendMode(BLENDMODE_OPAQUE, true); SetBlendMode(BLENDMODE_OPAQUE, true);
@ -761,12 +770,12 @@ namespace TEN::Renderer
if (drawLogo) if (drawLogo)
{ {
float factorX = (float)m_screenWidth / REFERENCE_RES_WIDTH; float factorX = (float)m_screenWidth / SCREEN_SPACE_RES.x;
float factorY = (float)m_screenHeight / REFERENCE_RES_HEIGHT; float factorY = (float)m_screenHeight / SCREEN_SPACE_RES.y;
float scale = m_screenWidth > m_screenHeight ? factorX : factorY; float scale = m_screenWidth > m_screenHeight ? factorX : factorY;
int logoLeft = (REFERENCE_RES_WIDTH / 2) - (LogoWidth / 2); int logoLeft = (SCREEN_SPACE_RES.x / 2) - (LogoWidth / 2);
int logoRight = (REFERENCE_RES_WIDTH / 2) + (LogoWidth / 2); int logoRight = (SCREEN_SPACE_RES.x / 2) + (LogoWidth / 2);
int logoBottom = LogoTop + LogoHeight; int logoBottom = LogoTop + LogoHeight;
RECT rect; RECT rect;
@ -919,13 +928,11 @@ namespace TEN::Renderer
case RENDERER_DEBUG_PAGE::DIMENSION_STATS: case RENDERER_DEBUG_PAGE::DIMENSION_STATS:
PrintDebugMessage("Lara Location: %d %d", LaraItem->Location.roomNumber, LaraItem->Location.yNumber); PrintDebugMessage("Lara Location: %d %d", LaraItem->Location.roomNumber, LaraItem->Location.yNumber);
PrintDebugMessage("Lara RoomNumber: %d", LaraItem->RoomNumber); PrintDebugMessage("Lara RoomNumber: %d", LaraItem->RoomNumber);
PrintDebugMessage("LaraItem BoxNumber: %d",/* canJump: %d, canLongJump: %d, canMonkey: %d,*/ PrintDebugMessage("LaraItem BoxNumber: %d",/* canJump: %d, canLongJump: %d, canMonkey: %d,*/ LaraItem->BoxNumber);
LaraItem->BoxNumber);
PrintDebugMessage("Lara Pos: %d %d %d", LaraItem->Pose.Position.x, LaraItem->Pose.Position.y, LaraItem->Pose.Position.z); PrintDebugMessage("Lara Pos: %d %d %d", LaraItem->Pose.Position.x, LaraItem->Pose.Position.y, LaraItem->Pose.Position.z);
PrintDebugMessage("Lara Rot: %d %d %d", LaraItem->Pose.Orientation.x, LaraItem->Pose.Orientation.y, LaraItem->Pose.Orientation.z); PrintDebugMessage("Lara Rot: %d %d %d", LaraItem->Pose.Orientation.x, LaraItem->Pose.Orientation.y, LaraItem->Pose.Orientation.z);
PrintDebugMessage("Lara WaterSurfaceDist: %d", Lara.WaterSurfaceDist); PrintDebugMessage("Lara WaterSurfaceDist: %d", Lara.WaterSurfaceDist);
PrintDebugMessage("Room: %d %d %d %d", r->x, r->z, r->x + r->xSize * SECTOR(1), PrintDebugMessage("Room: %d %d %d %d", r->x, r->z, r->x + r->xSize * SECTOR(1), r->z + r->zSize * SECTOR(1));
r->z + r->zSize * SECTOR(1));
PrintDebugMessage("Room.y, minFloor, maxCeiling: %d %d %d ", r->y, r->minfloor, r->maxceiling); PrintDebugMessage("Room.y, minFloor, maxCeiling: %d %d %d ", r->y, r->minfloor, r->maxceiling);
PrintDebugMessage("Camera.pos: %d %d %d", Camera.pos.x, Camera.pos.y, Camera.pos.z); PrintDebugMessage("Camera.pos: %d %d %d", Camera.pos.x, Camera.pos.y, Camera.pos.z);
PrintDebugMessage("Camera.target: %d %d %d", Camera.target.x, Camera.target.y, Camera.target.z); PrintDebugMessage("Camera.target: %d %d %d", Camera.target.x, Camera.target.y, Camera.target.z);

View file

@ -240,12 +240,12 @@ constexpr auto FAST_ALPHA_BLEND_THRESHOLD = 0.5f;
constexpr auto MAX_BONES = 32; constexpr auto MAX_BONES = 32;
constexpr auto REFERENCE_FONT_SIZE = 35.0f; constexpr auto SCREEN_SPACE_RES = Vector2(800.0f, 600.0f);
constexpr auto REFERENCE_RES_WIDTH = 800.0f; constexpr auto INVALID_SCREEN_SPACE_POSITION = Vector2(FLT_MAX, FLT_MAX);
constexpr auto REFERENCE_RES_HEIGHT = 600.0f; constexpr auto REFERENCE_FONT_SIZE = 35.0f;
constexpr auto HUD_UNIT_X = 1.0f / REFERENCE_RES_WIDTH; constexpr auto HUD_UNIT_X = 1.0f / SCREEN_SPACE_RES.x;
constexpr auto HUD_UNIT_Y = 1.0f / REFERENCE_RES_HEIGHT; constexpr auto HUD_UNIT_Y = 1.0f / SCREEN_SPACE_RES.y;
constexpr auto HUD_ZERO_Y = -REFERENCE_RES_HEIGHT; constexpr auto HUD_ZERO_Y = -SCREEN_SPACE_RES.y;
constexpr auto UNDERWATER_FOG_MIN_DISTANCE = 4; constexpr auto UNDERWATER_FOG_MIN_DISTANCE = 4;
constexpr auto UNDERWATER_FOG_MAX_DISTANCE = 30; constexpr auto UNDERWATER_FOG_MAX_DISTANCE = 30;

View file

@ -365,7 +365,9 @@ namespace TEN::Renderer
bool Renderer11::SphereBoxIntersection(BoundingBox box, Vector3 sphereCentre, float sphereRadius) bool Renderer11::SphereBoxIntersection(BoundingBox box, Vector3 sphereCentre, float sphereRadius)
{ {
if (sphereRadius == 0.0f) if (sphereRadius == 0.0f)
{
return box.Contains(sphereCentre); return box.Contains(sphereCentre);
}
else else
{ {
BoundingSphere sphere = BoundingSphere(sphereCentre, sphereRadius); BoundingSphere sphere = BoundingSphere(sphereCentre, sphereRadius);
@ -373,10 +375,6 @@ namespace TEN::Renderer
} }
} }
void Renderer11::GetLaraBonePosition(Vector3 *pos, int bone)
{
}
void Renderer11::FlipRooms(short roomNumber1, short roomNumber2) void Renderer11::FlipRooms(short roomNumber1, short roomNumber2)
{ {
std::swap(m_rooms[roomNumber1], m_rooms[roomNumber2]); std::swap(m_rooms[roomNumber1], m_rooms[roomNumber2]);
@ -407,31 +405,6 @@ namespace TEN::Renderer
return m_meshes[meshIndex]; return m_meshes[meshIndex];
} }
void Renderer11::GetItemAbsBonePosition(int itemNumber, Vector3& pos, int jointIndex)
{
auto* rendererItem = &m_items[itemNumber];
auto* nativeItem = &g_Level.Items[itemNumber];
rendererItem->ItemNumber = itemNumber;
if (!rendererItem)
return;
if (!rendererItem->DoneAnimations)
{
if (itemNumber == Lara.ItemNumber)
UpdateLaraAnimations(false);
else
UpdateItemAnimations(itemNumber, false);
}
if (jointIndex >= MAX_BONES)
jointIndex = 0;
auto world = rendererItem->AnimationTransforms[jointIndex] * rendererItem->World;
pos = Vector3::Transform(pos, world);
}
int Renderer11::GetSpheres(short itemNumber, BoundingSphere* spheres, char worldSpace, Matrix local) int Renderer11::GetSpheres(short itemNumber, BoundingSphere* spheres, char worldSpace, Matrix local)
{ {
auto* itemToDraw = &m_items[itemNumber]; auto* itemToDraw = &m_items[itemNumber];
@ -532,4 +505,63 @@ namespace TEN::Renderer
return s; return s;
} }
}
Vector2i Renderer11::GetScreenResolution() const
{
return Vector2i(m_screenWidth, m_screenHeight);
}
Vector2 Renderer11::GetScreenSpacePosition(const Vector3& pos) const
{
auto point = Vector4(pos.x, pos.y, pos.z, 1.0f);
auto cameraPos = Vector4(
gameCamera.camera.WorldPosition.x,
gameCamera.camera.WorldPosition.y,
gameCamera.camera.WorldPosition.z,
1.0f);
auto cameraDirection = Vector4(
gameCamera.camera.WorldDirection.x,
gameCamera.camera.WorldDirection.y,
gameCamera.camera.WorldDirection.z,
1.0f);
// If point is behind camera, return invalid screen space position.
if ((point - cameraPos).Dot(cameraDirection) < 0.0f)
return INVALID_SCREEN_SPACE_POSITION;
// Calculate clip space coords.
point = Vector4::Transform(point, gameCamera.camera.ViewProjection);
// Calculate normalized device coords.
point /= point.w;
// Calculate and return screen space position.
return Vector2(
((point.x + 1.0f) * SCREEN_SPACE_RES.x) / 2,
((1.0f - point.y) * SCREEN_SPACE_RES.y) / 2);
}
Vector3 Renderer11::GetAbsEntityBonePosition(int itemNumber, int jointIndex, const Vector3& relOffset)
{
auto* rendererItem = &m_items[itemNumber];
rendererItem->ItemNumber = itemNumber;
if (!rendererItem)
return Vector3::Zero;
if (!rendererItem->DoneAnimations)
{
if (itemNumber == Lara.ItemNumber)
UpdateLaraAnimations(false);
else
UpdateItemAnimations(itemNumber, false);
}
if (jointIndex >= MAX_BONES)
jointIndex = 0;
auto world = rendererItem->AnimationTransforms[jointIndex] * rendererItem->World;
return Vector3::Transform(relOffset, world);
}
}

View file

@ -116,7 +116,7 @@ void TEN::Renderer::Renderer11::Initialise(int w, int h, bool windowed, HWND han
m_cbHUD = CreateConstantBuffer<CHUDBuffer>(); m_cbHUD = CreateConstantBuffer<CHUDBuffer>();
m_cbSprite = CreateConstantBuffer<CSpriteBuffer>(); m_cbSprite = CreateConstantBuffer<CSpriteBuffer>();
m_stHUD.View = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, 1), Vector3(0, -1, 0)); m_stHUD.View = Matrix::CreateLookAt(Vector3::Zero, Vector3(0, 0, 1), Vector3(0, -1, 0));
m_stHUD.Projection = Matrix::CreateOrthographicOffCenter(0, REFERENCE_RES_WIDTH, 0, REFERENCE_RES_HEIGHT, 0, 1.0f); m_stHUD.Projection = Matrix::CreateOrthographicOffCenter(0, SCREEN_SPACE_RES.x, 0, SCREEN_SPACE_RES.y, 0, 1.0f);
m_cbHUD.updateData(m_stHUD, m_context.Get()); m_cbHUD.updateData(m_stHUD, m_context.Get());
m_currentCausticsFrame = 0; m_currentCausticsFrame = 0;

View file

@ -60,7 +60,7 @@ namespace TEN::Renderer
dxgiAdapter->GetDesc(&adapterDesc); dxgiAdapter->GetDesc(&adapterDesc);
dxgiFactory->Release(); dxgiFactory->Release();
return TEN::Utils::FromWchar(adapterDesc.Description); return TEN::Utils::ToString(adapterDesc.Description);
} }
void Renderer11::SetTextureOrDefault(Texture2D& texture, std::wstring path) void Renderer11::SetTextureOrDefault(Texture2D& texture, std::wstring path)

View file

@ -1,57 +1,54 @@
#include "framework.h" #include "framework.h"
#include "Renderer/Renderer11.h" #include "Renderer/Renderer11.h"
#include "Specific/trutils.h" #include "Specific/trutils.h"
namespace TEN::Renderer namespace TEN::Renderer
{ {
void Renderer11::AddString(int x, int y, const char* string, D3DCOLOR color, int flags) void Renderer11::AddString(int x, int y, const char* string, D3DCOLOR color, int flags)
{
AddString(std::string(string), Vector2(x, y), Color(color), 1.0f, flags);
}
void Renderer11::AddString(const std::string& string, const Vector2& pos, const Color& color, float scale, int flags)
{ {
if (m_Locked) if (m_Locked)
return; return;
if (string == NULL) if (string.empty())
return; return;
try try
{ {
float factorX = m_screenWidth / REFERENCE_RES_WIDTH; auto screenRes = GetScreenResolution();
float factorY = m_screenHeight / REFERENCE_RES_HEIGHT; auto factor = Vector2(screenRes.x / SCREEN_SPACE_RES.x, screenRes.y / SCREEN_SPACE_RES.y);
float UIScale = m_screenWidth > m_screenHeight ? factorY : factorX; float UIScale = (screenRes.x > screenRes.y) ? factor.y : factor.x;
float fontSpacing = m_gameFont->GetLineSpacing(); float fontSpacing = m_gameFont->GetLineSpacing();
float fontScale = REFERENCE_FONT_SIZE / fontSpacing; float fontScale = REFERENCE_FONT_SIZE / fontSpacing;
float currentY = 0; auto stringLines = SplitString(string);
float yOffset = 0.0f;
auto lines = TEN::Utils::SplitString(string); for (const auto& line : stringLines)
for (auto line : lines)
{ {
auto cLine = line.c_str(); // Prepare structure for renderer.
RendererStringToDraw rString;
rString.String = TEN::Utils::ToWString(line);
rString.Flags = flags;
rString.X = 0;
rString.Y = 0;
rString.Color = color.ToVector3() * UCHAR_MAX;
rString.Scale = (UIScale * fontScale) * scale;
// Convert the string to wstring // Measure string.
int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, cLine, line.size(), NULL, 0); auto size = Vector2(m_gameFont->MeasureString(rString.String.c_str()));
std::wstring wstr(sizeNeeded, 0); float width = size.x * rString.Scale;
MultiByteToWideChar(CP_UTF8, 0, cLine, strlen(cLine), &wstr[0], sizeNeeded);
// Prepare the structure for the renderer rString.X = (flags & PRINTSTRING_CENTER) ? ((pos.x * factor.x) - (width / 2.0f)) : (pos.x * factor.x);
RendererStringToDraw str; rString.Y = (pos.y * UIScale) + yOffset;
str.String = wstr;
str.Flags = flags;
str.X = 0;
str.Y = 0;
str.Color = Vector3((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF);
str.Scale = UIScale * fontScale;
// Measure the string
Vector2 size = m_gameFont->MeasureString(wstr.c_str());
float width = size.x * str.Scale;
str.X = (flags & PRINTSTRING_CENTER) ? (float)x * factorX - (width / 2.0f) : (float)x * factorX;
str.Y = y * UIScale + currentY;
if (flags & PRINTSTRING_BLINK) if (flags & PRINTSTRING_BLINK)
{ {
str.Color = Vector3(m_blinkColorValue, m_blinkColorValue, m_blinkColorValue); rString.Color = Vector3(m_blinkColorValue, m_blinkColorValue, m_blinkColorValue);
if (!m_blinkUpdated) if (!m_blinkUpdated)
{ {
@ -64,24 +61,23 @@ namespace TEN::Renderer
m_blinkColorDirection = 1; m_blinkColorDirection = 1;
} }
if (m_blinkColorValue > 255) if (m_blinkColorValue > UCHAR_MAX)
{ {
m_blinkColorValue = 255; m_blinkColorValue = UCHAR_MAX;
m_blinkColorDirection = -1; m_blinkColorDirection = -1;
} }
} }
} }
m_strings.push_back(str); m_strings.push_back(rString);
currentY += fontSpacing * 1.1f; yOffset += fontSpacing * 1.1f;
} }
} }
catch (std::exception& ex) catch (std::exception& ex)
{ {
TENLog(std::string("Unable to process string: '") + string + TENLog(std::string("Unable to process string: '") + string + "'. Exception: " + std::string(ex.what()), LogLevel::Error);
"'. Exception: " + std::string(ex.what()), LogLevel::Error);
} }
} }
@ -91,20 +87,24 @@ namespace TEN::Renderer
m_spriteBatch->Begin(); m_spriteBatch->Begin();
for (int i = 0; i < m_strings.size(); i++) for (const auto& rString : m_strings)
{ {
RendererStringToDraw* str = &m_strings[i]; // Draw shadow.
if (rString.Flags & PRINTSTRING_OUTLINE)
// Draw shadow if needed {
if (str->Flags & PRINTSTRING_OUTLINE) m_gameFont->DrawString(
m_gameFont->DrawString(m_spriteBatch.get(), str->String.c_str(), Vector2(str->X + shadeOffset * str->Scale, str->Y + shadeOffset * str->Scale), m_spriteBatch.get(), rString.String.c_str(),
Vector2(rString.X + shadeOffset * rString.Scale, rString.Y + shadeOffset * rString.Scale),
Vector4(0.0f, 0.0f, 0.0f, 1.0f) * ScreenFadeCurrent, Vector4(0.0f, 0.0f, 0.0f, 1.0f) * ScreenFadeCurrent,
0.0f, Vector4::Zero, str->Scale); 0.0f, Vector4::Zero, rString.Scale);
}
// Draw string // Draw string.
m_gameFont->DrawString(m_spriteBatch.get(), str->String.c_str(), Vector2(str->X, str->Y), m_gameFont->DrawString(
Vector4(str->Color.x / 255.0f, str->Color.y / 255.0f, str->Color.z / 255.0f, 1.0f) * ScreenFadeCurrent, m_spriteBatch.get(), rString.String.c_str(),
0.0f, Vector4::Zero, str->Scale); Vector2(rString.X, rString.Y),
Vector4(rString.Color.x / UCHAR_MAX, rString.Color.y / UCHAR_MAX, rString.Color.z / UCHAR_MAX, 1.0f) * ScreenFadeCurrent,
0.0f, Vector4::Zero, rString.Scale);
} }
m_spriteBatch->End(); m_spriteBatch->End();

View file

@ -215,17 +215,13 @@ namespace TEN::Input
{ {
for (int i = 0; i < KEY_COUNT; i++) for (int i = 0; i < KEY_COUNT; i++)
{ {
if (ActionQueue[i] != QueueState::None) if (ActionQueue[i] == QueueState::None)
{ continue;
if (ActionQueue[i] == QueueState::Push)
{ if (ActionQueue[i] == QueueState::Push)
ActionMap[i].Update(true); ActionMap[i].Update(true);
} else
else ActionMap[i].Clear();
{
ActionMap[i].Clear();
}
}
} }
} }

View file

@ -1038,7 +1038,7 @@ unsigned int _stdcall LoadLevel(void* data)
FILE* filePtr = nullptr; FILE* filePtr = nullptr;
char* dataPtr = nullptr; char* dataPtr = nullptr;
g_Renderer.SetLoadingScreen(TEN::Utils::FromChar(level->LoadScreenFileName.c_str())); g_Renderer.SetLoadingScreen(TEN::Utils::ToWString(level->LoadScreenFileName.c_str()));
SetScreenFadeIn(FADE_SCREEN_SPEED); SetScreenFadeIn(FADE_SCREEN_SPEED);
g_Renderer.UpdateProgress(0); g_Renderer.UpdateProgress(0);

View file

@ -5,52 +5,60 @@
namespace TEN::Utils namespace TEN::Utils
{ {
std::string ToUpper(std::string source) std::string ToUpper(std::string string)
{ {
std::transform(source.begin(), source.end(), source.begin(), [](unsigned char c) { return std::toupper(c); }); std::transform(string.begin(), string.end(), string.begin(), [](unsigned char c) { return std::toupper(c); });
return source; return string;
} }
std::string ToLower(std::string source) std::string ToLower(std::string string)
{ {
std::transform(source.begin(), source.end(), source.begin(), [](unsigned char c) { return std::tolower(c); }); std::transform(string.begin(), string.end(), string.begin(), [](unsigned char c) { return std::tolower(c); });
return source; return string;
} }
std::string FromWchar(const wchar_t* source) std::string ToString(const wchar_t* string)
{ {
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter; auto converter = std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>();
return converter.to_bytes(std::wstring(source)); return converter.to_bytes(std::wstring(string));
} }
std::wstring FromChar(const char* source) std::wstring ToWString(const std::string& string)
{
auto cString = string.c_str();
int size = MultiByteToWideChar(CP_UTF8, 0, cString, string.size(), nullptr, 0);
auto wString = std::wstring(size, 0);
MultiByteToWideChar(CP_UTF8, 0, cString, strlen(cString), &wString[0], size);
return wString;
}
std::wstring ToWString(const char* source)
{ {
wchar_t buffer[UCHAR_MAX]; wchar_t buffer[UCHAR_MAX];
std::mbstowcs(buffer, source, UCHAR_MAX); std::mbstowcs(buffer, source, UCHAR_MAX);
return std::wstring(buffer); return std::wstring(buffer);
} }
std::vector<std::string> SplitString(const std::string& source) std::vector<std::string> SplitString(const std::string& string)
{ {
std::vector<std::string> strings; auto strings = std::vector<std::string>{};
// String is single line; exit early. // String is single line; exit early.
if (source.find('\n') == std::string::npos) if (string.find('\n') == std::string::npos)
{ {
strings.push_back(source); strings.push_back(string);
return strings; return strings;
} }
std::string::size_type pos = 0; std::string::size_type pos = 0;
std::string::size_type prev = 0; std::string::size_type prev = 0;
while ((pos = source.find('\n', prev)) != std::string::npos) while ((pos = string.find('\n', prev)) != std::string::npos)
{ {
strings.push_back(source.substr(prev, pos - prev)); strings.push_back(string.substr(prev, pos - prev));
prev = pos + 1; prev = pos + 1;
} }
strings.push_back(source.substr(prev)); strings.push_back(string.substr(prev));
return strings; return strings;
} }
@ -66,14 +74,14 @@ namespace TEN::Utils
int size = GetFileVersionInfoSizeA(fileName, NULL); int size = GetFileVersionInfoSizeA(fileName, NULL);
if (!size) if (size == 0)
{ {
TENLog("GetFileVersionInfoSizeA failed", LogLevel::Error); TENLog("GetFileVersionInfoSizeA failed", LogLevel::Error);
return {}; return {};
} }
std::unique_ptr<unsigned char> buffer(new unsigned char[size]); std::unique_ptr<unsigned char> buffer(new unsigned char[size]);
// Load the version info. // Load version info.
if (!GetFileVersionInfoA(fileName, 0, size, buffer.get())) if (!GetFileVersionInfoA(fileName, 0, size, buffer.get()))
{ {
TENLog("GetFileVersionInfoA failed", LogLevel::Error); TENLog("GetFileVersionInfoA failed", LogLevel::Error);
@ -96,6 +104,7 @@ namespace TEN::Utils
} }
if (productVersion) if (productVersion)
{
return return
{ {
HIWORD(info->dwProductVersionMS), HIWORD(info->dwProductVersionMS),
@ -103,7 +112,9 @@ namespace TEN::Utils
HIWORD(info->dwProductVersionLS), HIWORD(info->dwProductVersionLS),
LOWORD(info->dwProductVersionLS) LOWORD(info->dwProductVersionLS)
}; };
}
else else
{
return return
{ {
HIWORD(info->dwFileVersionMS), HIWORD(info->dwFileVersionMS),
@ -111,5 +122,6 @@ namespace TEN::Utils
HIWORD(info->dwFileVersionLS), HIWORD(info->dwFileVersionLS),
LOWORD(info->dwFileVersionLS) LOWORD(info->dwFileVersionLS)
}; };
}
} }
} }

View file

@ -1,13 +1,14 @@
#pragma once #pragma once
#include <string>
namespace TEN::Utils namespace TEN::Utils
{ {
std::string ToUpper(std::string source); // String utilities
std::string ToLower(std::string source); std::string ToUpper(std::string string);
std::string FromWchar(const wchar_t* source); std::string ToLower(std::string string);
std::wstring FromChar(const char* source); std::string ToString(const wchar_t* string);
std::vector<std::string> SplitString(const std::string& source); std::wstring ToWString(const std::string& string);
std::wstring ToWString(const char* string);
std::vector<std::string> SplitString(const std::string& string);
std::vector<unsigned short> GetProductOrFileVersion(bool productVersion); std::vector<unsigned short> GetProductOrFileVersion(bool productVersion);
} }

View file

@ -45,7 +45,7 @@ extern "C"
bool ArgEquals(wchar_t* incomingArg, std::string name) bool ArgEquals(wchar_t* incomingArg, std::string name)
{ {
auto lowerArg = TEN::Utils::ToLower(TEN::Utils::FromWchar(incomingArg)); auto lowerArg = TEN::Utils::ToLower(TEN::Utils::ToString(incomingArg));
return (lowerArg == "-" + name) || (lowerArg == "/" + name); return (lowerArg == "-" + name) || (lowerArg == "/" + name);
} }
@ -259,7 +259,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
} }
else if (ArgEquals(argv[i], "level") && argc > (i + 1)) else if (ArgEquals(argv[i], "level") && argc > (i + 1))
{ {
levelFile = TEN::Utils::FromWchar(argv[i + 1]); levelFile = TEN::Utils::ToString(argv[i + 1]);
} }
else if (ArgEquals(argv[i], "hash") && argc > (i + 1)) else if (ArgEquals(argv[i], "hash") && argc > (i + 1))
{ {

View file

@ -166,6 +166,7 @@ CALL gen.bat</Command>
<ClInclude Include="Game\effects\item_fx.h" /> <ClInclude Include="Game\effects\item_fx.h" />
<ClInclude Include="Game\effects\Electricity.h" /> <ClInclude Include="Game\effects\Electricity.h" />
<ClInclude Include="Game\GuiObjects.h" /> <ClInclude Include="Game\GuiObjects.h" />
<ClInclude Include="Game\Hud\PickupSummary.h" />
<ClInclude Include="Math\Objects\AxisAngle.h" /> <ClInclude Include="Math\Objects\AxisAngle.h" />
<ClInclude Include="Objects\TR1\Trap\DamoclesSword.h" /> <ClInclude Include="Objects\TR1\Trap\DamoclesSword.h" />
<ClInclude Include="Objects\TR5\Entity\HeavyGuard.h" /> <ClInclude Include="Objects\TR5\Entity\HeavyGuard.h" />
@ -582,7 +583,7 @@ CALL gen.bat</Command>
<ClInclude Include="Game\effects\effects.h" /> <ClInclude Include="Game\effects\effects.h" />
<ClInclude Include="Game\control\flipeffect.h" /> <ClInclude Include="Game\control\flipeffect.h" />
<ClInclude Include="Game\effects\hair.h" /> <ClInclude Include="Game\effects\hair.h" />
<ClInclude Include="Game\health.h" /> <ClInclude Include="Game\Hud\Hud.h" />
<ClInclude Include="Game\items.h" /> <ClInclude Include="Game\items.h" />
<ClInclude Include="Game\Lara\lara.h" /> <ClInclude Include="Game\Lara\lara.h" />
<ClInclude Include="Game\Lara\lara_one_gun.h" /> <ClInclude Include="Game\Lara\lara_one_gun.h" />
@ -643,6 +644,7 @@ CALL gen.bat</Command>
<ClCompile Include="Game\collision\floordata.cpp" /> <ClCompile Include="Game\collision\floordata.cpp" />
<ClCompile Include="Game\effects\footprint.cpp" /> <ClCompile Include="Game\effects\footprint.cpp" />
<ClCompile Include="Game\GuiObjects.cpp" /> <ClCompile Include="Game\GuiObjects.cpp" />
<ClCompile Include="Game\Hud\PickupSummary.cpp" />
<ClCompile Include="Math\Objects\AxisAngle.cpp" /> <ClCompile Include="Math\Objects\AxisAngle.cpp" />
<ClCompile Include="Objects\TR1\Trap\DamoclesSword.cpp" /> <ClCompile Include="Objects\TR1\Trap\DamoclesSword.cpp" />
<ClCompile Include="Objects\TR5\Entity\HeavyGuard.cpp" /> <ClCompile Include="Objects\TR5\Entity\HeavyGuard.cpp" />
@ -944,7 +946,7 @@ CALL gen.bat</Command>
<ClCompile Include="Game\effects\effects.cpp" /> <ClCompile Include="Game\effects\effects.cpp" />
<ClCompile Include="Game\control\flipeffect.cpp" /> <ClCompile Include="Game\control\flipeffect.cpp" />
<ClCompile Include="Game\effects\hair.cpp" /> <ClCompile Include="Game\effects\hair.cpp" />
<ClCompile Include="Game\health.cpp" /> <ClCompile Include="Game\Hud\Hud.cpp" />
<ClCompile Include="Game\items.cpp" /> <ClCompile Include="Game\items.cpp" />
<ClCompile Include="Game\Lara\lara.cpp" /> <ClCompile Include="Game\Lara\lara.cpp" />
<ClCompile Include="Game\Lara\lara_one_gun.cpp" /> <ClCompile Include="Game\Lara\lara_one_gun.cpp" />