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)
* Implement squash and stretch water bubbles.
* 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
* 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/camera.h"
#include "Game/collision/collide_room.h"
#include "Game/health.h"
#include "Game/Hud/Hud.h"
#include "Game/items.h"
#include "Game/Lara/lara.h"
#include "Game/Lara/lara_tests.h"

View file

@ -1,7 +1,7 @@
#include "framework.h"
#include "Game/Lara/lara_initialise.h"
#include "Game/health.h"
#include "Game/Hud/Hud.h"
#include "Game/items.h"
#include "Game/Lara/lara.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)
{
// Use matrices done in the renderer to transform the offset vector.
auto pos = relOffset.ToVector3();
g_Renderer.GetItemAbsBonePosition(item->Index, pos, jointIndex);
return Vector3i(pos);
// Use matrices done in renderer to transform relative offset.
return Vector3i(g_Renderer.GetAbsEntityBonePosition(item->Index, jointIndex, relOffset.ToVector3()));
}

View file

@ -24,11 +24,11 @@
#include "Game/effects/tomb4fx.h"
#include "Game/effects/weather.h"
#include "Game/Gui.h"
#include "Game/Hud/Hud.h"
#include "Game/Lara/lara.h"
#include "Game/Lara/lara_cheat.h"
#include "Game/Lara/lara_helpers.h"
#include "Game/Lara/lara_one_gun.h"
#include "Game/health.h"
#include "Game/items.h"
#include "Game/pickup/pickup.h"
#include "Game/room.h"
@ -68,6 +68,7 @@ using namespace TEN::Entities::Generic;
using namespace TEN::Entities::Switches;
using namespace TEN::Entities::TR4;
using namespace TEN::Floordata;
using namespace TEN::Hud;
using namespace TEN::Input;
using namespace TEN::Math;
using namespace TEN::Renderer;
@ -213,9 +214,10 @@ GameStatus ControlPhase(int numFrames)
UpdateBeetleSwarm();
UpdateLocusts();
// Update screen UI and overlays.
// Update HUD.
UpdateBars(LaraItem);
UpdateFadeScreenAndCinematicBars();
g_Hud.Update();
// Rumble screen (like in submarine level of TRC).
if (g_GameFlow->GetLevel(CurrentLevel)->Rumble)
@ -285,7 +287,6 @@ GameStatus DoLevel(int levelIndex, bool loadGame)
// Initialize items, effects, lots, and cameras.
InitialiseFXArray(true);
InitialisePickupDisplay();
InitialiseCamera();
InitialiseSpotCamSequences(isTitle);
InitialiseHair();
@ -411,6 +412,9 @@ void CleanUp()
// Clear swarm enemies.
ClearSwarmEnemies(nullptr);
// Clear HUD.
g_Hud.Clear();
// Clear soundtrack masks.
ClearSoundTrackMasks();
@ -434,9 +438,10 @@ void InitialiseScripting(int levelIndex, bool loadGame)
g_GameScript->InitCallbacks();
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,
float(y) / float(g_Configuration.Height) * REFERENCE_RES_HEIGHT,
key.c_str(), col, flags);
g_Renderer.AddString(
float(x) / float(g_Configuration.Width) * SCREEN_SPACE_RES.x,
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
{
constexpr int LINE_HEIGHT = 25;
constexpr int PHD_CENTER_X = REFERENCE_RES_WIDTH / 2;
constexpr int PHD_CENTER_Y = REFERENCE_RES_HEIGHT / 2;
constexpr int PHD_CENTER_X = SCREEN_SPACE_RES.x / 2;
constexpr int PHD_CENTER_Y = SCREEN_SPACE_RES.y / 2;
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);
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
g_Renderer.DrawObjectOn2DPosition(x, y, objectNumber, AmmoObjectList[n].Orientation, scaler);
g_Renderer.DrawObjectOn2DPosition(objectNumber, Vector2(x, y), AmmoObjectList[n].Orientation, scaler);
}
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;
}
@ -2775,9 +2777,9 @@ namespace TEN::Gui
int objectNumber;
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
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);
}
@ -2830,7 +2832,7 @@ namespace TEN::Gui
auto& orientation = Rings[ringIndex]->CurrentObjectList[n].Orientation;
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)
n = 0;
@ -3043,7 +3045,7 @@ namespace TEN::Gui
// TODO
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 compassAngle = (item->Pose.Orientation.y + compassSpeed) - ANGLE(180.0f);
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/effects/debris.h"
#include "Game/Gui.h"
#include "Game/Hud/Hud.h"
#include "Game/items.h"
#include "Game/health.h"
#include "Game/Lara/lara.h"
#include "Game/Lara/lara_fire.h"
#include "Game/Lara/lara_flare.h"
@ -31,6 +31,7 @@
#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h"
using namespace TEN::Entities::Generic;
using namespace TEN::Hud;
using namespace TEN::Input;
static auto PickUpPosition = Vector3i(0, 0, -100);
@ -39,12 +40,10 @@ const ObjectCollisionBounds PickUpBounds =
GameBoundingBox(
-CLICK(1), CLICK(1),
-200, 200,
-CLICK(1), CLICK(1)
),
-CLICK(1), CLICK(1)),
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)))
};
static auto HiddenPickUpPosition = Vector3i(0, 0, -690);
@ -53,12 +52,10 @@ const ObjectCollisionBounds HiddenPickUpBounds =
GameBoundingBox(
-CLICK(1), CLICK(1),
-100, 100,
-800, -CLICK(1)
),
-800, -CLICK(1)),
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)))
};
static auto CrowbarPickUpPosition = Vector3i(0, 0, 215);
@ -67,12 +64,10 @@ const ObjectCollisionBounds CrowbarPickUpBounds =
GameBoundingBox(
-CLICK(1), CLICK(1),
-100, 100,
200, CLICK(2)
),
200, CLICK(2) ),
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)))
};
static auto JobyCrowPickUpPosition = Vector3i(-224, 0, 240);
@ -81,12 +76,10 @@ const ObjectCollisionBounds JobyCrowPickUpBounds =
GameBoundingBox(
-CLICK(2), 0,
-100, 100,
0, CLICK(2)
),
0, CLICK(2)),
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)))
};
static auto PlinthPickUpPosition = Vector3i(0, 0, -460);
@ -95,12 +88,10 @@ ObjectCollisionBounds PlinthPickUpBounds =
GameBoundingBox(
-CLICK(1), CLICK(1),
-640, 640,
-511, 0
),
-511, 0),
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)))
};
static auto PickUpPositionUW = Vector3i(0, -200, -350);
@ -109,12 +100,10 @@ const ObjectCollisionBounds PickUpBoundsUW =
GameBoundingBox(
-CLICK(2), CLICK(2),
-CLICK(2), CLICK(2),
-CLICK(2), CLICK(2)
),
-CLICK(2), CLICK(2)),
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)))
};
static auto SOPos = Vector3i::Zero;
@ -123,8 +112,7 @@ ObjectCollisionBounds SOBounds =
GameBoundingBox::Zero,
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)))
};
short SearchCollectFrames[4] = { 180, 100, 153, 83 };
@ -136,8 +124,7 @@ const ObjectCollisionBounds MSBounds =
GameBoundingBox::Zero,
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)))
};
int NumRPickups;
@ -154,6 +141,7 @@ bool SetInventoryCount(GAME_OBJECT_ID objectID, int count)
{
return false;
}
return true;
}
@ -215,7 +203,7 @@ void CollectCarriedItems(ItemInfo* item)
{
auto* pickupItem = &g_Level.Items[pickupNumber];
AddDisplayPickup(pickupItem->ObjectNumber);
g_Hud.PickupSummary.AddDisplayPickup(pickupItem->ObjectNumber, pickupItem->Pose.Position.ToVector3());
KillItem(pickupNumber);
pickupNumber = pickupItem->CarriedItem;
@ -239,7 +227,7 @@ void CollectMultiplePickups(int itemNumber)
if (!Objects[currentItem->ObjectNumber].isPickup)
continue;
AddDisplayPickup(currentItem->ObjectNumber);
g_Hud.PickupSummary.AddDisplayPickup(currentItem->ObjectNumber, currentItem->Pose.Position.ToVector3());
if (currentItem->TriggerFlags & 0x100)
{
for (int i = 0; i < g_Level.NumItems; i++)
@ -281,7 +269,7 @@ void DoPickup(ItemInfo* laraItem)
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();
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
{
AddDisplayPickup(pickupItem->ObjectNumber);
g_Hud.PickupSummary.AddDisplayPickup(pickupItem->ObjectNumber, pickupItem->Pose.Position.ToVector3());
if (!(pickupItem->TriggerFlags & 0xC0))
KillItem(pickupItemNumber);
else
@ -340,7 +328,7 @@ void DoPickup(ItemInfo* laraItem)
{
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;
KillItem(pickupItemNumber);
}
@ -355,7 +343,7 @@ void DoPickup(ItemInfo* laraItem)
return;
}
AddDisplayPickup(pickupItem->ObjectNumber);
g_Hud.PickupSummary.AddDisplayPickup(pickupItem->ObjectNumber, pickupItem->Pose.Position.ToVector3());
if (pickupItem->TriggerFlags & 0x100)
{
for (int i = 0; i < g_Level.NumItems; i++)
@ -1249,9 +1237,13 @@ void SearchObjectControl(short itemNumber)
else if (item->ObjectNumber == ID_SEARCH_OBJECT2)
{
if (frameNumber == 18)
{
item->MeshBits = 1;
}
else if (frameNumber == 172)
{
item->MeshBits = 2;
}
}
else if (item->ObjectNumber == ID_SEARCH_OBJECT4)
{
@ -1284,7 +1276,7 @@ void SearchObjectControl(short itemNumber)
if (Objects[item2->ObjectNumber].isPickup)
{
AddDisplayPickup(item2->ObjectNumber);
g_Hud.PickupSummary.AddDisplayPickup(item2->ObjectNumber, item2->Pose.Position.ToVector3());
KillItem(item->ItemFlags[1]);
}
else
@ -1299,7 +1291,9 @@ void SearchObjectControl(short itemNumber)
}
}
else
{
CollectCarriedItems(item);
}
}

View file

@ -12,17 +12,6 @@ using namespace TEN::Math;
//{
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)
{
auto directionNorm = direction;
@ -40,11 +29,11 @@ using namespace TEN::Math;
EulerAngles::EulerAngles(const Quaternion& quat)
{
static constexpr auto singularityThreshold = 1.0f - EPSILON;
constexpr auto SINGULARITY_THRESHOLD = 1.0f - EPSILON;
// Handle singularity case.
float sinP = ((quat.w * quat.x) - (quat.y * quat.z)) * 2;
if (abs(sinP) > singularityThreshold)
if (abs(sinP) > SINGULARITY_THRESHOLD)
{
if (sinP > 0.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".
// Constructors
EulerAngles();
EulerAngles(short x, short y, short z);
EulerAngles(const Vector3& direction);
EulerAngles(const AxisAngle& axisAngle);
EulerAngles(const Quaternion& quat);
EulerAngles(const Matrix& rotMatrix);
constexpr EulerAngles() {};
constexpr EulerAngles(short x, short y, short z) { this->x = x; this->y = y; this->z = z; };
EulerAngles(const Vector3& direction);
EulerAngles(const AxisAngle& axisAngle);
EulerAngles(const Quaternion& quat);
EulerAngles(const Matrix& rotMatrix);
// Utilities
static bool Compare(const EulerAngles& eulers0, const EulerAngles& eulers1, short epsilon = 2);

View file

@ -5,6 +5,8 @@
#include "Game/items.h"
#include "Math/Objects/EulerAngles.h"
#include "Math/Objects/Pose.h"
#include "Objects/game_object_ids.h"
#include "Specific/setup.h"
//namespace TEN::Math
//{
@ -24,6 +26,11 @@
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)
{
int rate = 0;
@ -53,15 +60,14 @@
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
{
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)
{
auto rotMatrix = orient.ToRotationMatrix();

View file

@ -1,8 +1,10 @@
#pragma once
enum GAME_OBJECT_ID : short;
class EulerAngles;
struct ItemInfo;
class Pose;
struct ItemInfo;
struct ObjectInfo;
//namespace TEN::Math
//{
@ -23,6 +25,7 @@ class Pose;
// Constructors
GameBoundingBox();
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);
// Getters

View file

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

View file

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

View file

@ -117,7 +117,7 @@ namespace TEN::Renderer
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;
array<Vector3, 16> barBorderVertices = {
//top left
@ -377,35 +377,35 @@ namespace TEN::Renderer
switch (blendMode)
{
case BLENDMODE_ALPHABLEND:
m_context->OMSetBlendState(m_states->NonPremultiplied(), NULL, 0xFFFFFFFF);
m_context->OMSetBlendState(m_states->NonPremultiplied(), nullptr, 0xFFFFFFFF);
break;
case BLENDMODE_ALPHATEST:
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->OMSetBlendState(m_states->Opaque(), nullptr, 0xFFFFFFFF);
break;
case BLENDMODE_OPAQUE:
m_context->OMSetBlendState(m_states->Opaque(), NULL, 0xFFFFFFFF);
m_context->OMSetBlendState(m_states->Opaque(), nullptr, 0xFFFFFFFF);
break;
case BLENDMODE_SUBTRACTIVE:
m_context->OMSetBlendState(m_subtractiveBlendState.Get(), NULL, 0xFFFFFFFF);
m_context->OMSetBlendState(m_subtractiveBlendState.Get(), nullptr, 0xFFFFFFFF);
break;
case BLENDMODE_ADDITIVE:
m_context->OMSetBlendState(m_states->Additive(), NULL, 0xFFFFFFFF);
m_context->OMSetBlendState(m_states->Additive(), nullptr, 0xFFFFFFFF);
break;
case BLENDMODE_SCREEN:
m_context->OMSetBlendState(m_screenBlendState.Get(), NULL, 0xFFFFFFFF);
m_context->OMSetBlendState(m_screenBlendState.Get(), nullptr, 0xFFFFFFFF);
break;
case BLENDMODE_LIGHTEN:
m_context->OMSetBlendState(m_lightenBlendState.Get(), NULL, 0xFFFFFFFF);
m_context->OMSetBlendState(m_lightenBlendState.Get(), nullptr, 0xFFFFFFFF);
break;
case BLENDMODE_EXCLUDE:
m_context->OMSetBlendState(m_excludeBlendState.Get(), NULL, 0xFFFFFFFF);
m_context->OMSetBlendState(m_excludeBlendState.Get(), nullptr, 0xFFFFFFFF);
break;
}
@ -426,7 +426,6 @@ namespace TEN::Renderer
default:
SetDepthState(DEPTH_STATE_READ_ONLY_ZBUFFER);
break;
}
}

View file

@ -7,7 +7,9 @@
#include "Game/items.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/Electricity.h"
#include "Specific/level.h"
@ -53,6 +55,7 @@ struct RendererRectangle;
using namespace TEN::Effects::Electricity;
using namespace TEN::Gui;
using namespace TEN::Hud;
namespace TEN::Renderer
{
@ -244,8 +247,9 @@ namespace TEN::Renderer
struct RendererLine2D
{
Vector2 Vertices[2];
Vector4 Color;
Vector2 Origin = Vector2::Zero;
Vector2 Target = Vector2::Zero;
Vector4 Color = Vector4::Zero;
};
struct RendererRect2D
@ -454,9 +458,6 @@ namespace TEN::Renderer
// A flag to prevent extra renderer object addition
bool m_Locked = false;
// Misc
int m_pickupRotation = 0;
// Caching state changes
TextureBase* lastTexture;
@ -655,19 +656,19 @@ namespace TEN::Renderer
void PrintDebugMessage(LPCSTR message, ...);
void DrawDebugInfo(RenderView& view);
void SwitchDebugPage(bool back);
void DrawPickup(short objectNum);
void DrawPickup(const DisplayPickup& pickup);
int Synchronize();
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 AddDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b);
void RenderLoadingScreen(float percentage);
void UpdateProgress(float value);
void GetLaraBonePosition(Vector3* pos, int bone);
void ToggleFullScreen(bool force = false);
void SetFullScreen();
bool IsFullsScreen();
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 AddBox(Vector3 min, Vector3 max, Vector4 color);
void AddBox(Vector3* corners, Vector4 color);
@ -679,13 +680,16 @@ namespace TEN::Renderer
void FlipRooms(short roomNumber1, short roomNumber2);
void UpdateLaraAnimations(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);
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 SetTextureOrDefault(Texture2D& texture, std::wstring path);
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;

View file

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

View file

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

View file

@ -5,7 +5,7 @@
#include "Game/control/control.h"
#include "Game/control/volume.h"
#include "Game/Gui.h"
#include "Game/health.h"
#include "Game/Hud/Hud.h"
#include "Game/Lara/lara.h"
#include "Game/savegame.h"
#include "Math/Math.h"
@ -16,6 +16,7 @@
#include "Specific/trutils.h"
#include "Specific/winmain.h"
using namespace TEN::Hud;
using namespace TEN::Input;
using namespace TEN::Math;
@ -505,61 +506,67 @@ namespace TEN::Renderer
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;
m_context->OMGetRenderTargets(1, nullptr, &dsv);
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
m_pickupRotation += 45 * 360 / 30;
// Draw display pickup.
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;
Matrix rotation;
Matrix world;
Matrix view;
Matrix projection;
Matrix scale;
constexpr auto AMBIENT_LIGHT_COLOR = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
UINT stride = sizeof(RendererVertex);
UINT offset = 0;
float factorX = m_screenWidth / REFERENCE_RES_WIDTH;
float factorY = m_screenHeight / REFERENCE_RES_HEIGHT;
auto screenRes = GetScreenResolution();
auto factor = Vector2(
screenRes.x / SCREEN_SPACE_RES.x,
screenRes.y / SCREEN_SPACE_RES.y);
x *= factorX;
y *= factorY;
scale1 *= factorX > factorY ? factorY : factorX;
auto index = g_Gui.ConvertObjectToInventoryItem(objectNum);
screenPos *= factor;
scale *= (factor.x > factor.y) ? factor.y : factor.x;
int index = g_Gui.ConvertObjectToInventoryItem(objectNumber);
if (index != -1)
{
auto& invObject = InventoryObjectTable[index];
y += invObject.YOffset;
const auto& invObject = InventoryObjectTable[index];
screenPos.y += invObject.YOffset;
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));
projection = Matrix::CreateOrthographic(m_screenWidth, m_screenHeight, -1024.0f, 1024.0f);
auto viewMatrix = Matrix::CreateLookAt(Vector3(0.0f, 0.0f, BLOCK(2)), Vector3::Zero, Vector3::Down);
auto projMatrix = Matrix::CreateOrthographic(m_screenWidth, m_screenHeight, -BLOCK(1), BLOCK(1));
auto& moveableObj = m_moveableObjects[objectNum];
if (!moveableObj)
auto& moveableObject = m_moveableObjects[objectNumber];
if (!moveableObject)
return;
auto* obj = &Objects[objectNum];
if (obj->animIndex != -1)
const auto& object = Objects[objectNumber];
if (object.animIndex != -1)
{
AnimFrame* frame[] = { &g_Level.Frames[g_Level.Anims[obj->animIndex].FramePtr] };
UpdateAnimation(nullptr, *moveableObj, frame, 0, 0, 0xFFFFFFFF);
AnimFrame* frame[] = { &g_Level.Frames[g_Level.Anims[object.animIndex].FramePtr] };
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.
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);
// Set matrices.
CCameraMatrixBuffer HudCamera;
HudCamera.CamDirectionWS = -Vector4::UnitZ;
HudCamera.ViewProjection = view * projection;
m_cbCameraMatrices.updateData(HudCamera, m_context.Get());
CCameraMatrixBuffer hudCamera;
hudCamera.CamDirectionWS = -Vector4::UnitZ;
hudCamera.ViewProjection = viewMatrix * projMatrix;
m_cbCameraMatrices.updateData(hudCamera, m_context.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)))
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
translation = Matrix::CreateTranslation(pos.x, pos.y, pos.z + 1024.0f);
rotation = orient.ToRotationMatrix();
scale = Matrix::CreateScale(scale1);
world = scale * rotation;
world = world * translation;
if (obj->animIndex != -1)
m_stItem.World = ((*moveableObj).AnimationTransforms[n] * world);
if (object.animIndex != -1)
m_stItem.World = (*moveableObject).AnimationTransforms[n] * worldMatrix;
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.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());
BindConstantBufferVS(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)
continue;
@ -619,12 +624,10 @@ namespace TEN::Renderer
BindTexture(TEXTURE_NORMAL_MAP, &std::get<1>(m_moveablesTextures[bucket.Texture]), SAMPLER_NONE);
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);
DrawIndexedTriangles(bucket.NumIndices, bucket.StartIndex, 0);
m_numMoveablesDrawCalls++;
}
}
@ -633,7 +636,7 @@ namespace TEN::Renderer
void Renderer11::RenderTitleImage()
{
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)
return;
@ -651,7 +654,9 @@ namespace TEN::Renderer
timeout--;
}
else
{
currentFade = std::clamp(currentFade -= FADE_FACTOR, 0.0f, 1.0f);
}
DrawFullScreenImage(texture.ShaderResourceView.Get(), Smoothstep(currentFade), m_backBufferRTV, m_depthStencilView);
Synchronize();
@ -662,6 +667,8 @@ namespace TEN::Renderer
void Renderer11::DrawExamines()
{
constexpr auto SCREEN_POS = Vector2(400.0f, 300.0f);
static EulerAngles orient = EulerAngles::Zero;
static float scaler = 1.2f;
@ -695,23 +702,26 @@ namespace TEN::Renderer
float savedScale = object.Scale1;
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;
}
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];
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].
Strings[i].Position.y && !Lara.Inventory.Diary.Pages[Lara.Inventory.Diary.CurrentPage].Strings[i].StringID)
{
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);
}
@ -719,8 +729,7 @@ namespace TEN::Renderer
DrawAllStrings();
}
void Renderer11::RenderInventoryScene(ID3D11RenderTargetView* target, ID3D11DepthStencilView* depthTarget,
ID3D11ShaderResourceView* background)
void Renderer11::RenderInventoryScene(ID3D11RenderTargetView* target, ID3D11DepthStencilView* depthTarget, ID3D11ShaderResourceView* background)
{
// Set basic render states
SetBlendMode(BLENDMODE_OPAQUE, true);
@ -761,12 +770,12 @@ namespace TEN::Renderer
if (drawLogo)
{
float factorX = (float)m_screenWidth / REFERENCE_RES_WIDTH;
float factorY = (float)m_screenHeight / REFERENCE_RES_HEIGHT;
float factorX = (float)m_screenWidth / SCREEN_SPACE_RES.x;
float factorY = (float)m_screenHeight / SCREEN_SPACE_RES.y;
float scale = m_screenWidth > m_screenHeight ? factorX : factorY;
int logoLeft = (REFERENCE_RES_WIDTH / 2) - (LogoWidth / 2);
int logoRight = (REFERENCE_RES_WIDTH / 2) + (LogoWidth / 2);
int logoLeft = (SCREEN_SPACE_RES.x / 2) - (LogoWidth / 2);
int logoRight = (SCREEN_SPACE_RES.x / 2) + (LogoWidth / 2);
int logoBottom = LogoTop + LogoHeight;
RECT rect;
@ -919,13 +928,11 @@ namespace TEN::Renderer
case RENDERER_DEBUG_PAGE::DIMENSION_STATS:
PrintDebugMessage("Lara Location: %d %d", LaraItem->Location.roomNumber, LaraItem->Location.yNumber);
PrintDebugMessage("Lara RoomNumber: %d", LaraItem->RoomNumber);
PrintDebugMessage("LaraItem BoxNumber: %d",/* canJump: %d, canLongJump: %d, canMonkey: %d,*/
LaraItem->BoxNumber);
PrintDebugMessage("LaraItem BoxNumber: %d",/* canJump: %d, canLongJump: %d, canMonkey: %d,*/ LaraItem->BoxNumber);
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 WaterSurfaceDist: %d", Lara.WaterSurfaceDist);
PrintDebugMessage("Room: %d %d %d %d", r->x, r->z, r->x + r->xSize * SECTOR(1),
r->z + r->zSize * SECTOR(1));
PrintDebugMessage("Room: %d %d %d %d", r->x, r->z, r->x + r->xSize * SECTOR(1), r->z + r->zSize * SECTOR(1));
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.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 REFERENCE_FONT_SIZE = 35.0f;
constexpr auto REFERENCE_RES_WIDTH = 800.0f;
constexpr auto REFERENCE_RES_HEIGHT = 600.0f;
constexpr auto HUD_UNIT_X = 1.0f / REFERENCE_RES_WIDTH;
constexpr auto HUD_UNIT_Y = 1.0f / REFERENCE_RES_HEIGHT;
constexpr auto HUD_ZERO_Y = -REFERENCE_RES_HEIGHT;
constexpr auto SCREEN_SPACE_RES = Vector2(800.0f, 600.0f);
constexpr auto INVALID_SCREEN_SPACE_POSITION = Vector2(FLT_MAX, FLT_MAX);
constexpr auto REFERENCE_FONT_SIZE = 35.0f;
constexpr auto HUD_UNIT_X = 1.0f / SCREEN_SPACE_RES.x;
constexpr auto HUD_UNIT_Y = 1.0f / SCREEN_SPACE_RES.y;
constexpr auto HUD_ZERO_Y = -SCREEN_SPACE_RES.y;
constexpr auto UNDERWATER_FOG_MIN_DISTANCE = 4;
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)
{
if (sphereRadius == 0.0f)
{
return box.Contains(sphereCentre);
}
else
{
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)
{
std::swap(m_rooms[roomNumber1], m_rooms[roomNumber2]);
@ -407,31 +405,6 @@ namespace TEN::Renderer
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)
{
auto* itemToDraw = &m_items[itemNumber];
@ -532,4 +505,63 @@ namespace TEN::Renderer
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_cbSprite = CreateConstantBuffer<CSpriteBuffer>();
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_currentCausticsFrame = 0;

View file

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

View file

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

View file

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

View file

@ -1038,7 +1038,7 @@ unsigned int _stdcall LoadLevel(void* data)
FILE* filePtr = 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);
g_Renderer.UpdateProgress(0);

View file

@ -5,52 +5,60 @@
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); });
return source;
std::transform(string.begin(), string.end(), string.begin(), [](unsigned char c) { return std::toupper(c); });
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); });
return source;
std::transform(string.begin(), string.end(), string.begin(), [](unsigned char c) { return std::tolower(c); });
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;
return converter.to_bytes(std::wstring(source));
auto converter = std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t>();
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];
std::mbstowcs(buffer, source, UCHAR_MAX);
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.
if (source.find('\n') == std::string::npos)
if (string.find('\n') == std::string::npos)
{
strings.push_back(source);
strings.push_back(string);
return strings;
}
std::string::size_type pos = 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;
}
strings.push_back(source.substr(prev));
strings.push_back(string.substr(prev));
return strings;
}
@ -66,14 +74,14 @@ namespace TEN::Utils
int size = GetFileVersionInfoSizeA(fileName, NULL);
if (!size)
if (size == 0)
{
TENLog("GetFileVersionInfoSizeA failed", LogLevel::Error);
return {};
}
std::unique_ptr<unsigned char> buffer(new unsigned char[size]);
// Load the version info.
// Load version info.
if (!GetFileVersionInfoA(fileName, 0, size, buffer.get()))
{
TENLog("GetFileVersionInfoA failed", LogLevel::Error);
@ -96,6 +104,7 @@ namespace TEN::Utils
}
if (productVersion)
{
return
{
HIWORD(info->dwProductVersionMS),
@ -103,7 +112,9 @@ namespace TEN::Utils
HIWORD(info->dwProductVersionLS),
LOWORD(info->dwProductVersionLS)
};
}
else
{
return
{
HIWORD(info->dwFileVersionMS),
@ -111,5 +122,6 @@ namespace TEN::Utils
HIWORD(info->dwFileVersionLS),
LOWORD(info->dwFileVersionLS)
};
}
}
}

View file

@ -1,13 +1,14 @@
#pragma once
#include <string>
namespace TEN::Utils
{
std::string ToUpper(std::string source);
std::string ToLower(std::string source);
std::string FromWchar(const wchar_t* source);
std::wstring FromChar(const char* source);
std::vector<std::string> SplitString(const std::string& source);
// String utilities
std::string ToUpper(std::string string);
std::string ToLower(std::string string);
std::string ToString(const wchar_t* string);
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);
}

View file

@ -45,7 +45,7 @@ extern "C"
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);
}
@ -259,7 +259,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
}
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))
{

View file

@ -166,6 +166,7 @@ CALL gen.bat</Command>
<ClInclude Include="Game\effects\item_fx.h" />
<ClInclude Include="Game\effects\Electricity.h" />
<ClInclude Include="Game\GuiObjects.h" />
<ClInclude Include="Game\Hud\PickupSummary.h" />
<ClInclude Include="Math\Objects\AxisAngle.h" />
<ClInclude Include="Objects\TR1\Trap\DamoclesSword.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\control\flipeffect.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\Lara\lara.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\effects\footprint.cpp" />
<ClCompile Include="Game\GuiObjects.cpp" />
<ClCompile Include="Game\Hud\PickupSummary.cpp" />
<ClCompile Include="Math\Objects\AxisAngle.cpp" />
<ClCompile Include="Objects\TR1\Trap\DamoclesSword.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\control\flipeffect.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\Lara\lara.cpp" />
<ClCompile Include="Game\Lara\lara_one_gun.cpp" />