mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 15:57:59 +03:00
Improve streamer effect implementation
This commit is contained in:
parent
44128eda43
commit
1e143c6e0a
5 changed files with 253 additions and 163 deletions
|
@ -5,6 +5,7 @@
|
|||
#include "Game/effects/effects.h"
|
||||
#include "Game/items.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Renderer/RendererEnums.h"
|
||||
#include "Specific/clock.h"
|
||||
|
||||
using namespace TEN::Math;
|
||||
|
@ -27,25 +28,36 @@ namespace TEN::Effects::Streamer
|
|||
if (Color.w > 0.0f)
|
||||
Color.w = EaseInOutSine(0.0f, OpacityMax, Life / LifeMax);
|
||||
|
||||
// TODO: Not working.
|
||||
// TODO: Not working. Make it work. -- Sezz 2025.03.02
|
||||
// Update orientation.
|
||||
Orientation.SetAngle(Orientation.GetAngle() + Rotation);
|
||||
|
||||
// Update vertices.
|
||||
TransformVertices(Velocity, ScaleRate);
|
||||
TransformVertices(Velocity, ExpRate);
|
||||
|
||||
// Update life.
|
||||
Life -= 1.0f;
|
||||
}
|
||||
|
||||
void Streamer::StreamerSegment::TransformVertices(float vel, float scaleRate)
|
||||
void Streamer::StreamerSegment::TransformVertices(float vel, float expRate)
|
||||
{
|
||||
// Apply expansion.
|
||||
if (scaleRate != 0.0f)
|
||||
// Apply expansion/contraction.
|
||||
if (expRate != 0.0f)
|
||||
{
|
||||
auto dir = Orientation.ToDirection();
|
||||
Vertices[0] = Geometry::TranslatePoint(Vertices[0], -dir, scaleRate);
|
||||
Vertices[1] = Geometry::TranslatePoint(Vertices[1], dir, scaleRate);
|
||||
float distSqr = Vector3::DistanceSquared(Vertices[0], Vertices[1]);
|
||||
if (expRate < 0.0f && distSqr <= SQUARE(abs(expRate)))
|
||||
{
|
||||
auto center = (Vertices[0] + Vertices[1]) / 2;
|
||||
Vertices[0] =
|
||||
Vertices[1] = center;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
auto dir = Orientation.ToDirection();
|
||||
Vertices[0] = Geometry::TranslatePoint(Vertices[0], -dir, expRate);
|
||||
Vertices[1] = Geometry::TranslatePoint(Vertices[1], dir, expRate);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply directional velocity.
|
||||
|
@ -57,8 +69,34 @@ namespace TEN::Effects::Streamer
|
|||
}
|
||||
}
|
||||
|
||||
Streamer::Streamer(StreamerFeatherType featherType, BlendMode blendMode)
|
||||
{
|
||||
_featherType = featherType;
|
||||
_blendMode = blendMode;
|
||||
}
|
||||
|
||||
const std::vector<Streamer::StreamerSegment>& Streamer::GetSegments() const
|
||||
{
|
||||
return _segments;
|
||||
}
|
||||
|
||||
StreamerFeatherType Streamer::GetFeatherType() const
|
||||
{
|
||||
return _featherType;
|
||||
}
|
||||
|
||||
BlendMode Streamer::GetBlendMode() const
|
||||
{
|
||||
return _blendMode;
|
||||
}
|
||||
|
||||
bool Streamer::IsBroken() const
|
||||
{
|
||||
return _isBroken;
|
||||
}
|
||||
|
||||
void Streamer::AddSegment(const Vector3& pos, const Vector3& dir, short orient, const Vector4& color,
|
||||
float width, float life, float vel, float scaleRate, short rot, int flags, unsigned int segmentCount)
|
||||
float width, float life, float vel, float expRate, short rot, unsigned int segmentCount)
|
||||
{
|
||||
constexpr auto FADE_IN_COEFF = 3.0f;
|
||||
|
||||
|
@ -76,61 +114,66 @@ namespace TEN::Effects::Streamer
|
|||
segment.LifeMax = lifeMax;
|
||||
segment.OpacityMax = opacityMax;
|
||||
segment.Velocity = vel;
|
||||
segment.ScaleRate = scaleRate;
|
||||
segment.ExpRate = expRate;
|
||||
segment.Rotation = rot;
|
||||
segment.Flags = flags;
|
||||
segment.InitializeVertices(pos, width);
|
||||
}
|
||||
|
||||
void Streamer::Update()
|
||||
{
|
||||
if (Segments.empty())
|
||||
if (_segments.empty())
|
||||
return;
|
||||
|
||||
// If streamer was broken, set bool flag to track it.
|
||||
const auto& newestSegment = Segments.back();
|
||||
// Set flag to track if streamer was broken.
|
||||
const auto& newestSegment = _segments.back();
|
||||
if (newestSegment.Life != newestSegment.LifeMax)
|
||||
IsBroken = true;
|
||||
_isBroken = true;
|
||||
|
||||
// Update segments.
|
||||
for (auto& segment : Segments)
|
||||
for (auto& segment : _segments)
|
||||
segment.Update();
|
||||
|
||||
ClearInactiveEffects(Segments);
|
||||
ClearInactiveEffects(_segments);
|
||||
}
|
||||
|
||||
Streamer::StreamerSegment& Streamer::GetNewSegment()
|
||||
{
|
||||
TENAssert(Segments.size() <= SEGMENT_COUNT_MAX, "Streamer segment count overflow.");
|
||||
TENAssert(_segments.size() <= SEGMENT_COUNT_MAX, "Streamer segment count overflow.");
|
||||
|
||||
// Clear oldest segment if vector is full.
|
||||
if (Segments.size() == SEGMENT_COUNT_MAX)
|
||||
Segments.erase(Segments.begin());
|
||||
if (_segments.size() == SEGMENT_COUNT_MAX)
|
||||
_segments.erase(_segments.begin());
|
||||
|
||||
// Add and return new segment.
|
||||
return Segments.emplace_back();
|
||||
return _segments.emplace_back();
|
||||
}
|
||||
|
||||
void StreamerModule::AddStreamer(int tag, const Vector3& pos, const Vector3& dir, short orient, const Vector4& color,
|
||||
float width, float life, float vel, float scaleRate, short rot, int flags)
|
||||
const std::unordered_map<int, std::vector<Streamer>>& StreamerGroup::GetPools() const
|
||||
{
|
||||
TENAssert(Pools.size() <= POOL_COUNT_MAX, "Streamer pool count overflow.");
|
||||
return _pools;
|
||||
}
|
||||
|
||||
void StreamerGroup::AddStreamer(int tag, const Vector3& pos, const Vector3& dir, short orient, const Vector4& color,
|
||||
float width, float life, float vel, float expRate, short rot,
|
||||
StreamerFeatherType featherType, BlendMode blendMode)
|
||||
{
|
||||
TENAssert(_pools.size() <= POOL_COUNT_MAX, "Streamer pool count overflow.");
|
||||
|
||||
// Return early if pool map is full and element with tag key doesn't already exist.
|
||||
if (Pools.size() == POOL_COUNT_MAX && !Pools.count(tag))
|
||||
if (_pools.size() == POOL_COUNT_MAX && !_pools.count(tag))
|
||||
return;
|
||||
|
||||
// Get and extend streamer with new segment.
|
||||
auto& streamer = GetStreamer(tag);
|
||||
streamer.AddSegment(pos, dir, orient, color, width, life, vel, scaleRate, rot, flags, (unsigned int)streamer.Segments.size());
|
||||
// Get new streamer iteration or extend existing streamer iteration with new segment.
|
||||
auto& streamer = GetStreamerIteration(tag, featherType, blendMode);
|
||||
streamer.AddSegment(pos, dir, orient, color, width, life, vel, expRate, rot, (unsigned int)streamer.GetSegments().size());
|
||||
}
|
||||
|
||||
void StreamerModule::Update()
|
||||
void StreamerGroup::Update()
|
||||
{
|
||||
if (Pools.empty())
|
||||
if (_pools.empty())
|
||||
return;
|
||||
|
||||
for (auto& [tag, pool] : Pools)
|
||||
for (auto& [tag, pool] : _pools)
|
||||
{
|
||||
for (auto& streamer : pool)
|
||||
streamer.Update();
|
||||
|
@ -141,15 +184,15 @@ namespace TEN::Effects::Streamer
|
|||
ClearInactivePools();
|
||||
}
|
||||
|
||||
std::vector<Streamer>& StreamerModule::GetPool(int tag)
|
||||
std::vector<Streamer>& StreamerGroup::GetPool(int tag)
|
||||
{
|
||||
// Get pool at tag key.
|
||||
Pools.insert({ tag, {} });
|
||||
auto& pool = Pools.at(tag);
|
||||
_pools.insert({ tag, {} });
|
||||
auto& pool = _pools.at(tag);
|
||||
return pool;
|
||||
}
|
||||
|
||||
Streamer& StreamerModule::GetStreamer(int tag)
|
||||
Streamer& StreamerGroup::GetStreamerIteration(int tag, StreamerFeatherType featherType, BlendMode blendMode)
|
||||
{
|
||||
auto& pool = GetPool(tag);
|
||||
TENAssert(pool.size() <= STREAMER_COUNT_MAX, "Streamer pool size overflow.");
|
||||
|
@ -158,7 +201,7 @@ namespace TEN::Effects::Streamer
|
|||
if (!pool.empty())
|
||||
{
|
||||
auto& streamer = pool.back();
|
||||
if (!streamer.IsBroken)
|
||||
if (!streamer.IsBroken())
|
||||
return streamer;
|
||||
}
|
||||
|
||||
|
@ -167,17 +210,17 @@ namespace TEN::Effects::Streamer
|
|||
pool.erase(pool.begin());
|
||||
|
||||
// Add and return new streamer iteration.
|
||||
return pool.emplace_back();
|
||||
return pool.emplace_back(Streamer(featherType, blendMode));
|
||||
}
|
||||
|
||||
void StreamerModule::ClearInactivePools()
|
||||
void StreamerGroup::ClearInactivePools()
|
||||
{
|
||||
for (auto it = Pools.begin(); it != Pools.end();)
|
||||
for (auto it = _pools.begin(); it != _pools.end();)
|
||||
{
|
||||
const auto& pool = it->second;
|
||||
if (pool.empty())
|
||||
{
|
||||
it = Pools.erase(it);
|
||||
it = _pools.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -185,43 +228,49 @@ namespace TEN::Effects::Streamer
|
|||
}
|
||||
}
|
||||
|
||||
void StreamerModule::ClearInactiveStreamers(int tag)
|
||||
void StreamerGroup::ClearInactiveStreamers(int tag)
|
||||
{
|
||||
auto& pool = Pools.at(tag);
|
||||
auto& pool = _pools.at(tag);
|
||||
|
||||
pool.erase(
|
||||
std::remove_if(
|
||||
pool.begin(), pool.end(),
|
||||
[](const auto& streamer)
|
||||
{
|
||||
return streamer.Segments.empty();
|
||||
return streamer.GetSegments().empty();
|
||||
}),
|
||||
pool.end());
|
||||
}
|
||||
|
||||
void StreamerEffectController::Spawn(int itemNumber, int tag, const Vector3& pos, const Vector3& direction, short orient, const Vector4& color,
|
||||
float width, float life, float vel, float scaleRate, short rot, int flags)
|
||||
const std::unordered_map<int, StreamerGroup>& StreamerEffectController::GetGroups() const
|
||||
{
|
||||
TENAssert(Modules.size() <= MODULE_COUNT_MAX, "Streamer module count overflow.");
|
||||
return _groups;
|
||||
}
|
||||
|
||||
// Return early if module map is full and element with itemNumber key doesn't already exist.
|
||||
if (Modules.size() == MODULE_COUNT_MAX && !Modules.count(itemNumber))
|
||||
void StreamerEffectController::Spawn(int itemNumber, int tag, const Vector3& pos, const Vector3& direction, short orient, const Vector4& color,
|
||||
float width, float life, float vel, float expRate, short rot,
|
||||
StreamerFeatherType featherType, BlendMode blendMode)
|
||||
{
|
||||
TENAssert(_groups.size() <= GROUP_COUNT_MAX, "Streamer group count overflow.");
|
||||
|
||||
// Return early if group map is full and element with itemNumber key doesn't already exist.
|
||||
if (_groups.size() == GROUP_COUNT_MAX && !_groups.count(itemNumber))
|
||||
return;
|
||||
|
||||
// Get module and extend streamer within pool.
|
||||
auto& module = GetModule(itemNumber);
|
||||
module.AddStreamer(tag, pos, direction, orient, color, width, life, vel, scaleRate, rot, flags);
|
||||
// Get group and extend streamer within pool.
|
||||
auto& group = GetGroup(itemNumber);
|
||||
group.AddStreamer(tag, pos, direction, orient, color, width, life, vel, expRate, rot, featherType, blendMode);
|
||||
}
|
||||
|
||||
void StreamerEffectController::Update()
|
||||
{
|
||||
if (Modules.empty())
|
||||
if (_groups.empty())
|
||||
return;
|
||||
|
||||
for (auto& [itemNumber, module] : Modules)
|
||||
module.Update();
|
||||
for (auto& [itemNumber, group] : _groups)
|
||||
group.Update();
|
||||
|
||||
ClearInactiveModules();
|
||||
ClearInactiveGroups();
|
||||
}
|
||||
|
||||
void StreamerEffectController::Clear()
|
||||
|
@ -229,22 +278,22 @@ namespace TEN::Effects::Streamer
|
|||
*this = {};
|
||||
}
|
||||
|
||||
StreamerModule& StreamerEffectController::GetModule(int itemNumber)
|
||||
StreamerGroup& StreamerEffectController::GetGroup(int itemNumber)
|
||||
{
|
||||
// Get module at itemNumber key.
|
||||
Modules.insert({ itemNumber, {} });
|
||||
auto& module = Modules.at(itemNumber);
|
||||
return module;
|
||||
// Get group at itemNumber key.
|
||||
_groups.insert({ itemNumber, {} });
|
||||
auto& group = _groups.at(itemNumber);
|
||||
return group;
|
||||
}
|
||||
|
||||
void StreamerEffectController::ClearInactiveModules()
|
||||
void StreamerEffectController::ClearInactiveGroups()
|
||||
{
|
||||
for (auto it = Modules.begin(); it != Modules.end();)
|
||||
for (auto it = _groups.begin(); it != _groups.end();)
|
||||
{
|
||||
const auto& module = it->second;
|
||||
if (module.Pools.empty())
|
||||
const auto& group = it->second;
|
||||
if (group.GetPools().empty())
|
||||
{
|
||||
it = Modules.erase(it);
|
||||
it = _groups.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Math/Math.h"
|
||||
#include "Renderer/RendererEnums.h"
|
||||
|
||||
using namespace TEN::Math;
|
||||
|
||||
|
@ -7,11 +9,12 @@ struct ItemInfo;
|
|||
|
||||
namespace TEN::Effects::Streamer
|
||||
{
|
||||
enum class StreamerFlags
|
||||
enum class StreamerFeatherType
|
||||
{
|
||||
FadeLeft = 1 << 0,
|
||||
FadeRight = 1 << 1,
|
||||
BlendModeAdditive = 1 << 2
|
||||
None,
|
||||
Center,
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
class Streamer
|
||||
|
@ -21,32 +24,29 @@ namespace TEN::Effects::Streamer
|
|||
|
||||
static constexpr auto SEGMENT_COUNT_MAX = 128;
|
||||
|
||||
public:
|
||||
struct StreamerSegment
|
||||
{
|
||||
static constexpr auto VERTEX_COUNT = 2;
|
||||
|
||||
AxisAngle Orientation = AxisAngle::Identity;
|
||||
Vector4 Color = Vector4::Zero;
|
||||
std::array<Vector3, VERTEX_COUNT> Vertices = {};
|
||||
AxisAngle Orientation = AxisAngle::Identity; // TODO: Interpolate?
|
||||
Vector4 Color = Vector4::Zero;
|
||||
|
||||
float Life = 0.0f;
|
||||
float LifeMax = 0.0f;
|
||||
float OpacityMax = 0.0f;
|
||||
float Velocity = 0.0f;
|
||||
float ScaleRate = 0.0f;
|
||||
float ExpRate = 0.0f;
|
||||
short Rotation = 0;
|
||||
int Flags = 0;
|
||||
|
||||
std::array<Vector3, VERTEX_COUNT> Vertices = {};
|
||||
|
||||
Vector4 PrevColor = Vector4::Zero;
|
||||
Vector4 PrevColor = Vector4::Zero;
|
||||
std::array<Vector3, VERTEX_COUNT> PrevVertices = {};
|
||||
|
||||
void InitializeVertices(const Vector3& pos, float width);
|
||||
void Update();
|
||||
|
||||
private:
|
||||
void TransformVertices(float vel, float scaleRate);
|
||||
void TransformVertices(float vel, float expRate);
|
||||
|
||||
void StoreInterpolationData()
|
||||
{
|
||||
|
@ -58,13 +58,32 @@ namespace TEN::Effects::Streamer
|
|||
|
||||
// Fields
|
||||
|
||||
bool IsBroken = false;
|
||||
std::vector<StreamerSegment> Segments = {};
|
||||
std::vector<StreamerSegment> _segments = {};
|
||||
|
||||
StreamerFeatherType _featherType = StreamerFeatherType::None;
|
||||
BlendMode _blendMode = BlendMode::AlphaBlend;
|
||||
bool _isBroken = false;
|
||||
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
Streamer(StreamerFeatherType featherType, BlendMode blendMode);
|
||||
|
||||
// Getters
|
||||
|
||||
const std::vector<StreamerSegment>& GetSegments() const;
|
||||
StreamerFeatherType GetFeatherType() const;
|
||||
BlendMode GetBlendMode() const;
|
||||
|
||||
// Inquirers
|
||||
|
||||
bool IsBroken() const;
|
||||
|
||||
// Utilities
|
||||
|
||||
void AddSegment(const Vector3& pos, const Vector3& dir, short orient, const Vector4& color,
|
||||
float width, float life, float vel, float scaleRate, short rot, int flags, unsigned int segmentCount);
|
||||
float width, float life, float vel, float expRate, short rot, unsigned int segmentCount);
|
||||
void Update();
|
||||
|
||||
private:
|
||||
|
@ -73,30 +92,36 @@ namespace TEN::Effects::Streamer
|
|||
StreamerSegment& GetNewSegment();
|
||||
};
|
||||
|
||||
class StreamerModule
|
||||
class StreamerGroup
|
||||
{
|
||||
private:
|
||||
// Constants
|
||||
|
||||
static constexpr auto POOL_COUNT_MAX = 8;
|
||||
static constexpr auto STREAMER_COUNT_MAX = 8;
|
||||
static constexpr auto POOL_COUNT_MAX = 64;
|
||||
static constexpr auto STREAMER_COUNT_MAX = 4;
|
||||
|
||||
// Fields
|
||||
|
||||
std::unordered_map<int, std::vector<Streamer>> _pools = {}; // Key = tag.
|
||||
|
||||
public:
|
||||
// Members
|
||||
|
||||
std::unordered_map<int, std::vector<Streamer>> Pools = {}; // Key = tag.
|
||||
// Getters
|
||||
|
||||
const std::unordered_map<int, std::vector<Streamer>>& GetPools() const;
|
||||
|
||||
// Utilities
|
||||
|
||||
void AddStreamer(int tag, const Vector3& pos, const Vector3& dir, short orient, const Vector4& color,
|
||||
float width, float life, float vel, float scaleRate, short rot, int flags);
|
||||
float width, float life, float vel, float expRate, short rot,
|
||||
StreamerFeatherType featherType, BlendMode blendMode);
|
||||
void Update();
|
||||
|
||||
private:
|
||||
// Helpers
|
||||
|
||||
std::vector<Streamer>& GetPool(int tag);
|
||||
Streamer& GetStreamer(int tag);
|
||||
Streamer& GetStreamerIteration(int tag, StreamerFeatherType featherType, BlendMode blendMode);
|
||||
void ClearInactivePools();
|
||||
void ClearInactiveStreamers(int tag);
|
||||
};
|
||||
|
@ -106,25 +131,30 @@ namespace TEN::Effects::Streamer
|
|||
private:
|
||||
// Constants
|
||||
|
||||
static constexpr auto MODULE_COUNT_MAX = 64;
|
||||
static constexpr auto GROUP_COUNT_MAX = 64;
|
||||
|
||||
public:
|
||||
// Fields
|
||||
|
||||
std::unordered_map<int, StreamerModule> Modules = {}; // Key = item number.
|
||||
std::unordered_map<int, StreamerGroup> _groups = {}; // Key = item number.
|
||||
|
||||
public:
|
||||
// Getters
|
||||
|
||||
const std::unordered_map<int, StreamerGroup>& GetGroups() const;
|
||||
|
||||
// Utilities
|
||||
|
||||
void Spawn(int itemNumber, int tag, const Vector3& pos, const Vector3& dir, short orient, const Vector4& color,
|
||||
float width, float life, float vel, float scaleRate, short rot, int flags = 0);
|
||||
float width, float life, float vel, float expRate, short rot,
|
||||
StreamerFeatherType featherType = StreamerFeatherType::None, BlendMode blendMode = BlendMode::AlphaBlend);
|
||||
void Update();
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
// Helpers
|
||||
|
||||
StreamerModule& GetModule(int itemNumber);
|
||||
void ClearInactiveModules();
|
||||
StreamerGroup& GetGroup(int itemNumber);
|
||||
void ClearInactiveGroups();
|
||||
};
|
||||
|
||||
extern StreamerEffectController StreamerEffect;
|
||||
|
|
|
@ -38,12 +38,11 @@ namespace TEN::Entities::TR4
|
|||
|
||||
static void SpawnWraithTails(const ItemInfo& item)
|
||||
{
|
||||
constexpr auto OFFSET = Vector3(0.0f, -10.0f, -50.0f);
|
||||
constexpr auto WIDTH = 8.0f;
|
||||
constexpr auto LIFE_MAX = 0.5f;
|
||||
constexpr auto VEL = 4.0f;
|
||||
constexpr auto SCALE_RATE = 1.0f;
|
||||
constexpr auto FLAGS = (int)StreamerFlags::FadeRight;
|
||||
constexpr auto OFFSET = Vector3(0.0f, -10.0f, -50.0f);
|
||||
constexpr auto WIDTH = 8.0f;
|
||||
constexpr auto LIFE_MAX = 0.5f;
|
||||
constexpr auto VEL = 4.0f;
|
||||
constexpr auto EXP_RATE = 1.0f;
|
||||
|
||||
enum class TailTag
|
||||
{
|
||||
|
@ -83,19 +82,22 @@ namespace TEN::Entities::TR4
|
|||
StreamerEffect.Spawn(
|
||||
item.Index, (int)TailTag::First,
|
||||
pos, direction0, orient2D, color,
|
||||
WIDTH, LIFE_MAX, VEL, SCALE_RATE, 0, FLAGS);
|
||||
WIDTH, LIFE_MAX, VEL, EXP_RATE, 0,
|
||||
StreamerFeatherType::Center, BlendMode::Additive);
|
||||
|
||||
// Spawn second tail.
|
||||
StreamerEffect.Spawn(
|
||||
item.Index, (int)TailTag::Second,
|
||||
pos, direction1, orient2D, color,
|
||||
WIDTH, LIFE_MAX, VEL, SCALE_RATE, 0, FLAGS);
|
||||
WIDTH, LIFE_MAX, VEL, EXP_RATE, 0,
|
||||
StreamerFeatherType::Center, BlendMode::Additive);
|
||||
|
||||
// Spawn third tail.
|
||||
StreamerEffect.Spawn(
|
||||
item.Index, (int)TailTag::Third,
|
||||
pos, direction2, orient2D, color,
|
||||
WIDTH, LIFE_MAX, VEL, SCALE_RATE, 0, FLAGS);
|
||||
WIDTH, LIFE_MAX, VEL, EXP_RATE, 0,
|
||||
StreamerFeatherType::Center, BlendMode::Additive);
|
||||
}
|
||||
|
||||
static void WraithWallEffect(Vector3i pos, short yRot, int objectNumber)
|
||||
|
|
|
@ -355,11 +355,11 @@ namespace TEN::Entities::Vehicles
|
|||
|
||||
void SpawnVehicleWake(const ItemInfo& vehicleItem, const Vector3& relOffset, int waterHeight, bool isUnderwater)
|
||||
{
|
||||
constexpr auto COLOR = Vector4(0.75f);
|
||||
constexpr auto LIFE_MAX = 2.5f;
|
||||
constexpr auto VEL_ABS = 4.0f;
|
||||
constexpr auto SCALE_RATE_ON_WATER = 6.0f;
|
||||
constexpr auto SCALE_RATE_UNDERWATER = 1.5f;
|
||||
constexpr auto COLOR = Vector4(0.75f);
|
||||
constexpr auto LIFE_MAX = 2.5f;
|
||||
constexpr auto VEL_ABS = 4.0f;
|
||||
constexpr auto EXP_RATE_ON_WATER = 6.0f;
|
||||
constexpr auto EXP_RATE_UNDERWATER = 1.5f;
|
||||
|
||||
// Vehicle is out of water; return early.
|
||||
if (waterHeight == NO_HEIGHT)
|
||||
|
@ -373,23 +373,25 @@ namespace TEN::Entities::Vehicles
|
|||
|
||||
// Determine key parameters.
|
||||
auto positions = GetVehicleWakePositions(vehicleItem, relOffset, waterHeight, isUnderwater, isMovingForward);
|
||||
auto direction = -vehicleItem.Pose.Orientation.ToDirection();
|
||||
auto dir = -vehicleItem.Pose.Orientation.ToDirection();
|
||||
short orient2D = isUnderwater ? vehicleItem.Pose.Orientation.z : 0;
|
||||
float life = isUnderwater ? (LIFE_MAX / 2) : LIFE_MAX;
|
||||
float vel = isMovingForward ? VEL_ABS : -VEL_ABS;
|
||||
float scaleRate = isUnderwater ? SCALE_RATE_UNDERWATER : SCALE_RATE_ON_WATER;
|
||||
float expRate = isUnderwater ? EXP_RATE_UNDERWATER : EXP_RATE_ON_WATER;
|
||||
|
||||
// Spawn left wake.
|
||||
StreamerEffect.Spawn(
|
||||
vehicleItem.Index, (int)tagLeft,
|
||||
positions.first, direction, orient2D, COLOR,
|
||||
0.0f, life, vel, scaleRate, 0, (int)StreamerFlags::FadeLeft);
|
||||
positions.first, dir, orient2D, COLOR,
|
||||
0.0f, life, vel, expRate, 0,
|
||||
StreamerFeatherType::Right, BlendMode::Additive);
|
||||
|
||||
// Spawn right wake.
|
||||
StreamerEffect.Spawn(
|
||||
vehicleItem.Index, (int)tagRight,
|
||||
positions.second, direction, orient2D, COLOR,
|
||||
0.0f, life, vel, scaleRate, 0, (int)StreamerFlags::FadeRight);
|
||||
positions.second, dir, orient2D, COLOR,
|
||||
0.0f, life, vel, expRate, 0,
|
||||
StreamerFeatherType::Left, BlendMode::Additive);
|
||||
}
|
||||
|
||||
void HandleVehicleSpeedometer(float vel, float velMax)
|
||||
|
|
|
@ -112,65 +112,72 @@ namespace TEN::Renderer
|
|||
|
||||
void Renderer::PrepareStreamers(RenderView& view)
|
||||
{
|
||||
constexpr auto DEFAULT_BLEND_MODE = BlendMode::Additive;
|
||||
|
||||
for (const auto& [itemNumber, module] : StreamerEffect.Modules)
|
||||
for (const auto& [itemNumber, group] : StreamerEffect.GetGroups())
|
||||
{
|
||||
for (const auto& [tag, pool] : module.Pools)
|
||||
for (const auto& [tag, pool] : group.GetPools())
|
||||
{
|
||||
for (const auto& streamer : pool)
|
||||
{
|
||||
for (int i = 0; i < streamer.Segments.size(); i++)
|
||||
for (int i = 0; i < streamer.GetSegments().size(); i++)
|
||||
{
|
||||
const auto& segment = streamer.Segments[i];
|
||||
const auto& prevSegment = streamer.Segments[std::max(i - 1, 0)];
|
||||
const auto& segment = streamer.GetSegments()[i];
|
||||
const auto& prevSegment = streamer.GetSegments()[std::max(i - 1, 0)];
|
||||
|
||||
if (segment.Life <= 0.0f)
|
||||
continue;
|
||||
|
||||
// Determine blend mode.
|
||||
auto blendMode = DEFAULT_BLEND_MODE;
|
||||
if (segment.Flags & (int)StreamerFlags::BlendModeAdditive)
|
||||
blendMode = BlendMode::AlphaBlend;
|
||||
|
||||
if (segment.Flags & (int)StreamerFlags::FadeLeft)
|
||||
auto vertex0 = Vector3::Lerp(segment.PrevVertices[0], segment.Vertices[0], GetInterpolationFactor());
|
||||
auto vertex1 = Vector3::Lerp(segment.PrevVertices[1], segment.Vertices[1], GetInterpolationFactor());
|
||||
auto prevVertex0 = Vector3::Lerp(prevSegment.PrevVertices[0], prevSegment.Vertices[0], GetInterpolationFactor());
|
||||
auto prevVertex1 = Vector3::Lerp(prevSegment.PrevVertices[1], prevSegment.Vertices[1], GetInterpolationFactor());
|
||||
|
||||
auto color = Vector4::Lerp(segment.PrevColor, segment.Color, GetInterpolationFactor());
|
||||
auto prevColor = Vector4::Lerp(prevSegment.PrevColor, prevSegment.Color, GetInterpolationFactor());
|
||||
|
||||
switch (streamer.GetFeatherType())
|
||||
{
|
||||
AddColoredQuad(
|
||||
Vector3::Lerp(segment.PrevVertices[0], segment.Vertices[0], GetInterpolationFactor()),
|
||||
Vector3::Lerp(segment.PrevVertices[1], segment.Vertices[1], GetInterpolationFactor()),
|
||||
Vector3::Lerp(prevSegment.PrevVertices[1], prevSegment.Vertices[1], GetInterpolationFactor()),
|
||||
Vector3::Lerp(prevSegment.PrevVertices[0], prevSegment.Vertices[0], GetInterpolationFactor()),
|
||||
Vector4::Zero,
|
||||
Vector4::Lerp(segment.PrevColor, segment.Color, GetInterpolationFactor()),
|
||||
Vector4::Lerp(prevSegment.PrevColor, prevSegment.Color, GetInterpolationFactor()),
|
||||
Vector4::Zero,
|
||||
blendMode, view);
|
||||
}
|
||||
else if (segment.Flags & (int)StreamerFlags::FadeRight)
|
||||
{
|
||||
AddColoredQuad(
|
||||
Vector3::Lerp(segment.PrevVertices[0], segment.Vertices[0], GetInterpolationFactor()),
|
||||
Vector3::Lerp(segment.PrevVertices[1], segment.Vertices[1], GetInterpolationFactor()),
|
||||
Vector3::Lerp(prevSegment.PrevVertices[1], prevSegment.Vertices[1], GetInterpolationFactor()),
|
||||
Vector3::Lerp(prevSegment.PrevVertices[0], prevSegment.Vertices[0], GetInterpolationFactor()),
|
||||
Vector4::Lerp(segment.PrevColor, segment.Color, GetInterpolationFactor()),
|
||||
Vector4::Zero,
|
||||
Vector4::Zero,
|
||||
Vector4::Lerp(prevSegment.PrevColor, prevSegment.Color, GetInterpolationFactor()),
|
||||
blendMode, view);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddColoredQuad(
|
||||
Vector3::Lerp(segment.PrevVertices[0], segment.Vertices[0], GetInterpolationFactor()),
|
||||
Vector3::Lerp(segment.PrevVertices[1], segment.Vertices[1], GetInterpolationFactor()),
|
||||
Vector3::Lerp(prevSegment.PrevVertices[1], prevSegment.Vertices[1], GetInterpolationFactor()),
|
||||
Vector3::Lerp(prevSegment.PrevVertices[0], prevSegment.Vertices[0], GetInterpolationFactor()),
|
||||
Vector4::Lerp(segment.PrevColor, segment.Color, GetInterpolationFactor()),
|
||||
Vector4::Lerp(segment.PrevColor, segment.Color, GetInterpolationFactor()),
|
||||
Vector4::Lerp(prevSegment.PrevColor, prevSegment.Color, GetInterpolationFactor()),
|
||||
Vector4::Lerp(prevSegment.PrevColor, prevSegment.Color, GetInterpolationFactor()),
|
||||
blendMode, view);
|
||||
default:
|
||||
case StreamerFeatherType::None:
|
||||
AddColoredQuad(
|
||||
vertex0, vertex1,
|
||||
prevVertex1,
|
||||
prevVertex0,
|
||||
color,
|
||||
color,
|
||||
prevColor,
|
||||
prevColor,
|
||||
streamer.GetBlendMode(), view);
|
||||
break;
|
||||
|
||||
case StreamerFeatherType::Center:
|
||||
{
|
||||
auto center = (vertex0 + vertex1) / 2;
|
||||
auto prevCenter = (prevVertex0 + prevVertex1) / 2;
|
||||
|
||||
AddColoredQuad(
|
||||
center, vertex1, prevVertex1, prevCenter,
|
||||
color, Vector4::Zero, Vector4::Zero, prevColor,
|
||||
streamer.GetBlendMode(), view);
|
||||
AddColoredQuad(
|
||||
vertex0, center, prevCenter, prevVertex0,
|
||||
Vector4::Zero, color, prevColor, Vector4::Zero,
|
||||
streamer.GetBlendMode(), view);
|
||||
}
|
||||
break;
|
||||
|
||||
case StreamerFeatherType::Left:
|
||||
AddColoredQuad(
|
||||
vertex0, vertex1, prevVertex1, prevVertex0,
|
||||
color, Vector4::Zero, Vector4::Zero, prevColor,
|
||||
streamer.GetBlendMode(), view);
|
||||
break;
|
||||
|
||||
case StreamerFeatherType::Right:
|
||||
AddColoredQuad(
|
||||
vertex0, vertex1, prevVertex1, prevVertex0,
|
||||
Vector4::Zero, color, prevColor, Vector4::Zero,
|
||||
streamer.GetBlendMode(), view);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue