refactor(Core/Game): restyle game lib with astyle (#3466)

This commit is contained in:
Kargatum
2020-10-12 15:08:15 +07:00
committed by GitHub
parent e99b526e17
commit a2b26272d2
338 changed files with 52196 additions and 50944 deletions

View File

@@ -9,301 +9,304 @@
#include "Log.h"
#include "Creature.h"
namespace Movement{
Location MoveSpline::ComputePosition() const
namespace Movement
{
ASSERT(Initialized());
float u = 1.f;
int32 seg_time = spline.length(point_Idx, point_Idx+1);
if (seg_time > 0)
u = (time_passed - spline.length(point_Idx)) / (float)seg_time;
Location c;
c.orientation = initialOrientation;
spline.evaluate_percent(point_Idx, u, c);
if (splineflags.animation)
;// MoveSplineFlag::Animation disables falling or parabolic movement
else if (splineflags.parabolic)
computeParabolicElevation(c.z);
else if (splineflags.falling)
computeFallElevation(c.z);
if (splineflags.done && splineflags.isFacing())
Location MoveSpline::ComputePosition() const
{
if (splineflags.final_angle)
c.orientation = facing.angle;
else if (splineflags.final_point)
c.orientation = atan2(facing.f.y - c.y, facing.f.x - c.x);
//nothing to do for MoveSplineFlag::Final_Target flag
}
else
{
if (!splineflags.hasFlag(MoveSplineFlag::OrientationFixed | MoveSplineFlag::Falling))
ASSERT(Initialized());
float u = 1.f;
int32 seg_time = spline.length(point_Idx, point_Idx + 1);
if (seg_time > 0)
u = (time_passed - spline.length(point_Idx)) / (float)seg_time;
Location c;
c.orientation = initialOrientation;
spline.evaluate_percent(point_Idx, u, c);
if (splineflags.animation)
;// MoveSplineFlag::Animation disables falling or parabolic movement
else if (splineflags.parabolic)
computeParabolicElevation(c.z);
else if (splineflags.falling)
computeFallElevation(c.z);
if (splineflags.done && splineflags.isFacing())
{
Vector3 hermite;
spline.evaluate_derivative(point_Idx, u, hermite);
c.orientation = atan2(hermite.y, hermite.x);
if (splineflags.final_angle)
c.orientation = facing.angle;
else if (splineflags.final_point)
c.orientation = atan2(facing.f.y - c.y, facing.f.x - c.x);
//nothing to do for MoveSplineFlag::Final_Target flag
}
if (splineflags.orientationInversed)
c.orientation = -c.orientation;
}
return c;
}
void MoveSpline::computeParabolicElevation(float& el) const
{
if (time_passed > effect_start_time)
{
float t_passedf = MSToSec(time_passed - effect_start_time);
float t_durationf = MSToSec(Duration() - effect_start_time); //client use not modified duration here
// -a*x*x + bx + c:
//(dur * v3->z_acceleration * dt)/2 - (v3->z_acceleration * dt * dt)/2 + Z;
el += (t_durationf - t_passedf) * 0.5f * vertical_acceleration * t_passedf;
}
}
void MoveSpline::computeFallElevation(float& el) const
{
float z_now = spline.getPoint(spline.first(), false).z - Movement::computeFallElevation(MSToSec(time_passed), false);
float final_z = FinalDestination().z;
el = std::max(z_now, final_z);
}
inline uint32 computeDuration(float length, float velocity)
{
return SecToMS(length / velocity);
}
struct FallInitializer
{
FallInitializer(float _start_elevation) : start_elevation(_start_elevation) {}
float start_elevation;
inline int32 operator()(Spline<int32>& s, int32 i)
{
return Movement::computeFallTime(start_elevation - s.getPoint(i+1, false).z, false) * 1000.f;
}
};
enum{
minimal_duration = 1
};
struct CommonInitializer
{
CommonInitializer(float _velocity) : velocityInv(1000.f/_velocity), time(minimal_duration) {}
float velocityInv;
int32 time;
inline int32 operator()(Spline<int32>& s, int32 i)
{
time += (s.SegLength(i) * velocityInv);
return time;
}
};
void MoveSpline::init_spline(const MoveSplineInitArgs& args)
{
const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear, SplineBase::ModeCatmullrom};
if (args.flags.cyclic)
{
uint32 cyclic_point = 0;
// MoveSplineFlag::Enter_Cycle support dropped
//if (splineflags & SPLINEFLAG_ENTER_CYCLE)
//cyclic_point = 1; // shouldn't be modified, came from client
spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point);
}
else
{
spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]);
}
// init spline timestamps
if (splineflags.falling)
{
FallInitializer init(spline.getPoint(spline.first(), false).z);
spline.initLengths(init);
}
else
{
CommonInitializer init(args.velocity);
spline.initLengths(init);
}
// TODO: what to do in such cases? problem is in input data (all points are at same coords)
if (spline.length() < minimal_duration)
{
//sLog->outError("MoveSpline::init_spline: zero length spline, wrong input data?"); // ZOMG! temp comment to avoid console spam from transports
spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1);
}
point_Idx = spline.first();
}
void MoveSpline::Initialize(MoveSplineInitArgs const& args)
{
splineflags = args.flags;
facing = args.facing;
m_Id = args.splineId;
point_Idx_offset = args.path_Idx_offset;
initialOrientation = args.initialOrientation;
time_passed = 0;
vertical_acceleration = 0.f;
effect_start_time = 0;
// Check if its a stop spline
if (args.flags.done)
{
spline.clear();
return;
}
init_spline(args);
// init parabolic / animation
// spline initialized, duration known and i able to compute parabolic acceleration
if (args.flags & (MoveSplineFlag::Parabolic | MoveSplineFlag::Animation))
{
effect_start_time = Duration() * args.time_perc;
if (args.flags.parabolic && effect_start_time < Duration())
else
{
float f_duration = MSToSec(Duration() - effect_start_time);
vertical_acceleration = args.parabolic_amplitude * 8.f / (f_duration * f_duration);
if (!splineflags.hasFlag(MoveSplineFlag::OrientationFixed | MoveSplineFlag::Falling))
{
Vector3 hermite;
spline.evaluate_derivative(point_Idx, u, hermite);
c.orientation = atan2(hermite.y, hermite.x);
}
if (splineflags.orientationInversed)
c.orientation = -c.orientation;
}
return c;
}
void MoveSpline::computeParabolicElevation(float& el) const
{
if (time_passed > effect_start_time)
{
float t_passedf = MSToSec(time_passed - effect_start_time);
float t_durationf = MSToSec(Duration() - effect_start_time); //client use not modified duration here
// -a*x*x + bx + c:
//(dur * v3->z_acceleration * dt)/2 - (v3->z_acceleration * dt * dt)/2 + Z;
el += (t_durationf - t_passedf) * 0.5f * vertical_acceleration * t_passedf;
}
}
}
MoveSpline::MoveSpline() : m_Id(0), time_passed(0),
vertical_acceleration(0.f), initialOrientation(0.f), effect_start_time(0), point_Idx(0), point_Idx_offset(0),
onTransport(false)
{
splineflags.done = true;
}
void MoveSpline::computeFallElevation(float& el) const
{
float z_now = spline.getPoint(spline.first(), false).z - Movement::computeFallElevation(MSToSec(time_passed), false);
float final_z = FinalDestination().z;
el = std::max(z_now, final_z);
}
/// ============================================================================================
inline uint32 computeDuration(float length, float velocity)
{
return SecToMS(length / velocity);
}
bool MoveSplineInitArgs::Validate(Unit* unit) const
{
struct FallInitializer
{
FallInitializer(float _start_elevation) : start_elevation(_start_elevation) {}
float start_elevation;
inline int32 operator()(Spline<int32>& s, int32 i)
{
return Movement::computeFallTime(start_elevation - s.getPoint(i + 1, false).z, false) * 1000.f;
}
};
enum
{
minimal_duration = 1
};
struct CommonInitializer
{
CommonInitializer(float _velocity) : velocityInv(1000.f / _velocity), time(minimal_duration) {}
float velocityInv;
int32 time;
inline int32 operator()(Spline<int32>& s, int32 i)
{
time += (s.SegLength(i) * velocityInv);
return time;
}
};
void MoveSpline::init_spline(const MoveSplineInitArgs& args)
{
const SplineBase::EvaluationMode modes[2] = {SplineBase::ModeLinear, SplineBase::ModeCatmullrom};
if (args.flags.cyclic)
{
uint32 cyclic_point = 0;
// MoveSplineFlag::Enter_Cycle support dropped
//if (splineflags & SPLINEFLAG_ENTER_CYCLE)
//cyclic_point = 1; // shouldn't be modified, came from client
spline.init_cyclic_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()], cyclic_point);
}
else
{
spline.init_spline(&args.path[0], args.path.size(), modes[args.flags.isSmooth()]);
}
// init spline timestamps
if (splineflags.falling)
{
FallInitializer init(spline.getPoint(spline.first(), false).z);
spline.initLengths(init);
}
else
{
CommonInitializer init(args.velocity);
spline.initLengths(init);
}
// TODO: what to do in such cases? problem is in input data (all points are at same coords)
if (spline.length() < minimal_duration)
{
//sLog->outError("MoveSpline::init_spline: zero length spline, wrong input data?"); // ZOMG! temp comment to avoid console spam from transports
spline.set_length(spline.last(), spline.isCyclic() ? 1000 : 1);
}
point_Idx = spline.first();
}
void MoveSpline::Initialize(MoveSplineInitArgs const& args)
{
splineflags = args.flags;
facing = args.facing;
m_Id = args.splineId;
point_Idx_offset = args.path_Idx_offset;
initialOrientation = args.initialOrientation;
time_passed = 0;
vertical_acceleration = 0.f;
effect_start_time = 0;
// Check if its a stop spline
if (args.flags.done)
{
spline.clear();
return;
}
init_spline(args);
// init parabolic / animation
// spline initialized, duration known and i able to compute parabolic acceleration
if (args.flags & (MoveSplineFlag::Parabolic | MoveSplineFlag::Animation))
{
effect_start_time = Duration() * args.time_perc;
if (args.flags.parabolic && effect_start_time < Duration())
{
float f_duration = MSToSec(Duration() - effect_start_time);
vertical_acceleration = args.parabolic_amplitude * 8.f / (f_duration * f_duration);
}
}
}
MoveSpline::MoveSpline() : m_Id(0), time_passed(0),
vertical_acceleration(0.f), initialOrientation(0.f), effect_start_time(0), point_Idx(0), point_Idx_offset(0),
onTransport(false)
{
splineflags.done = true;
}
/// ============================================================================================
bool MoveSplineInitArgs::Validate(Unit* unit) const
{
#define CHECK(exp) \
if (!(exp))\
{\
sLog->outError("MoveSplineInitArgs::Validate: expression '%s' failed for GUID: %u Entry: %u", #exp, unit->GetTypeId() == TYPEID_PLAYER ? unit->GetGUIDLow() : unit->ToCreature()->GetDBTableGUIDLow(), unit->GetEntry());\
return false;\
}
CHECK(path.size() > 1);
CHECK(velocity > 0.01f);
CHECK(time_perc >= 0.f && time_perc <= 1.f);
//CHECK(_checkPathBounds());
return true;
CHECK(path.size() > 1);
CHECK(velocity > 0.01f);
CHECK(time_perc >= 0.f && time_perc <= 1.f);
//CHECK(_checkPathBounds());
return true;
#undef CHECK
}
}
// MONSTER_MOVE packet format limitation for not CatmullRom movement:
// each vertex offset packed into 11 bytes
bool MoveSplineInitArgs::_checkPathBounds() const
{
if (!(flags & MoveSplineFlag::Mask_CatmullRom) && path.size() > 2)
// MONSTER_MOVE packet format limitation for not CatmullRom movement:
// each vertex offset packed into 11 bytes
bool MoveSplineInitArgs::_checkPathBounds() const
{
enum{
MAX_OFFSET = (1 << 11) / 2
};
Vector3 middle = (path.front()+path.back()) / 2;
Vector3 offset;
for (uint32 i = 1; i < path.size()-1; ++i)
if (!(flags & MoveSplineFlag::Mask_CatmullRom) && path.size() > 2)
{
offset = path[i] - middle;
if (fabs(offset.x) >= MAX_OFFSET || fabs(offset.y) >= MAX_OFFSET || fabs(offset.z) >= MAX_OFFSET)
enum
{
sLog->outError("MoveSplineInitArgs::_checkPathBounds check failed");
return false;
MAX_OFFSET = (1 << 11) / 2
};
Vector3 middle = (path.front() + path.back()) / 2;
Vector3 offset;
for (uint32 i = 1; i < path.size() - 1; ++i)
{
offset = path[i] - middle;
if (fabs(offset.x) >= MAX_OFFSET || fabs(offset.y) >= MAX_OFFSET || fabs(offset.z) >= MAX_OFFSET)
{
sLog->outError("MoveSplineInitArgs::_checkPathBounds check failed");
return false;
}
}
}
}
return true;
}
/// ============================================================================================
MoveSpline::UpdateResult MoveSpline::_updateState(int32& ms_time_diff)
{
if (Finalized())
{
ms_time_diff = 0;
return Result_Arrived;
return true;
}
UpdateResult result = Result_None;
/// ============================================================================================
int32 minimal_diff = std::min(ms_time_diff, segment_time_elapsed());
if (minimal_diff < 0)
minimal_diff = 0;
ASSERT(minimal_diff >= 0);
time_passed += minimal_diff;
ms_time_diff -= minimal_diff;
if (time_passed >= next_timestamp())
MoveSpline::UpdateResult MoveSpline::_updateState(int32& ms_time_diff)
{
++point_Idx;
if (point_Idx < spline.last())
if (Finalized())
{
result = Result_NextSegment;
ms_time_diff = 0;
return Result_Arrived;
}
else
UpdateResult result = Result_None;
int32 minimal_diff = std::min(ms_time_diff, segment_time_elapsed());
if (minimal_diff < 0)
minimal_diff = 0;
ASSERT(minimal_diff >= 0);
time_passed += minimal_diff;
ms_time_diff -= minimal_diff;
if (time_passed >= next_timestamp())
{
if (spline.isCyclic())
++point_Idx;
if (point_Idx < spline.last())
{
point_Idx = spline.first();
time_passed = time_passed % Duration();
result = Movement::MoveSpline::UpdateResult(Result_NextCycle | Result_JustArrived);
result = Result_NextSegment;
}
else
{
_Finalize();
ms_time_diff = 0;
result = Movement::MoveSpline::UpdateResult(Result_Arrived | Result_JustArrived);
if (spline.isCyclic())
{
point_Idx = spline.first();
time_passed = time_passed % Duration();
result = Movement::MoveSpline::UpdateResult(Result_NextCycle | Result_JustArrived);
}
else
{
_Finalize();
ms_time_diff = 0;
result = Movement::MoveSpline::UpdateResult(Result_Arrived | Result_JustArrived);
}
}
}
return result;
}
return result;
}
std::string MoveSpline::ToString() const
{
std::stringstream str;
str << "MoveSpline" << std::endl;
str << "spline Id: " << GetId() << std::endl;
str << "flags: " << splineflags.ToString() << std::endl;
if (splineflags.final_angle)
str << "facing angle: " << facing.angle;
else if (splineflags.final_target)
str << "facing target: " << facing.target;
else if (splineflags.final_point)
str << "facing point: " << facing.f.x << " " << facing.f.y << " " << facing.f.z;
str << std::endl;
str << "time passed: " << time_passed << std::endl;
str << "total time: " << Duration() << std::endl;
str << "spline point Id: " << point_Idx << std::endl;
str << "path point Id: " << currentPathIdx() << std::endl;
str << spline.ToString();
return str.str();
}
std::string MoveSpline::ToString() const
{
std::stringstream str;
str << "MoveSpline" << std::endl;
str << "spline Id: " << GetId() << std::endl;
str << "flags: " << splineflags.ToString() << std::endl;
if (splineflags.final_angle)
str << "facing angle: " << facing.angle;
else if (splineflags.final_target)
str << "facing target: " << facing.target;
else if (splineflags.final_point)
str << "facing point: " << facing.f.x << " " << facing.f.y << " " << facing.f.z;
str << std::endl;
str << "time passed: " << time_passed << std::endl;
str << "total time: " << Duration() << std::endl;
str << "spline point Id: " << point_Idx << std::endl;
str << "path point Id: " << currentPathIdx() << std::endl;
str << spline.ToString();
return str.str();
}
void MoveSpline::_Finalize()
{
splineflags.done = true;
point_Idx = spline.last() - 1;
time_passed = Duration();
}
void MoveSpline::_Finalize()
{
splineflags.done = true;
point_Idx = spline.last() - 1;
time_passed = Duration();
}
int32 MoveSpline::currentPathIdx() const
{
int32 point = point_Idx_offset + point_Idx - spline.first() + (int)Finalized();
if (isCyclic())
point = point % (spline.last()-spline.first());
return point;
}
int32 MoveSpline::currentPathIdx() const
{
int32 point = point_Idx_offset + point_Idx - spline.first() + (int)Finalized();
if (isCyclic())
point = point % (spline.last() - spline.first());
return point;
}
}

View File

@@ -24,7 +24,7 @@ namespace Movement
enum eFlags
{
None = 0x00000000,
// x00-xFF(first byte) used as animation Ids storage in pair with Animation flag
// x00-xFF(first byte) used as animation Ids storage in pair with Animation flag
Done = 0x00000100,
Falling = 0x00000200, // Affects elevation computation, can't be combined with Parabolic flag
No_Spline = 0x00000400,
@@ -59,21 +59,21 @@ namespace Movement
// CatmullRom interpolation mode used
Mask_CatmullRom = Flying | Catmullrom,
// Unused, not suported flags
Mask_Unused = No_Spline|Enter_Cycle|Frozen|Unknown7|Unknown8|Unknown10|Unknown11|Unknown12|Unknown13
Mask_Unused = No_Spline | Enter_Cycle | Frozen | Unknown7 | Unknown8 | Unknown10 | Unknown11 | Unknown12 | Unknown13
};
inline uint32& raw() { return (uint32&)*this; }
inline const uint32& raw() const { return (const uint32&)*this; }
inline uint32& raw() { return (uint32&) * this; }
inline const uint32& raw() const { return (const uint32&) * this; }
MoveSplineFlag() { raw() = 0; }
MoveSplineFlag(uint32 f) { raw() = f; }
MoveSplineFlag(const MoveSplineFlag& f) { raw() = f.raw(); }
/* requried as of C++ 11 */
#if __cplusplus >= 201103L
#if __cplusplus >= 201103L
MoveSplineFlag(MoveSplineFlag&&) = default;
MoveSplineFlag& operator=(const MoveSplineFlag&) = default;
MoveSplineFlag& operator=(MoveSplineFlag&&) = default;
#endif
#endif
// Constant interface

View File

@@ -79,7 +79,7 @@ namespace Movement
move_spline.onTransport = transport;
uint32 moveFlags = unit->m_movementInfo.GetMovementFlags();
moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED|MOVEMENTFLAG_FORWARD);
moveFlags |= (MOVEMENTFLAG_SPLINE_ENABLED | MOVEMENTFLAG_FORWARD);
if (moveFlags & MOVEMENTFLAG_ROOT)
moveFlags &= ~MOVEMENTFLAG_MASK_MOVING;
@@ -121,7 +121,7 @@ namespace Movement
std::copy(move_spline._Spline().getPoints(false).begin(), move_spline._Spline().getPoints(false).end(), visualPoints->begin());
PacketBuilder::WriteMonsterMove(move_spline, data);
unit->SendMessageToSet(&data,true);
unit->SendMessageToSet(&data, true);
return move_spline.Duration();
}

View File

@@ -18,7 +18,8 @@ namespace Movement
union FacingInfo
{
struct {
struct
{
float x, y, z;
} f;
uint64 target;

View File

@@ -88,7 +88,7 @@ namespace Movement
void WriteLinearPath(const Spline<int32>& spline, ByteBuffer& data)
{
uint32 last_idx = spline.getPointCount() - 3;
const Vector3 * real_path = &spline.getPoint(1, true);
const Vector3* real_path = &spline.getPoint(1, true);
data << last_idx;
data << real_path[last_idx]; // destination
@@ -115,7 +115,7 @@ namespace Movement
void WriteCatmullRomCyclicPath(const Spline<int32>& spline, ByteBuffer& data, bool flying)
{
uint32 count = spline.getPointCount() - 3;
data << uint32(count+1);
data << uint32(count + 1);
if (flying)
{
data << spline.getPoint(1, true); // fake point, client will erase it from the spline after first cycle done

View File

@@ -3,7 +3,7 @@
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#ifndef TRINITYSERVER_PACKET_BUILDER_H
#define TRINITYSERVER_PACKET_BUILDER_H

View File

@@ -17,8 +17,8 @@ namespace Movement
float terminalVelocity = 60.148003f;
float terminalSafefallVelocity = 7.0f;
const float terminal_length = float(terminalVelocity * terminalVelocity) / (2.0f * gravity);
const float terminal_safeFall_length = (terminalSafefallVelocity * terminalSafefallVelocity) / (2.0f * gravity);
const float terminal_length = float(terminalVelocity* terminalVelocity) / (2.0f * gravity);
const float terminal_safeFall_length = (terminalSafefallVelocity* terminalSafefallVelocity) / (2.0f * gravity);
const float terminal_fallTime = float(terminalVelocity / gravity); // the time that needed to reach terminalVelocity
const float terminal_safeFall_fallTime = float(terminalSafefallVelocity / gravity); // the time that needed to reach terminalVelocity with safefall
@@ -64,8 +64,8 @@ namespace Movement
if (t_passed > terminal_time)
{
result = termVel * (t_passed - terminal_time) +
start_velocity * terminal_time +
gravity * terminal_time * terminal_time*0.5f;
start_velocity * terminal_time +
gravity * terminal_time * terminal_time * 0.5f;
}
else
result = t_passed * (start_velocity + t_passed * gravity * 0.5f);
@@ -73,7 +73,7 @@ namespace Movement
return result;
}
#define STR(x) #x
#define STR(x) #x
char const* g_MovementFlag_names[] =
{
@@ -165,7 +165,7 @@ namespace Movement
};
template<class Flags, int N>
void print_flags(Flags t, char const* (&names)[N], std::string& str)
void print_flags(Flags t, char const * (&names)[N], std::string& str)
{
for (int i = 0; i < N; ++i)
{

View File

@@ -8,287 +8,288 @@
#include <sstream>
#include <G3D/Matrix4.h>
namespace Movement{
SplineBase::EvaluationMethtod SplineBase::evaluators[SplineBase::ModesEnd] =
namespace Movement
{
&SplineBase::EvaluateLinear,
&SplineBase::EvaluateCatmullRom,
&SplineBase::EvaluateBezier3,
&SplineBase::UninitializedSplineEvaluationMethod,
};
SplineBase::EvaluationMethtod SplineBase::derivative_evaluators[SplineBase::ModesEnd] =
{
&SplineBase::EvaluateDerivativeLinear,
&SplineBase::EvaluateDerivativeCatmullRom,
&SplineBase::EvaluateDerivativeBezier3,
&SplineBase::UninitializedSplineEvaluationMethod,
};
SplineBase::SegLenghtMethtod SplineBase::seglengths[SplineBase::ModesEnd] =
{
&SplineBase::SegLengthLinear,
&SplineBase::SegLengthCatmullRom,
&SplineBase::SegLengthBezier3,
&SplineBase::UninitializedSplineSegLenghtMethod,
};
SplineBase::InitMethtod SplineBase::initializers[SplineBase::ModesEnd] =
{
//&SplineBase::InitLinear,
&SplineBase::InitCatmullRom, // we should use catmullrom initializer even for linear mode! (client's internal structure limitation)
&SplineBase::InitCatmullRom,
&SplineBase::InitBezier3,
&SplineBase::UninitializedSplineInitMethod,
};
///////////
using G3D::Matrix4;
static const Matrix4 s_catmullRomCoeffs(
-0.5f, 1.5f, -1.5f, 0.5f,
1.f, -2.5f, 2.f, -0.5f,
-0.5f, 0.f, 0.5f, 0.f,
0.f, 1.f, 0.f, 0.f);
static const Matrix4 s_Bezier3Coeffs(
-1.f, 3.f, -3.f, 1.f,
3.f, -6.f, 3.f, 0.f,
-3.f, 3.f, 0.f, 0.f,
1.f, 0.f, 0.f, 0.f);
/* classic view:
inline void C_Evaluate(const Vector3 *vertice, float t, const float (&matrix)[4][4], Vector3 &position)
{
Vector3 tvec(t*t*t, t*t, t);
int i = 0;
double c;
double x = 0, y = 0, z = 0;
while ( i < 4 )
SplineBase::EvaluationMethtod SplineBase::evaluators[SplineBase::ModesEnd] =
{
c = matrix[0][i]*tvec.x + matrix[1][i]*tvec.y + matrix[2][i]*tvec.z + matrix[3][i];
&SplineBase::EvaluateLinear,
&SplineBase::EvaluateCatmullRom,
&SplineBase::EvaluateBezier3,
&SplineBase::UninitializedSplineEvaluationMethod,
};
x += c * vertice->x;
y += c * vertice->y;
z += c * vertice->z;
SplineBase::EvaluationMethtod SplineBase::derivative_evaluators[SplineBase::ModesEnd] =
{
&SplineBase::EvaluateDerivativeLinear,
&SplineBase::EvaluateDerivativeCatmullRom,
&SplineBase::EvaluateDerivativeBezier3,
&SplineBase::UninitializedSplineEvaluationMethod,
};
++i;
++vertice;
SplineBase::SegLenghtMethtod SplineBase::seglengths[SplineBase::ModesEnd] =
{
&SplineBase::SegLengthLinear,
&SplineBase::SegLengthCatmullRom,
&SplineBase::SegLengthBezier3,
&SplineBase::UninitializedSplineSegLenghtMethod,
};
SplineBase::InitMethtod SplineBase::initializers[SplineBase::ModesEnd] =
{
//&SplineBase::InitLinear,
&SplineBase::InitCatmullRom, // we should use catmullrom initializer even for linear mode! (client's internal structure limitation)
&SplineBase::InitCatmullRom,
&SplineBase::InitBezier3,
&SplineBase::UninitializedSplineInitMethod,
};
///////////
using G3D::Matrix4;
static const Matrix4 s_catmullRomCoeffs(
-0.5f, 1.5f, -1.5f, 0.5f,
1.f, -2.5f, 2.f, -0.5f,
-0.5f, 0.f, 0.5f, 0.f,
0.f, 1.f, 0.f, 0.f);
static const Matrix4 s_Bezier3Coeffs(
-1.f, 3.f, -3.f, 1.f,
3.f, -6.f, 3.f, 0.f,
-3.f, 3.f, 0.f, 0.f,
1.f, 0.f, 0.f, 0.f);
/* classic view:
inline void C_Evaluate(const Vector3 *vertice, float t, const float (&matrix)[4][4], Vector3 &position)
{
Vector3 tvec(t*t*t, t*t, t);
int i = 0;
double c;
double x = 0, y = 0, z = 0;
while ( i < 4 )
{
c = matrix[0][i]*tvec.x + matrix[1][i]*tvec.y + matrix[2][i]*tvec.z + matrix[3][i];
x += c * vertice->x;
y += c * vertice->y;
z += c * vertice->z;
++i;
++vertice;
}
position.x = x;
position.y = y;
position.z = z;
}*/
inline void C_Evaluate(const Vector3* vertice, float t, const Matrix4& matr, Vector3& result)
{
Vector4 tvec(t * t * t, t * t, t, 1.f);
Vector4 weights(tvec * matr);
result = vertice[0] * weights[0] + vertice[1] * weights[1]
+ vertice[2] * weights[2] + vertice[3] * weights[3];
}
position.x = x;
position.y = y;
position.z = z;
}*/
inline void C_Evaluate(const Vector3 *vertice, float t, const Matrix4& matr, Vector3 &result)
{
Vector4 tvec(t*t*t, t*t, t, 1.f);
Vector4 weights(tvec * matr);
result = vertice[0] * weights[0] + vertice[1] * weights[1]
+ vertice[2] * weights[2] + vertice[3] * weights[3];
}
inline void C_Evaluate_Derivative(const Vector3 *vertice, float t, const Matrix4& matr, Vector3 &result)
{
Vector4 tvec(3.f*t*t, 2.f*t, 1.f, 0.f);
Vector4 weights(tvec * matr);
result = vertice[0] * weights[0] + vertice[1] * weights[1]
+ vertice[2] * weights[2] + vertice[3] * weights[3];
}
void SplineBase::EvaluateLinear(index_type index, float u, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
result = points[index] + (points[index+1] - points[index]) * u;
}
void SplineBase::EvaluateCatmullRom( index_type index, float t, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate(&points[index - 1], t, s_catmullRomCoeffs, result);
}
void SplineBase::EvaluateBezier3(index_type index, float t, Vector3& result) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate(&points[index], t, s_Bezier3Coeffs, result);
}
void SplineBase::EvaluateDerivativeLinear(index_type index, float, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
result = points[index+1] - points[index];
}
void SplineBase::EvaluateDerivativeCatmullRom(index_type index, float t, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate_Derivative(&points[index - 1], t, s_catmullRomCoeffs, result);
}
void SplineBase::EvaluateDerivativeBezier3(index_type index, float t, Vector3& result) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate_Derivative(&points[index], t, s_Bezier3Coeffs, result);
}
float SplineBase::SegLengthLinear(index_type index) const
{
ASSERT(index >= index_lo && index < index_hi);
return (points[index] - points[index+1]).length();
}
float SplineBase::SegLengthCatmullRom(index_type index) const
{
ASSERT(index >= index_lo && index < index_hi);
Vector3 curPos, nextPos;
const Vector3 * p = &points[index - 1];
curPos = nextPos = p[1];
index_type i = 1;
double length = 0;
while (i <= STEPS_PER_SEGMENT)
inline void C_Evaluate_Derivative(const Vector3* vertice, float t, const Matrix4& matr, Vector3& result)
{
C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_catmullRomCoeffs, nextPos);
length += (nextPos - curPos).length();
Vector4 tvec(3.f * t * t, 2.f * t, 1.f, 0.f);
Vector4 weights(tvec * matr);
result = vertice[0] * weights[0] + vertice[1] * weights[1]
+ vertice[2] * weights[2] + vertice[3] * weights[3];
}
void SplineBase::EvaluateLinear(index_type index, float u, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
result = points[index] + (points[index + 1] - points[index]) * u;
}
void SplineBase::EvaluateCatmullRom( index_type index, float t, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate(&points[index - 1], t, s_catmullRomCoeffs, result);
}
void SplineBase::EvaluateBezier3(index_type index, float t, Vector3& result) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate(&points[index], t, s_Bezier3Coeffs, result);
}
void SplineBase::EvaluateDerivativeLinear(index_type index, float, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
result = points[index + 1] - points[index];
}
void SplineBase::EvaluateDerivativeCatmullRom(index_type index, float t, Vector3& result) const
{
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate_Derivative(&points[index - 1], t, s_catmullRomCoeffs, result);
}
void SplineBase::EvaluateDerivativeBezier3(index_type index, float t, Vector3& result) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
C_Evaluate_Derivative(&points[index], t, s_Bezier3Coeffs, result);
}
float SplineBase::SegLengthLinear(index_type index) const
{
ASSERT(index >= index_lo && index < index_hi);
return (points[index] - points[index + 1]).length();
}
float SplineBase::SegLengthCatmullRom(index_type index) const
{
ASSERT(index >= index_lo && index < index_hi);
Vector3 curPos, nextPos;
const Vector3* p = &points[index - 1];
curPos = nextPos = p[1];
index_type i = 1;
double length = 0;
while (i <= STEPS_PER_SEGMENT)
{
C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_catmullRomCoeffs, nextPos);
length += (nextPos - curPos).length();
curPos = nextPos;
++i;
}
return length;
}
float SplineBase::SegLengthBezier3(index_type index) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
Vector3 curPos, nextPos;
const Vector3* p = &points[index];
C_Evaluate(p, 0.f, s_Bezier3Coeffs, nextPos);
curPos = nextPos;
++i;
index_type i = 1;
double length = 0;
while (i <= STEPS_PER_SEGMENT)
{
C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_Bezier3Coeffs, nextPos);
length += (nextPos - curPos).length();
curPos = nextPos;
++i;
}
return length;
}
return length;
}
float SplineBase::SegLengthBezier3(index_type index) const
{
index *= 3u;
ASSERT(index >= index_lo && index < index_hi);
Vector3 curPos, nextPos;
const Vector3 * p = &points[index];
C_Evaluate(p, 0.f, s_Bezier3Coeffs, nextPos);
curPos = nextPos;
index_type i = 1;
double length = 0;
while (i <= STEPS_PER_SEGMENT)
void SplineBase::init_spline(const Vector3* controls, index_type count, EvaluationMode m)
{
C_Evaluate(p, float(i) / float(STEPS_PER_SEGMENT), s_Bezier3Coeffs, nextPos);
length += (nextPos - curPos).length();
curPos = nextPos;
++i;
m_mode = m;
cyclic = false;
(this->*initializers[m_mode])(controls, count, cyclic, 0);
}
return length;
}
void SplineBase::init_spline(const Vector3 * controls, index_type count, EvaluationMode m)
{
m_mode = m;
cyclic = false;
(this->*initializers[m_mode])(controls, count, cyclic, 0);
}
void SplineBase::init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point)
{
m_mode = m;
cyclic = true;
(this->*initializers[m_mode])(controls, count, cyclic, cyclic_point);
}
void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
{
ASSERT(count >= 2);
const int real_size = count + 1;
points.resize(real_size);
memcpy(&points[0], controls, sizeof(Vector3) * count);
// first and last two indexes are space for special 'virtual points'
// these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
if (cyclic)
points[count] = controls[cyclic_point];
else
points[count] = controls[count-1];
index_lo = 0;
index_hi = cyclic ? count : (count - 1);
}
void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
{
const int real_size = count + (cyclic ? (1+2) : (1+1));
points.resize(real_size);
int lo_index = 1;
int high_index = lo_index + count - 1;
memcpy(&points[lo_index], controls, sizeof(Vector3) * count);
// first and last two indexes are space for special 'virtual points'
// these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
if (cyclic)
void SplineBase::init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point)
{
if (cyclic_point == 0)
points[0] = controls[count-1];
m_mode = m;
cyclic = true;
(this->*initializers[m_mode])(controls, count, cyclic, cyclic_point);
}
void SplineBase::InitLinear(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
{
ASSERT(count >= 2);
const int real_size = count + 1;
points.resize(real_size);
memcpy(&points[0], controls, sizeof(Vector3) * count);
// first and last two indexes are space for special 'virtual points'
// these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
if (cyclic)
points[count] = controls[cyclic_point];
else
points[0] = controls[0].lerp(controls[1], -1);
points[count] = controls[count - 1];
points[high_index+1] = controls[cyclic_point];
points[high_index+2] = controls[cyclic_point+1];
index_lo = 0;
index_hi = cyclic ? count : (count - 1);
}
else
void SplineBase::InitCatmullRom(const Vector3* controls, index_type count, bool cyclic, index_type cyclic_point)
{
points[0] = controls[0].lerp(controls[1], -1);
points[high_index+1] = controls[count-1];
const int real_size = count + (cyclic ? (1 + 2) : (1 + 1));
points.resize(real_size);
int lo_index = 1;
int high_index = lo_index + count - 1;
memcpy(&points[lo_index], controls, sizeof(Vector3) * count);
// first and last two indexes are space for special 'virtual points'
// these points are required for proper C_Evaluate and C_Evaluate_Derivative methtod work
if (cyclic)
{
if (cyclic_point == 0)
points[0] = controls[count - 1];
else
points[0] = controls[0].lerp(controls[1], -1);
points[high_index + 1] = controls[cyclic_point];
points[high_index + 2] = controls[cyclic_point + 1];
}
else
{
points[0] = controls[0].lerp(controls[1], -1);
points[high_index + 1] = controls[count - 1];
}
index_lo = lo_index;
index_hi = high_index + (cyclic ? 1 : 0);
}
index_lo = lo_index;
index_hi = high_index + (cyclic ? 1 : 0);
}
void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/)
{
index_type c = count / 3u * 3u;
index_type t = c / 3u;
void SplineBase::InitBezier3(const Vector3* controls, index_type count, bool /*cyclic*/, index_type /*cyclic_point*/)
{
index_type c = count / 3u * 3u;
index_type t = c / 3u;
points.resize(c);
memcpy(&points[0], controls, sizeof(Vector3) * c);
points.resize(c);
memcpy(&points[0], controls, sizeof(Vector3) * c);
index_lo = 0;
index_hi = t - 1;
//mov_assert(points.size() % 3 == 0);
}
index_lo = 0;
index_hi = t-1;
//mov_assert(points.size() % 3 == 0);
}
void SplineBase::clear()
{
index_lo = 0;
index_hi = 0;
points.clear();
pointsVisual.clear();
}
void SplineBase::clear()
{
index_lo = 0;
index_hi = 0;
points.clear();
pointsVisual.clear();
}
std::string SplineBase::ToString() const
{
std::stringstream str;
const char* mode_str[ModesEnd] = {"Linear", "CatmullRom", "Bezier3", "Uninitialized"};
std::string SplineBase::ToString() const
{
std::stringstream str;
const char * mode_str[ModesEnd] = {"Linear", "CatmullRom", "Bezier3", "Uninitialized"};
index_type count = this->points.size();
str << "mode: " << mode_str[mode()] << std::endl;
str << "points count: " << count << std::endl;
for (index_type i = 0; i < count; ++i)
str << "point " << i << " : " << points[i].toString() << std::endl;
index_type count = this->points.size();
str << "mode: " << mode_str[mode()] << std::endl;
str << "points count: " << count << std::endl;
for (index_type i = 0; i < count; ++i)
str << "point " << i << " : " << points[i].toString() << std::endl;
return str.str();
}
return str.str();
}
}

View File

@@ -11,192 +11,194 @@
#include <G3D/Vector3.h>
#include <limits>
namespace Movement {
class SplineBase
namespace Movement
{
public:
typedef int index_type;
typedef std::vector<Vector3> ControlArray;
enum EvaluationMode
class SplineBase
{
ModeLinear,
ModeCatmullrom,
ModeBezier3_Unused,
UninitializedMode,
ModesEnd
};
public:
typedef int index_type;
typedef std::vector<Vector3> ControlArray;
protected:
ControlArray points;
ControlArray pointsVisual;
index_type index_lo;
index_type index_hi;
uint8 m_mode;
bool cyclic;
enum{
// could be modified, affects segment length evaluation precision
// lesser value saves more performance in cost of lover precision
// minimal value is 1
// client's value is 20, blizzs use 2-3 steps to compute length
STEPS_PER_SEGMENT = 3
};
static_assert(STEPS_PER_SEGMENT > 0, "shouldn't be lesser than 1");
protected:
void EvaluateLinear(index_type, float, Vector3&) const;
void EvaluateCatmullRom(index_type, float, Vector3&) const;
void EvaluateBezier3(index_type, float, Vector3&) const;
typedef void (SplineBase::*EvaluationMethtod)(index_type, float, Vector3&) const;
static EvaluationMethtod evaluators[ModesEnd];
void EvaluateDerivativeLinear(index_type, float, Vector3&) const;
void EvaluateDerivativeCatmullRom(index_type, float, Vector3&) const;
void EvaluateDerivativeBezier3(index_type, float, Vector3&) const;
static EvaluationMethtod derivative_evaluators[ModesEnd];
float SegLengthLinear(index_type) const;
float SegLengthCatmullRom(index_type) const;
float SegLengthBezier3(index_type) const;
typedef float (SplineBase::*SegLenghtMethtod)(index_type) const;
static SegLenghtMethtod seglengths[ModesEnd];
void InitLinear(const Vector3*, index_type, bool, index_type);
void InitCatmullRom(const Vector3*, index_type, bool, index_type);
void InitBezier3(const Vector3*, index_type, bool, index_type);
typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, bool, index_type);
static InitMethtod initializers[ModesEnd];
void UninitializedSplineEvaluationMethod(index_type, float, Vector3&) const { ABORT(); }
float UninitializedSplineSegLenghtMethod(index_type) const { ABORT(); }
void UninitializedSplineInitMethod(Vector3 const*, index_type, bool, index_type) { ABORT(); }
public:
explicit SplineBase() : index_lo(0), index_hi(0), m_mode(UninitializedMode), cyclic(false) {}
/** Caclulates the position for given segment Idx, and percent of segment length t
@param t - percent of segment length, assumes that t in range [0, 1]
@param Idx - spline segment index, should be in range [first, last)
*/
void evaluate_percent(index_type Idx, float u, Vector3& c) const {(this->*evaluators[m_mode])(Idx, u,c);}
/** Caclulates derivation in index Idx, and percent of segment length t
@param Idx - spline segment index, should be in range [first, last)
@param t - percent of spline segment length, assumes that t in range [0, 1]
*/
void evaluate_derivative(index_type Idx, float u, Vector3& hermite) const {(this->*derivative_evaluators[m_mode])(Idx, u,hermite);}
/** Bounds for spline indexes. All indexes should be in range [first, last). */
index_type first() const { return index_lo;}
index_type last() const { return index_hi;}
bool empty() const { return index_lo == index_hi;}
EvaluationMode mode() const { return (EvaluationMode)m_mode;}
bool isCyclic() const { return cyclic;}
// Xinef: DO NOT USE EXCEPT FOR SPLINE INITIALIZATION!!!!!!
const ControlArray* allocateVisualPoints() const { return &pointsVisual; }
const ControlArray& getPoints(bool visual) const { return visual ? pointsVisual : points;}
index_type getPointCount() const { return points.size();}
const Vector3& getPoint(index_type i, bool visual) const { return visual ? pointsVisual[i] : points[i];}
/** Initializes spline. Don't call other methods while spline not initialized. */
void init_spline(const Vector3 * controls, index_type count, EvaluationMode m);
void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point);
/** As i can see there are a lot of ways how spline can be initialized
would be no harm to have some custom initializers. */
template<class Init> inline void init_spline_custom(Init& initializer)
{
initializer(m_mode, cyclic, points, index_lo, index_hi);
}
void clear();
/** Calculates distance between [i; i+1] points, assumes that index i is in bounds. */
float SegLength(index_type i) const { return (this->*seglengths[m_mode])(i);}
std::string ToString() const;
};
template<typename length_type>
class Spline : public SplineBase
{
public:
typedef length_type LengthType;
typedef std::vector<length_type> LengthArray;
protected:
LengthArray lengths;
index_type computeIndexInBounds(length_type length) const;
public:
explicit Spline(){}
/** Calculates the position for given t
@param t - percent of spline's length, assumes that t in range [0, 1]. */
void evaluate_percent(float t, Vector3 & c) const;
/** Calculates derivation for given t
@param t - percent of spline's length, assumes that t in range [0, 1]. */
void evaluate_derivative(float t, Vector3& hermite) const;
/** Calculates the position for given segment Idx, and percent of segment length t
@param t = partial_segment_length / whole_segment_length
@param Idx - spline segment index, should be in range [first, last). */
void evaluate_percent(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_percent(Idx, u,c);}
/** Caclulates derivation for index Idx, and percent of segment length t
@param Idx - spline segment index, should be in range [first, last)
@param t - percent of spline segment length, assumes that t in range [0, 1]. */
void evaluate_derivative(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_derivative(Idx, u,c);}
// Assumes that t in range [0, 1]
index_type computeIndexInBounds(float t) const;
void computeIndex(float t, index_type& out_idx, float& out_u) const;
/** Initializes spline. Don't call other methods while spline not initialized. */
void init_spline(const Vector3 * controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls, count, m);}
void init_cyclic_spline(const Vector3 * controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls, count, m,cyclic_point);}
/** Initializes lengths with SplineBase::SegLength method. */
void initLengths();
/** Initializes lengths in some custom way
Note that value returned by cacher must be greater or equal to previous value. */
template<class T> inline void initLengths(T& cacher)
{
index_type i = index_lo;
lengths.resize(index_hi+1);
length_type prev_length = 0, new_length = 0;
while (i < index_hi)
enum EvaluationMode
{
new_length = cacher(*this, i);
// length overflowed, assign to max positive value
if (new_length < 0)
new_length = std::numeric_limits<length_type>::max();
lengths[++i] = new_length;
ModeLinear,
ModeCatmullrom,
ModeBezier3_Unused,
UninitializedMode,
ModesEnd
};
ASSERT(prev_length <= new_length);
prev_length = new_length;
protected:
ControlArray points;
ControlArray pointsVisual;
index_type index_lo;
index_type index_hi;
uint8 m_mode;
bool cyclic;
enum
{
// could be modified, affects segment length evaluation precision
// lesser value saves more performance in cost of lover precision
// minimal value is 1
// client's value is 20, blizzs use 2-3 steps to compute length
STEPS_PER_SEGMENT = 3
};
static_assert(STEPS_PER_SEGMENT > 0, "shouldn't be lesser than 1");
protected:
void EvaluateLinear(index_type, float, Vector3&) const;
void EvaluateCatmullRom(index_type, float, Vector3&) const;
void EvaluateBezier3(index_type, float, Vector3&) const;
typedef void (SplineBase::*EvaluationMethtod)(index_type, float, Vector3&) const;
static EvaluationMethtod evaluators[ModesEnd];
void EvaluateDerivativeLinear(index_type, float, Vector3&) const;
void EvaluateDerivativeCatmullRom(index_type, float, Vector3&) const;
void EvaluateDerivativeBezier3(index_type, float, Vector3&) const;
static EvaluationMethtod derivative_evaluators[ModesEnd];
float SegLengthLinear(index_type) const;
float SegLengthCatmullRom(index_type) const;
float SegLengthBezier3(index_type) const;
typedef float (SplineBase::*SegLenghtMethtod)(index_type) const;
static SegLenghtMethtod seglengths[ModesEnd];
void InitLinear(const Vector3*, index_type, bool, index_type);
void InitCatmullRom(const Vector3*, index_type, bool, index_type);
void InitBezier3(const Vector3*, index_type, bool, index_type);
typedef void (SplineBase::*InitMethtod)(const Vector3*, index_type, bool, index_type);
static InitMethtod initializers[ModesEnd];
void UninitializedSplineEvaluationMethod(index_type, float, Vector3&) const { ABORT(); }
float UninitializedSplineSegLenghtMethod(index_type) const { ABORT(); }
void UninitializedSplineInitMethod(Vector3 const*, index_type, bool, index_type) { ABORT(); }
public:
explicit SplineBase() : index_lo(0), index_hi(0), m_mode(UninitializedMode), cyclic(false) {}
/** Caclulates the position for given segment Idx, and percent of segment length t
@param t - percent of segment length, assumes that t in range [0, 1]
@param Idx - spline segment index, should be in range [first, last)
*/
void evaluate_percent(index_type Idx, float u, Vector3& c) const {(this->*evaluators[m_mode])(Idx, u, c);}
/** Caclulates derivation in index Idx, and percent of segment length t
@param Idx - spline segment index, should be in range [first, last)
@param t - percent of spline segment length, assumes that t in range [0, 1]
*/
void evaluate_derivative(index_type Idx, float u, Vector3& hermite) const {(this->*derivative_evaluators[m_mode])(Idx, u, hermite);}
/** Bounds for spline indexes. All indexes should be in range [first, last). */
index_type first() const { return index_lo;}
index_type last() const { return index_hi;}
bool empty() const { return index_lo == index_hi;}
EvaluationMode mode() const { return (EvaluationMode)m_mode;}
bool isCyclic() const { return cyclic;}
// Xinef: DO NOT USE EXCEPT FOR SPLINE INITIALIZATION!!!!!!
const ControlArray* allocateVisualPoints() const { return &pointsVisual; }
const ControlArray& getPoints(bool visual) const { return visual ? pointsVisual : points;}
index_type getPointCount() const { return points.size();}
const Vector3& getPoint(index_type i, bool visual) const { return visual ? pointsVisual[i] : points[i];}
/** Initializes spline. Don't call other methods while spline not initialized. */
void init_spline(const Vector3* controls, index_type count, EvaluationMode m);
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point);
/** As i can see there are a lot of ways how spline can be initialized
would be no harm to have some custom initializers. */
template<class Init> inline void init_spline_custom(Init& initializer)
{
initializer(m_mode, cyclic, points, index_lo, index_hi);
}
}
/** Returns length of the whole spline. */
length_type length() const { return lengths[index_hi];}
/** Returns length between given nodes. */
length_type length(index_type first, index_type last) const { return lengths[last]-lengths[first];}
length_type length(index_type Idx) const { return lengths[Idx];}
void clear();
void set_length(index_type i, length_type length) { lengths[i] = length;}
void clear();
};
/** Calculates distance between [i; i+1] points, assumes that index i is in bounds. */
float SegLength(index_type i) const { return (this->*seglengths[m_mode])(i);}
std::string ToString() const;
};
template<typename length_type>
class Spline : public SplineBase
{
public:
typedef length_type LengthType;
typedef std::vector<length_type> LengthArray;
protected:
LengthArray lengths;
index_type computeIndexInBounds(length_type length) const;
public:
explicit Spline() {}
/** Calculates the position for given t
@param t - percent of spline's length, assumes that t in range [0, 1]. */
void evaluate_percent(float t, Vector3& c) const;
/** Calculates derivation for given t
@param t - percent of spline's length, assumes that t in range [0, 1]. */
void evaluate_derivative(float t, Vector3& hermite) const;
/** Calculates the position for given segment Idx, and percent of segment length t
@param t = partial_segment_length / whole_segment_length
@param Idx - spline segment index, should be in range [first, last). */
void evaluate_percent(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_percent(Idx, u, c);}
/** Caclulates derivation for index Idx, and percent of segment length t
@param Idx - spline segment index, should be in range [first, last)
@param t - percent of spline segment length, assumes that t in range [0, 1]. */
void evaluate_derivative(index_type Idx, float u, Vector3& c) const { SplineBase::evaluate_derivative(Idx, u, c);}
// Assumes that t in range [0, 1]
index_type computeIndexInBounds(float t) const;
void computeIndex(float t, index_type& out_idx, float& out_u) const;
/** Initializes spline. Don't call other methods while spline not initialized. */
void init_spline(const Vector3* controls, index_type count, EvaluationMode m) { SplineBase::init_spline(controls, count, m);}
void init_cyclic_spline(const Vector3* controls, index_type count, EvaluationMode m, index_type cyclic_point) { SplineBase::init_cyclic_spline(controls, count, m, cyclic_point);}
/** Initializes lengths with SplineBase::SegLength method. */
void initLengths();
/** Initializes lengths in some custom way
Note that value returned by cacher must be greater or equal to previous value. */
template<class T> inline void initLengths(T& cacher)
{
index_type i = index_lo;
lengths.resize(index_hi + 1);
length_type prev_length = 0, new_length = 0;
while (i < index_hi)
{
new_length = cacher(*this, i);
// length overflowed, assign to max positive value
if (new_length < 0)
new_length = std::numeric_limits<length_type>::max();
lengths[++i] = new_length;
ASSERT(prev_length <= new_length);
prev_length = new_length;
}
}
/** Returns length of the whole spline. */
length_type length() const { return lengths[index_hi];}
/** Returns length between given nodes. */
length_type length(index_type first, index_type last) const { return lengths[last] - lengths[first];}
length_type length(index_type Idx) const { return lengths[Idx];}
void set_length(index_type i, length_type length) { lengths[i] = length;}
void clear();
};
}

View File

@@ -6,80 +6,80 @@
namespace Movement
{
template<typename length_type> void Spline<length_type>::evaluate_percent( float t, Vector3 & c ) const
{
index_type Index;
float u;
computeIndex(t, Index, u);
evaluate_percent(Index, u, c);
}
template<typename length_type> void Spline<length_type>::evaluate_derivative(float t, Vector3& hermite) const
{
index_type Index;
float u;
computeIndex(t, Index, u);
evaluate_derivative(Index, u, hermite);
}
template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds(length_type length_) const
{
// Temporary disabled: causes infinite loop with t = 1.f
/*
index_type hi = index_hi;
index_type lo = index_lo;
index_type i = lo + (float)(hi - lo) * t;
while ((lengths[i] > length) || (lengths[i + 1] <= length))
template<typename length_type> void Spline<length_type>::evaluate_percent( float t, Vector3& c ) const
{
if (lengths[i] > length)
hi = i - 1; // too big
else if (lengths[i + 1] <= length)
lo = i + 1; // too small
i = (hi + lo) / 2;
}*/
index_type i = index_lo;
index_type N = index_hi;
while (i+1 < N && lengths[i+1] < length_)
++i;
return i;
}
template<typename length_type> void Spline<length_type>::computeIndex(float t, index_type& index, float& u) const
{
ASSERT(t >= 0.f && t <= 1.f);
length_type length_ = t * length();
index = computeIndexInBounds(length_);
ASSERT(index < index_hi);
u = (length_ - length(index)) / (float)length(index, index+1);
}
template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds( float t ) const
{
ASSERT(t >= 0.f && t <= 1.f);
return computeIndexInBounds(t * length());
}
template<typename length_type> void Spline<length_type>::initLengths()
{
index_type i = index_lo;
length_type length = 0;
lengths.resize(index_hi+1);
while (i < index_hi)
{
length += SegLength(i);
lengths[++i] = length;
index_type Index;
float u;
computeIndex(t, Index, u);
evaluate_percent(Index, u, c);
}
}
template<typename length_type> void Spline<length_type>::clear()
{
SplineBase::clear();
lengths.clear();
}
template<typename length_type> void Spline<length_type>::evaluate_derivative(float t, Vector3& hermite) const
{
index_type Index;
float u;
computeIndex(t, Index, u);
evaluate_derivative(Index, u, hermite);
}
template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds(length_type length_) const
{
// Temporary disabled: causes infinite loop with t = 1.f
/*
index_type hi = index_hi;
index_type lo = index_lo;
index_type i = lo + (float)(hi - lo) * t;
while ((lengths[i] > length) || (lengths[i + 1] <= length))
{
if (lengths[i] > length)
hi = i - 1; // too big
else if (lengths[i + 1] <= length)
lo = i + 1; // too small
i = (hi + lo) / 2;
}*/
index_type i = index_lo;
index_type N = index_hi;
while (i + 1 < N && lengths[i + 1] < length_)
++i;
return i;
}
template<typename length_type> void Spline<length_type>::computeIndex(float t, index_type& index, float& u) const
{
ASSERT(t >= 0.f && t <= 1.f);
length_type length_ = t * length();
index = computeIndexInBounds(length_);
ASSERT(index < index_hi);
u = (length_ - length(index)) / (float)length(index, index + 1);
}
template<typename length_type> SplineBase::index_type Spline<length_type>::computeIndexInBounds( float t ) const
{
ASSERT(t >= 0.f && t <= 1.f);
return computeIndexInBounds(t * length());
}
template<typename length_type> void Spline<length_type>::initLengths()
{
index_type i = index_lo;
length_type length = 0;
lengths.resize(index_hi + 1);
while (i < index_hi)
{
length += SegLength(i);
lengths[++i] = length;
}
}
template<typename length_type> void Spline<length_type>::clear()
{
SplineBase::clear();
lengths.clear();
}
}