Merge branch 'ten_beta' into lua_funcs

This commit is contained in:
hispidence 2022-08-01 19:33:19 +01:00
commit be4b98dc41
80 changed files with 1272 additions and 1173 deletions

View file

@ -1,39 +0,0 @@
ANIM.C
X BOX.C
CAMERA.C
* COLLIDE.C
* CONTROL.C
* DEBRIS.C
X DOOR.C
* DRAW.C
X EFFECT2.C
X EFFECTS.C
FLMTRCH.C
GUARDIAN.C
HAIR.C
X HEALTH.C
HYDRA.C
X ITEMS.C
* LARA.C
X LARA1GUN.C
X LARA2GUN.C
X LARASURF.C
* LARACLMB.C
X LARAFIRE.C
X LARAFLAR.C
X LARAMISC.C
X LARASWIM.C
X LION.C
X LOT.C
X MAFIA2.C
MISSILE.C
X OBJECTS.C
X PEOPLE.C
X PICKUP.C
RAT.C
* ROPE.C
X SPHERE.C
X SWITCH.C
* TOMB4FX.C
* TRAPS.C
TWOGUN.C

View file

@ -462,6 +462,8 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
bool isWater = TestEnvironment(ENV_FLAG_WATER, item);
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
bool isWaterOnHeadspace = false;
int waterDepth = GetWaterDepth(item);
int waterHeight = GetWaterHeight(item);
@ -475,7 +477,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
if (lara->Vehicle == NO_ITEM)
WadeSplash(item, waterHeight, waterDepth);
if (lara->Vehicle == NO_ITEM && lara->ExtraAnim == -1)
if (lara->Vehicle == NO_ITEM && lara->ExtraAnim == NO_ITEM)
{
switch (lara->Control.WaterStatus)
{
@ -553,14 +555,15 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
break;
case WaterStatus::Underwater:
if (isWater ||
waterDepth == DEEP_WATER || abs(heightFromWater) >= CLICK(1) ||
item->Animation.AnimNumber == LA_UNDERWATER_RESURFACE ||
item->Animation.AnimNumber == LA_ONWATER_DIVE)
isWaterOnHeadspace = TestEnvironment(ENV_FLAG_WATER, item->Pose.Position.x, item->Pose.Position.y - CLICK(1), item->Pose.Position.z,
GetCollision(item->Pose.Position.x, item->Pose.Position.y - CLICK(1), item->Pose.Position.z, item->RoomNumber).RoomNumber);
if (waterDepth == NO_HEIGHT || abs(heightFromWater) >= CLICK(1) || isWaterOnHeadspace ||
item->Animation.AnimNumber == LA_UNDERWATER_RESURFACE || item->Animation.AnimNumber == LA_ONWATER_DIVE)
{
if (!isWater)
{
if (waterDepth == DEEP_WATER || abs(heightFromWater) >= CLICK(1))
if (waterDepth == NO_HEIGHT || abs(heightFromWater) >= CLICK(1))
{
SetAnimation(item, LA_FALL_START);
ResetLaraLean(item);
@ -779,7 +782,7 @@ void LaraAboveWater(ItemInfo* item, CollisionInfo* coll)
AnimateLara(item);
if (lara->ExtraAnim == -1)
if (lara->ExtraAnim == NO_ITEM)
{
// Check for collision with items.
DoObjectCollision(item, coll);

View file

@ -28,6 +28,7 @@
#include "ScriptInterfaceGame.h"
#include "Objects/ScriptInterfaceObjectsHandler.h"
#include "Game/Lara/lara_tests.h"
using namespace TEN::Entities::Generic;
using namespace TEN::Input;
@ -261,8 +262,8 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] =
}
};
// States in which Lara will hold the flare out in front.
int HoldStates[] =
// States in which Lara will hold a flare out in front.
const std::vector<LaraState> FlarePoseStates =
{
LS_WALK_FORWARD,
LS_RUN_FORWARD,
@ -281,29 +282,8 @@ int HoldStates[] =
LS_CROUCH_IDLE,
LS_CROUCH_TURN_LEFT,
LS_CROUCH_TURN_RIGHT,
LS_SOFT_SPLAT,
-1
LS_SOFT_SPLAT
};
bool CheckForHoldingState(LaraState state)
{
#if 0
if (lara->ExtraAnim != NO_ITEM)
return false;
#endif
int* holdState = HoldStates;
while (*holdState >= 0)
{
if (state == *holdState)
return true;
holdState++;
}
return false;
}
GAME_OBJECT_ID WeaponObject(LaraWeaponType weaponType)
{
switch (weaponType)
@ -623,7 +603,7 @@ void LaraGun(ItemInfo* laraItem)
if (lara->Control.Weapon.GunType == LaraWeaponType::Flare)
{
if (lara->Vehicle != NO_ITEM ||
CheckForHoldingState((LaraState)laraItem->Animation.ActiveState))
CheckLaraState((LaraState)laraItem->Animation.ActiveState, FlarePoseStates))
{
if (lara->Flare.ControlLeft)
{
@ -653,7 +633,7 @@ void LaraGun(ItemInfo* laraItem)
{
if (lara->MeshPtrs[LM_LHAND] == Objects[ID_LARA_FLARE_ANIM].meshIndex + LM_LHAND)
{
lara->Flare.ControlLeft = (lara->Vehicle != NO_ITEM || CheckForHoldingState((LaraState)laraItem->Animation.ActiveState));
lara->Flare.ControlLeft = (lara->Vehicle != NO_ITEM || CheckLaraState((LaraState)laraItem->Animation.ActiveState, FlarePoseStates));
DoFlareInHand(laraItem, lara->Flare.Life);
SetFlareArm(laraItem, lara->LeftArm.FrameNumber);
}

View file

@ -57,6 +57,5 @@ void HitTarget(ItemInfo* laraItem, ItemInfo* target, GameVector* hitPos, int dam
FireWeaponType FireWeapon(LaraWeaponType weaponType, ItemInfo* target, ItemInfo* src, Vector3Shrt armOrient);
void FindTargetPoint(ItemInfo* laraItem, GameVector* target);
void LaraTargetInfo(ItemInfo* laraItem, WeaponInfo* weaponInfo);
bool CheckForHoldingState(LaraState state);
void LaraGetNewTarget(ItemInfo* laraItem, WeaponInfo* weaponInfo);
HolsterSlot HolsterSlotForWeapon(LaraWeaponType weaponType);

View file

@ -17,7 +17,8 @@
using namespace TEN::Math::Random;
constexpr auto FlareMainColor = Vector3(0.8f, 0.42947f, 0.2921f);
constexpr auto FLARE_MAIN_COLOR = Vector3(0.8f, 0.42947f, 0.2921f);
constexpr auto FLARE_LIFE_MAX = 60 * FPS; // 60 * 30 frames = 60 seconds.
void FlareControl(short itemNumber)
{
@ -409,9 +410,9 @@ int DoFlareLight(Vector3Int* pos, int flareLife)
{
int falloff = 6 * (1.0f - (flareLife / FLARE_LIFE_MAX));
int r = FlareMainColor.x * 255;
int g = FlareMainColor.y * 255;
int b = FlareMainColor.z * 255;
int r = FLARE_MAIN_COLOR.x * 255;
int g = FLARE_MAIN_COLOR.y * 255;
int b = FLARE_MAIN_COLOR.z * 255;
TriggerDynamicLight(x, y, z, falloff, r, g, b);
@ -422,9 +423,9 @@ int DoFlareLight(Vector3Int* pos, int flareLife)
float multiplier = GenerateFloat(0.05f, 1.0f);
int falloff = 8 * multiplier;
int r = FlareMainColor.x * 255 * multiplier;
int g = FlareMainColor.y * 255 * multiplier;
int b = FlareMainColor.z * 255 * multiplier;
int r = FLARE_MAIN_COLOR.x * 255 * multiplier;
int g = FLARE_MAIN_COLOR.y * 255 * multiplier;
int b = FLARE_MAIN_COLOR.z * 255 * multiplier;
TriggerDynamicLight(x, y, z, falloff, r, g, b);
result = (random < 0.4f);
@ -434,9 +435,9 @@ int DoFlareLight(Vector3Int* pos, int flareLife)
float multiplier = GenerateFloat(0.6f, 0.8f);
int falloff = 8 * (1.0f - (flareLife / FLARE_LIFE_MAX));
int r = FlareMainColor.x * 255 * multiplier;
int g = FlareMainColor.y * 255 * multiplier;
int b = FlareMainColor.z * 255 * multiplier;
int r = FLARE_MAIN_COLOR.x * 255 * multiplier;
int g = FLARE_MAIN_COLOR.y * 255 * multiplier;
int b = FLARE_MAIN_COLOR.z * 255 * multiplier;
TriggerDynamicLight(x, y, z, falloff, r, g, b);
result = (random < 0.3f);

View file

@ -1,13 +1,11 @@
#pragma once
#include "Game/control/control.h"
struct ItemInfo;
struct CollisionInfo;
struct ItemInfo;
struct Vector3Int;
enum GAME_OBJECT_ID : short;
constexpr auto FLARE_LIFE_MAX = 60 * FPS; // 60 * 30 frames = 60 seconds.
void FlareControl(short itemNumber);
void ReadyFlare(ItemInfo* laraItem);
void UndrawFlareMeshes(ItemInfo* laraItem);

View file

@ -345,7 +345,7 @@ short ModulateLaraTurnRate(short turnRate, short accelRate, short minTurnRate, s
short newTurnRate = (turnRate + (accelRate * sign)) * sign;
newTurnRate = std::clamp(newTurnRate, minTurnRateNormalized, maxTurnRateNormalized);
return newTurnRate * sign;
return (newTurnRate * sign);
}
// TODO: Make these two functions methods of LaraInfo someday. @Sezz 2022.06.26

View file

@ -21,18 +21,12 @@ void InitialiseLara(int restore)
LaraItem->Location.roomNumber = LaraItem->RoomNumber;
LaraItem->Location.yNumber = LaraItem->Pose.Position.y;
LaraInfo backup = {};
if (restore)
{
LaraInfo backup;
memcpy(&backup, &Lara, sizeof(LaraInfo));
ZeroMemory(&Lara, sizeof(LaraInfo));
}
else
{
ZeroMemory(&Lara, sizeof(LaraInfo));
Lara.ExtraAnim = NO_ITEM;
Lara.Vehicle = NO_ITEM;
}
ZeroMemory(&Lara, sizeof(LaraInfo));
Lara.Control.CanLook = true;
Lara.ItemNumber = itemNumber;
@ -40,11 +34,11 @@ void InitialiseLara(int restore)
Lara.SprintEnergy = LARA_SPRINT_ENERGY_MAX;
Lara.Air = LARA_AIR_MAX;
Lara.Control.Weapon.WeaponItem = NO_ITEM;
PoisonFlag = 0;
Lara.PoisonPotency = 0;
Lara.WaterSurfaceDist = 100;
Lara.Vehicle = -1;
Lara.ExtraAnim = NO_ITEM;
Lara.Vehicle = NO_ITEM;
Lara.Location = -1;
Lara.HighestLocation = -1;
Lara.Control.Rope.Ptr = -1;

View file

@ -130,6 +130,8 @@ void lara_as_freefall(ItemInfo* item, CollisionInfo* coll)
{
item->Animation.Velocity = item->Animation.Velocity * 0.95f;
ModulateLaraTurnRateY(item, 0, 0, 0);
if (item->Animation.VerticalVelocity == LARA_DEATH_VELOCITY &&
item->HitPoints > 0)
{
@ -804,6 +806,8 @@ void lara_as_freefall_dive(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
ModulateLaraTurnRateY(item, 0, 0, 0);
if (item->HitPoints <= 0)
{
if (TestLaraLand(item, coll))

View file

@ -743,7 +743,7 @@ void lara_as_pole_idle(ItemInfo* item, CollisionInfo* coll)
if (item->Animation.ActiveState == LA_POLE_IDLE) // HACK.
{
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX);
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX, true);
}
// TODO: Add forward jump.
@ -834,7 +834,7 @@ void lara_as_pole_up(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_ACTION)
{
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX);
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX, true);
if (TrInput & IN_JUMP)
{
@ -883,7 +883,7 @@ void lara_as_pole_down(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_ACTION)
{
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX);
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX, true);
if (TrInput & IN_JUMP)
{
@ -973,7 +973,7 @@ void lara_as_pole_turn_clockwise(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_LEFT)
{
item->Animation.TargetState = LS_POLE_TURN_CLOCKWISE;
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX);
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX, true);
return;
}
@ -1025,7 +1025,7 @@ void lara_as_pole_turn_counter_clockwise(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_RIGHT)
{
item->Animation.TargetState = LS_POLE_TURN_COUNTER_CLOCKWISE;
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX);
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX, true);
return;
}

View file

@ -541,7 +541,10 @@ void HarpoonBoltControl(short itemNumber)
if (item->HitPoints > 0)
item->HitPoints--;
else
{
ExplodeItemNode(item, 0, 0, BODY_EXPLODE);
KillItem(itemNumber);
}
return;
}

View file

@ -447,7 +447,7 @@ bool TestLaraNearClimbableWall(ItemInfo* item, FloorInfo* floor)
if (floor == nullptr)
floor = GetCollision(item).BottomBlock;
return ((1 << (GetQuadrant(item->Pose.Orientation.y) + 8)) & GetClimbFlags(floor));
return ((256 << (GetQuadrant(item->Pose.Orientation.y))) & GetClimbFlags(floor));
}
bool TestLaraHangOnClimbableWall(ItemInfo* item, CollisionInfo* coll)
@ -1111,86 +1111,106 @@ void GetTightropeFallOff(ItemInfo* item, int regularity)
}
#endif
bool IsStandingWeapon(ItemInfo* item, LaraWeaponType weaponType)
// TODO: Organise all of this properly. -- Sezz 2022.07.28
bool CheckLaraState(LaraState state, std::vector<LaraState> stateList)
{
auto* lara = GetLaraInfo(item);
if (weaponType == LaraWeaponType::Shotgun ||
weaponType == LaraWeaponType::HK ||
weaponType == LaraWeaponType::Crossbow ||
weaponType == LaraWeaponType::Torch ||
weaponType == LaraWeaponType::GrenadeLauncher ||
weaponType == LaraWeaponType::HarpoonGun ||
weaponType == LaraWeaponType::RocketLauncher||
weaponType == LaraWeaponType::Snowmobile ||
lara->Weapons[(int)weaponType].HasLasersight)
for (auto listedState : stateList)
{
return true;
if (state == listedState)
return true;
}
return false;
}
bool CheckLaraWeaponType(LaraWeaponType weaponType, std::vector<LaraWeaponType> weaponTypeList)
{
for (auto listedWeaponType : weaponTypeList)
{
if (weaponType == listedWeaponType)
return true;
}
return false;
}
static std::vector<LaraWeaponType> StandingWeaponTypes
{
LaraWeaponType::Shotgun,
LaraWeaponType::HK,
LaraWeaponType::Crossbow,
LaraWeaponType::Torch,
LaraWeaponType::GrenadeLauncher,
LaraWeaponType::HarpoonGun,
LaraWeaponType::RocketLauncher,
LaraWeaponType::Snowmobile
};
bool IsStandingWeapon(ItemInfo* item, LaraWeaponType weaponType)
{
return (CheckLaraWeaponType(weaponType, StandingWeaponTypes) || GetLaraInfo(item)->Weapons[(int)weaponType].HasLasersight);
}
static std::vector<LaraState> VaultStates
{
LS_VAULT,
LS_VAULT_2_STEPS,
LS_VAULT_3_STEPS,
LS_VAULT_1_STEP_CROUCH,
LS_VAULT_2_STEPS_CROUCH,
LS_VAULT_3_STEPS_CROUCH,
LS_AUTO_JUMP
};
bool IsVaultState(LaraState state)
{
if (state == LS_VAULT ||
state == LS_VAULT_2_STEPS ||
state == LS_VAULT_3_STEPS ||
state == LS_VAULT_1_STEP_CROUCH ||
state == LS_VAULT_2_STEPS_CROUCH ||
state == LS_VAULT_3_STEPS_CROUCH ||
state == LS_AUTO_JUMP)
{
return true;
}
return false;
return CheckLaraState(state, VaultStates);
}
static std::vector<LaraState> JumpStates
{
LS_JUMP_FORWARD,
LS_JUMP_BACK,
LS_JUMP_LEFT,
LS_JUMP_RIGHT,
LS_JUMP_UP,
LS_FALL_BACK,
LS_REACH,
LS_SWAN_DIVE,
LS_FREEFALL_DIVE,
LS_FREEFALL
};
bool IsJumpState(LaraState state)
{
if (state == LS_JUMP_FORWARD ||
state == LS_JUMP_BACK ||
state == LS_JUMP_LEFT ||
state == LS_JUMP_RIGHT ||
state == LS_JUMP_UP ||
state == LS_FALL_BACK ||
state == LS_REACH ||
state == LS_SWAN_DIVE ||
state == LS_FREEFALL_DIVE ||
state == LS_FREEFALL)
{
return true;
}
return false;
return CheckLaraState(state, JumpStates);
}
static std::vector<LaraState> RunningJumpQueuableStates
{
LS_RUN_FORWARD,
LS_SPRINT,
LS_STEP_UP,
LS_STEP_DOWN
};
bool IsRunJumpQueueableState(LaraState state)
{
if (state == LS_RUN_FORWARD ||
state == LS_SPRINT ||
state == LS_STEP_UP ||
state == LS_STEP_DOWN)
{
return true;
}
return false;
return CheckLaraState(state, RunningJumpQueuableStates);
}
static std::vector<LaraState> RunningJumpTimerStates
{
LS_WALK_FORWARD,
LS_RUN_FORWARD,
LS_SPRINT,
LS_SPRINT_DIVE,
LS_JUMP_FORWARD
};
bool IsRunJumpCountableState(LaraState state)
{
if (state == LS_WALK_FORWARD ||
state == LS_RUN_FORWARD ||
state == LS_SPRINT ||
state == LS_SPRINT_DIVE ||
state == LS_JUMP_FORWARD)
{
return true;
}
return false;
return CheckLaraState(state, RunningJumpTimerStates);
}
bool TestLaraPose(ItemInfo* item, CollisionInfo* coll)
@ -1224,12 +1244,31 @@ bool TestLaraKeepLow(ItemInfo* item, CollisionInfo* coll)
auto probeFront = GetCollision(item, item->Pose.Orientation.y, radius, -coll->Setup.Height);
auto probeBack = GetCollision(item, item->Pose.Orientation.y + ANGLE(180.0f), radius, -coll->Setup.Height);
auto probeMiddle = GetCollision(item);
auto probeMiddle = GetCollision(item, 0.0f, 0.0f, -LARA_HEIGHT / 2);
if (abs(probeFront.Position.Ceiling - probeFront.Position.Floor) < LARA_HEIGHT || // Front is not a clamp.
abs(probeBack.Position.Ceiling - probeBack.Position.Floor) < LARA_HEIGHT || // Back is not a clamp.
abs(probeMiddle.Position.Ceiling - probeMiddle.Position.Floor) < LARA_HEIGHT || // Middle is not a clamp.
abs(coll->Middle.Ceiling - LARA_HEIGHT_CRAWL) < LARA_HEIGHT) // TEMP: Consider statics overhead detected by GetCollisionInfo().
// Assess middle.
if (abs(probeMiddle.Position.Ceiling - probeMiddle.Position.Floor) < LARA_HEIGHT || // Middle space is low enough.
abs(coll->Middle.Ceiling - LARA_HEIGHT_CRAWL) < LARA_HEIGHT) // Consider statics overhead detected by GetCollisionInfo().
{
return true;
}
// TODO: Check whether < or <= and > or >=.
// Assess front.
if (abs(probeFront.Position.Ceiling - probeFront.Position.Floor) < LARA_HEIGHT && // Front space is low enough.
abs(probeFront.Position.Ceiling - probeFront.Position.Floor) > LARA_HEIGHT_CRAWL && // Front space not a clamp.
abs(probeFront.Position.Floor - probeMiddle.Position.Floor) <= (CLICK(1) - 1) && // Front is withing upper/lower floor bounds.
probeFront.Position.Floor != NO_HEIGHT)
{
return true;
}
// Assess back.
if (abs(probeBack.Position.Ceiling - probeBack.Position.Floor) < LARA_HEIGHT && // Back space is low enough.
abs(probeBack.Position.Ceiling - probeBack.Position.Floor) > LARA_HEIGHT_CRAWL && // Back space not a clamp.
abs(probeBack.Position.Floor - probeMiddle.Position.Floor) <= (CLICK(1) - 1) && // Back is withing upper/lower floor bounds.
probeBack.Position.Floor != NO_HEIGHT)
{
return true;
}

View file

@ -46,6 +46,7 @@ void TestLaraWaterDepth(ItemInfo* item, CollisionInfo* coll);
void GetTightropeFallOff(ItemInfo* item, int regularity);
#endif
bool CheckLaraState(LaraState state, std::vector<LaraState> stateList);
bool IsStandingWeapon(ItemInfo* item, LaraWeaponType weaponType);
bool IsVaultState(LaraState state);
bool IsJumpState(LaraState state);

View file

@ -95,7 +95,10 @@ void LookAt(CAMERA_INFO* cam, short roll)
float fov = TO_RAD(CurrentFOV / 1.333333f);
float r = TO_RAD(roll);
g_Renderer.UpdateCameraMatrices(cam, r, fov);
float gameFarView = g_GameFlow->GetGameFarView() * float(SECTOR(1));
float levelFarView = g_GameFlow->GetLevel(CurrentLevel)->GetFarView() * float(SECTOR(1));
g_Renderer.UpdateCameraMatrices(cam, r, fov, std::min(gameFarView, levelFarView));
}
void AlterFOV(int value)

View file

@ -408,7 +408,7 @@ bool TestLaraPosition(OBJECT_COLLISION_BOUNDS* bounds, ItemInfo* item, ItemInfo*
return true;
}
void AlignLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem)
bool AlignLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem)
{
laraItem->Pose.Orientation = item->Pose.Orientation;
@ -419,10 +419,25 @@ void AlignLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem)
);
Vector3 pos = Vector3::Transform(Vector3(vec->x, vec->y, vec->z), matrix);
Vector3 newPos = item->Pose.Position.ToVector3() + pos;
laraItem->Pose.Position.x = item->Pose.Position.x + pos.x;
laraItem->Pose.Position.y = item->Pose.Position.y + pos.y;
laraItem->Pose.Position.z = item->Pose.Position.z + pos.z;
int height = GetCollision(newPos.x, newPos.y, newPos.z, laraItem->RoomNumber).Position.Floor;
if (abs(height - laraItem->Pose.Position.y) <= CLICK(2))
{
laraItem->Pose.Position.x = newPos.x;
laraItem->Pose.Position.y = newPos.y;
laraItem->Pose.Position.z = newPos.z;
return true;
}
auto* lara = GetLaraInfo(laraItem);
if (lara->Control.IsMoving)
{
lara->Control.IsMoving = false;
lara->Control.HandStatus = HandStatus::Free;
}
return false;
}
bool MoveLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem)
@ -856,8 +871,8 @@ void CollideSolidStatics(ItemInfo* item, CollisionInfo* coll)
{
if (phd_Distance(&item->Pose, &mesh->pos) < COLLISION_CHECK_DISTANCE)
{
auto staticInfo = StaticObjects[mesh->staticNumber];
if (CollideSolidBounds(item, staticInfo.collisionBox, mesh->pos, coll))
auto staticInfo = &StaticObjects[mesh->staticNumber];
if (CollideSolidBounds(item, staticInfo->collisionBox, mesh->pos, coll))
coll->HitStatic = true;
}
}
@ -910,9 +925,13 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX box, PHD_3DPOS pos, Collisi
}
// Get and test DX item coll bounds
auto collBounds = TO_DX_BBOX(PHD_3DPOS(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z), &collBox);
auto collBounds = TO_DX_BBOX(PHD_3DPOS(item->Pose.Position), &collBox);
bool intersects = staticBounds.Intersects(collBounds);
// Check if previous item horizontal position intersects bounds
auto oldCollBounds = TO_DX_BBOX(PHD_3DPOS(coll->Setup.OldPosition.x, item->Pose.Position.y, coll->Setup.OldPosition.z), &collBox);
bool oldHorIntersects = staticBounds.Intersects(oldCollBounds);
// Draw item coll bounds
g_Renderer.AddDebugBox(collBounds, intersects ? Vector4(1, 0, 0, 1) : Vector4(0, 1, 0, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS);
@ -973,7 +992,7 @@ bool CollideSolidBounds(ItemInfo* item, BOUNDING_BOX box, PHD_3DPOS pos, Collisi
auto distanceToVerticalPlane = height / 2 - yPoint;
// Correct position according to top/bottom bounds, if collided and plane is nearby
if (intersects && minDistance < height)
if (intersects && oldHorIntersects && minDistance < height)
{
if (bottom)
{
@ -1180,6 +1199,11 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
auto oldCollResult = GetCollision(x, y, z, item->RoomNumber);
auto collResult = GetCollision(item);
auto* bounds = GetBoundsAccurate(item);
int radius = abs(bounds->Y2 - bounds->Y1);
item->Pose.Position.y += radius;
if (item->Pose.Position.y >= collResult.Position.Floor)
{
bs = 0;
@ -1670,8 +1694,16 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
}
collResult = GetCollision(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber);
if (collResult.RoomNumber != item->RoomNumber)
{
if (item->ObjectNumber == ID_GRENADE && TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, collResult.RoomNumber))
Splash(item);
ItemNewRoom(itemNumber, collResult.RoomNumber);
}
item->Pose.Position.y -= radius;
}
void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
@ -1844,42 +1876,43 @@ void CreatureCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll
{
auto* item = &g_Level.Items[itemNumber];
if (item->ObjectNumber != ID_HITMAN || item->Animation.ActiveState != LS_INSERT_PUZZLE)
if (!TestBoundsCollide(item, laraItem, coll->Setup.Radius))
return;
if (!TestCollision(item, laraItem))
return;
bool playerCollision = laraItem->IsLara();
bool waterPlayerCollision = playerCollision && GetLaraInfo(laraItem)->Control.WaterStatus >= WaterStatus::TreadWater;
if (waterPlayerCollision || coll->Setup.EnableObjectPush)
{
if (TestBoundsCollide(item, laraItem, coll->Setup.Radius))
ItemPushItem(item, laraItem, coll, coll->Setup.EnableSpasm, 0);
}
else if (playerCollision && coll->Setup.EnableSpasm)
{
int x = laraItem->Pose.Position.x - item->Pose.Position.x;
int z = laraItem->Pose.Position.z - item->Pose.Position.z;
float sinY = phd_sin(item->Pose.Orientation.y);
float cosY = phd_cos(item->Pose.Orientation.y);
auto* frame = GetBestFrame(item);
int rx = (frame->boundingBox.X1 + frame->boundingBox.X2) / 2;
int rz = (frame->boundingBox.X2 + frame->boundingBox.Z2) / 2;
if (frame->boundingBox.Y2 - frame->boundingBox.Y1 > STEP_SIZE)
{
if (TestCollision(item, laraItem))
{
if (coll->Setup.EnableObjectPush ||
Lara.Control.WaterStatus == WaterStatus::Underwater ||
Lara.Control.WaterStatus == WaterStatus::TreadWater)
{
ItemPushItem(item, laraItem, coll, coll->Setup.EnableSpasm, 0);
}
else if (coll->Setup.EnableSpasm)
{
int x = laraItem->Pose.Position.x - item->Pose.Position.x;
int z = laraItem->Pose.Position.z - item->Pose.Position.z;
int angle = (laraItem->Pose.Orientation.y - phd_atan(z - cosY * rx - sinY * rz, x - cosY * rx + sinY * rz) - ANGLE(135.0f)) / ANGLE(90.0f);
float sinY = phd_sin(item->Pose.Orientation.y);
float cosY = phd_cos(item->Pose.Orientation.y);
auto* lara = GetLaraInfo(laraItem);
auto* frame = GetBestFrame(item);
int rx = (frame->boundingBox.X1 + frame->boundingBox.X2) / 2;
int rz = (frame->boundingBox.X2 + frame->boundingBox.Z2) / 2;
lara->HitDirection = (short)angle;
if (frame->boundingBox.Y2 - frame->boundingBox.Y1 > STEP_SIZE)
{
int angle = (laraItem->Pose.Orientation.y - phd_atan(z - cosY * rx - sinY * rz, x - cosY * rx + sinY * rz) - ANGLE(135.0f)) / ANGLE(90.0f);
Lara.HitDirection = (short)angle;
// TODO: check if a second Lara.hitFrame++; is required there !
Lara.HitFrame++;
if (Lara.HitFrame > 30)
Lara.HitFrame = 30;
}
}
}
// TODO: check if a second Lara.hitFrame++; is required there !
lara->HitFrame++;
if (lara->HitFrame > 30)
lara->HitFrame = 30;
}
}
}

View file

@ -33,7 +33,7 @@ bool TestWithGlobalCollisionBounds(ItemInfo* item, ItemInfo* laraItem, Collision
void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll);
bool TestLaraPosition(OBJECT_COLLISION_BOUNDS* bounds, ItemInfo* item, ItemInfo* laraItem);
void AlignLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem);
bool AlignLaraPosition(Vector3Int* vec, ItemInfo* item, ItemInfo* laraItem);
bool MoveLaraPosition(Vector3Int* pos, ItemInfo* item, ItemInfo* laraItem);
bool ItemNearLara(PHD_3DPOS* pos, int radius);

View file

@ -954,6 +954,11 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
auto floorHeight = GetFloorHeight(ROOM_VECTOR{ block->Room, y }, ffpX, ffpZ).value_or(NO_HEIGHT);
auto ceilingHeight = GetCeilingHeight(ROOM_VECTOR{ block->Room, y }, ffpX, ffpZ).value_or(NO_HEIGHT);
// If probe landed inside wall (i.e. both floor/ceiling heights are NO_HEIGHT), make a fake
// ledge for algorithm to further succeed.
if (floorHeight == NO_HEIGHT && ceilingHeight == NO_HEIGHT)
floorHeight = y - CLICK(4);
// If ceiling height tests lower than Y value, it means ceiling
// ledge is in front and we should use it instead of floor.
bool useCeilingLedge = ceilingHeight > y;
@ -1306,6 +1311,7 @@ int GetWaterDepth(int x, int y, int z, short roomNumber)
while (floor->RoomBelow(x, y, z).value_or(NO_ROOM) != NO_ROOM)
{
room = &g_Level.Rooms[floor->RoomBelow(x, y, z).value_or(floor->Room)];
if (TestEnvironment(ENV_FLAG_WATER, room) ||
TestEnvironment(ENV_FLAG_SWAMP, room))
{

View file

@ -11,14 +11,10 @@ void InitTENLog()
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("Logs/TENLog.txt", true);
std::shared_ptr<spdlog::logger> logger;
if constexpr (DebugBuild)
{
// Set the file and console log targets
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
logger = std::make_shared<spdlog::logger>(std::string{ "multi_sink" }, spdlog::sinks_init_list{file_sink, console_sink });
}
else
logger = std::make_shared<spdlog::logger>(std::string{ "multi_sink" }, file_sink);
// Set the file and console log targets
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
logger = std::make_shared<spdlog::logger>(std::string{ "multi_sink" }, spdlog::sinks_init_list{ file_sink, console_sink });
spdlog::initialize_logger(logger);
logger->set_level(spdlog::level::info);

View file

@ -33,7 +33,8 @@ public:
inline void assertion(const bool& expr, const char* msg)
{
if constexpr (DebugBuild) {
if constexpr (DebugBuild)
{
if (!expr)
{
TENLog(msg, LogLevel::Error);

View file

@ -99,8 +99,17 @@ void TriggerChaffEffects(ItemInfo* item, Vector3Int* pos, Vector3Int* vel, int s
}
}
auto cond = TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, item);
SoundEffect(cond ? SFX_TR4_FLARE_BURN_UNDERWATER : SFX_TR4_FLARE_BURN_DRY, & item->Pose, cond ? SoundEnvironment::Water : SoundEnvironment::Always, 1.0f, 0.5f);
PHD_3DPOS position = item->Pose;
if (item->IsLara())
{
Vector3Int handPos = {};
GetJointAbsPosition(item, &handPos, LM_RHAND);
position.Position = handPos;
position.Position.y -= 64;
}
auto cond = TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, position.Position.x, position.Position.y, position.Position.z, item->RoomNumber);
SoundEffect(cond ? SFX_TR4_FLARE_BURN_UNDERWATER : SFX_TR4_FLARE_BURN_DRY, &position, SoundEnvironment::Always, 1.0f, 0.5f);
}
void TriggerChaffSparkles(Vector3Int* pos, Vector3Int* vel, CVECTOR* color, int age, ItemInfo* item)

View file

@ -162,6 +162,7 @@ void ShatterObject(SHATTER_ITEM* item, MESH_INFO* mesh, int num, short roomNumbe
fragment->velocity = CalculateFragmentImpactVelocity(fragment->worldPosition, ShatterImpactData.impactDirection, ShatterImpactData.impactLocation);
fragment->roomNumber = roomNumber;
fragment->numBounces = 0;
fragment->color = isStatic ? mesh->color : Vector4::One; // FIXME: SHATTER_ITEM must be refactored! -- Lwmte, 15.07.22
}
}
}

View file

@ -63,6 +63,7 @@ struct DebrisFragment
float angularDrag;
float friction;
float restitution;
Vector4 color;
uint32_t roomNumber;
uint32_t numBounces;
bool active;

View file

@ -285,7 +285,7 @@ namespace TEN::Effects::Lightning
}*/
}
long LSpline(int x, int* knots, int nk)
int LSpline(int x, int* knots, int nk)
{
int* k;
int c1, c2, c3, ret, span;
@ -299,11 +299,12 @@ namespace TEN::Effects::Lightning
x -= 65536 * span;
k = &knots[3 * span];
c1 = k[3] + (k[3] >> 1) - (k[6] >> 1) - k[6] + (k[9] >> 1) + ((-k[0] - 1) >> 1);
ret = (long long) c1 * x >> 16;
ret = (long long)c1 * x >> 16;
c2 = ret + 2 * k[6] - 2 * k[3] - (k[3] >> 1) - (k[9] >> 1) + k[0];
ret = (long long) c2 * x >> 16;
ret = (long long)c2 * x >> 16;
c3 = ret + (k[6] >> 1) + ((-k[0] - 1) >> 1);
ret = (long long) c3 * x >> 16;
ret = (long long)c3 * x >> 16;
return ret + k[3];
}

View file

@ -569,7 +569,8 @@ void GuiController::DoDebouncedInput()
{
if (!dbSelect)
{
goSelect = (TrInput & IN_OPTION || TrInput & IN_DESELECT) ? 0 : 1;
goSelect = ((TrInput & IN_OPTION) || (TrInput & IN_DESELECT) ||
g_Gui.GetEnterInventory() != NO_ITEM) ? 0 : 1;
dbSelect = !goSelect;
}
}
@ -1091,7 +1092,7 @@ void GuiController::HandleOtherSettingsInput(bool pause)
}
}
if (goLeft)
if (dbLeft)
{
switch (selected_option)
{
@ -1129,7 +1130,7 @@ void GuiController::HandleOtherSettingsInput(bool pause)
}
}
if (goRight)
if (dbRight)
{
switch (selected_option)
{
@ -1951,8 +1952,6 @@ void GuiController::InitialiseInventory()
{
if (IsObjectInInventory(enterInventory))
SetupObjectListStartPosition2(enterInventory);
enterInventory = NO_ITEM;
}
ammo_selector_fade_val = 0;
@ -3014,11 +3013,11 @@ void GuiController::DrawCurrentObjectList(int ringnum)
nummeup = count;
break;
case ID_ROCKET_LAUNCHER_ITEM:
case ID_ROCKET_LAUNCHER_AMMO_ITEM:
nummeup = Lara.Weapons[(int)LaraWeaponType::RocketLauncher].Ammo[(int)WeaponAmmoType::Ammo1].getCount();
break;
case ID_HARPOON_ITEM:
case ID_HARPOON_AMMO_ITEM:
nummeup = Lara.Weapons[(int)LaraWeaponType::HarpoonGun].Ammo[(int)WeaponAmmoType::Ammo1].getCount();
break;
@ -3284,6 +3283,8 @@ bool GuiController::CallInventory(bool reset_mode)
if (useItem && !TrInput)
exitLoop = true;
SetEnterInventory(NO_ITEM);
Camera.numberFrames = g_Renderer.SyncRenderer();
}

View file

@ -25,7 +25,6 @@ float HealthBar = OldHitPoints;
float MutateAmount = 0;
int FlashState = 0;
int FlashCount = 0;
int PoisonFlag = 0;
extern RendererHUDBar* g_HealthBar;
extern RendererHUDBar* g_DashBar;
extern RendererHUDBar* g_AirBar;
@ -145,9 +144,6 @@ void UpdateHealthBar(ItemInfo* item, int flash)
else
DrawHealthBarOverlay(item, HealthBar / LARA_HEALTH_MAX);
}
if (PoisonFlag)
PoisonFlag--;
}
void DrawAirBar(float value)

View file

@ -34,6 +34,5 @@ extern int HealthBarTimer;
extern float HealthBar;
extern float MutateAmount;
extern int FlashState;
extern int PoisonFlag;
extern bool EnableSmoothHealthBar;

View file

@ -612,7 +612,8 @@ void PickupCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
if (item->ObjectNumber == ID_BURNING_TORCH_ITEM)
break;
AlignLaraPosition(&PickUpPosition, item, laraItem);
if (!AlignLaraPosition(&PickUpPosition, item, laraItem))
break;
if (item->ObjectNumber == ID_FLARE_ITEM)
{
@ -634,7 +635,8 @@ void PickupCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
if (item->ObjectNumber == ID_BURNING_TORCH_ITEM)
break;
AlignLaraPosition(&PickUpPosition, item, laraItem);
if (!AlignLaraPosition(&PickUpPosition, item, laraItem))
break;
if (item->ObjectNumber == ID_FLARE_ITEM)
{

View file

@ -242,7 +242,7 @@ namespace TEN::Entities::Generic
if (GetCollidedObjects(item, 0, true, CollidedItems, CollidedMeshes, true))
{
LaraCollision.Setup.EnableObjectPush = true;
if (CollidedItems)
if (CollidedItems[0])
{
if (!Objects[CollidedItems[0]->ObjectNumber].intelligent &&
CollidedItems[0]->ObjectNumber != ID_LARA)
@ -250,10 +250,12 @@ namespace TEN::Entities::Generic
ObjectCollision(CollidedItems[0] - g_Level.Items.data(), item, &LaraCollision);
}
}
else
else if (CollidedMeshes[0])
{
ItemPushStatic(item, CollidedMeshes[0], &LaraCollision);
}
item->Animation.Velocity /= 2;
item->Animation.Velocity = -int(item->Animation.Velocity / 1.5f);
}
if (item->ItemFlags[3])

View file

@ -44,14 +44,15 @@ namespace TEN::Entities::Vehicles
constexpr auto MINECART_VELOCITY_DECEL = 6 * VEHICLE_VELOCITY_SCALE;
constexpr auto MINECART_SPEED_MIN = 10 * VEHICLE_VELOCITY_SCALE; // TODO: These two have confusing names. @Sezz
constexpr auto MINECART_VELOCITY_MIN = 32;
constexpr auto MINECART_FRICTION_VELOCITY_MIN = 70;
constexpr auto MINECART_STOP_VELOCITY_MAX = 240;
constexpr auto MINECART_VELOCITY_MIN = 10 * VEHICLE_VELOCITY_SCALE;
constexpr auto MINECART_FRICTION_VELOCITY_MIN = 70 * VEHICLE_VELOCITY_SCALE;
constexpr auto MINECART_STOP_VELOCITY_MIN = 1 * VEHICLE_VELOCITY_SCALE;
constexpr auto MINECART_STOP_VELOCITY_MAX = 240 * VEHICLE_VELOCITY_SCALE;
constexpr auto MINECART_VERTICAL_VELOCITY_MAX = 63 * VEHICLE_VELOCITY_SCALE;
constexpr auto MINECART_JUMP_VERTICAL_VELOCITY = 252 * VEHICLE_VELOCITY_SCALE;
constexpr auto MINECART_TURN_DEATH_VELOCITY = 128;
constexpr auto MINECART_ANIM_VELOCITY_MIN = 32;
constexpr auto MINECART_TURN_DEATH_ANIM_VELOCITY = 128;
constexpr auto MINECART_FORWARD_GRADIENT = -CLICK(0.5f);
constexpr auto MINECART_BACK_GRADIENT = CLICK(0.5f);
@ -244,14 +245,14 @@ namespace TEN::Entities::Vehicles
}
}
static short GetMinecartCollision(ItemInfo* minecartItem, short angle, int distance)
static int GetMinecartCollision(ItemInfo* minecartItem, short angle, int distance)
{
auto probe = GetCollision(minecartItem, angle, distance, -LARA_HEIGHT);
if (probe.Position.Floor != NO_HEIGHT)
probe.Position.Floor -= minecartItem->Pose.Position.y;
return (short)probe.Position.Floor;
return probe.Position.Floor;
}
static bool TestMinecartDismount(ItemInfo* laraItem, int direction)
@ -446,15 +447,15 @@ namespace TEN::Entities::Vehicles
minecart->Flags |= flags.MinecartLeft() ? MINECART_FLAG_TURNING_LEFT : MINECART_FLAG_TURNING_RIGHT;
}
if (minecart->Velocity < MINECART_SPEED_MIN)
minecart->Velocity = MINECART_SPEED_MIN;
if (minecart->Velocity < MINECART_VELOCITY_MIN)
minecart->Velocity = MINECART_VELOCITY_MIN;
minecart->Velocity -= minecart->Gradient * 4;
minecartItem->Animation.Velocity = minecart->Velocity / VEHICLE_VELOCITY_SCALE;
if (minecartItem->Animation.Velocity < MINECART_VELOCITY_MIN)
if (minecartItem->Animation.Velocity < MINECART_ANIM_VELOCITY_MIN)
{
minecartItem->Animation.Velocity = MINECART_VELOCITY_MIN;
minecartItem->Animation.Velocity = MINECART_ANIM_VELOCITY_MIN;
StopSoundEffect(SFX_TR3_VEHICLE_MINECART_TRACK_LOOP);
if (minecart->VerticalVelocity)
@ -531,7 +532,7 @@ namespace TEN::Entities::Vehicles
minecartItem->Pose.Position.x = minecart->TurnX + x * 3584;
minecartItem->Pose.Position.z = minecart->TurnZ + z * 3584;
if (minecartItem->Animation.Velocity > MINECART_FRICTION_VELOCITY_MIN)
if (minecart->Velocity > MINECART_FRICTION_VELOCITY_MIN)
{
SoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE, &minecartItem->Pose, SoundEnvironment::Always);
TriggerWheelSparkles(minecartItem, (minecart->Flags & MINECART_FLAG_TURNING_RIGHT) != 0);
@ -588,7 +589,7 @@ namespace TEN::Entities::Vehicles
auto* minecart = GetMinecartInfo(minecartItem);
auto* lara = GetLaraInfo(laraItem);
short floorHeight;
int floorHeight;
switch (laraItem->Animation.ActiveState)
{
@ -599,7 +600,7 @@ namespace TEN::Entities::Vehicles
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
else if (TrInput & (VEHICLE_IN_BRAKE | VEHICLE_IN_SLOW))
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
else if (minecart->Velocity == MINECART_VELOCITY_MIN || minecart->Flags & MINECART_FLAG_STOPPED)
else if (minecart->Velocity <= MINECART_STOP_VELOCITY_MIN || minecart->Flags & MINECART_FLAG_STOPPED)
laraItem->Animation.TargetState = MINECART_STATE_IDLE;
else if (minecart->Gradient < MINECART_FORWARD_GRADIENT)
laraItem->Animation.TargetState = MINECART_STATE_FORWARD;
@ -684,7 +685,7 @@ namespace TEN::Entities::Vehicles
}
}
if (minecart->Velocity > MINECART_VELOCITY_MIN)
if (minecart->Velocity >= MINECART_VELOCITY_MIN)
{
if (TrInput & MINECART_IN_DUCK)
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
@ -724,7 +725,7 @@ namespace TEN::Entities::Vehicles
minecart->Velocity -= MINECART_VELOCITY_DECEL;
SoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE, &laraItem->Pose, SoundEnvironment::Always);
if (minecartItem->Animation.Velocity > MINECART_FRICTION_VELOCITY_MIN)
if (minecart->Velocity > MINECART_FRICTION_VELOCITY_MIN)
{
TriggerWheelSparkles(minecartItem, false);
TriggerWheelSparkles(minecartItem, true);
@ -819,7 +820,7 @@ namespace TEN::Entities::Vehicles
if ((Wibble & 7) == 0)
SoundEffect(SFX_TR3_VEHICLE_QUADBIKE_FRONT_IMPACT, &minecartItem->Pose, SoundEnvironment::Always);
TranslateItem(minecartItem, minecartItem->Pose.Orientation.y, MINECART_TURN_DEATH_VELOCITY);
TranslateItem(minecartItem, minecartItem->Pose.Orientation.y, MINECART_TURN_DEATH_ANIM_VELOCITY);
}
else
{

View file

@ -1215,6 +1215,7 @@ namespace TEN::Entities::Vehicles
else
{
motorbikeItem->ClearBits(JointBitType::Mesh, MotorbikeHeadLightJoints);
motorbikeItem->ClearBits(JointBitType::Mesh, MotorbikeBrakeLightJoints);
drive = -1;
collide = 0;

View file

@ -131,6 +131,8 @@ void ControlBodyPart(short fxNumber)
fx->pos.Position.y + GenerateInt( 16, 32),
fx->pos.Position.z + GenerateInt(-16, 16), fx->roomNumber);
}
ExplodeFX(fx, -1, 32);
KillEffect(fxNumber);
return;
}

View file

@ -258,8 +258,8 @@ void RollingBallControl(short itemNumber)
SplashSetup.y = waterHeight - 1;
SplashSetup.x = item->Pose.Position.x;
SplashSetup.z = item->Pose.Position.z;
SplashSetup.splashPower = item->Animation.VerticalVelocity * 2;
SplashSetup.innerRadius = 96;
SplashSetup.splashPower = item->Animation.VerticalVelocity * 4;
SplashSetup.innerRadius = 160;
SetupSplash(&SplashSetup, roomNumber);
}

View file

@ -3,7 +3,8 @@
struct alignas(16) CItemBuffer
{
Matrix World;
Matrix BonesMatrices[32];
Matrix BonesMatrices[MAX_BONES];
Vector4 Position;
Vector4 AmbientLight;
int BoneLightModes[MAX_BONES];
};

View file

@ -6,5 +6,4 @@ struct alignas(16) CLightBuffer
{
ShaderLight Lights[NUM_LIGHTS_PER_BUFFER];
int NumLights;
Vector3 CameraPosition;
};

View file

@ -4,5 +4,5 @@
struct alignas(16) CRoomBuffer
{
DirectX::SimpleMath::Vector4 AmbientColor;
int Water;
unsigned int Water;
};

View file

@ -3,13 +3,14 @@
struct alignas(16) ShaderLight
{
Vector3 Position;
int Type;
unsigned int Type;
Vector3 Color;
int LocalIntensity;
Vector3 Direction;
float Distance;
float Intensity;
Vector3 Direction;
float In;
float Out;
float Range;
float InRange;
float OutRange;
float padding;
};

View file

@ -5,4 +5,5 @@ struct alignas(16) CStaticBuffer
Matrix World;
Vector4 Position;
Vector4 Color;
int LightMode;
};

View file

@ -43,10 +43,11 @@ namespace TEN::Renderer
m_spritesTextures.resize(0);
m_animatedTextures.resize(0);
m_animatedTextureSets.resize(0);
for (auto& mesh : m_meshes) {
for (auto& mesh : m_meshes)
delete mesh;
}
m_meshes.resize(0);
for (auto& item : m_items)
{
item.PreviousRoomNumber = NO_ROOM;
@ -315,6 +316,16 @@ namespace TEN::Renderer
m_context->PSSetSamplers(registerType, 1, &samplerState);
}
void Renderer11::BindLights(std::vector<RendererLight*>& lights)
{
m_stLights.NumLights = lights.size();
for (int j = 0; j < lights.size(); j++)
memcpy(&m_stLights.Lights[j], lights[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindConstantBufferVS(CB_LIGHTS, m_cbLights.get());
}
void Renderer11::BindConstantBufferVS(CONSTANT_BUFFERS constantBufferType, ID3D11Buffer** buffer)
{
m_context->VSSetConstantBuffers(static_cast<UINT>(constantBufferType), 1, buffer);

View file

@ -81,9 +81,10 @@ namespace TEN::Renderer
struct RendererStatic
{
int Id;
short RoomIndex;
MESH_INFO* Mesh;
int RoomIndex;
Matrix World;
Vector4 AmbientLight;
std::vector<RendererLight*> LightsToDraw;
};
struct RendererRoomNode
@ -95,7 +96,7 @@ namespace TEN::Renderer
struct RendererItem
{
short ItemNumber;
int ItemNumber;
bool DoneAnimations;
Matrix World;
Matrix Translation;
@ -111,8 +112,9 @@ namespace TEN::Renderer
struct RendererMesh
{
LIGHT_MODES LightMode;
BoundingSphere Sphere;
std::vector<RendererBucket> buckets;
std::vector<RendererBucket> Buckets;
std::vector<Vector3> Positions;
};
@ -122,7 +124,7 @@ namespace TEN::Renderer
FX_INFO* Effect;
Matrix World;
RendererMesh* Mesh;
std::vector<RendererLight*> Lights;
std::vector<RendererLight*> LightsToDraw;
};
struct RendererObject
@ -194,9 +196,9 @@ namespace TEN::Renderer
struct RendererLine3D
{
Vector3 start;
Vector3 end;
Vector4 color;
Vector3 Start;
Vector3 End;
Vector4 Color;
};
struct RendererLine2D
@ -421,6 +423,7 @@ namespace TEN::Renderer
// Private functions
void BindTexture(TEXTURE_REGISTERS registerType, TextureBase* texture, SAMPLER_STATES samplerType);
void BindLights(std::vector<RendererLight*>& lights);
void BindRenderTargetAsTexture(TEXTURE_REGISTERS registerType, RenderTarget2D* target, SAMPLER_STATES samplerType);
void BindConstantBufferVS(CONSTANT_BUFFERS constantBufferType, ID3D11Buffer** buffer);
void BindConstantBufferPS(CONSTANT_BUFFERS constantBufferType, ID3D11Buffer** buffer);
@ -434,11 +437,13 @@ namespace TEN::Renderer
void SetRoomBounds(ROOM_DOOR* door, short parentRoomNumber, RenderView& renderView);
void CollectRooms(RenderView& renderView, bool onlyRooms);
void CollectItems(short roomNumber, RenderView& renderView);
void CollectStatics(short roomNumber, RenderView& renderView);
void CollectLightsForEffect(short roomNumber, RendererEffect* effect, RenderView& renderView);
void CollectLightsForItem(short roomNumber, RendererItem* item, RenderView& renderView);
void CollectStatics(short roomNumber);
void CollectLights(Vector3Int position, int roomNumber, bool collectShadowLight, std::vector<RendererLight*>& lights);
void CollectLightsForItem(short roomNumber, RendererItem* item, bool collectShadowLight);
void CollectLightsForEffect(short roomNumber, RendererEffect* effect);
void CollectLightsForRoom(short roomNumber, RenderView& renderView);
void CollectEffects(short roomNumber, RenderView& renderView);
void CalculateAmbientLight(RendererItem* item);
void CollectEffects(short roomNumber);
void ClearScene();
void ClearSceneItems();
void ClearDynamicLights();
@ -585,7 +590,7 @@ namespace TEN::Renderer
void Initialise(int w, int h, bool windowed, HWND handle);
void Draw();
bool PrepareDataForTheRenderer();
void UpdateCameraMatrices(CAMERA_INFO* cam, float roll, float fov);
void UpdateCameraMatrices(CAMERA_INFO* cam, float roll, float fov, float farView);
void RenderSimpleScene(ID3D11RenderTargetView* target, ID3D11DepthStencilView* depthTarget, RenderView& view);
void DumpGameScene();
void RenderInventory();
@ -602,7 +607,7 @@ namespace TEN::Renderer
void RenderLoadingScreen(float percentage);
void UpdateProgress(float value);
void GetLaraBonePosition(Vector3* pos, int bone);
void ToggleFullScreen();
void ToggleFullScreen(bool force = false);
bool IsFullsScreen();
void RenderTitleImage();
void AddLine2D(int x1, int y1, int x2, int y2, byte r, byte g, byte b, byte a);

View file

@ -165,9 +165,7 @@ namespace TEN::Renderer
r->TransparentFacesToDraw.reserve(MAX_TRANSPARENT_FACES_PER_ROOM);
if (room.mesh.size() > 0)
{
r->StaticsToDraw.reserve(room.mesh.size());
}
if (room.positions.size() == 0)
continue;
@ -218,13 +216,13 @@ namespace TEN::Renderer
vertex->UV = poly.textureCoordinates[k];
vertex->Color = Vector4(room.colors[index].x, room.colors[index].y, room.colors[index].z, 1.0f);
vertex->Tangent = poly.tangents[k];
vertex->BiTangent = poly.bitangents[k];
vertex->AnimationFrameOffset = poly.animatedFrame;
vertex->IndexInPoly = k;
vertex->OriginalIndex = index;
vertex->Effects = Vector4(room.effects[index].x, room.effects[index].y, room.effects[index].z, 0);
const unsigned long long primes[]{ 73856093ULL, 19349663ULL, 83492791ULL };
vertex->hash = std::hash<float>{}((vertex->Position.x)* primes[0]) ^ (std::hash<float>{}(vertex->Position.y)* primes[1]) ^ std::hash<float>{}(vertex->Position.z) * primes[2];
vertex->Hash = std::hash<float>{}((vertex->Position.x)* primes[0]) ^ (std::hash<float>{}(vertex->Position.y)* primes[1]) ^ std::hash<float>{}(vertex->Position.z) * primes[2];
vertex->Bone = 0;
lastVertex++;
@ -269,12 +267,14 @@ namespace TEN::Renderer
RendererLight* light = &r->Lights[l];
ROOM_LIGHT* oldLight = &room.lights[l];
// Monty's temp variables for sorting
light->LocalIntensity = 0;
light->Distance = 0;
if (oldLight->type == LIGHT_TYPES::LIGHT_TYPE_SUN)
{
light->Color = Vector3(oldLight->r, oldLight->g, oldLight->b) * oldLight->intensity;
light->Intensity = 1.0f;
light->LocalIntensity = 0;
light->Distance = 0;
light->Intensity = oldLight->intensity;
light->Direction = Vector3(oldLight->dx, oldLight->dy, oldLight->dz);
light->CastShadows = oldLight->castShadows;
light->Type = LIGHT_TYPES::LIGHT_TYPE_SUN;
@ -283,9 +283,7 @@ namespace TEN::Renderer
{
light->Position = Vector3(oldLight->x, oldLight->y, oldLight->z);
light->Color = Vector3(oldLight->r, oldLight->g, oldLight->b) * oldLight->intensity;
light->Intensity = 1.0f;
light->LocalIntensity = 0;
light->Distance = 0;
light->Intensity = oldLight->intensity;
light->In = oldLight->in;
light->Out = oldLight->out;
light->CastShadows = oldLight->castShadows;
@ -295,25 +293,22 @@ namespace TEN::Renderer
{
light->Position = Vector3(oldLight->x, oldLight->y, oldLight->z);
light->Color = Vector3(oldLight->r, oldLight->g, oldLight->b) * oldLight->intensity;
light->Intensity = 1.0f;
light->LocalIntensity = 0;
light->Distance = 0;
light->Intensity = oldLight->intensity;
light->In = oldLight->in;
light->Out = oldLight->out;
light->CastShadows = false;
light->Type = LIGHT_TYPE_SHADOW;
light->Intensity = 1.0f;
}
else if (oldLight->type == LIGHT_TYPE_SPOT)
{
light->Position = Vector3(oldLight->x, oldLight->y, oldLight->z);
light->Color = Vector3(oldLight->r, oldLight->g, oldLight->b) * oldLight->intensity;
light->Intensity = 1.0f;
light->LocalIntensity = 0;
light->Distance = 0;
light->Intensity = oldLight->intensity;
light->Direction = Vector3(oldLight->dx, oldLight->dy, oldLight->dz);
light->In = oldLight->in;
light->Out = oldLight->out;
light->Range = oldLight->length;
light->In = oldLight->length;
light->Out = oldLight->cutoff;
light->InRange = oldLight->in;
light->OutRange = oldLight->out;
light->CastShadows = oldLight->castShadows;
light->Type = LIGHT_TYPE_SPOT;
}
@ -503,9 +498,9 @@ namespace TEN::Renderer
BonesToCheck[0] = jointBone->Parent->Index;
BonesToCheck[1] = j;
for (int b1 = 0; b1 < jointMesh->buckets.size(); b1++)
for (int b1 = 0; b1 < jointMesh->Buckets.size(); b1++)
{
RendererBucket *jointBucket = &jointMesh->buckets[b1];
RendererBucket *jointBucket = &jointMesh->Buckets[b1];
for (int v1 = 0; v1 < jointBucket->NumVertices; v1++)
{
@ -518,9 +513,9 @@ namespace TEN::Renderer
RendererMesh *skinMesh = objSkin.ObjectMeshes[BonesToCheck[k]];
RendererBone *skinBone = objSkin.LinearizedBones[BonesToCheck[k]];
for (int b2 = 0; b2 < skinMesh->buckets.size(); b2++)
for (int b2 = 0; b2 < skinMesh->Buckets.size(); b2++)
{
RendererBucket *skinBucket = &skinMesh->buckets[b2];
RendererBucket *skinBucket = &skinMesh->Buckets[b2];
for (int v2 = 0; v2 < skinBucket->NumVertices; v2++)
{
RendererVertex *skinVertex = &moveablesVertices[skinBucket->StartVertex + v2];
@ -565,9 +560,9 @@ namespace TEN::Renderer
RendererMesh* currentMesh = moveable.ObjectMeshes[j];
RendererBone* currentBone = moveable.LinearizedBones[j];
for (int b1 = 0; b1 < currentMesh->buckets.size(); b1++)
for (int b1 = 0; b1 < currentMesh->Buckets.size(); b1++)
{
RendererBucket* currentBucket = &currentMesh->buckets[b1];
RendererBucket* currentBucket = &currentMesh->Buckets[b1];
for (int v1 = 0; v1 < currentBucket->NumVertices; v1++)
{
@ -585,9 +580,9 @@ namespace TEN::Renderer
if (currentVertex->OriginalIndex < 4)
{
for (int b2 = 0; b2 < parentMesh->buckets.size(); b2++)
for (int b2 = 0; b2 < parentMesh->Buckets.size(); b2++)
{
RendererBucket* parentBucket = &parentMesh->buckets[b2];
RendererBucket* parentBucket = &parentMesh->Buckets[b2];
for (int v2 = 0; v2 < parentBucket->NumVertices; v2++)
{
RendererVertex* parentVertex = &moveablesVertices[parentBucket->StartVertex + v2];
@ -608,9 +603,9 @@ namespace TEN::Renderer
RendererMesh* parentMesh = moveable.ObjectMeshes[j - 1];
RendererBone* parentBone = moveable.LinearizedBones[j - 1];
for (int b2 = 0; b2 < parentMesh->buckets.size(); b2++)
for (int b2 = 0; b2 < parentMesh->Buckets.size(); b2++)
{
RendererBucket* parentBucket = &parentMesh->buckets[b2];
RendererBucket* parentBucket = &parentMesh->Buckets[b2];
for (int v2 = 0; v2 < parentBucket->NumVertices; v2++)
{
RendererVertex* parentVertex = &moveablesVertices[parentBucket->StartVertex + v2];
@ -628,7 +623,7 @@ namespace TEN::Renderer
currentVertex->Bone = j;
currentVertex->Position = parentVertex->Position;
currentVertex->Normal = parentVertex->Normal;
currentVertex->BiTangent = parentVertex->BiTangent;
currentVertex->AnimationFrameOffset = parentVertex->AnimationFrameOffset;
currentVertex->Tangent = parentVertex->Tangent;
break;
}
@ -753,6 +748,7 @@ namespace TEN::Renderer
RendererMesh* mesh = new RendererMesh();
mesh->Sphere = meshPtr->sphere;
mesh->LightMode = LIGHT_MODES(meshPtr->lightMode);
if (meshPtr->positions.size() == 0)
return mesh;
@ -811,7 +807,7 @@ namespace TEN::Renderer
vertex.OriginalIndex = v;
vertex.Effects = Vector4(meshPtr->effects[v].x, meshPtr->effects[v].y, meshPtr->effects[v].z, poly->shineStrength);
vertex.hash = std::hash<float>{}(vertex.Position.x) ^ std::hash<float>{}(vertex.Position.y) ^ std::hash<float>{}(vertex.Position.z);
vertex.Hash = std::hash<float>{}(vertex.Position.x) ^ std::hash<float>{}(vertex.Position.y) ^ std::hash<float>{}(vertex.Position.z);
if (obj->Type == 0)
moveablesVertices[*lastVertex] = vertex;
@ -869,7 +865,7 @@ namespace TEN::Renderer
bucket.Polygons.push_back(newPoly);
}
mesh->buckets.push_back(bucket);
mesh->Buckets.push_back(bucket);
}
m_meshes.push_back(mesh);

View file

@ -182,20 +182,19 @@ namespace TEN::Renderer
if (shadowLight->Type == LIGHT_TYPE_POINT)
{
view = Matrix::CreateLookAt(lightPos, lightPos +
RenderTargetCube::forwardVectors[step]*10240,
RenderTargetCube::forwardVectors[step] * SECTOR(10),
RenderTargetCube::upVectors[step]);
projection = Matrix::CreatePerspectiveFieldOfView(90.0f, 1.0f, 16.0f,
shadowLight->Out);
projection = Matrix::CreatePerspectiveFieldOfView(90.0f, 1.0f, 16.0f, shadowLight->Out);
}
else if(shadowLight->Type == LIGHT_TYPE_SPOT)
else if (shadowLight->Type == LIGHT_TYPE_SPOT)
{
view = Matrix::CreateLookAt(lightPos,
lightPos - shadowLight->Direction*10240,
lightPos - shadowLight->Direction * SECTOR(10),
Vector3(0.0f, -1.0f, 0.0f));
projection = Matrix::CreatePerspectiveFieldOfView(shadowLight->Out, 1.0f, 16.0f,shadowLight->Range);
projection = Matrix::CreatePerspectiveFieldOfView(shadowLight->OutRange, 1.0f, 16.0f, shadowLight->Out);
}
CCameraMatrixBuffer shadowProjection;
@ -214,16 +213,19 @@ namespace TEN::Renderer
m_stItem.World = m_LaraWorldMatrix;
m_stItem.Position = Vector4(LaraItem->Pose.Position.x, LaraItem->Pose.Position.y, LaraItem->Pose.Position.z, 1.0f);
m_stItem.AmbientLight = room.AmbientLight;
memcpy(m_stItem.BonesMatrices, laraObj.AnimationTransforms.data(), sizeof(Matrix) * 32);
memcpy(m_stItem.BonesMatrices, laraObj.AnimationTransforms.data(), sizeof(Matrix) * MAX_BONES);
for (int k = 0; k < laraSkin.ObjectMeshes.size(); k++)
m_stItem.BoneLightModes[k] = GetMesh(Lara.MeshPtrs[k])->LightMode;
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get());
for (int k = 0; k < laraSkin.ObjectMeshes.size(); k++)
{
RendererMesh* mesh = GetMesh(Lara.MeshPtrs[k]);
auto* mesh = GetMesh(Lara.MeshPtrs[k]);
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (bucket.NumVertices == 0 && bucket.BlendMode != BLEND_MODES::BLENDMODE_OPAQUE)
continue;
@ -243,7 +245,7 @@ namespace TEN::Renderer
{
RendererMesh* mesh = laraSkinJoints.ObjectMeshes[k];
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (bucket.NumVertices == 0 && bucket.BlendMode != BLEND_MODES::BLENDMODE_OPAQUE)
continue;
@ -260,7 +262,7 @@ namespace TEN::Renderer
{
RendererMesh* mesh = laraSkin.ObjectMeshes[k];
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (bucket.NumVertices == 0 && bucket.BlendMode != BLEND_MODES::BLENDMODE_OPAQUE)
continue;
@ -278,16 +280,17 @@ namespace TEN::Renderer
// First matrix is Lara's head matrix, then all 6 hairs matrices. Bones are adjusted at load time for accounting this.
m_stItem.World = Matrix::Identity;
Matrix matrices[7];
matrices[0] = laraObj.AnimationTransforms[LM_HEAD] * m_LaraWorldMatrix;
m_stItem.BonesMatrices[0] = laraObj.AnimationTransforms[LM_HEAD] * m_LaraWorldMatrix;
for (int i = 0; i < hairsObj.BindPoseTransforms.size(); i++)
{
HAIR_STRUCT* hairs = &Hairs[0][i];
auto* hairs = &Hairs[0][i];
Matrix world = Matrix::CreateFromYawPitchRoll(TO_RAD(hairs->pos.Orientation.y), TO_RAD(hairs->pos.Orientation.x), 0) *
Matrix::CreateTranslation(hairs->pos.Position.x, hairs->pos.Position.y, hairs->pos.Position.z);
matrices[i + 1] = world;
Matrix::CreateTranslation(hairs->pos.Position.x, hairs->pos.Position.y, hairs->pos.Position.z);
m_stItem.BonesMatrices[i + 1] = world;
m_stItem.BoneLightModes[i] = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
}
memcpy(m_stItem.BonesMatrices, matrices, sizeof(Matrix) * 7);
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get());
@ -296,7 +299,7 @@ namespace TEN::Renderer
{
RendererMesh* mesh = hairsObj.ObjectMeshes[k];
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (bucket.NumVertices == 0 && bucket.BlendMode != BLEND_MODES::BLENDMODE_OPAQUE)
continue;
@ -316,14 +319,10 @@ namespace TEN::Renderer
RendererRoom& room = m_rooms[LaraItem->RoomNumber];
RendererItem* item = &m_items[Lara.ItemNumber];
m_stItem.AmbientLight = room.AmbientLight;
memcpy(m_stItem.BonesMatrices, &Matrix::Identity, sizeof(Matrix));
m_stStatic.Color = room.AmbientLight;
m_stStatic.LightMode = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
m_stLights.NumLights = item->LightsToDraw.size();
for (int j = 0; j < item->LightsToDraw.size(); j++)
memcpy(&m_stLights.Lights[j], item->LightsToDraw[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindLights(item->LightsToDraw);
SetAlphaTest(ALPHA_TEST_GREATER_THAN, ALPHA_TEST_THRESHOLD);
@ -342,13 +341,16 @@ namespace TEN::Renderer
TO_RAD(gunshell->pos.Orientation.z));
Matrix world = rotation * translation;
m_stItem.World = world;
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
m_stStatic.World = world;
m_stStatic.LightMode = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
m_cbStatic.updateData(m_stStatic, m_context.Get());
BindConstantBufferVS(CB_STATIC, m_cbStatic.get());
BindConstantBufferPS(CB_STATIC, m_cbStatic.get());
RendererMesh* mesh = moveableObj.ObjectMeshes[0];
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (bucket.NumVertices == 0 && bucket.BlendMode == BLEND_MODES::BLENDMODE_OPAQUE)
continue;
@ -552,8 +554,10 @@ namespace TEN::Renderer
ObjectInfo* obj = &Objects[ID_RATS_EMITTER];
RendererObject& moveableObj = *m_moveableObjects[ID_RATS_EMITTER];
for (int m = 0; m < 32; m++)
for (int m = 0; m < MAX_BONES; m++)
memcpy(&m_stItem.BonesMatrices[m], &Matrix::Identity, sizeof(Matrix));
for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++)
m_stItem.BoneLightModes[k] = moveableObj.ObjectMeshes[k]->LightMode;
for (int i = 0; i < NUM_RATS; i++)
{
@ -572,9 +576,9 @@ namespace TEN::Renderer
m_stItem.AmbientLight = m_rooms[rat->RoomNumber].AmbientLight;
m_cbItem.updateData(m_stItem, m_context.Get());
for (int b = 0; b < mesh->buckets.size(); b++)
for (int b = 0; b < mesh->Buckets.size(); b++)
{
RendererBucket* bucket = &mesh->buckets[b];
RendererBucket* bucket = &mesh->Buckets[b];
if (bucket->Polygons.size() == 0)
continue;
@ -604,12 +608,14 @@ namespace TEN::Renderer
RendererObject& moveableObj = *m_moveableObjects[ID_BATS_EMITTER];
RendererMesh* mesh = GetMesh(Objects[ID_BATS_EMITTER].meshIndex + (-GlobalCounter & 3));
for (int m = 0; m < 32; m++)
for (int m = 0; m < MAX_BONES; m++)
memcpy(&m_stItem.BonesMatrices[m], &Matrix::Identity, sizeof(Matrix));
for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++)
m_stItem.BoneLightModes[k] = moveableObj.ObjectMeshes[k]->LightMode;
for (int b = 0; b < mesh->buckets.size(); b++)
for (int b = 0; b < mesh->Buckets.size(); b++)
{
RendererBucket* bucket = &mesh->buckets[b];
RendererBucket* bucket = &mesh->Buckets[b];
if (bucket->Polygons.size() == 0)
continue;
@ -654,8 +660,10 @@ namespace TEN::Renderer
ObjectInfo* obj = &Objects[ID_LITTLE_BEETLE];
RendererObject& moveableObj = *m_moveableObjects[ID_LITTLE_BEETLE];
for (int m = 0; m < 32; m++)
for (int m = 0; m < MAX_BONES; m++)
memcpy(&m_stItem.BonesMatrices[m], &Matrix::Identity, sizeof(Matrix));
for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++)
m_stItem.BoneLightModes[k] = moveableObj.ObjectMeshes[k]->LightMode;
for (int i = 0; i < TEN::Entities::TR4::NUM_BEETLES; i++)
{
@ -675,9 +683,9 @@ namespace TEN::Renderer
m_stItem.AmbientLight = m_rooms[beetle->RoomNumber].AmbientLight;
m_cbItem.updateData(m_stItem, m_context.Get());
for (int b = 0; b < mesh->buckets.size(); b++)
for (int b = 0; b < mesh->Buckets.size(); b++)
{
RendererBucket* bucket = &mesh->buckets[b];
RendererBucket* bucket = &mesh->Buckets[b];
if (bucket->Polygons.size() == 0)
continue;
@ -706,8 +714,10 @@ namespace TEN::Renderer
ObjectInfo* obj = &Objects[ID_LOCUSTS];
RendererObject& moveableObj = *m_moveableObjects[ID_LOCUSTS];
for (int m = 0; m < 32; m++)
for (int m = 0; m < MAX_BONES; m++)
memcpy(&m_stItem.BonesMatrices[m], &Matrix::Identity, sizeof(Matrix));
for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++)
m_stItem.BoneLightModes[k] = moveableObj.ObjectMeshes[k]->LightMode;
for (int i = 0; i < TEN::Entities::TR4::MAX_LOCUSTS; i++)
{
@ -727,9 +737,9 @@ namespace TEN::Renderer
m_stItem.AmbientLight = m_rooms[locust->roomNumber].AmbientLight;
m_cbItem.updateData(m_stItem, m_context.Get());
for (int b = 0; b < mesh->buckets.size(); b++)
for (int b = 0; b < mesh->Buckets.size(); b++)
{
RendererBucket* bucket = &mesh->buckets[b];
RendererBucket* bucket = &mesh->Buckets[b];
if (bucket->Polygons.size() == 0)
continue;
@ -761,12 +771,12 @@ namespace TEN::Renderer
RendererLine3D* line = &m_lines3DToDraw[i];
RendererVertex v1;
v1.Position = line->start;
v1.Color = line->color;
v1.Position = line->Start;
v1.Color = line->Color;
RendererVertex v2;
v2.Position = line->end;
v2.Color = line->color;
v2.Position = line->End;
v2.Color = line->Color;
m_primitiveBatch->DrawLine(v1, v2);
}
@ -780,9 +790,9 @@ namespace TEN::Renderer
{
RendererLine3D line;
line.start = start;
line.end = end;
line.color = color;
line.Start = start;
line.End = end;
line.Color = color;
m_lines3DToDraw.push_back(line);
}
@ -838,49 +848,49 @@ namespace TEN::Renderer
switch (i)
{
case 0: line.start = corners[0];
line.end = corners[1];
case 0: line.Start = corners[0];
line.End = corners[1];
break;
case 1: line.start = corners[1];
line.end = corners[2];
case 1: line.Start = corners[1];
line.End = corners[2];
break;
case 2: line.start = corners[2];
line.end = corners[3];
case 2: line.Start = corners[2];
line.End = corners[3];
break;
case 3: line.start = corners[3];
line.end = corners[0];
case 3: line.Start = corners[3];
line.End = corners[0];
break;
case 4: line.start = corners[4];
line.end = corners[5];
case 4: line.Start = corners[4];
line.End = corners[5];
break;
case 5: line.start = corners[5];
line.end = corners[6];
case 5: line.Start = corners[5];
line.End = corners[6];
break;
case 6: line.start = corners[6];
line.end = corners[7];
case 6: line.Start = corners[6];
line.End = corners[7];
break;
case 7: line.start = corners[7];
line.end = corners[4];
case 7: line.Start = corners[7];
line.End = corners[4];
break;
case 8: line.start = corners[0];
line.end = corners[4];
case 8: line.Start = corners[0];
line.End = corners[4];
break;
case 9: line.start = corners[1];
line.end = corners[5];
case 9: line.Start = corners[1];
line.End = corners[5];
break;
case 10: line.start = corners[2];
line.end = corners[6];
case 10: line.Start = corners[2];
line.End = corners[6];
break;
case 11: line.start = corners[3];
line.end = corners[7];
case 11: line.Start = corners[3];
line.End = corners[7];
break;
}
line.color = color;
line.Color = color;
m_lines3DToDraw.push_back(line);
}
}
@ -893,47 +903,47 @@ namespace TEN::Renderer
switch (i)
{
case 0: line.start = Vector3(min.x, min.y, min.z);
line.end = Vector3(min.x, min.y, max.z);
case 0: line.Start = Vector3(min.x, min.y, min.z);
line.End = Vector3(min.x, min.y, max.z);
break;
case 1: line.start = Vector3(min.x, min.y, max.z);
line.end = Vector3(max.x, min.y, max.z);
case 1: line.Start = Vector3(min.x, min.y, max.z);
line.End = Vector3(max.x, min.y, max.z);
break;
case 2: line.start = Vector3(max.x, min.y, max.z);
line.end = Vector3(max.x, min.y, min.z);
case 2: line.Start = Vector3(max.x, min.y, max.z);
line.End = Vector3(max.x, min.y, min.z);
break;
case 3: line.start = Vector3(max.x, min.y, min.z);
line.end = Vector3(min.x, min.y, min.z);
case 3: line.Start = Vector3(max.x, min.y, min.z);
line.End = Vector3(min.x, min.y, min.z);
break;
case 4: line.start = Vector3(min.x, max.y, min.z);
line.end = Vector3(min.x, max.y, max.z);
case 4: line.Start = Vector3(min.x, max.y, min.z);
line.End = Vector3(min.x, max.y, max.z);
break;
case 5: line.start = Vector3(min.x, max.y, max.z);
line.end = Vector3(max.x, max.y, max.z);
case 5: line.Start = Vector3(min.x, max.y, max.z);
line.End = Vector3(max.x, max.y, max.z);
break;
case 6: line.start = Vector3(max.x, max.y, max.z);
line.end = Vector3(max.x, max.y, min.z);
case 6: line.Start = Vector3(max.x, max.y, max.z);
line.End = Vector3(max.x, max.y, min.z);
break;
case 7: line.start = Vector3(max.x, max.y, min.z);
line.end = Vector3(min.x, max.y, min.z);
case 7: line.Start = Vector3(max.x, max.y, min.z);
line.End = Vector3(min.x, max.y, min.z);
break;
case 8: line.start = Vector3(min.x, min.y, min.z);
line.end = Vector3(min.x, max.y, min.z);
case 8: line.Start = Vector3(min.x, min.y, min.z);
line.End = Vector3(min.x, max.y, min.z);
break;
case 9: line.start = Vector3(min.x, min.y, max.z);
line.end = Vector3(min.x, max.y, max.z);
case 9: line.Start = Vector3(min.x, min.y, max.z);
line.End = Vector3(min.x, max.y, max.z);
break;
case 10: line.start = Vector3(max.x, min.y, max.z);
line.end = Vector3(max.x, max.y, max.z);
case 10: line.Start = Vector3(max.x, min.y, max.z);
line.End = Vector3(max.x, max.y, max.z);
break;
case 11: line.start = Vector3(max.x, min.y, min.z);
line.end = Vector3(max.x, max.y, min.z);
case 11: line.Start = Vector3(max.x, min.y, min.z);
line.End = Vector3(max.x, max.y, min.z);
break;
}
line.color = color;
line.Color = color;
m_lines3DToDraw.push_back(line);
}
}
@ -961,7 +971,7 @@ namespace TEN::Renderer
void Renderer11::AddDynamicLight(int x, int y, int z, short falloff, byte r, byte g, byte b)
{
RendererLight dynamicLight;
RendererLight dynamicLight = {};
if (falloff >= 8)
{
@ -976,6 +986,7 @@ namespace TEN::Renderer
dynamicLight.Color = Vector3(r / 255.0f, g / 255.0f, b / 255.0f) * 2.0f;
}
dynamicLight.Intensity = 1.0f;
dynamicLight.Position = Vector3(float(x), float(y), float(z));
dynamicLight.Out = falloff * 256.0f;
dynamicLight.Type = LIGHT_TYPES::LIGHT_TYPE_POINT;
@ -1288,11 +1299,7 @@ namespace TEN::Renderer
BindConstantBufferVS(CB_SHADOW_LIGHT, m_cbShadowMap.get());
BindConstantBufferPS(CB_SHADOW_LIGHT, m_cbShadowMap.get());
m_stLights.NumLights = view.lightsToDraw.size();
for (int j = 0; j < view.lightsToDraw.size(); j++)
memcpy(&m_stLights.Lights[j], view.lightsToDraw[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindLights(view.lightsToDraw);
m_stMisc.Caustics = (nativeRoom->flags & ENV_FLAG_WATER);
m_cbMisc.updateData(m_stMisc, m_context.Get());
@ -1382,9 +1389,14 @@ namespace TEN::Renderer
m_stStatic.World = info->world;
m_stStatic.Position = Vector4(info->position.x, info->position.y, info->position.z, 1.0f);
m_stStatic.Color = info->color;
m_stStatic.Color = info->room->AmbientLight * info->color;
m_stStatic.LightMode = m_staticObjects[info->staticMesh->Id]->ObjectMeshes[0]->LightMode;
m_cbStatic.updateData(m_stStatic, m_context.Get());
BindConstantBufferVS(CB_STATIC, m_cbStatic.get());
BindConstantBufferPS(CB_STATIC, m_cbStatic.get());
BindLights(info->staticMesh->LightsToDraw);
SetBlendMode(info->blendMode);
@ -1420,8 +1432,6 @@ namespace TEN::Renderer
ScriptInterfaceLevel* level = g_GameFlow->GetLevel(CurrentLevel);
m_stLights.CameraPosition = view.camera.WorldPosition;
// Prepare the scene to draw
auto time1 = std::chrono::high_resolution_clock::now();
CollectRooms(view, false);
@ -1433,15 +1443,16 @@ namespace TEN::Renderer
m_stAlphaTest.AlphaThreshold = -1;
m_stShadowMap.NumSpheres = 0;
// Setup Lara item
m_items[Lara.ItemNumber].ItemNumber = Lara.ItemNumber;
CalculateAmbientLight(&m_items[Lara.ItemNumber]);
CollectLightsForItem(LaraItem->RoomNumber, &m_items[Lara.ItemNumber], true);
// Prepare the shadow map
ClearShadowMap(view);
RenderShadowMap(view);
RenderBlobShadows(view);
// Setup Lara item
m_items[Lara.ItemNumber].ItemNumber = Lara.ItemNumber;
CollectLightsForItem(LaraItem->RoomNumber, &m_items[Lara.ItemNumber], view);
auto time2 = std::chrono::high_resolution_clock::now();
m_timeUpdate = (std::chrono::duration_cast<ns>(time2 - time1)).count() / 1000000;
time1 = time2;
@ -1668,17 +1679,16 @@ namespace TEN::Renderer
m_stItem.World = item->World;
m_stItem.Position = Vector4(nativeItem->Pose.Position.x, nativeItem->Pose.Position.y, nativeItem->Pose.Position.z, 1.0f);
m_stItem.AmbientLight = item->AmbientLight;
memcpy(m_stItem.BonesMatrices, item->AnimationTransforms, sizeof(Matrix) * 32);
memcpy(m_stItem.BonesMatrices, item->AnimationTransforms, sizeof(Matrix) * MAX_BONES);
for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++)
m_stItem.BoneLightModes[k] = moveableObj.ObjectMeshes[k]->LightMode;
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get());
// Bind lights touching that item
m_stLights.NumLights = item->LightsToDraw.size();
for (int j = 0; j < m_stLights.NumLights; j++)
memcpy(&m_stLights.Lights[j], item->LightsToDraw[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindLights(item->LightsToDraw);
for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++)
{
@ -1722,17 +1732,16 @@ namespace TEN::Renderer
m_stItem.World = info->item->World;
m_stItem.Position = Vector4(info->position.x, info->position.y, info->position.z, 1.0f);
m_stItem.AmbientLight = room.AmbientLight;
memcpy(m_stItem.BonesMatrices, info->item->AnimationTransforms, sizeof(Matrix) * 32);
m_stItem.AmbientLight = info->room->AmbientLight * info->color;
memcpy(m_stItem.BonesMatrices, info->item->AnimationTransforms, sizeof(Matrix) * MAX_BONES);
for (int k = 0; k < moveableObj.ObjectMeshes.size(); k++)
m_stItem.BoneLightModes[k] = moveableObj.ObjectMeshes[k]->LightMode;
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get());
m_stLights.NumLights = info->item->LightsToDraw.size();
for (int j = 0; j < info->item->LightsToDraw.size(); j++)
memcpy(&m_stLights.Lights[j], info->item->LightsToDraw[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindLights(info->item->LightsToDraw);
// Set texture
BindTexture(TEXTURE_COLOR_MAP, &std::get<0>(m_moveablesTextures[info->bucket->Texture]),
@ -1807,28 +1816,16 @@ namespace TEN::Renderer
for (auto room : view.roomsToDraw)
{
for (auto msh : room->StaticsToDraw)
for (auto& msh : room->StaticsToDraw)
{
if (!m_staticObjects[msh->staticNumber])
continue;
Matrix world = (Matrix::CreateFromYawPitchRoll(TO_RAD(msh->pos.Orientation.y), TO_RAD(msh->pos.Orientation.x),
TO_RAD(msh->pos.Orientation.z)) *
Matrix::CreateTranslation(msh->pos.Position.x, msh->pos.Position.y, msh->pos.Position.z));
m_stStatic.World = world;
m_stStatic.Position = Vector4(msh->pos.Position.x, msh->pos.Position.y, msh->pos.Position.z, 1);
m_stStatic.Color = msh->color;
m_cbStatic.updateData(m_stStatic, m_context.Get());
BindConstantBufferVS(CB_STATIC, m_cbStatic.get());
RendererObject& staticObj = *m_staticObjects[msh->staticNumber];
RendererObject& staticObj = *m_staticObjects[msh.Id];
if (staticObj.ObjectMeshes.size() > 0)
{
RendererMesh* mesh = staticObj.ObjectMeshes[0];
RendererMesh* mesh = staticObj.ObjectMeshes[0];
auto pos = Vector3::Transform(Vector3::Zero, msh.World);
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ transparent))
{
@ -1848,7 +1845,7 @@ namespace TEN::Renderer
RendererPolygon* p = &bucket.Polygons[j];
// As polygon distance, for moveables, we use the averaged distance
Vector3 centre = Vector3::Transform(p->centre, world);
Vector3 centre = Vector3::Transform(p->centre, msh.World);
int distance = (centre - cameraPosition).Length();
RendererTransparentFace face;
@ -1858,10 +1855,10 @@ namespace TEN::Renderer
face.info.animated = bucket.Animated;
face.info.texture = bucket.Texture;
face.info.room = room;
face.info.staticMesh = msh;
face.info.staticMesh = &msh;
face.info.world = m_stStatic.World;
face.info.position = Vector3(msh->pos.Position.x, msh->pos.Position.y, msh->pos.Position.z);
face.info.color = Vector4(msh->color.x, msh->color.y, msh->color.z, 1.0f);
face.info.position = Vector3(pos.x, pos.y, pos.z);
face.info.color = Vector4(msh.AmbientLight.x, msh.AmbientLight.y, msh.AmbientLight.z, msh.AmbientLight.w);
face.info.blendMode = bucket.BlendMode;
face.info.bucket = &bucket;
room->TransparentFacesToDraw.push_back(face);
@ -1869,6 +1866,17 @@ namespace TEN::Renderer
}
else
{
m_stStatic.World = msh.World;
m_stStatic.Position = Vector4(pos.x, pos.y, pos.z, 1);
m_stStatic.Color = msh.AmbientLight;
m_stStatic.LightMode = mesh->LightMode;
m_cbStatic.updateData(m_stStatic, m_context.Get());
BindConstantBufferVS(CB_STATIC, m_cbStatic.get());
BindConstantBufferPS(CB_STATIC, m_cbStatic.get());
BindLights(msh.LightsToDraw);
int passes = bucket.BlendMode == BLENDMODE_ALPHATEST ? 2 : 1;
for (int pass = 0; pass < passes; pass++)
@ -1953,11 +1961,7 @@ namespace TEN::Renderer
Vector3 cameraPosition = Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z);
Vector3 roomPosition = Vector3(nativeRoom->x, nativeRoom->y, nativeRoom->z);
m_stLights.NumLights = view.lightsToDraw.size();
for (int j = 0; j < view.lightsToDraw.size(); j++)
memcpy(&m_stLights.Lights[j], view.lightsToDraw[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindLights(view.lightsToDraw);
// TODO: make caustics optional in Tomb Editor
m_stMisc.Caustics = false; // (nativeRoom->flags & ENV_FLAG_WATER);
@ -2186,6 +2190,8 @@ namespace TEN::Renderer
m_stStatic.World = (rotation * translation);
m_stStatic.Color = weather.SkyColor();
m_stStatic.LightMode = LIGHT_MODES::LIGHT_MODE_STATIC;
m_cbStatic.updateData(m_stStatic, m_context.Get());
BindConstantBufferVS(CB_STATIC, m_cbStatic.get());
BindConstantBufferPS(CB_STATIC, m_cbStatic.get());
@ -2209,6 +2215,8 @@ namespace TEN::Renderer
m_stStatic.World = Matrix::CreateTranslation(Camera.pos.x, Camera.pos.y, Camera.pos.z);
m_stStatic.Position = Vector4::Zero;
m_stStatic.Color = Vector4::One;
m_stStatic.LightMode = LIGHT_MODES::LIGHT_MODE_STATIC;
m_cbStatic.updateData(m_stStatic, m_context.Get());
BindConstantBufferVS(CB_STATIC, m_cbStatic.get());
BindConstantBufferPS(CB_STATIC, m_cbStatic.get());
@ -2217,7 +2225,7 @@ namespace TEN::Renderer
{
RendererMesh* mesh = moveableObj.ObjectMeshes[k];
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (bucket.NumVertices == 0)
continue;
@ -2253,7 +2261,7 @@ namespace TEN::Renderer
{
Vector3 cameraPosition = Vector3(Camera.pos.x, Camera.pos.y, Camera.pos.z);
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (!((bucket.BlendMode == BLENDMODE_OPAQUE || bucket.BlendMode == BLENDMODE_ALPHATEST) ^ transparent))
{
@ -2285,6 +2293,7 @@ namespace TEN::Renderer
face.info.texture = bucket.Texture;
face.info.room = room;
face.info.item = itemToDraw;
face.info.color = itemToDraw->AmbientLight;
face.info.blendMode = bucket.BlendMode;
face.info.bucket = &bucket;
room->TransparentFacesToDraw.push_back(face);

View file

@ -607,13 +607,10 @@ namespace TEN::Renderer
RendererItem* item = &m_items[Lara.ItemNumber];
m_stItem.AmbientLight = room.AmbientLight;
m_stItem.BoneLightModes[0] = LIGHT_MODES::LIGHT_MODE_STATIC;
memcpy(m_stItem.BonesMatrices, &Matrix::Identity, sizeof(Matrix));
m_stLights.NumLights = item->LightsToDraw.size();
for (int j = 0; j < item->LightsToDraw.size(); j++)
memcpy(&m_stLights.Lights[j], item->LightsToDraw[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindLights(item->LightsToDraw); // FIXME: Is it really needed for gunflashes? -- Lwmte, 15.07.22
short length = 0;
short zOffset = 0;
@ -668,7 +665,7 @@ namespace TEN::Renderer
RendererObject& flashMoveable = *m_moveableObjects[gunflash];
RendererMesh* flashMesh = flashMoveable.ObjectMeshes[0];
for (auto& flashBucket : flashMesh->buckets)
for (auto& flashBucket : flashMesh->Buckets)
{
if (flashBucket.BlendMode == BLENDMODE_OPAQUE)
continue;
@ -738,13 +735,10 @@ namespace TEN::Renderer
RendererObject& flashMoveable = *m_moveableObjects[ID_GUN_FLASH];
m_stItem.AmbientLight = room.AmbientLight;
m_stItem.BoneLightModes[0] = LIGHT_MODES::LIGHT_MODE_STATIC;
memcpy(m_stItem.BonesMatrices, &Matrix::Identity, sizeof(Matrix));
m_stLights.NumLights = item->LightsToDraw.size();
for (int j = 0; j < item->LightsToDraw.size(); j++)
memcpy(&m_stLights.Lights[j], item->LightsToDraw[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindLights(item->LightsToDraw); // FIXME: Is it really needed for gunflashes? -- Lwmte, 15.07.22
SetBlendMode(BLENDMODE_ADDITIVE);
@ -763,7 +757,7 @@ namespace TEN::Renderer
RendererMesh* flashMesh = flashMoveable.ObjectMeshes[0];
for (auto& flashBucket : flashMesh->buckets)
for (auto& flashBucket : flashMesh->Buckets)
{
if (flashBucket.BlendMode == BLENDMODE_OPAQUE)
continue;
@ -1088,16 +1082,12 @@ namespace TEN::Renderer
m_stItem.World = effect->World;
m_stItem.Position = Vector4(effect->Effect->pos.Position.x, effect->Effect->pos.Position.y, effect->Effect->pos.Position.z, 1.0f);
m_stItem.AmbientLight = room.AmbientLight;
Matrix matrices[1] = { Matrix::Identity };
memcpy(m_stItem.BonesMatrices, matrices, sizeof(Matrix));
m_stItem.BoneLightModes[0] = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
memcpy(m_stItem.BonesMatrices, &Matrix::Identity, sizeof(Matrix));
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
m_stLights.NumLights = effect->Lights.size();
for (int j = 0; j < effect->Lights.size(); j++)
memcpy(&m_stLights.Lights[j], effect->Lights[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
BindLights(effect->LightsToDraw);
if (transparent)
{
@ -1110,7 +1100,7 @@ namespace TEN::Renderer
RendererMesh* mesh = effect->Mesh;
for (auto& bucket : mesh->buckets)
for (auto& bucket : mesh->Buckets)
{
if (bucket.NumVertices == 0)
continue;
@ -1163,8 +1153,8 @@ namespace TEN::Renderer
Matrix world = rotation * translation;
m_primitiveBatch->Begin();
m_context->VSSetShader(m_vsStatics.Get(), NULL, 0);
m_context->PSSetShader(m_psStatics.Get(), NULL, 0);
m_context->VSSetShader(m_vsStatics.Get(), nullptr, 0);
m_context->PSSetShader(m_psStatics.Get(), nullptr, 0);
if (deb->isStatic)
{
@ -1185,7 +1175,9 @@ namespace TEN::Renderer
}
m_stStatic.World = world;
m_stStatic.Color = Vector4::One;
m_stStatic.Color = deb->color;
m_stStatic.LightMode = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
m_cbStatic.updateData(m_stStatic, m_context.Get());
BindConstantBufferVS(CB_STATIC, m_cbStatic.get());
@ -1289,55 +1281,4 @@ namespace TEN::Renderer
AddSpriteBillboard(&m_sprites[Objects[s.sequence].meshIndex + s.sprite], s.worldPosition, Vector4(1, 1, 1, 1), 0, 1.0f, { s.size, s.size / 2 }, BLENDMODE_ALPHABLEND,view);
}
}
DebrisFragment* getNewDebrisFragment()
{
return nullptr;
/*DebrisFragment* fragment = GetFreeDebrisFragment();
if (!fragment)
{
return nullptr;
}
if (!fragment->active)
{
Matrix rotationMatrix = Matrix::CreateFromYawPitchRoll(TO_RAD(yRot), 0, 0);
RendererVertex vtx0 = meshVertices.at(renderBucket.Indices[i]);
RendererVertex vtx1 = meshVertices.at(renderBucket.Indices[i + 1]);
RendererVertex vtx2 = meshVertices.at(renderBucket.Indices[i + 2]);
//Take the average of all 3 local positions
Vector3 localPos = (vtx0.Position + vtx1.Position + vtx2.Position) / 3;
vtx0.Position -= localPos;
vtx1.Position -= localPos;
vtx2.Position -= localPos;
Vector3 worldPos = Vector3::Transform(localPos, rotationMatrix);
fragment->worldPosition = worldPos + pos;
fragment->mesh.vertices[0] = vtx0;
fragment->mesh.vertices[1] = vtx1;
fragment->mesh.vertices[2] = vtx2;
fragment->mesh.blendMode = renderBucket.BlendMode;
fragment->mesh.tex = renderBucket.Texture;
fragment->isStatic = isStatic;
fragment->active = true;
fragment->terminalVelocity = 1024;
fragment->gravity = Vector3(0, 7, 0);
fragment->restitution = 0.6f;
fragment->friction = 0.6f;
fragment->linearDrag = .99f;
fragment->angularVelocity = Vector3(GenerateFloat(-1, 1) * 0.39, GenerateFloat(-1, 1) * 0.39, GenerateFloat(-1, 1) * 0.39);
fragment->angularDrag = GenerateFloat(0.9f, 0.999f);
fragment->velocity = CalculateFragmentImpactVelocity(fragment->worldPosition, ShatterImpactData.impactDirection, ShatterImpactData.impactLocation);
fragment->roomNumber = roomNumber;
fragment->numBounces = 0;
return fragment;
}
else
{
return nullptr;
}*/
}
}

View file

@ -574,12 +574,15 @@ namespace TEN::Renderer
m_stItem.World = ((*moveableObj).AnimationTransforms[n] * world);
else
m_stItem.World = ((*moveableObj).BindPoseTransforms[n] * world);
m_stItem.BoneLightModes[n] = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
m_stItem.AmbientLight = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
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 (auto& bucket : mesh->Buckets)
{
if (bucket.NumVertices == 0)
continue;

View file

@ -68,6 +68,12 @@ enum SHADOW_MODES
SHADOW_ALL
};
enum LIGHT_MODES
{
LIGHT_MODE_DYNAMIC,
LIGHT_MODE_STATIC
};
enum DEPTH_STATES
{
DEPTH_STATE_WRITE_ZBUFFER = 0,
@ -209,7 +215,7 @@ constexpr auto FADE_FRAMES_COUNT = 16;
constexpr auto FADE_FACTOR = 0.0625f;
constexpr auto NUM_LIGHTS_PER_BUFFER = 48;
constexpr auto MAX_LIGHTS_PER_ITEM = 48;
constexpr auto MAX_LIGHTS_PER_ITEM = 8;
constexpr auto MAX_LIGHTS = 100;
constexpr auto AMBIENT_LIGHT_INTERPOLATION_STEPS = 8;
constexpr auto MAX_DYNAMIC_SHADOWS = 1;
@ -233,4 +239,7 @@ constexpr auto HUD_ZERO_Y = -REFERENCE_RES_HEIGHT;
constexpr auto UNDERWATER_FOG_MIN_DISTANCE = 4;
constexpr auto UNDERWATER_FOG_MAX_DISTANCE = 30;
constexpr auto MAX_ROOM_BOUNDS = 256;
constexpr auto MAX_ROOM_BOUNDS = 256;
constexpr auto MIN_FAR_VIEW = 3200.0f;
constexpr auto DEFAULT_FAR_VIEW = 102400.0f;

View file

@ -69,7 +69,7 @@ namespace TEN::Renderer
// Project vertices of the door in clip space
Vector4 tmp = Vector4(
door->vertices[i].x + parentNativeRoom->x,
door->vertices[i].y + parentNativeRoom->y,
door->vertices[i].y,
door->vertices[i].z + parentNativeRoom->z,
1.0f);
@ -251,8 +251,8 @@ namespace TEN::Renderer
{
CollectLightsForRoom(roomNumber, renderView);
CollectItems(roomNumber, renderView);
CollectStatics(roomNumber, renderView);
CollectEffects(roomNumber, renderView);
CollectStatics(roomNumber);
CollectEffects(roomNumber);
}
}
@ -272,14 +272,13 @@ namespace TEN::Renderer
{
ROOM_DOOR* portal = &nativeRoom->doors[i];
Vector3 n = portal->normal;
Vector3 v = Vector3(
Vector3Int n = Vector3Int(portal->normal.x, portal->normal.y, portal->normal.z);
Vector3Int v = Vector3Int(
Camera.pos.x - (nativeRoom->x + portal->vertices[0].x),
Camera.pos.y - (nativeRoom->y + portal->vertices[0].y),
Camera.pos.z - (nativeRoom->z + portal->vertices[0].z));
// Test camera and normal positions and decide if process door or not
if (n.Dot(v) <= 0.0f)
if (n.x * v.x + n.y * v.y + n.z * v.z < 0)
continue;
SetRoomBounds(portal, roomNumber, renderView);
@ -317,7 +316,7 @@ namespace TEN::Renderer
GetRoomBounds(renderView, onlyRooms);
}
void Renderer11::CollectItems(short roomNumber, RenderView &renderView)
void Renderer11::CollectItems(short roomNumber, RenderView& renderView)
{
if (m_rooms.size() < roomNumber)
return;
@ -359,13 +358,14 @@ namespace TEN::Renderer
newItem->Scale = Matrix::CreateScale(1.0f);
newItem->World = newItem->Rotation * newItem->Translation;
CollectLightsForItem(item->RoomNumber, newItem, renderView);
CalculateAmbientLight(newItem);
CollectLightsForItem(item->RoomNumber, newItem, false);
room.ItemsToDraw.push_back(newItem);
}
}
void Renderer11::CollectStatics(short roomNumber, RenderView &renderView)
void Renderer11::CollectStatics(short roomNumber)
{
if (m_rooms.size() < roomNumber)
return;
@ -373,209 +373,81 @@ namespace TEN::Renderer
RendererRoom& room = m_rooms[roomNumber];
ROOM_INFO* r = &g_Level.Rooms[room.RoomNumber];
if (r->mesh.size() <= 0)
if (r->mesh.size() == 0)
return;
int numStatics = r->mesh.size();
for (int i = 0; i < numStatics; i++)
{
auto mesh = &r->mesh[i];
if (mesh->flags & StaticMeshFlags::SM_VISIBLE)
if (!(mesh->flags & StaticMeshFlags::SM_VISIBLE))
continue;
if (!m_staticObjects[mesh->staticNumber].has_value())
continue;
auto& obj = *m_staticObjects[mesh->staticNumber];
if (obj.ObjectMeshes.size() == 0)
continue;
std::vector<RendererLight*> lights;
if (obj.ObjectMeshes.front()->LightMode != LIGHT_MODES::LIGHT_MODE_STATIC)
CollectLights(mesh->pos.Position, room.RoomNumber, false, lights);
Matrix world = (Matrix::CreateFromYawPitchRoll(TO_RAD(mesh->pos.Orientation.y), TO_RAD(mesh->pos.Orientation.x), TO_RAD(mesh->pos.Orientation.z)) *
Matrix::CreateTranslation(mesh->pos.Position.x, mesh->pos.Position.y, mesh->pos.Position.z));
auto staticInfo = RendererStatic
{
auto sinfo = &StaticObjects[mesh->staticNumber];
mesh->staticNumber,
room.RoomNumber,
world,
room.AmbientLight * mesh->color,
lights
};
auto bounds = TO_DX_BBOX(mesh->pos, &sinfo->visibilityBox);
Vector3 min = bounds.Center - bounds.Extents;
Vector3 max = bounds.Center + bounds.Extents;
if (!renderView.camera.frustum.AABBInFrustum(min, max))
continue;
room.StaticsToDraw.push_back(mesh);
}
room.StaticsToDraw.push_back(staticInfo);
}
}
void Renderer11::CollectLightsForEffect(short roomNumber, RendererEffect *effect, RenderView &renderView)
void Renderer11::CollectLights(Vector3Int position, int roomNumber, bool collectShadowLight, std::vector<RendererLight*>& lights)
{
effect->Lights.clear();
if (m_rooms.size() < roomNumber)
return;
RendererRoom& room = m_rooms[roomNumber];
ROOM_INFO* r = &g_Level.Rooms[room.RoomNumber];
if (r->lights.size() <= 0)
return;
LinearArrayBuffer<RendererLight*, 8> tempLights;
Vector3 itemPosition = Vector3(effect->Effect->pos.Position.x, effect->Effect->pos.Position.y, effect->Effect->pos.Position.z);
// Dynamic lights have the priority
for (int i = 0; i < dynamicLights.size(); i++)
{
RendererLight* light = &dynamicLights[i];
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
if (distance > light->Out)
continue;
tempLights.push_back(light);
}
int numLights = room.Lights.size();
RendererLight* brightestLight = NULL;
float brightest = 0.0f;
for (int j = 0; j < numLights; j++)
{
RendererLight *light = &room.Lights[j];
// Check only lights different from sun
if (light->Type == LIGHT_TYPE_SUN)
{
// Sun is added without checks
}
else if (light->Type == LIGHT_TYPE_POINT || light->Type == LIGHT_TYPE_SHADOW)
{
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
continue;
// Check the out radius
if (distance > light->Out)
continue;
// If Lara, try to collect shadow casting light
if (light->CastShadows && effect->Effect->objectNumber == ID_LARA)
{
float attenuation = 1.0f - distance / light->Out;
float intensity = std::max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
if (intensity >= brightest)
{
brightest = intensity;
brightestLight = light;
}
}
}
else if (light->Type == LIGHT_TYPE_SPOT)
{
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
continue;
// Check the range
if (distance > light->Range)
continue;
}
else
{
// Invalid light type
continue;
}
tempLights.push_back(light);
}
for (int i = 0; i < std::min(static_cast<size_t>(MAX_LIGHTS_PER_ITEM), tempLights.size()); i++)
{
if (renderView.lightsToDraw.size() < NUM_LIGHTS_PER_BUFFER - 1)
renderView.lightsToDraw.push_back(tempLights[i]);
}
}
void Renderer11::CollectLightsForItem(short roomNumber, RendererItem *item, RenderView &renderView)
{
item->LightsToDraw.clear();
if (m_rooms.size() < roomNumber)
return;
RendererRoom& room = m_rooms[roomNumber];
ROOM_INFO* nativeRoom = &g_Level.Rooms[room.RoomNumber];
ItemInfo* nativeItem = &g_Level.Items[item->ItemNumber];
std::vector<int> roomsToCheck;
roomsToCheck.push_back(roomNumber);
for (auto& door : nativeRoom->doors)
{
roomsToCheck.push_back(door.room);
};
// Interpolate ambient light between rooms
if (item->PreviousRoomNumber == NO_ITEM)
{
item->PreviousRoomNumber = nativeItem->RoomNumber;
item->CurrentRoomNumber = nativeItem->RoomNumber;
item->AmbientLightSteps = AMBIENT_LIGHT_INTERPOLATION_STEPS;
}
else if (nativeItem->RoomNumber != item->CurrentRoomNumber)
{
item->PreviousRoomNumber = item->CurrentRoomNumber;
item->CurrentRoomNumber = nativeItem->RoomNumber;
item->AmbientLightSteps = 0;
}
else if (item->AmbientLightSteps < AMBIENT_LIGHT_INTERPOLATION_STEPS)
item->AmbientLightSteps++;
if (item->PreviousRoomNumber == NO_ITEM)
item->AmbientLight = m_rooms[nativeItem->RoomNumber].AmbientLight;
else
{
item->AmbientLight = (((AMBIENT_LIGHT_INTERPOLATION_STEPS - item->AmbientLightSteps) / (float)AMBIENT_LIGHT_INTERPOLATION_STEPS) * m_rooms[item->PreviousRoomNumber].AmbientLight +
(item->AmbientLightSteps / (float)AMBIENT_LIGHT_INTERPOLATION_STEPS) * m_rooms[item->CurrentRoomNumber].AmbientLight);
item->AmbientLight.w = 1.0f;
}
// Multiply calculated ambient light by object tint
item->AmbientLight *= nativeItem->Color;
// Now collect lights from dynamic list and from rooms
std::vector<RendererLight*> tempLights;
tempLights.reserve(MAX_LIGHTS_DRAW);
RendererRoom& room = m_rooms[roomNumber];
ROOM_INFO* nativeRoom = &g_Level.Rooms[room.RoomNumber];
Vector3 itemPosition = Vector3(nativeItem->Pose.Position.x, nativeItem->Pose.Position.y, nativeItem->Pose.Position.z);
auto roomsToCheck = GetRoomList(roomNumber);
auto itemPosition = position.ToVector3();
if (nativeItem->ObjectNumber == ID_LARA)
shadowLight = nullptr;
RendererLight* brightestLight = NULL;
RendererLight* brightestLight = nullptr;
float brightest = 0.0f;
// Dynamic lights have the priority
for (int i = 0; i < dynamicLights.size(); i++)
for (auto& light : dynamicLights)
{
RendererLight* light = &dynamicLights[i];
Vector3 lightPosition = Vector3(light->Position.x, light->Position.y, light->Position.z);
float distance = (itemPosition - lightPosition).Length();
if (distance > light->Out)
float distance = (itemPosition - light.Position).Length();
if (distance > light.Out)
continue;
float attenuation = 1.0f - distance / light->Out;
float intensity = std::max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
float attenuation = 1.0f - distance / light.Out;
float intensity = std::max(0.0f, attenuation * light.Intensity * Luma(light.Color));
light->LocalIntensity = intensity;
light->Distance = distance;
light.LocalIntensity = intensity;
light.Distance = distance;
tempLights.push_back(light);
tempLights.push_back(&light);
}
// Check current room and also neighbour rooms
for (int roomToCheck : roomsToCheck)
for (auto roomToCheck : roomsToCheck)
{
RendererRoom& currentRoom = m_rooms[roomToCheck];
int numLights = currentRoom.Lights.size();
@ -611,13 +483,13 @@ namespace TEN::Renderer
continue;
float attenuation = 1.0f - distance / light->Out;
float intensity = std::max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
float intensity = std::max(0.0f, attenuation * light->Intensity * Luma(light->Color));
light->LocalIntensity = intensity;
light->Distance = distance;
// If Lara, try to collect shadow casting light
if (light->CastShadows && nativeItem->ObjectNumber == ID_LARA && light->Type == LIGHT_TYPE_POINT)
// If collecting shadows, try to collect shadow casting light
if (light->CastShadows && collectShadowLight && light->Type == LIGHT_TYPE_POINT)
{
if (intensity >= brightest)
{
@ -633,20 +505,20 @@ namespace TEN::Renderer
float distance = (itemPosition - lightPosition).Length();
// Collect only lights nearer than 20 sectors
if (distance >= 20 * WALL_SIZE)
if (distance >= SECTOR(20))
continue;
// Check the range
if (distance > light->Range)
if (distance > light->Out)
continue;
float attenuation = 1.0f - distance / light->Range;
float intensity = std::max(0.0f, attenuation * (light->Color.x + light->Color.y + light->Color.z) / 3.0f);
float attenuation = 1.0f - distance / light->Out;
float intensity = std::max(0.0f, attenuation * light->Intensity * Luma(light->Color));
light->LocalIntensity = intensity;
// If Lara, try to collect shadow casting light
if (light->CastShadows && nativeItem->ObjectNumber == ID_LARA)
// If shadow pointer provided, try to collect shadow casting light
if (light->CastShadows && collectShadowLight)
{
if (intensity >= brightest)
{
@ -667,9 +539,6 @@ namespace TEN::Renderer
}
}
if (nativeItem->ObjectNumber == ID_LARA)
shadowLight = brightestLight;
// Sort lights by distance
std::sort(
tempLights.begin(),
@ -680,21 +549,75 @@ namespace TEN::Renderer
}
);
// Now put actual lights to provided vector
lights.clear();
// Always add brightest light, if collecting shadow light is specified, even if it's far in range
if (collectShadowLight && brightestLight)
lights.push_back(brightestLight);
// Add max 8 lights per item, including the shadow light for Lara eventually
if (shadowLight != nullptr)
item->LightsToDraw.push_back(shadowLight);
for (int i = 0; i < tempLights.size(); i++)
for (auto l : tempLights)
{
if (shadowLight != nullptr && shadowLight == tempLights[i])
if (collectShadowLight && brightestLight == l)
continue;
item->LightsToDraw.push_back(tempLights[i]);
lights.push_back(l);
if (item->LightsToDraw.size() == MAX_LIGHTS_PER_ITEM)
if (lights.size() == MAX_LIGHTS_PER_ITEM)
break;
}
}
void Renderer11::CollectLightsForEffect(short roomNumber, RendererEffect *effect)
{
CollectLights(effect->Effect->pos.Position, roomNumber, false, effect->LightsToDraw);
}
void Renderer11::CollectLightsForItem(short roomNumber, RendererItem* item, bool collectShadowLight)
{
ItemInfo* nativeItem = &g_Level.Items[item->ItemNumber];
CollectLights(nativeItem->Pose.Position, roomNumber, collectShadowLight, item->LightsToDraw);
if (collectShadowLight && item->LightsToDraw.size() > 0 && item->LightsToDraw.front()->CastShadows)
shadowLight = item->LightsToDraw.front();
else
shadowLight = nullptr;
}
void Renderer11::CalculateAmbientLight(RendererItem *item)
{
ItemInfo* nativeItem = &g_Level.Items[item->ItemNumber];
// Interpolate ambient light between rooms
if (item->PreviousRoomNumber == NO_ITEM)
{
item->PreviousRoomNumber = nativeItem->RoomNumber;
item->CurrentRoomNumber = nativeItem->RoomNumber;
item->AmbientLightSteps = AMBIENT_LIGHT_INTERPOLATION_STEPS;
}
else if (nativeItem->RoomNumber != item->CurrentRoomNumber)
{
item->PreviousRoomNumber = item->CurrentRoomNumber;
item->CurrentRoomNumber = nativeItem->RoomNumber;
item->AmbientLightSteps = 0;
}
else if (item->AmbientLightSteps < AMBIENT_LIGHT_INTERPOLATION_STEPS)
item->AmbientLightSteps++;
if (item->PreviousRoomNumber == NO_ITEM)
item->AmbientLight = m_rooms[nativeItem->RoomNumber].AmbientLight;
else
{
item->AmbientLight = (((AMBIENT_LIGHT_INTERPOLATION_STEPS - item->AmbientLightSteps) / (float)AMBIENT_LIGHT_INTERPOLATION_STEPS) * m_rooms[item->PreviousRoomNumber].AmbientLight +
(item->AmbientLightSteps / (float)AMBIENT_LIGHT_INTERPOLATION_STEPS) * m_rooms[item->CurrentRoomNumber].AmbientLight);
item->AmbientLight.w = 1.0f;
}
// Multiply calculated ambient light by object tint
item->AmbientLight *= nativeItem->Color;
}
void Renderer11::CollectLightsForRoom(short roomNumber, RenderView &renderView)
{
if (m_rooms.size() < roomNumber)
@ -720,7 +643,7 @@ namespace TEN::Renderer
}
}
void Renderer11::CollectEffects(short roomNumber, RenderView &renderView)
void Renderer11::CollectEffects(short roomNumber)
{
if (m_rooms.size() < roomNumber)
return;
@ -745,7 +668,7 @@ namespace TEN::Renderer
newEffect->World = Matrix::CreateFromYawPitchRoll(fx->pos.Orientation.y, fx->pos.Position.x, fx->pos.Position.z) * Matrix::CreateTranslation(fx->pos.Position.x, fx->pos.Position.y, fx->pos.Position.z);
newEffect->Mesh = GetMesh(obj->nmeshes ? obj->meshIndex : fx->frameNumber);
CollectLightsForEffect(fx->roomNumber, newEffect, renderView);
CollectLightsForEffect(fx->roomNumber, newEffect);
room.EffectsToDraw.push_back(newEffect);
}

View file

@ -9,14 +9,13 @@
#include "Game/Lara/lara.h"
#include "Game/collision/sphere.h"
#include "Flow/ScriptInterfaceFlowHandler.h"
#include "Renderer\RenderView\RenderView.h"
#include "Renderer/RenderView/RenderView.h"
#include "Objects/TR3/Vehicles/quad_bike.h"
#include "Objects/TR3/Vehicles/rubber_boat.h"
#include "Objects/TR3/Vehicles/upv.h"
#include "Objects/TR3/Vehicles/big_gun.h"
#include "Objects/TR4/Vehicles/jeep.h"
#include "Objects/TR4/Vehicles/motorbike.h"
#include <algorithm>
#include "Game/itemdata/creature_info.h"
#include "Objects/TR3/Vehicles/quad_bike_info.h"
#include "Objects/TR4/Vehicles/jeep_info.h"
@ -25,6 +24,7 @@
#include "Objects/TR3/Vehicles/upv_info.h"
#include "Objects/TR3/Vehicles/big_gun_info.h"
#include "Game/items.h"
#include <algorithm>
extern GameConfiguration g_Configuration;
extern ScriptInterfaceFlowHandler *g_GameFlow;
@ -52,7 +52,7 @@ namespace TEN::Renderer
static std::vector<int> boneIndexList;
boneIndexList.clear();
RendererBone *Bones[32] = {};
RendererBone *Bones[MAX_BONES] = {};
int nextBone = 0;
Matrix rotation;
@ -359,9 +359,12 @@ namespace TEN::Renderer
return (!m_windowed);
}
void Renderer11::UpdateCameraMatrices(CAMERA_INFO *cam, float roll, float fov)
void Renderer11::UpdateCameraMatrices(CAMERA_INFO *cam, float roll, float fov, float farView)
{
gameCamera = RenderView(cam, roll, fov, 32, 102400, g_Configuration.Width, g_Configuration.Height);
if (farView < MIN_FAR_VIEW)
farView = DEFAULT_FAR_VIEW;
gameCamera = RenderView(cam, roll, fov, 32, farView, g_Configuration.Width, g_Configuration.Height);
}
bool Renderer11::SphereBoxIntersection(Vector3 boxMin, Vector3 boxMax, Vector3 sphereCentre, float sphereRadius)

View file

@ -47,7 +47,7 @@ void TEN::Renderer::Renderer11::Initialise(int w, int h, bool windowed, HWND han
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"BITANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"ANIMATIONFRAMEOFFSET", 0, DXGI_FORMAT_R8_UINT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"EFFECTS", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"BLENDINDICES", 0, DXGI_FORMAT_R32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"POLYINDEX", 0, DXGI_FORMAT_R32_UINT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
@ -115,7 +115,7 @@ void TEN::Renderer::Renderer11::Initialise(int w, int h, bool windowed, HWND han
for (int i = 0; i < NUM_ITEMS; i++)
{
m_items[i].LightsToDraw = createVector<RendererLight*>(MAX_LIGHTS_PER_ITEM);
m_effects[i].Lights = createVector<RendererLight*>(MAX_LIGHTS_PER_ITEM);
m_effects[i].LightsToDraw = createVector<RendererLight*>(MAX_LIGHTS_PER_ITEM);
}
m_transparentFacesVertexBuffer = VertexBuffer(m_device.Get(), TRANSPARENT_BUCKET_SIZE);
@ -336,15 +336,15 @@ void TEN::Renderer::Renderer11::Create()
Utils::throwIfFailed(res);
}
void Renderer11::ToggleFullScreen()
void Renderer11::ToggleFullScreen(bool force)
{
m_windowed = !m_windowed;
m_windowed = force ? false : !m_windowed;
if (!m_windowed)
{
SetWindowLongPtr(WindowsHandle, GWL_STYLE, 0);
SetWindowLongPtr(WindowsHandle, GWL_EXSTYLE, WS_EX_TOPMOST);
SetWindowPos(WindowsHandle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
SetWindowPos(WindowsHandle, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
ShowWindow(WindowsHandle, SW_SHOWMAXIMIZED);
}
else

View file

@ -267,13 +267,13 @@ void TEN::Renderer::Renderer11::DrawLara(bool shadowMap, RenderView& view, bool
// Set shaders
if (shadowMap)
{
m_context->VSSetShader(m_vsShadowMap.Get(), NULL, 0);
m_context->PSSetShader(m_psShadowMap.Get(), NULL, 0);
m_context->VSSetShader(m_vsShadowMap.Get(), nullptr, 0);
m_context->PSSetShader(m_psShadowMap.Get(), nullptr, 0);
}
else
{
m_context->VSSetShader(m_vsItems.Get(), NULL, 0);
m_context->PSSetShader(m_psItems.Get(), NULL, 0);
m_context->VSSetShader(m_vsItems.Get(), nullptr, 0);
m_context->PSSetShader(m_psItems.Get(), nullptr, 0);
}
// Set texture
@ -289,21 +289,16 @@ void TEN::Renderer::Renderer11::DrawLara(bool shadowMap, RenderView& view, bool
m_stItem.World = m_LaraWorldMatrix;
m_stItem.Position = Vector4(LaraItem->Pose.Position.x, LaraItem->Pose.Position.y, LaraItem->Pose.Position.z, 1.0f);
m_stItem.AmbientLight = item->AmbientLight;
memcpy(m_stItem.BonesMatrices, laraObj.AnimationTransforms.data(), sizeof(Matrix) * 32);
memcpy(m_stItem.BonesMatrices, laraObj.AnimationTransforms.data(), sizeof(Matrix) * MAX_BONES);
for (int k = 0; k < laraSkin.ObjectMeshes.size(); k++)
m_stItem.BoneLightModes[k] = GetMesh(Lara.MeshPtrs[k])->LightMode;
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get());
if (!shadowMap)
{
m_stLights.NumLights = item->LightsToDraw.size();
for (int j = 0; j < item->LightsToDraw.size(); j++)
memcpy(&m_stLights.Lights[j], item->LightsToDraw[j], sizeof(ShaderLight));
m_cbLights.updateData(m_stLights, m_context.Get());
BindConstantBufferPS(CB_LIGHTS, m_cbLights.get());
}
BindLights(item->LightsToDraw);
for (int k = 0; k < laraSkin.ObjectMeshes.size(); k++)
{
@ -334,16 +329,17 @@ void TEN::Renderer::Renderer11::DrawLara(bool shadowMap, RenderView& view, bool
// First matrix is Lara's head matrix, then all 6 hairs matrices. Bones are adjusted at load time for accounting this.
m_stItem.World = Matrix::Identity;
Matrix matrices[7];
matrices[0] = laraObj.AnimationTransforms[LM_HEAD] * m_LaraWorldMatrix;
m_stItem.BonesMatrices[0] = laraObj.AnimationTransforms[LM_HEAD] * m_LaraWorldMatrix;
for (int i = 0; i < hairsObj.BindPoseTransforms.size(); i++)
{
HAIR_STRUCT* hairs = &Hairs[0][i];
Matrix world = Matrix::CreateFromYawPitchRoll(TO_RAD(hairs->pos.Orientation.y), TO_RAD(hairs->pos.Orientation.x), 0) * Matrix::CreateTranslation(hairs->pos.Position.x, hairs->pos.Position.y, hairs->pos.Position.z);
matrices[i + 1] = world;
auto* hairs = &Hairs[0][i];
Matrix world = Matrix::CreateFromYawPitchRoll(TO_RAD(hairs->pos.Orientation.y), TO_RAD(hairs->pos.Orientation.x), 0) *
Matrix::CreateTranslation(hairs->pos.Position.x, hairs->pos.Position.y, hairs->pos.Position.z);
m_stItem.BonesMatrices[i + 1] = world;
m_stItem.BoneLightModes[i] = LIGHT_MODES::LIGHT_MODE_DYNAMIC;
}
memcpy(m_stItem.BonesMatrices, matrices, sizeof(Matrix) * 7);
m_cbItem.updateData(m_stItem, m_context.Get());
BindConstantBufferVS(CB_ITEM, m_cbItem.get());
BindConstantBufferPS(CB_ITEM, m_cbItem.get());

View file

@ -1,5 +1,6 @@
#include "framework.h"
#include "Renderer/Renderer11.h"
#include "Specific/trutils.h"
namespace TEN::Renderer
{
@ -11,53 +12,65 @@ namespace TEN::Renderer
float factorX = m_screenWidth / REFERENCE_RES_WIDTH;
float factorY = m_screenHeight / REFERENCE_RES_HEIGHT;
float UIScale = m_screenWidth > m_screenHeight ? factorY : factorX;
float fontScale = REFERENCE_FONT_SIZE / m_gameFont->GetLineSpacing();
float fontSpacing = m_gameFont->GetLineSpacing();
float fontScale = REFERENCE_FONT_SIZE / fontSpacing;
// Convert the string to wstring
int sizeNeeded = MultiByteToWideChar(CP_UTF8, 0, string, strlen(string), NULL, 0);
std::wstring wstr(sizeNeeded, 0);
MultiByteToWideChar(CP_UTF8, 0, string, strlen(string), &wstr[0], sizeNeeded);
float currentY = 0;
// 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;
auto lines = TEN::Utils::SplitString(string);
// 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;
if (flags & PRINTSTRING_BLINK)
for (auto line : lines)
{
str.Color = Vector3(m_blinkColorValue, m_blinkColorValue, m_blinkColorValue);
auto cLine = line.c_str();
if (!m_blinkUpdated)
// 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);
// 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;
if (flags & PRINTSTRING_BLINK)
{
m_blinkColorValue += m_blinkColorDirection * 16;
m_blinkUpdated = true;
str.Color = Vector3(m_blinkColorValue, m_blinkColorValue, m_blinkColorValue);
if (m_blinkColorValue < 0)
if (!m_blinkUpdated)
{
m_blinkColorValue = 0;
m_blinkColorDirection = 1;
}
m_blinkColorValue += m_blinkColorDirection * 16;
m_blinkUpdated = true;
if (m_blinkColorValue > 255)
{
m_blinkColorValue = 255;
m_blinkColorDirection = -1;
if (m_blinkColorValue < 0)
{
m_blinkColorValue = 0;
m_blinkColorDirection = 1;
}
if (m_blinkColorValue > 255)
{
m_blinkColorValue = 255;
m_blinkColorDirection = -1;
}
}
}
}
m_strings.push_back(str);
m_strings.push_back(str);
currentY += fontSpacing * 1.1f;
}
}
void Renderer11::DrawAllStrings()

View file

@ -21,7 +21,7 @@ namespace TEN::Renderer
RendererRoom* room;
RendererBucket* bucket;
RendererItem* item;
MESH_INFO* staticMesh;
RendererStatic* staticMesh;
Vector4 color;
Matrix world;
Vector3 position;

View file

@ -10,11 +10,11 @@ namespace TEN::Renderer
DirectX::SimpleMath::Vector2 UV;
DirectX::SimpleMath::Vector4 Color;
DirectX::SimpleMath::Vector3 Tangent;
DirectX::SimpleMath::Vector3 BiTangent;
unsigned char AnimationFrameOffset;
DirectX::SimpleMath::Vector4 Effects;
float Bone;
int IndexInPoly;
int OriginalIndex;
int hash;
int Hash;
};
}

View file

@ -6,15 +6,17 @@ namespace TEN::Renderer
struct RendererLight
{
Vector3 Position;
int Type;
unsigned int Type;
Vector3 Color;
float LocalIntensity;
Vector3 Direction;
float Distance;
float Intensity;
Vector3 Direction;
float In;
float Out;
float Range;
float InRange;
float OutRange;
float LocalIntensity;
float Distance;
bool AffectNeighbourRooms;
bool CastShadows;
};

View file

@ -25,7 +25,7 @@ namespace TEN::Renderer
std::vector<RendererLight> Lights;
std::vector<RendererItem*> ItemsToDraw;
std::vector<RendererEffect*> EffectsToDraw;
std::vector<MESH_INFO*> StaticsToDraw;
std::vector<RendererStatic> StaticsToDraw;
std::vector<RendererTransparentFace> TransparentFacesToDraw;
};
}

View file

@ -33,6 +33,7 @@ public:
virtual bool HasSlideExtended() const = 0;
virtual ScriptInterfaceLevel * GetLevel(int level) = 0;
virtual int GetLevelNumber(std::string const& flieName) = 0;
virtual short GetGameFarView() const = 0;
virtual bool CanPlayAnyLevel() const = 0;
virtual bool DoFlow() = 0;
};

View file

@ -42,4 +42,5 @@ public:
virtual RGBAColor8Byte GetFogColor() const = 0;
virtual short GetFogMinDistance() const = 0;
virtual short GetFogMaxDistance() const = 0;
virtual short GetFarView() const = 0;
};

View file

@ -10,6 +10,7 @@
#include "Game/gui.h"
#include "Vec3/Vec3.h"
#include "Objects/ScriptInterfaceObjectsHandler.h"
#include "Specific/trutils.h"
/***
Functions for use in Flow.lua, settings.lua and strings.lua
@ -170,10 +171,10 @@ void FlowHandler::SetTitleScreenImagePath(std::string const& path)
TitleScreenImagePath = path;
}
void FlowHandler::SetGameFarView(byte val)
void FlowHandler::SetGameFarView(short val)
{
bool cond = val <= 127 && val >= 1;
std::string msg{ "Game far view value must be in the range [1, 127]." };
std::string msg{ "Game far view value must be in the range [1, 255]." };
if (!ScriptAssert(cond, msg))
{
ScriptWarn("Setting game far view to 32.");
@ -220,14 +221,11 @@ int FlowHandler::GetLevelNumber(std::string const& fileName)
if (fileName.empty())
return -1;
auto lcFilename = fileName;
std::transform(lcFilename.begin(), lcFilename.end(), lcFilename.begin(), [](unsigned char c) { return std::tolower(c); });
auto lcFilename = TEN::Utils::ToLower(fileName);
for (int i = 0; i < Levels.size(); i++)
{
auto level = this->GetLevel(i)->FileName;
std::transform(level.begin(), level.end(), level.begin(), [](unsigned char c) { return std::tolower(c); });
auto level = TEN::Utils::ToLower(this->GetLevel(i)->FileName);
if (level == lcFilename && std::filesystem::exists(fileName))
return i;
}
@ -308,17 +306,16 @@ bool FlowHandler::DoFlow()
// Load level
CurrentLevel = header.Level;
GameTimer = header.Timer;
loadFromSavegame = true;
break;
case GameStatus::LevelComplete:
if (LevelComplete >= Levels.size())
{
// TODO: final credits
CurrentLevel = 0;
}
CurrentLevel = 0; // TODO: final credits
else
CurrentLevel++;
CurrentLevel = LevelComplete;
LevelComplete = 0;
break;
}
}
@ -330,4 +327,9 @@ bool FlowHandler::DoFlow()
bool FlowHandler::CanPlayAnyLevel() const
{
return PlayAnyLevel;
}
short FlowHandler::GetGameFarView() const
{
return GameFarView;
}

View file

@ -27,7 +27,7 @@ public:
bool PlayAnyLevel{ true };
bool FlyCheat{ true };
bool DebugMode{ false };
byte GameFarView{ 0 };
short GameFarView{ 0 };
// New animation flag table
Animations Anims{};
@ -51,7 +51,8 @@ public:
int GetNumLevels() const;
void SetIntroImagePath(std::string const& path);
void SetTitleScreenImagePath(std::string const& path);
void SetGameFarView(byte val);
void SetGameFarView(short val);
short GetGameFarView() const;
bool IsFlyCheatEnabled() const;
bool CanPlayAnyLevel() const;

View file

@ -119,7 +119,7 @@ e.g. `myLevel.laraType = LaraType.Divesuit`
/*** (byte) The maximum draw distance for level.
Given in sectors (blocks).
Must be in the range [1, 127], and equal to or less than the value passed to SetGameFarView.
Must be in the range [1, 255], and equal to or less than the value passed to SetGameFarView.
This is equivalent to TRNG's LevelFarView variable.
@ -156,9 +156,9 @@ void Level::SetWeatherStrength(float val)
}
}
void Level::SetLevelFarView(byte val)
void Level::SetLevelFarView(short val)
{
bool cond = val <= 127 && val >= 1;
bool cond = val <= 255 && val >= 1;
std::string msg{ "levelFarView value must be in the range [1, 127]." };
if (!ScriptAssert(cond, msg))
{
@ -258,3 +258,9 @@ short Level::GetFogMaxDistance() const
{
return Fog.MaxDistance;
}
short Level::GetFarView() const
{
return float(LevelFarView);
}

View file

@ -49,10 +49,11 @@ struct Level : public ScriptInterfaceLevel
RGBAColor8Byte GetSkyLayerColor(int index) const override;
LaraType GetLaraType() const override;
void SetWeatherStrength(float val);
void SetLevelFarView(byte val);
void SetLevelFarView(short val);
static void Register(sol::table & parent);
WeatherType GetWeatherType() const override;
short GetMirrorRoom() const override;
short GetFogMinDistance() const override;
short GetFogMaxDistance() const override;
short GetFarView() const override;
};

View file

@ -121,6 +121,7 @@ static std::unique_ptr<Moveable> Create(
ptr->SetHP(USE_IF_HAVE(short, hp, 10));
ptr->SetOCB(USE_IF_HAVE(short, ocb, 0));
ptr->SetAIBits(USE_IF_HAVE(aiBitsType, aiBits, aiBitsType{}));
ptr->SetColor(ScriptColor(Vector4::One));
item->CarriedItem = NO_ITEM;
// call this when resetting name too?

View file

@ -31,12 +31,11 @@ PixelShaderInput VS(VertexShaderInput input)
output.Normal = (mul(float4(input.Normal, 0.0f), World).xyz);
output.Color = input.Color;
output.UV = input.UV;
output.WorldPosition = (mul(float4(input.Position, 1.0f), World));
output.WorldPosition = (mul(float4(input.Position, 1.0f), World).xyz);
output.Sheen = input.Effects.w;
return output;
}
[earlydepthstencil]
float4 PS(PixelShaderInput input) : SV_TARGET
{
float4 output = Texture.Sample(Sampler, input.UV);

View file

@ -1,46 +1,39 @@
#include "./Math.hlsli"
#include "./CameraMatrixBuffer.hlsli"
#include "./ShaderLight.hlsli"
#include "./VertexEffects.hlsli"
#include "./VertexInput.hlsli"
#include "./AlphaTestBuffer.hlsli"
#define MAX_BONES 32
cbuffer ItemBuffer : register(b1)
{
float4x4 World;
float4x4 Bones[32];
float4x4 Bones[MAX_BONES];
float4 ItemPosition;
float4 AmbientLight;
};
cbuffer LightsBuffer : register(b2)
{
ShaderLight Lights[MAX_LIGHTS];
int NumLights;
float3 CameraPosition;
};
cbuffer MiscBuffer : register(b3)
{
int Caustics;
int4 BoneLightModes[MAX_BONES / 4];
};
struct PixelShaderInput
{
float4 Position: SV_POSITION;
float3 Normal: NORMAL;
float3 WorldPosition : POSITION;
float3 WorldPosition: POSITION;
float2 UV: TEXCOORD;
float4 Color: COLOR;
float Sheen : SHEEN;
float3x3 TBN : TBN;
float Fog : FOG;
float4 PositionCopy : TEXCOORD2;
float Sheen: SHEEN;
float3x3 TBN: TBN;
float Fog: FOG;
float4 PositionCopy: TEXCOORD2;
uint Bone: BONE;
};
struct PixelShaderOutput
{
float4 Color: SV_Target0;
float4 Depth: SV_Target1;
float4 Color: SV_TARGET0;
float4 Depth: SV_TARGET1;
};
Texture2D Texture : register(t0);
@ -56,46 +49,29 @@ PixelShaderInput VS(VertexShaderInput input)
float4x4 world = mul(Bones[input.Bone], World);
float3 Normal = (mul(float4(input.Normal, 0.0f), world).xyz);
float3 WorldPosition = (mul(float4(input.Position, 1.0f), world));
float3 normal = (mul(float4(input.Normal, 0.0f), world).xyz);
float3 worldPosition = (mul(float4(input.Position, 1.0f), world).xyz);
output.Normal = Normal;
output.Normal = normal;
output.UV = input.UV;
output.WorldPosition = WorldPosition;
output.WorldPosition = worldPosition;
float3 Tangent = mul(float4(input.Tangent, 0), world).xyz;
float3 Bitangent = mul(float4(input.Bitangent, 0), world).xyz;
float3x3 TBN = float3x3(Tangent, Bitangent, Normal);
float3 Bitangent = cross(normal, Tangent);
float3x3 TBN = float3x3(Tangent, Bitangent, normal);
output.TBN = transpose(TBN);
float3 pos = input.Position;
float4 col = input.Color;
// Setting effect weight on TE side prevents portal vertices from moving.
// Here we just read weight and decide if we should apply refraction or movement effect.
float weight = input.Effects.z;
// Wibble effect returns different value depending on vertex hash and frame number.
// In theory, hash could be affected by WaterScheme value from room.
float wibble = sin((((Frame + input.Hash) % 256) / 256.0) * (PI2)); // sin from -1 to 1 with a period of 64 frames
// Glow
if (input.Effects.x > 0.0f)
{
float intensity = input.Effects.x * lerp(-0.5f, 1.0f, wibble * 0.5f + 0.5f);
col = saturate(col + float4(intensity, intensity, intensity, 0));
}
// Movement
if (input.Effects.y > 0.0f)
pos.y += wibble * input.Effects.y * weight * 128.0f; // 128 units offset to top and bottom (256 total)
// Calculate vertex effects
float wibble = Wibble(input.Effects.xyz, input.Hash);
float3 pos = Move(input.Position, input.Effects.xyz, wibble);
float3 col = Glow(input.Color.xyz, input.Effects.xyz, wibble);
output.Position = mul(mul(float4(pos, 1.0f), world), ViewProjection);
output.Color = col;
output.Color = float4(col, input.Color.w);
// Apply distance fog
float d = distance(CamPositionWS.xyz,WorldPosition);
float d = distance(CamPositionWS.xyz, worldPosition);
if (FogMaxDistance == 0)
output.Fog = 1;
else
@ -103,62 +79,32 @@ PixelShaderInput VS(VertexShaderInput input)
output.PositionCopy = output.Position;
output.Sheen = input.Effects.w;
output.Bone = input.Bone;
return output;
}
PixelShaderOutput PS(PixelShaderInput input) : SV_TARGET
PixelShaderOutput PS(PixelShaderInput input)
{
PixelShaderOutput output;
float4 tex = Texture.Sample(Sampler, input.UV);
float4 tex = Texture.Sample(Sampler, input.UV);
DoAlphaTest(tex);
float3 ambient = AmbientLight.xyz * tex.xyz;
float3 normal = NormalTexture.Sample(Sampler, input.UV).rgb;
normal = normal * 2 - 1;
normal = normalize(mul(input.TBN, normal));
float3 diffuse = 0;
float3 spec = 0;
for (int i = 0; i < NumLights; i++)
{
int lightType = Lights[i].Type;
float3 color = (BoneLightModes[input.Bone / 4][input.Bone % 4] == 0) ?
CombineLights(AmbientLight.xyz, input.Color.xyz, tex.xyz, input.WorldPosition, normal, input.Sheen) :
StaticLight(AmbientLight.xyz, input.Color.xyz, tex.xyz);
if (lightType == LT_POINT || lightType == LT_SHADOW)
{
diffuse += DoPointLight(input.WorldPosition, normal, Lights[i]);
spec += DoSpecularPoint(input.WorldPosition, normal, Lights[i], input.Sheen);
output.Color = saturate(float4(color, tex.w));
}
else if (lightType == LT_SUN)
{
diffuse += DoDirectionalLight(input.WorldPosition, normal, Lights[i]);
spec += DoSpecularSun(normal, Lights[i], input.Sheen);
}
else if (lightType == LT_SPOT)
{
diffuse += DoSpotLight(input.WorldPosition, normal, Lights[i]);
spec += DoSpecularSpot(input.WorldPosition, normal, Lights[i], input.Sheen);
}
}
diffuse.xyz *= tex.xyz;
output.Depth = tex.w > 0.0f ?
float4(input.PositionCopy.z / input.PositionCopy.w, 0.0f, 0.0f, 1.0f) :
float4(0.0f, 0.0f, 0.0f, 0.0f);
output.Color = float4(ambient + diffuse + spec, tex.w);
float3 colorMul = min(input.Color.xyz, 1.0f);
output.Color.xyz *= colorMul.xyz;
if (FogMaxDistance != 0)
{
output.Color.xyz = lerp(output.Color.xyz, FogColor.xyz, input.Fog);
}
return output;
}

View file

@ -1,17 +1,12 @@
#include "./CameraMatrixBuffer.hlsli"
#include "./VertexInput.hlsli"
#include "./VertexEffects.hlsli"
#include "./Math.hlsli"
#include "./ShaderLight.hlsli"
#include "./AlphaTestBuffer.hlsli"
#define SHADOW_INTENSITY (0.55f)
#define INV_SHADOW_INTENSITY (1.0f-SHADOW_INTENSITY)
cbuffer LightsBuffer : register(b2)
{
ShaderLight Lights[MAX_LIGHTS];
int NumLights;
float3 Padding;
};
#define SHADOW_INTENSITY (0.55f)
#define INV_SHADOW_INTENSITY (1.0f - SHADOW_INTENSITY)
struct Sphere
{
@ -22,7 +17,6 @@ struct Sphere
cbuffer MiscBuffer : register(b3)
{
int Caustics;
};
cbuffer ShadowLightBuffer : register(b4)
@ -38,7 +32,7 @@ cbuffer ShadowLightBuffer : register(b4)
cbuffer RoomBuffer : register(b5)
{
float4 AmbientColor;
int Water;
uint Water;
};
struct AnimatedFrameUV
@ -79,38 +73,27 @@ SamplerComparisonState ShadowMapSampler : register(s3);
struct PixelShaderOutput
{
float4 Color: SV_Target0;
float4 Depth: SV_Target1;
float4 Color: SV_TARGET0;
float4 Depth: SV_TARGET1;
};
PixelShaderInput VS(VertexShaderInput input)
{
PixelShaderInput output;
float3 pos = input.Position;
float4 col = input.Color;
// Setting effect weight on TE side prevents portal vertices from moving.
// Here we just read weight and decide if we should apply refraction or movement effect.
float weight = input.Effects.z;
// Wibble effect returns different value depending on vertex hash and frame number.
// In theory, hash could be affected by WaterScheme value from room.
float wibble = sin((((Frame + input.Hash) % 64) / 64.0) * (PI2)); // sin from -1 to 1 with a period of 64 frames
// Glow
if (input.Effects.x > 0.0f)
{
float intensity = input.Effects.x * lerp(-0.5f, 1.0f, wibble * 0.5f + 0.5f);
col = saturate(col + float4(intensity, intensity, intensity, 0));
}
// Movement
if (input.Effects.y > 0.0f)
pos.y += wibble * input.Effects.y * weight * 128.0f; // 128 units offset to top and bottom (256 total)
// Calculate vertex effects
float wibble = Wibble(input.Effects.xyz, input.Hash);
float3 pos = Move(input.Position, input.Effects.xyz * weight, wibble);
float3 col = Glow(input.Color.xyz, input.Effects.xyz, wibble);
// Refraction
float4 screenPos = mul(float4(pos, 1.0f), ViewProjection);
float2 clipPos = screenPos.xy / screenPos.w;
if (CameraUnderwater != Water)
{
float factor = (Frame + clipPos.x * 320);
@ -122,12 +105,12 @@ PixelShaderInput VS(VertexShaderInput input)
output.Position = screenPos;
output.Normal = input.Normal;
output.Color = col;
output.Color = float4(col, input.Color.w);
output.PositionCopy = screenPos;
#ifdef ANIMATED
float speed = fps / 30.0f;
int frame = (int)(Frame * speed) % numAnimFrames;
int frame = (int)(Frame * speed + input.AnimationFrameOffset) % numAnimFrames;
switch (input.PolyIndex) {
case 0:
output.UV = AnimFrames[frame].topLeft;
@ -144,16 +127,15 @@ PixelShaderInput VS(VertexShaderInput input)
}
#else
output.UV = input.UV;
#endif
output.WorldPosition = input.Position.xyz;
float3x3 TBN = float3x3(input.Tangent, input.Bitangent, input.Normal);
float3x3 TBN = float3x3(input.Tangent, cross(input.Normal,input.Tangent), input.Normal);
output.TBN = TBN;
// Apply distance fog
float4 d = length(CamPositionWS - output.WorldPosition);
float d = length(CamPositionWS.xyz - output.WorldPosition);
if (FogMaxDistance == 0)
output.Fog = 1;
else
@ -287,7 +269,6 @@ void doBlobShadows(float3 worldPos, inout float3 lighting)
}
shadowFactor = saturate(shadowFactor);
lighting *= saturate((shadowFactor+SHADOW_INTENSITY));
}
void doSpotLightShadow(float3 worldPos,inout float3 lighting)
@ -319,7 +300,8 @@ void doSpotLightShadow(float3 worldPos,inout float3 lighting)
float angleFactor = min(max(sin(lightClipSpace.x * PI)*1.2, 0), 1);
lighting *= saturate((shadowFactor + SHADOW_INTENSITY) + (pow(distanceFactor, 4) * (1 - angleFactor) * INV_SHADOW_INTENSITY));
}
PixelShaderOutput PS(PixelShaderInput input) : SV_TARGET
PixelShaderOutput PS(PixelShaderInput input)
{
PixelShaderOutput output;
@ -329,7 +311,7 @@ PixelShaderOutput PS(PixelShaderInput input) : SV_TARGET
float3 Normal = NormalTexture.Sample(Sampler,input.UV).rgb;
Normal = Normal * 2 - 1;
Normal = normalize(mul(Normal,input.TBN));
Normal = normalize(mul(Normal, input.TBN));
float3 lighting = input.Color.xyz;
bool doLights = true;
@ -352,7 +334,7 @@ PixelShaderOutput PS(PixelShaderInput input) : SV_TARGET
if (doLights)
{
for (uint i = 0; i < NumLights; i++)
for (int i = 0; i < NumLights; i++)
{
float3 lightPos = Lights[i].Position.xyz;
float3 color = Lights[i].Color.xyz;
@ -395,17 +377,17 @@ PixelShaderOutput PS(PixelShaderInput input) : SV_TARGET
float3 yaxis = CausticsTexture.Sample(Sampler, p.xz).xyz;
float3 zaxis = CausticsTexture.Sample(Sampler, p.xy).xyz;
lighting += float4((xaxis * blending.x + yaxis * blending.y + zaxis * blending.z).xyz, 0.0f) * attenuation * 2.0f;
lighting += float3((xaxis * blending.x + yaxis * blending.y + zaxis * blending.z).xyz) * attenuation * 2.0f;
}
output.Color.xyz = output.Color.xyz * lighting;
output.Color.xyz = saturate(output.Color.xyz * lighting);
output.Depth = output.Color.w > 0.0f ?
float4(input.PositionCopy.z / input.PositionCopy.w, 0.0f, 0.0f, 1.0f) :
float4(0.0f, 0.0f, 0.0f, 0.0f);
if (FogMaxDistance != 0)
output.Color.xyz = lerp(output.Color.xyz, FogColor, input.Fog);
output.Color.xyz = lerp(output.Color.xyz, FogColor.xyz, input.Fog);
return output;
}

View file

@ -5,7 +5,7 @@
cbuffer StaticMatrixBuffer : register(b8)
{
float4x4 World;
float4 StaticPosition;
float4 Position;
float4 Color;
};

View file

@ -1,4 +1,7 @@
#include "./Math.hlsli"
#include "./CameraMatrixBuffer.hlsli"
#include "./ShaderLight.hlsli"
#include "./VertexEffects.hlsli"
#include "./VertexInput.hlsli"
#include "./AlphaTestBuffer.hlsli"
@ -7,22 +10,25 @@ cbuffer StaticMatrixBuffer : register(b8)
float4x4 World;
float4 Position;
float4 Color;
int LightType;
};
struct PixelShaderInput
{
float4 Position: SV_POSITION;
float3 Normal: NORMAL;
float3 WorldPosition: POSITION;
float2 UV: TEXCOORD1;
float4 Color: COLOR;
float Fog : FOG;
float Sheen: SHEEN;
float Fog: FOG;
float4 PositionCopy: TEXCOORD2;
};
struct PixelShaderOutput
{
float4 Color: SV_Target0;
float4 Depth: SV_Target1;
float4 Color: SV_TARGET0;
float4 Depth: SV_TARGET1;
};
Texture2D Texture : register(t0);
@ -32,13 +38,18 @@ PixelShaderInput VS(VertexShaderInput input)
{
PixelShaderInput output;
float4 worldPosition = mul(float4(input.Position, 1.0f), World);
float4 worldPosition = (mul(float4(input.Position, 1.0f), World));
float3 normal = (mul(float4(input.Normal, 0.0f), World).xyz);
output.Position = mul(worldPosition, ViewProjection);
output.Normal = input.Normal;
output.Color = input.Color * Color;
output.Normal = normal;
output.UV = input.UV;
output.PositionCopy = output.Position;
output.WorldPosition = worldPosition;
float3 pos = Move(input.Position, input.Effects.xyz, input.Hash);
float3 col = Glow(input.Color.xyz, input.Effects.xyz, input.Hash);
output.Position = mul(worldPosition, ViewProjection);
output.Color = float4(col, input.Color.w);
// Apply distance fog
float4 d = length(CamPositionWS - worldPosition);
@ -46,27 +57,31 @@ PixelShaderInput VS(VertexShaderInput input)
output.Fog = 1;
else
output.Fog = clamp((d - FogMinDistance * 1024) / (FogMaxDistance * 1024 - FogMinDistance * 1024), 0, 1);
output.PositionCopy = output.Position;
output.Sheen = input.Effects.w;
return output;
}
PixelShaderOutput PS(PixelShaderInput input) : SV_TARGET
PixelShaderOutput PS(PixelShaderInput input)
{
PixelShaderOutput output;
output.Color = Texture.Sample(Sampler, input.UV);
DoAlphaTest(output.Color);
float4 tex = Texture.Sample(Sampler, input.UV);
DoAlphaTest(tex);
float3 colorMul = min(input.Color.xyz, 1.0f);
output.Color.xyz = output.Color.xyz * colorMul.xyz;
float3 color = (LightType == 0) ?
CombineLights(Color.xyz, input.Color.xyz, tex.xyz, input.WorldPosition, normalize(input.Normal), input.Sheen) :
StaticLight(Color.xyz, input.Color.xyz, tex.xyz);
output.Depth = output.Color.w > 0.0f ?
output.Color = float4(color, tex.w);
output.Depth = tex.w > 0.0f ?
float4(input.PositionCopy.z / input.PositionCopy.w, 0.0f, 0.0f, 1.0f) :
float4(0.0f, 0.0f, 0.0f, 0.0f);
if (FogMaxDistance != 0)
output.Color.xyz = lerp(output.Color.xyz, FogColor, input.Fog);
output.Color.xyz = lerp(output.Color.xyz, FogColor.xyz, input.Fog);
return output;
}

View file

@ -1,3 +1,2 @@
#pragma once
#define PI 3.1415926535897932384626433832795028841971693993751058209749445923
#define PI2 6.2831853071795864769252867665590057683943387987502116419498891846

View file

@ -1,3 +1,4 @@
#include "./Math.hlsli"
#define LT_SUN 0
#define LT_POINT 1
@ -5,139 +6,159 @@
#define LT_SHADOW 3
#define MAX_LIGHTS 48
#define SPEC_FACTOR 64
struct ShaderLight
{
float3 Position;
int Type;
uint Type;
float3 Color;
float LocalIntensity;
float3 Direction;
float Distance;
float Intensity;
float3 Direction;
float In;
float Out;
float Range;
float InRange;
float OutRange;
float padding;
};
cbuffer LightsBuffer : register(b2)
{
ShaderLight Lights[MAX_LIGHTS];
int NumLights;
};
float3 DoSpecularPoint(float3 pos, float3 n, ShaderLight light, float strength)
{
if (!(strength > 0.0))
{
return float3(0, 0, 0);
}
float3 lightPos = light.Position.xyz;
float radius = light.Out;
if ((strength <= 0.0))
return float3(0, 0, 0);
else
{
float3 lightPos = light.Position.xyz;
float radius = light.Out;
float dist = distance(lightPos, pos);
if (dist > radius)
{
return float3(0, 0, 0);
}
float3 lightDir = normalize(lightPos - pos);
float3 reflectDir = reflect(lightDir, n);
float3 color = light.Color.xyz;
float spec = pow(saturate(dot(CamDirectionWS.xyz, reflectDir)), strength * 64);
float attenuation = (radius - dist) / radius;
return attenuation * spec * color;
float dist = distance(lightPos, pos);
if (dist > radius)
return float3(0, 0, 0);
else
{
float3 lightDir = normalize(lightPos - pos);
float3 reflectDir = reflect(lightDir, n);
float3 color = light.Color.xyz;
float spec = pow(saturate(dot(CamDirectionWS.xyz, reflectDir)), strength * SPEC_FACTOR);
float attenuation = (radius - dist) / radius;
return attenuation * spec * color;
}
}
}
float3 DoSpecularSun(float3 n, ShaderLight light, float strength)
{
if (!(strength > 0.0))
{
return float3(0, 0, 0);
}
float3 lightDir = normalize(light.Direction);
float3 reflectDir = reflect(lightDir, n);
float3 color = light.Color.xyz;
float spec = pow(saturate(dot(CamDirectionWS.xyz, reflectDir)), strength * 64);
return spec * color;
if (strength <= 0.0)
return float3(0, 0, 0);
else
{
float3 lightDir = normalize(light.Direction);
float3 reflectDir = reflect(lightDir, n);
float3 color = light.Color.xyz;
float spec = pow(saturate(dot(CamDirectionWS.xyz, reflectDir)), strength * SPEC_FACTOR);
return spec * color;
}
}
float3 DoSpecularSpot(float3 pos, float3 n, ShaderLight light, float strength)
{
if (!(strength > 0.0))
{
return float3(0, 0, 0);
}
float3 lightPos = light.Position.xyz;
float radius = light.Range;
if (strength <= 0.0)
return float3(0, 0, 0);
else
{
float3 lightPos = light.Position.xyz;
float radius = light.OutRange;
float dist = distance(lightPos, pos);
if (dist > radius)
{
return float3(0, 0, 0);
}
float3 lightDir = normalize(lightPos - pos);
float3 reflectDir = reflect(lightDir, n);
float3 color = light.Color.xyz;
float spec = pow(saturate(dot(CamDirectionWS.xyz, reflectDir)), strength * 64);
float attenuation = (radius - dist) / radius;
return attenuation * spec * color;
float dist = distance(lightPos, pos);
if (dist > radius)
return float3(0, 0, 0);
else
{
float3 lightDir = normalize(lightPos - pos);
float3 reflectDir = reflect(lightDir, n);
float3 color = light.Color.xyz;
float spec = pow(saturate(dot(CamDirectionWS.xyz, reflectDir)), strength * SPEC_FACTOR);
float attenuation = (radius - dist) / radius;
return attenuation * spec * color;
}
}
}
float3 DoPointLight(float3 pos, float3 n, ShaderLight light)
{
float3 lightPos = light.Position.xyz;
float3 color = light.Color.xyz;
float intensity = light.Intensity;
float radius = light.Out;
float3 lightVec = (lightPos - pos);
float distance = length(lightVec);
if (distance > radius)
{
return float3(0, 0, 0);
else
{
lightVec = normalize(lightVec);
float d = saturate(dot(n, lightVec));
float attenuation = ((radius - distance) / radius);
return saturate(color * intensity * attenuation * d);
}
lightVec = normalize(lightVec);
float d = saturate(dot(n, lightVec));
float attenuation = ((radius - distance) / radius);
return (color * attenuation * d);
}
float3 DoSpotLight(float3 pos, float3 n, ShaderLight light)
{
float3 lightPos = light.Position.xyz;
float3 color = light.Color.xyz;
float3 direction = -light.Direction.xyz;
float range = light.Range;
float inAngle = light.In;
float outAngle = light.Out;
float intensity = light.Intensity;
float3 direction = -light.Direction.xyz;;
float innerRange = light.In;
float outerRange = light.Out;
float coneIn = light.InRange;
float coneOut = light.OutRange;
float3 lightVec = (lightPos - pos);
float distance = length(lightVec);
if (distance > range)
{
if (distance > outerRange)
return float3(0, 0, 0);
}
lightVec = normalize(lightVec);
float inCone = acos(dot(lightVec, direction));
if (inCone < outAngle)
else
{
return float3(0, 0, 0);
lightVec = normalize(lightVec);
float d = saturate(dot(n, lightVec));
if (d < 0)
return float3(0, 0, 0);
else
{
float cosine = dot(-lightVec, direction);
float minCosineIn = cos(coneIn * (PI / 180.0f));
float attenuationIn = max((cosine - minCosineIn), 0.0f) / (1.0f - minCosineIn);
float minCosineOut = cos(coneOut * (PI / 180.0f));
float attenuationOut = max((cosine - minCosineOut), 0.0f) / (1.0f - minCosineOut);
float attenuation = saturate(attenuationIn * 2.0f + attenuationOut);
if (attenuation > 0.0f)
{
float falloff = saturate((outerRange - distance) / (outerRange - innerRange + 1.0f));
return saturate(color * intensity * attenuation * falloff * d);
}
else
return float3(0, 0, 0);
}
}
float attenuation = 1;
float d = saturate(dot(n, lightVec));
if (d < 0)
{
return float3(0, 0, 0);
}
return (color * attenuation * d);
}
float3 DoDirectionalLight(float3 pos, float3 n, ShaderLight light)
@ -148,10 +169,54 @@ float3 DoDirectionalLight(float3 pos, float3 n, ShaderLight light)
direction = normalize(direction);
float d = dot(n, direction);
if (d < 0)
{
return float3(0, 0, 0);
else
return (color * d);
}
float Luma(float3 color)
{
// Use Rec.709 trichromat formula to get perceptive luma value
return float((color.x * 0.2126f) + (color.y * 0.7152f) + (color.z * 0.0722f));
}
float3 CombineLights(float3 ambient, float3 vertex, float3 tex, float3 pos, float3 normal, float sheen)
{
float3 ambTex = ambient * tex;
float3 diffuse = 0;
float3 spec = 0;
for (int i = 0; i < NumLights; i++)
{
int lightType = Lights[i].Type;
if (lightType == LT_POINT || lightType == LT_SHADOW)
{
diffuse += DoPointLight(pos, normal, Lights[i]);
spec += DoSpecularPoint(pos, normal, Lights[i], sheen);
}
else if (lightType == LT_SUN)
{
diffuse += DoDirectionalLight(pos, normal, Lights[i]);
spec += DoSpecularSun(normal, Lights[i], sheen);
}
else if (lightType == LT_SPOT)
{
diffuse += DoSpotLight(pos, normal, Lights[i]);
spec += DoSpecularSpot(pos, normal, Lights[i], sheen);
}
}
return (color * d);
diffuse.xyz *= tex.xyz;
float3 combined = ambTex + diffuse + spec;
return saturate(combined * vertex);
}
float3 StaticLight(float3 ambient, float3 vertex, float3 tex)
{
return saturate(ambient * tex * vertex);
}

View file

@ -0,0 +1,37 @@
#include "./Math.hlsli"
#define WIBBLE_FRAME_PERIOD 64.0f
float Wibble(float3 effect, int hash)
{
if (effect.x > 0.0f || effect.y > 0.0f)
return sin((((Frame + hash) % 256) / WIBBLE_FRAME_PERIOD) * (PI2));
else
return 0.0f; // Don't calculate if not necessary
}
float3 Glow(float3 color, float3 effect, float wibble)
{
float3 col = color;
if (effect.x > 0.0f)
{
float intensity = effect.x * lerp(-0.5f, 1.0f, wibble * 0.5f + 0.5f);
col = color + float3(intensity, intensity, intensity);
}
return col;
}
float3 Move(float3 position, float3 effect, float wibble)
{
float3 pos = position;
float weight = effect.z;
if (effect.y > 0.0f && weight > 0.0f)
{
pos.y += wibble * effect.y * weight * 128.0f; // 128 units offset to top and bottom (256 total)
}
return pos;
}

View file

@ -4,7 +4,7 @@ struct VertexShaderInput {
float2 UV: TEXCOORD0;
float4 Color: COLOR0;
float3 Tangent: TANGENT0;
float3 Bitangent: BITANGENT0;
uint AnimationFrameOffset: ANIMATIONFRAMEOFFSET;
float4 Effects: EFFECTS;
float Bone: BLENDINDICES;
uint PolyIndex : POLYINDEX;

View file

@ -442,17 +442,33 @@ namespace TEN::Input
{
// Switch debug pages
static int debugTimeout = 0;
static bool rawDebounce1 = false;
if (KeyMap[KC_F10] || KeyMap[KC_F11])
{
if (debugTimeout == 0)
if (!rawDebounce1)
{
debugTimeout = 1;
rawDebounce1 = true;
g_Renderer.SwitchDebugPage(KeyMap[KC_F10]);
}
}
else
debugTimeout = 0;
rawDebounce1 = false;
// Toggle full screen
static bool rawDebounce2 = false;
if ((KeyMap[KC_LMENU] || KeyMap[KC_RMENU]) && KeyMap[KC_RETURN])
{
if (!rawDebounce2)
{
rawDebounce2 = true;
g_Configuration.Windowed = !g_Configuration.Windowed;
SaveConfiguration();
g_Renderer.ToggleFullScreen();
}
}
else
rawDebounce2 = false;
// Handle flares

View file

@ -111,6 +111,18 @@ void ReadBytes(void* dest, int count)
LevelDataPtr += count;
}
std::string ReadString()
{
byte numBytes = ReadInt8(); // FIXME: incorrect, should be read in LEB128 format
if (!numBytes)
return std::string();
char buffer[255];
ReadBytes(buffer, numBytes);
return std::string(buffer, buffer + numBytes);
}
void LoadItems()
{
g_Level.NumItems = ReadInt32();
@ -139,11 +151,7 @@ void LoadItems()
item->Color = ReadVector4();
item->TriggerFlags = ReadInt16();
item->Flags = ReadInt16();
byte numBytes = ReadInt8();
char buffer[255];
ReadBytes(buffer, numBytes);
item->LuaName = std::string(buffer, buffer + numBytes);
item->LuaName = ReadString();
g_GameScriptEntities->AddName(item->LuaName, i);
g_GameScriptEntities->TryAddColliding(i);
@ -169,7 +177,7 @@ void LoadObjects()
{
MESH mesh;
mesh.LightMode = ReadInt8();
mesh.lightMode = ReadInt8();
mesh.sphere.Center.x = ReadFloat();
mesh.sphere.Center.y = ReadFloat();
@ -384,11 +392,7 @@ void LoadCameras()
camera.roomNumber = ReadInt32();
camera.flags = ReadInt32();
camera.speed = ReadInt32();
byte numBytes = ReadInt8();
char buffer[255];
ReadBytes(buffer, numBytes);
camera.luaName = std::string(buffer, buffer + numBytes);
camera.luaName = ReadString();
g_GameScriptEntities->AddName(camera.luaName, camera);
}
@ -641,14 +645,14 @@ void ReadRooms()
ROOM_DOOR door;
door.room = ReadInt16();
door.normal.x = ReadInt16();
door.normal.y = ReadInt16();
door.normal.z = ReadInt16();
door.normal.x = ReadInt32();
door.normal.y = ReadInt32();
door.normal.z = ReadInt32();
for (int k = 0; k < 4; k++)
{
door.vertices[k].x = ReadInt16();
door.vertices[k].y = ReadInt16();
door.vertices[k].z = ReadInt16();
door.vertices[k].x = ReadInt32();
door.vertices[k].y = ReadInt32();
door.vertices[k].z = ReadInt32();
}
room.doors.push_back(door);
@ -748,11 +752,7 @@ void ReadRooms()
mesh.color = ReadVector4();
mesh.staticNumber = ReadUInt16();
mesh.HitPoints = ReadInt16();
byte numBytes = ReadInt8();
char buffer[255];
ReadBytes(buffer, numBytes);
mesh.luaName = std::string(buffer, buffer + numBytes);
mesh.luaName = ReadString();
g_GameScriptEntities->AddName(mesh.luaName, mesh);
}
@ -986,7 +986,7 @@ void LoadAIObjects()
obj.triggerFlags = ReadInt16();
obj.flags = ReadInt16();
obj.yRot = ReadInt16();
obj.boxNumber = ReadInt16();
obj.boxNumber = ReadInt32();
byte numBytes = ReadInt8();
char buffer[255];
@ -1003,13 +1003,7 @@ void LoadLuaFunctionNames()
int luaFunctionsCount = ReadInt32();
for (int i = 0; i < luaFunctionsCount; i++)
{
byte numBytes = ReadInt8();
char buffer[255];
ReadBytes(buffer, numBytes);
auto luaFunctionName = std::string(buffer, buffer + numBytes);
g_Level.LuaFunctionNames.push_back(luaFunctionName);
}
g_Level.LuaFunctionNames.push_back(ReadString());
}
FILE* FileOpen(const char* fileName)

View file

@ -72,7 +72,7 @@ struct AI_OBJECT
short triggerFlags;
short flags;
short yRot;
short boxNumber;
int boxNumber;
std::string luaName;
};
@ -91,7 +91,7 @@ struct SPRITE
struct MESH
{
byte LightMode;
int lightMode;
BoundingSphere sphere;
std::vector<Vector3> positions;
std::vector<Vector3> normals;

View file

@ -1,6 +1,10 @@
#include "framework.h"
#include "phd_global.h"
const Vector2Int Vector2Int::Zero = Vector2Int(0, 0);
const Vector3Int Vector3Int::Zero = Vector3Int(0, 0, 0);
const Vector3Shrt Vector3Shrt::Zero = Vector3Shrt(0, 0, 0);
BOUNDING_BOX operator+(BOUNDING_BOX const & box, PHD_3DPOS const & vec)
{
BOUNDING_BOX box2 = box;

View file

@ -1,14 +1,17 @@
#pragma once
// TODO: Possibly rename these vector structs to more common standards later:
// Vector2i, Vector3i, Vector3s. -- Sezz 2022.07.23
struct Vector2Int
{
int x;
int y;
static const Vector2Int Zero;
Vector2Int()
{
this->x = 0;
this->y = 0;
*this = Vector2Int::Zero;
}
Vector2Int(int x, int y)
@ -24,6 +27,25 @@ struct Vector3Int
int y;
int z;
static const Vector3Int Zero;
Vector3Int()
{
*this = Vector3Int::Zero;
}
Vector3Int(int x, int y, int z)
{
this->x = x;
this->y = y;
this->z = z;
}
Vector3 ToVector3()
{
return Vector3(x, y, z);
}
bool operator ==(Vector3Int vector)
{
return (x == vector.x && y == vector.y && z == vector.z);
@ -96,15 +118,22 @@ struct Vector3Int
*this = *this / value;
return *this;
}
};
Vector3Int()
struct Vector3Shrt
{
short x;
short y;
short z;
static const Vector3Shrt Zero;
Vector3Shrt()
{
this->x = 0;
this->y = 0;
this->z = 0;
*this = Vector3Shrt::Zero;
}
Vector3Int(int x, int y, int z)
Vector3Shrt(short x, short y, short z)
{
this->x = x;
this->y = y;
@ -122,13 +151,6 @@ struct Vector3Int
{
return Vector3(x, y, z);
}
};
struct Vector3Shrt
{
short x;
short y;
short z;
bool operator ==(Vector3Shrt vector)
{
@ -202,25 +224,6 @@ struct Vector3Shrt
*this = *this / value;
return *this;
}
Vector3Shrt()
{
this->x = 0;
this->y = 0;
this->z = 0;
}
Vector3Shrt(short x, short y, short z)
{
this->x = x;
this->y = y;
this->z = z;
}
Vector3 ToVector3()
{
return Vector3(x, y, z);
}
};
struct RendererRectangle
@ -247,38 +250,40 @@ struct RendererRectangle
}
};
// TODO: Rename to PoseData (or something else that specifically describes a position + orientation representation, if we prefer).
// This struct has changed vastly and the old name is no longer appropriate. -- Sezz 2022.07.23
struct PHD_3DPOS
{
Vector3Int Position;
Vector3Int Position;
Vector3Shrt Orientation;
PHD_3DPOS()
{
this->Position = Vector3Int();
this->Orientation = Vector3Shrt();
this->Position = Vector3Int::Zero;
this->Orientation = Vector3Shrt::Zero;
}
PHD_3DPOS(Vector3Int pos)
{
this->Position = pos;
this->Orientation = Vector3Shrt();
this->Orientation = Vector3Shrt::Zero;
}
PHD_3DPOS(int xPos, int yPos, int zPos)
{
this->Position = Vector3Int(xPos, yPos, zPos);
this->Orientation = Vector3Shrt();
this->Orientation = Vector3Shrt::Zero;
}
PHD_3DPOS(Vector3Shrt orient)
{
this->Position = Vector3Int();
this->Position = Vector3Int::Zero;
this->Orientation = orient;
}
PHD_3DPOS(short xOrient, short yOrient, short zOrient)
{
this->Position = Vector3Int();
this->Position = Vector3Int::Zero;
this->Orientation = Vector3Shrt(xOrient, yOrient, zOrient);
}

View file

@ -286,6 +286,12 @@ const float Smoothstep(float edge0, float edge1, float x)
return x * x * (3 - 2 * x);
}
const float Luma(Vector3 color)
{
// Use Rec.709 trichromat formula to get perceptive luma value
return (float)((color.x * 0.2126f) + (color.y * 0.7152f) + (color.z * 0.0722f));
}
Vector3 TranslateVector(Vector3 vector, short angle, float forward, float up, float right)
{
if (forward == 0.0f && up == 0.0f && right == 0.0f)

View file

@ -16,9 +16,9 @@ constexpr auto WADE_DEPTH = STEPUP_HEIGHT;
constexpr auto SHALLOW_WATER_START_LEVEL = STEP_SIZE / 4;
constexpr auto BAD_JUMP_CEILING = ((STEP_SIZE * 3) / 4);
constexpr auto SLOPE_DIFFERENCE = 60;
constexpr auto NO_HEIGHT = (-0x7F00);
constexpr auto MAX_HEIGHT = (-0x7FFF);
constexpr auto DEEP_WATER = 0x7FFF;
constexpr auto NO_HEIGHT = INT_MIN + UCHAR_MAX;
constexpr auto MAX_HEIGHT = INT_MIN + 1; // Add 1 to prevent issue with sign changes
constexpr auto DEEP_WATER = INT_MAX - 1; // Subtract 1 to prevent issue with sign changes
constexpr auto SQUARE = [](auto x) { return x * x; };
constexpr auto CLICK = [](auto x) { return STEP_SIZE * x; };
@ -68,6 +68,7 @@ Vector3Int* FP_Normalise(Vector3Int* v);
const float Lerp(float v0, float v1, float t);
const float Smoothstep(float edge0, float edge1, float x);
const float Luma(Vector3 color);
Vector3 TranslateVector(Vector3 vector, short angle, float forward, float up = 0.0f, float right = 0.0f);
Vector3Int TranslateVector(Vector3Int vector, short angle, float forward, float up = 0.0f, float right = 0.0f);

View file

@ -0,0 +1,43 @@
#include "framework.h"
#include "Specific/trutils.h"
#include <codecvt>
namespace TEN::Utils
{
std::string ToLower(std::string source)
{
std::transform(source.begin(), source.end(), source.begin(), [](unsigned char c) { return std::tolower(c); });
return source;
}
std::string FromWchar(wchar_t* source)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
return converter.to_bytes(std::wstring(source));
}
std::vector<std::string> SplitString(const std::string& source)
{
std::vector<std::string> strings;
// String is single-line, early exit
if (source.find('\n') == std::string::npos)
{
strings.push_back(source);
return strings;
}
std::string::size_type pos = 0;
std::string::size_type prev = 0;
while ((pos = source.find('\n', prev)) != std::string::npos)
{
strings.push_back(source.substr(prev, pos - prev));
prev = pos + 1;
}
strings.push_back(source.substr(prev));
return strings;
}
}

View file

@ -0,0 +1,9 @@
#pragma once
#include <string>
namespace TEN::Utils
{
std::string ToLower(std::string source);
std::string FromWchar(wchar_t* source);
std::vector<std::string> SplitString(const std::string& source);
}

View file

@ -14,6 +14,7 @@
#include "Sound/sound.h"
#include "Specific/level.h"
#include "Specific/configuration.h"
#include "Specific/trutils.h"
#include "LanguageScript.h"
#include "ScriptInterfaceState.h"
#include "ScriptInterfaceLevel.h"
@ -46,6 +47,12 @@ extern "C"
string commit;
#endif
bool ArgEquals(wchar_t* incomingArg, std::string name)
{
auto lowerArg = TEN::Utils::ToLower(TEN::Utils::FromWchar(incomingArg));
return (lowerArg == "-" + name) || (lowerArg == "/" + name);
}
Vector2Int GetScreenResolution()
{
RECT desktop;
@ -150,16 +157,7 @@ LRESULT CALLBACK WinAppProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
return 0;
}
// Manually handle ALT + ENTER toggle fullscreen
if ((msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN)
&& wParam == VK_RETURN
&& (HIWORD(lParam) & KF_ALTDOWN))
{
g_Renderer.ToggleFullScreen();
return 0;
}
if (msg > 0x10)
if (msg > WM_CLOSE)
{
if (msg == WM_COMMAND)
HandleWmCommand((unsigned short)wParam);
@ -188,6 +186,9 @@ LRESULT CALLBACK WinAppProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if ((signed int)(unsigned short)wParam > 0 && (signed int)(unsigned short)wParam <= 2)
{
if (!g_Configuration.Windowed)
g_Renderer.ToggleFullScreen(true);
if (!Debug && ThreadHandle > 0)
{
TENLog("Resuming game thread", LogLevel::Info);
@ -200,6 +201,9 @@ LRESULT CALLBACK WinAppProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
else
{
if (!g_Configuration.Windowed)
ShowWindow(hWnd, SW_MINIMIZE);
if (!Debug)
{
TENLog("Suspending game thread", LogLevel::Info);
@ -228,26 +232,31 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
// Parse command line arguments
for (int i = 1; i < argc; i++)
{
if (wcscmp(argv[i], L"/setup") == 0)
if (ArgEquals(argv[i], "setup"))
{
setup = true;
}
else if (wcscmp(argv[i], L"/debug") == 0)
else if (ArgEquals(argv[i], "debug"))
{
Debug = true;
}
else if ((wcscmp(argv[i], L"/level") == 0) && argc > (i + 1))
else if (ArgEquals(argv[i], "level") && argc > (i + 1))
{
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
levelFile = converter.to_bytes(std::wstring(argv[i + 1]));
levelFile = TEN::Utils::FromWchar(argv[i + 1]);
}
else if ((wcscmp(argv[i], L"/hash") == 0) && argc > (i + 1))
else if (ArgEquals(argv[i], "hash") && argc > (i + 1))
{
SystemNameHash = std::stoul(std::wstring(argv[i + 1]));
}
}
LocalFree(argv);
// Hide console window if mode isn't debug
#ifndef _DEBUG
if (!Debug)
ShowWindow(GetConsoleWindow(), 0);
#endif
// Clear Application Structure
memset(&App, 0, sizeof(WINAPP));

View file

@ -44,7 +44,7 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)Build\$(Configuration)\</OutDir>
<ExecutablePath>$(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x86</ExecutablePath>
<IncludePath>$(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\bass;$(IncludePath)</IncludePath>
@ -52,7 +52,7 @@
<TargetExt>.exe</TargetExt>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>true</LinkIncremental>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(ProjectDir)..\Build\$(Configuration)\</OutDir>
<ExecutablePath>$(ExecutablePath);$(DXSDK_DIR)Utilities\bin\x86</ExecutablePath>
<IncludePath>$(SolutionDir)Libs;$(SolutionDir)Libs\lua;$(SolutionDir)Libs\sol;$(SolutionDir)Libs\ois;$(SolutionDir)Libs\spdlog;$(SolutionDir)Libs\zlib;$(SolutionDir)Libs\bass;$(IncludePath)</IncludePath>
@ -85,6 +85,7 @@
<AdditionalDependencies>comctl32.lib;lua53.lib;bass.lib;bassmix.lib;bass_fx.lib;D3DCompiler.lib;dxgi.lib;dxguid.lib;d3d11.lib;zlib.lib;spdlogd.lib;OIS_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<LargeAddressAware>true</LargeAddressAware>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<PostBuildEvent>
<Command>
@ -128,7 +129,7 @@ xcopy /Y "$(ProjectDir)Shaders\HUD\*.hlsl" "$(TargetDir)\Shaders\HUD\"</Command>
<DisableSpecificWarnings>4244;5051;4018;4554;%(DisableSpecificWarnings)</DisableSpecificWarnings>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
<AdditionalLibraryDirectories>C:\Program Files %28x86%29\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\lib\onecore\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -136,6 +137,7 @@ xcopy /Y "$(ProjectDir)Shaders\HUD\*.hlsl" "$(TargetDir)\Shaders\HUD\"</Command>
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
<LargeAddressAware>true</LargeAddressAware>
<TargetMachine>MachineX86</TargetMachine>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
<PostBuildEvent>
<Command>md "$(TargetDir)\Shaders"
@ -578,6 +580,7 @@ CALL gen.bat</Command>
<ClInclude Include="Specific\setup.h" />
<ClInclude Include="Specific\clock.h" />
<ClInclude Include="Specific\trmath.h" />
<ClInclude Include="Specific\trutils.h" />
<ClInclude Include="Specific\winmain.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="Objects\TR5\Object\tr5_genslot.h" />
@ -919,6 +922,7 @@ CALL gen.bat</Command>
<ClCompile Include="Specific\IO\Streams.cpp" />
<ClCompile Include="Specific\level.cpp" />
<ClCompile Include="Specific\setup.cpp" />
<ClCompile Include="Specific\trutils.cpp" />
<ClCompile Include="Specific\winmain.cpp" />
<ClCompile Include="Objects\TR5\Object\tr5_genslot.cpp" />
<ClCompile Include="Renderer\VertexBuffer\VertexBuffer.cpp" />
@ -944,6 +948,7 @@ CALL gen.bat</Command>
<None Include="Shaders\Math.hlsli">
<DeploymentContent>true</DeploymentContent>
</None>
<None Include="Shaders\VertexEffects.hlsli" />
<None Include="Shaders\VertexInput.hlsli">
<DeploymentContent>true</DeploymentContent>
</None>