CubicSpline class created. Temp spline rendering stuff in AMV.
This commit is contained in:
@@ -4,6 +4,11 @@ The StepMania 5 Changelog covers all post-sm-ssc changes. For a list of changes
|
|||||||
from StepMania 4 alpha 5 to sm-ssc v1.2.5, see Changelog_sm-ssc.txt.
|
from StepMania 4 alpha 5 to sm-ssc v1.2.5, see Changelog_sm-ssc.txt.
|
||||||
________________________________________________________________________________
|
________________________________________________________________________________
|
||||||
|
|
||||||
|
2014/12/26
|
||||||
|
----------
|
||||||
|
* [NoteField] Columns turned into actors that can be fetched with
|
||||||
|
GetColumnActors. [kyzentun]
|
||||||
|
|
||||||
2014/12/20
|
2014/12/20
|
||||||
----------
|
----------
|
||||||
* [Preferences] AllowMultipleHighScoreWithSameName, ComboContinuesBetweenSongs
|
* [Preferences] AllowMultipleHighScoreWithSameName, ComboContinuesBetweenSongs
|
||||||
|
|||||||
@@ -272,6 +272,7 @@
|
|||||||
<Function name='GetDiffuse'/>
|
<Function name='GetDiffuse'/>
|
||||||
<Function name='GetDiffuseAlpha'/>
|
<Function name='GetDiffuseAlpha'/>
|
||||||
<Function name='GetEffectDelta'/>
|
<Function name='GetEffectDelta'/>
|
||||||
|
<Function name='GetFakeParent'/>
|
||||||
<Function name='GetGlow'/>
|
<Function name='GetGlow'/>
|
||||||
<Function name='GetHAlign'/>
|
<Function name='GetHAlign'/>
|
||||||
<Function name='GetHeight'/>
|
<Function name='GetHeight'/>
|
||||||
@@ -301,6 +302,7 @@
|
|||||||
<Function name='Real'/>
|
<Function name='Real'/>
|
||||||
<Function name='RealInverse'/>
|
<Function name='RealInverse'/>
|
||||||
<Function name='RunCommandsRecursively'/>
|
<Function name='RunCommandsRecursively'/>
|
||||||
|
<Function name='SetFakeParent'/>
|
||||||
<Function name='SetHeight'/>
|
<Function name='SetHeight'/>
|
||||||
<Function name='SetSize'/>
|
<Function name='SetSize'/>
|
||||||
<Function name='SetTextureFiltering'/>
|
<Function name='SetTextureFiltering'/>
|
||||||
@@ -968,6 +970,7 @@
|
|||||||
<Class base='ActorFrame' name='NoteField'>
|
<Class base='ActorFrame' name='NoteField'>
|
||||||
<Function name='DidHoldNote'/>
|
<Function name='DidHoldNote'/>
|
||||||
<Function name='DidTapNote'/>
|
<Function name='DidTapNote'/>
|
||||||
|
<Function name='GetColumnActors'/>
|
||||||
<Function name='SetPressed'/>
|
<Function name='SetPressed'/>
|
||||||
<Function name='SetDidHoldNoteCallback'/>
|
<Function name='SetDidHoldNoteCallback'/>
|
||||||
<Function name='SetDidTapNoteCallback'/>
|
<Function name='SetDidTapNoteCallback'/>
|
||||||
|
|||||||
@@ -831,6 +831,12 @@ save yourself some time, copy this for undocumented things:
|
|||||||
<Function name='GetParent' return='Actor' arguments=''>
|
<Function name='GetParent' return='Actor' arguments=''>
|
||||||
Returns the Actor's parent, or <code>nil</code> if it doesn't have one.
|
Returns the Actor's parent, or <code>nil</code> if it doesn't have one.
|
||||||
</Function>
|
</Function>
|
||||||
|
<Function name='GetFakeParent' return='Actor' arguments=''>
|
||||||
|
Returns the Actor's fake parent, or <code>nil</code> if it doesn't have one.
|
||||||
|
</Function>
|
||||||
|
<Function name='SetFakeParent' return='' arguments='Actor p'>
|
||||||
|
Sets the Actor's fake parent to p, or clears it if p is nil.
|
||||||
|
</Function>
|
||||||
<Function name='GetVisible' return='bool' arguments=''>
|
<Function name='GetVisible' return='bool' arguments=''>
|
||||||
Returns the Actor's visibility.
|
Returns the Actor's visibility.
|
||||||
</Function>
|
</Function>
|
||||||
@@ -2953,6 +2959,9 @@ save yourself some time, copy this for undocumented things:
|
|||||||
Makes the NoteField act as if a tap note was hit in the column, with the given score and bright setting. <br />
|
Makes the NoteField act as if a tap note was hit in the column, with the given score and bright setting. <br />
|
||||||
The callback for DidTapNote will not be called.
|
The callback for DidTapNote will not be called.
|
||||||
</Function>
|
</Function>
|
||||||
|
<Function name='GetColumnActors' return='{actor}' arguments=''>
|
||||||
|
Returns a table of the actors for the columns.
|
||||||
|
</Function>
|
||||||
<Function name='SetDidHoldNoteCallback' return= '' arguments='function callback'>
|
<Function name='SetDidHoldNoteCallback' return= '' arguments='function callback'>
|
||||||
Same as SetDidTapNoteCallback, but for hold notes. Uses HoldNoteScore instead of TapNoteScore.
|
Same as SetDidTapNoteCallback, but for hold notes. Uses HoldNoteScore instead of TapNoteScore.
|
||||||
</Function>
|
</Function>
|
||||||
|
|||||||
@@ -1739,6 +1739,32 @@ public:
|
|||||||
pParent->PushSelf(L);
|
pParent->PushSelf(L);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
static int GetFakeParent(T* p, lua_State *L)
|
||||||
|
{
|
||||||
|
Actor* fake= p->GetFakeParent();
|
||||||
|
if(fake == NULL)
|
||||||
|
{
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fake->PushSelf(L);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
static int SetFakeParent(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
if(lua_isnoneornil(L, 1))
|
||||||
|
{
|
||||||
|
p->SetFakeParent(NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Actor* fake= Luna<Actor>::check(L, 1);
|
||||||
|
p->SetFakeParent(fake);
|
||||||
|
}
|
||||||
|
COMMON_RETURN_SELF;
|
||||||
|
}
|
||||||
static int Draw( T* p, lua_State *L )
|
static int Draw( T* p, lua_State *L )
|
||||||
{
|
{
|
||||||
LUA->YieldLua();
|
LUA->YieldLua();
|
||||||
@@ -1910,6 +1936,8 @@ public:
|
|||||||
|
|
||||||
ADD_METHOD( GetName );
|
ADD_METHOD( GetName );
|
||||||
ADD_METHOD( GetParent );
|
ADD_METHOD( GetParent );
|
||||||
|
ADD_METHOD( GetFakeParent );
|
||||||
|
ADD_METHOD( SetFakeParent );
|
||||||
|
|
||||||
ADD_METHOD( Draw );
|
ADD_METHOD( Draw );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "RageLog.h"
|
#include "RageLog.h"
|
||||||
#include "RageDisplay.h"
|
#include "RageDisplay.h"
|
||||||
#include "RageTexture.h"
|
#include "RageTexture.h"
|
||||||
|
#include "RageTimer.h"
|
||||||
#include "RageUtil.h"
|
#include "RageUtil.h"
|
||||||
#include "ActorUtil.h"
|
#include "ActorUtil.h"
|
||||||
#include "Foreach.h"
|
#include "Foreach.h"
|
||||||
@@ -62,6 +63,9 @@ ActorMultiVertex::ActorMultiVertex()
|
|||||||
|
|
||||||
_EffectMode = EffectMode_Normal;
|
_EffectMode = EffectMode_Normal;
|
||||||
_TextureMode = TextureMode_Modulate;
|
_TextureMode = TextureMode_Modulate;
|
||||||
|
_using_spline= false;
|
||||||
|
_spline.redimension(3);
|
||||||
|
_spline.loop= false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorMultiVertex::~ActorMultiVertex()
|
ActorMultiVertex::~ActorMultiVertex()
|
||||||
@@ -73,6 +77,8 @@ ActorMultiVertex::ActorMultiVertex( const ActorMultiVertex &cpy ):
|
|||||||
Actor( cpy )
|
Actor( cpy )
|
||||||
{
|
{
|
||||||
#define CPY(a) a = cpy.a
|
#define CPY(a) a = cpy.a
|
||||||
|
CPY( _spline );
|
||||||
|
CPY( _using_spline );
|
||||||
CPY( AMV_Tweens );
|
CPY( AMV_Tweens );
|
||||||
CPY( AMV_current );
|
CPY( AMV_current );
|
||||||
CPY( AMV_start );
|
CPY( AMV_start );
|
||||||
@@ -194,6 +200,75 @@ void ActorMultiVertex::SetVertexCoords( int index, float TexCoordX, float TexCoo
|
|||||||
AMV_DestTweenState().vertices[index].t = RageVector2( TexCoordX, TexCoordY );
|
AMV_DestTweenState().vertices[index].t = RageVector2( TexCoordX, TexCoordY );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ActorMultiVertex::GetUseSpline()
|
||||||
|
{
|
||||||
|
return _using_spline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorMultiVertex::SetUseSpline(bool use)
|
||||||
|
{
|
||||||
|
_using_spline= use;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorMultiVertex::SplineSetPoint(size_t i, float x , float y , float z)
|
||||||
|
{
|
||||||
|
vector<float> v(3);
|
||||||
|
v[0]= x; v[1]= y; v[2]= z;
|
||||||
|
_spline.set_point(i, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorMultiVertex::SplineResize(size_t s)
|
||||||
|
{
|
||||||
|
_spline.resize(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ActorMultiVertex::SplineSize()
|
||||||
|
{
|
||||||
|
return _spline.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActorMultiVertex::SplineSolve()
|
||||||
|
{
|
||||||
|
if(_spline.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_spline.solve();
|
||||||
|
float num_parts= 0.0f;
|
||||||
|
size_t num_verts= GetNumVertices();
|
||||||
|
switch(GetDestDrawMode())
|
||||||
|
{
|
||||||
|
case DrawMode_Quads:
|
||||||
|
break;
|
||||||
|
case DrawMode_QuadStrip:
|
||||||
|
break;
|
||||||
|
case DrawMode_Fan:
|
||||||
|
break;
|
||||||
|
case DrawMode_Strip:
|
||||||
|
break;
|
||||||
|
case DrawMode_Triangles:
|
||||||
|
break;
|
||||||
|
case DrawMode_LineStrip:
|
||||||
|
{
|
||||||
|
float conversion= static_cast<float>(_spline.size()-1) / static_cast<float>(num_verts-1);
|
||||||
|
if(_spline.loop)
|
||||||
|
{
|
||||||
|
conversion= static_cast<float>(_spline.size()) / static_cast<float>(num_verts-1);
|
||||||
|
}
|
||||||
|
for(size_t i= 0; i < num_verts; ++i)
|
||||||
|
{
|
||||||
|
float t= i * conversion;
|
||||||
|
vector<float> p;
|
||||||
|
_spline.evaluate(t, p);
|
||||||
|
SetVertexPos(i, p[0], p[1], p[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DrawMode_SymmetricQuadStrip:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ActorMultiVertex::DrawPrimitives()
|
void ActorMultiVertex::DrawPrimitives()
|
||||||
{
|
{
|
||||||
Actor::SetGlobalRenderStates(); // set Actor-specified render states
|
Actor::SetGlobalRenderStates(); // set Actor-specified render states
|
||||||
@@ -658,6 +733,48 @@ public:
|
|||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
DEFINE_METHOD(GetUseSpline, GetUseSpline());
|
||||||
|
DEFINE_METHOD(SplineGetLoop, SplineGetLoop());
|
||||||
|
static int SplineSetLoop(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
p->SplineSetLoop(lua_toboolean(L, 1));
|
||||||
|
COMMON_RETURN_SELF;
|
||||||
|
}
|
||||||
|
static int SplineSize(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
lua_pushnumber(L, p->SplineSize());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
static int SetUseSpline(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
p->SetUseSpline(lua_toboolean(L, 1));
|
||||||
|
COMMON_RETURN_SELF;
|
||||||
|
}
|
||||||
|
static int SplineSetPoint(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
size_t i= IArg(1)-1;
|
||||||
|
if(i >= p->SplineSize())
|
||||||
|
{
|
||||||
|
luaL_error(L, "Spline point index greater than the number of points.");
|
||||||
|
}
|
||||||
|
p->SplineSetPoint(i, FArg(2), FArg(3), FArg(4));
|
||||||
|
COMMON_RETURN_SELF;
|
||||||
|
}
|
||||||
|
static int SplineResize(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
int s= IArg(1);
|
||||||
|
if(s < 0)
|
||||||
|
{
|
||||||
|
luaL_error(L, "Negative spline size not allowed.");
|
||||||
|
}
|
||||||
|
p->SplineResize(static_cast<size_t>(s));
|
||||||
|
COMMON_RETURN_SELF;
|
||||||
|
}
|
||||||
|
static int SplineSolve(T* p, lua_State* L)
|
||||||
|
{
|
||||||
|
p->SplineSolve();
|
||||||
|
COMMON_RETURN_SELF;
|
||||||
|
}
|
||||||
|
|
||||||
LunaActorMultiVertex()
|
LunaActorMultiVertex()
|
||||||
{
|
{
|
||||||
@@ -679,6 +796,15 @@ public:
|
|||||||
ADD_METHOD( GetCurrFirstToDraw );
|
ADD_METHOD( GetCurrFirstToDraw );
|
||||||
ADD_METHOD( GetCurrNumToDraw );
|
ADD_METHOD( GetCurrNumToDraw );
|
||||||
|
|
||||||
|
ADD_METHOD(GetUseSpline);
|
||||||
|
ADD_METHOD(SetUseSpline);
|
||||||
|
ADD_METHOD(SplineGetLoop);
|
||||||
|
ADD_METHOD(SplineSetLoop);
|
||||||
|
ADD_METHOD(SplineSize);
|
||||||
|
ADD_METHOD(SplineResize);
|
||||||
|
ADD_METHOD(SplineSetPoint);
|
||||||
|
ADD_METHOD(SplineSolve);
|
||||||
|
|
||||||
// Copy from RageTexture
|
// Copy from RageTexture
|
||||||
ADD_METHOD( SetTexture );
|
ADD_METHOD( SetTexture );
|
||||||
ADD_METHOD( GetTexture );
|
ADD_METHOD( GetTexture );
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "Actor.h"
|
#include "Actor.h"
|
||||||
#include "RageDisplay.h"
|
#include "RageDisplay.h"
|
||||||
|
#include "RageMath.h"
|
||||||
#include "RageTextureID.h"
|
#include "RageTextureID.h"
|
||||||
|
|
||||||
enum DrawMode
|
enum DrawMode
|
||||||
@@ -102,11 +103,23 @@ public:
|
|||||||
void SetVertexColor( int index , RageColor c );
|
void SetVertexColor( int index , RageColor c );
|
||||||
void SetVertexCoords( int index , float TexCoordX , float TexCoordY );
|
void SetVertexCoords( int index , float TexCoordX , float TexCoordY );
|
||||||
|
|
||||||
|
bool GetUseSpline();
|
||||||
|
void SetUseSpline(bool use);
|
||||||
|
bool SplineGetLoop() { return _spline.loop; }
|
||||||
|
void SplineSetLoop(bool loop) { _spline.loop= loop; }
|
||||||
|
void SplineSetPoint(size_t i, float x , float y , float z);
|
||||||
|
void SplineResize(size_t s);
|
||||||
|
size_t SplineSize();
|
||||||
|
void SplineSolve();
|
||||||
|
|
||||||
virtual void PushSelf( lua_State *L );
|
virtual void PushSelf( lua_State *L );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RageTexture* _Texture;
|
RageTexture* _Texture;
|
||||||
|
|
||||||
|
CubicSplineN _spline;
|
||||||
|
bool _using_spline;
|
||||||
|
|
||||||
vector<RageSpriteVertex> _Vertices;
|
vector<RageSpriteVertex> _Vertices;
|
||||||
vector<AMV_TweenState> AMV_Tweens;
|
vector<AMV_TweenState> AMV_Tweens;
|
||||||
AMV_TweenState AMV_current;
|
AMV_TweenState AMV_current;
|
||||||
|
|||||||
+2
-2
@@ -179,7 +179,7 @@ private:
|
|||||||
float m_fYReverseOffsetPixels;
|
float m_fYReverseOffsetPixels;
|
||||||
};
|
};
|
||||||
|
|
||||||
// So, this is a bit screwy, and it's all because routine forces rendering
|
// So, this is a bit screwy, and it's partly because routine forces rendering
|
||||||
// notes from different noteskins in the same column.
|
// notes from different noteskins in the same column.
|
||||||
// NoteColumnRenderer exists to hold all the data needed for rendering a
|
// NoteColumnRenderer exists to hold all the data needed for rendering a
|
||||||
// column and apply any transforms from that column's actor to the
|
// column and apply any transforms from that column's actor to the
|
||||||
@@ -188,7 +188,7 @@ private:
|
|||||||
// actors so they can move with the rest of the column. I didn't use
|
// actors so they can move with the rest of the column. I didn't use
|
||||||
// ActorProxy because the receptor/ghost actors need to pull in the parent
|
// ActorProxy because the receptor/ghost actors need to pull in the parent
|
||||||
// state of their rows and the parent state of the column. -Kyz
|
// state of their rows and the parent state of the column. -Kyz
|
||||||
class NoteColumnRenderer : public ActorFrame
|
class NoteColumnRenderer : public Actor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NoteDisplay* m_displays[PLAYER_INVALID+1];
|
NoteDisplay* m_displays[PLAYER_INVALID+1];
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
#include "RageLog.h"
|
||||||
#include "RageMath.h"
|
#include "RageMath.h"
|
||||||
#include "RageTypes.h"
|
#include "RageTypes.h"
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
@@ -695,6 +696,265 @@ void RageBezier2D::SetFromBezier(
|
|||||||
m_Y.SetFromBezier( fC1Y, fC2Y, fC3Y, fC4Y );
|
m_Y.SetFromBezier( fC1Y, fC2Y, fC3Y, fC4Y );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CubicSpline implementation written by Kyzentun 2014/12/27
|
||||||
|
|
||||||
|
void CubicSpline::solve_looped()
|
||||||
|
{
|
||||||
|
if(check_minimum_size()) { return; }
|
||||||
|
size_t last= m_points.size();
|
||||||
|
vector<float> results(m_points.size());
|
||||||
|
vector<float> diagonals(m_points.size());
|
||||||
|
results[0]= 3 * (m_points[1].a - m_points[last-1].a);
|
||||||
|
diagonals[0]= 4.0f;
|
||||||
|
prep_inner(last, diagonals, results);
|
||||||
|
results[last-1]= 3 * (m_points[0].a - m_points[last-2].a);
|
||||||
|
diagonals[last-1]= 4.0f;
|
||||||
|
|
||||||
|
// The steps to solve the system of equations look like this:
|
||||||
|
// | 4 1 0 0 1 | -> | 4 0 0 0 1 | -> | 4 0 0 0 0 | -> | 4 0 0 0 0 |
|
||||||
|
// | 1 4 1 0 0 | -> | 0 d 1 0 x | -> | 0 d 1 0 x | -> | 0 d 0 0 x |
|
||||||
|
// | 0 1 4 1 0 | -> | 0 1 4 1 0 | -> | 0 1 4 1 0 | -> | 0 0 d 1 x |
|
||||||
|
// | 0 0 1 4 1 | -> | 0 0 1 4 1 | -> | 0 0 1 4 1 | -> | 0 0 1 4 1 |
|
||||||
|
// | 1 0 0 1 4 | -> | 1 x 0 1 4 | -> | 0 x 0 1 q | -> | 0 x x 1 q |
|
||||||
|
// V
|
||||||
|
// | 4 0 0 0 0 | -> | 4 0 0 0 0 | -> | 4 0 0 0 0 | -> | 4 0 0 0 0 |
|
||||||
|
// | 0 d 0 0 0 | -> | 0 d 0 0 0 | -> | 0 d 0 0 0 | -> | 0 d 0 0 0 |
|
||||||
|
// | 0 0 d 1 x | -> | 0 0 d 0 x | -> | 0 0 d 0 0 | -> | 0 0 d 0 0 |
|
||||||
|
// | 0 0 1 d 1 | -> | 0 0 0 d n | -> | 0 0 0 d n | -> | 0 0 0 d 0 |
|
||||||
|
// | 0 0 x 1 r | -> | 0 0 x n r | -> | 0 0 0 n s | -> | 0 0 0 0 t |
|
||||||
|
// Each time through the loop performs two of these steps, 4 operations.
|
||||||
|
|
||||||
|
size_t end= last-1;
|
||||||
|
size_t stop= end-1;
|
||||||
|
float cedge= 1.0f; // [ri][cl]
|
||||||
|
float redge= 1.0f; // [rl][ci]
|
||||||
|
// The loop stops before end because the case where [ri][cl] == [ri][ci+1]
|
||||||
|
// needs special handling.
|
||||||
|
for(size_t i= 0; i < stop; ++i)
|
||||||
|
{
|
||||||
|
float next_cedge= 0.0f; // [ri+1][ce]
|
||||||
|
float next_redge= 0.0f; // [re][ci+1]
|
||||||
|
// Operation: Add col[i] / -[ri][ci] to col[i+1] to zero [ri][ci+1].
|
||||||
|
float diag_recip= 1.0f / diagonals[i];
|
||||||
|
diagonals[i+1]-= diag_recip;
|
||||||
|
next_redge-= redge * diag_recip;
|
||||||
|
// Operation: Add row[i] / -[ri][ci] to row[i+1] to zero [ri+1][ci].
|
||||||
|
results[i+1]-= results[i] * diag_recip;
|
||||||
|
next_cedge-= cedge * diag_recip;
|
||||||
|
// Operation: Add col[i] * -(cedge/[ri][ci]) to col[e] to zero cedge.
|
||||||
|
diagonals[end]-= redge * (cedge / diagonals[i]);
|
||||||
|
cedge= next_cedge; // Do not use cedge after this point in the loop.
|
||||||
|
// Operation: Add row[i] * -(redge/[ri][ci]) to row[e] to zero redge.
|
||||||
|
results[end]-= results[i] * (redge / diagonals[i]);
|
||||||
|
redge= next_redge; // Do not use redge after this point in the loop.
|
||||||
|
}
|
||||||
|
// [rs][ce] is 1 - cedge, [re][cs] is 1 - redge
|
||||||
|
// Operation: Add col[s] * -([rs][ce] / [rs][cs]) to col[e] to zero redge.
|
||||||
|
diagonals[end]-= redge * ((1.0f - cedge) / diagonals[stop]);
|
||||||
|
// Operation: Add row[s] * -([re][cs] / [rs][cs]) to row[e] to zero redge.
|
||||||
|
results[end]-= results[stop] * ((1.0f - redge) / diagonals[stop]);
|
||||||
|
|
||||||
|
set_results(last, diagonals, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSpline::solve_straight()
|
||||||
|
{
|
||||||
|
if(check_minimum_size()) { return; }
|
||||||
|
size_t last= m_points.size();
|
||||||
|
vector<float> results(m_points.size());
|
||||||
|
vector<float> diagonals(m_points.size());
|
||||||
|
results[0]= 3 * (m_points[1].a - m_points[0].a);
|
||||||
|
diagonals[0]= 2.0f;
|
||||||
|
prep_inner(last, diagonals, results);
|
||||||
|
results[last-1]= 3 * (m_points[last-1].a - m_points[last-2].a);
|
||||||
|
diagonals[last-1]= 2.0f;
|
||||||
|
|
||||||
|
// The system of equations to be solved looks like this:
|
||||||
|
// | 2 1 0 0 | = | results[0] |
|
||||||
|
// | 1 4 1 0 | = | results[1] |
|
||||||
|
// | 0 1 4 1 | = | results[2] |
|
||||||
|
// | 0 0 1 2 | = | results[3] |
|
||||||
|
// Operations are carefully chosen to only modify the values in the
|
||||||
|
// diagonals and the results, leaving the 1s unchanged.
|
||||||
|
// Operation: Add col[0] * -.5 to col[1] to zero [r0][c1].
|
||||||
|
diagonals[1]-= .5f;
|
||||||
|
// Operation: Add row[0] * -.5 to row[1] to zero [r1][c0].
|
||||||
|
results[1]-= results[0] * .5f;
|
||||||
|
for(size_t i= 1; i < last - 1; ++i)
|
||||||
|
{
|
||||||
|
float diag_recip= 1.0f / diagonals[i];
|
||||||
|
// Operation: Add col[i] / -[ri][ci] to col[i+1] to zero [ri][ci+1].
|
||||||
|
diagonals[i+1]-= diag_recip;
|
||||||
|
// Operation: Add row[i] / -[ri][ci] to row[i+1] to zero [ri+1][ci];
|
||||||
|
results[i]-= results[i-1] * diag_recip;
|
||||||
|
}
|
||||||
|
set_results(last, diagonals, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CubicSpline::check_minimum_size()
|
||||||
|
{
|
||||||
|
size_t last= m_points.size();
|
||||||
|
if(last < 2) { return true; }
|
||||||
|
if(last == 2)
|
||||||
|
{
|
||||||
|
m_points[0].b= m_points[1].a - m_points[0].a;
|
||||||
|
m_points[0].c= m_points[0].d= 0.0f;
|
||||||
|
// These will be used in the looping case.
|
||||||
|
m_points[1].b= m_points[0].a - m_points[1].a;
|
||||||
|
m_points[1].c= m_points[1].d= 0.0f;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
float a= m_points[0].a;
|
||||||
|
for(size_t i= 1; i < m_points.size(); ++i)
|
||||||
|
{
|
||||||
|
m_points[i].b= m_points[i].c= m_points[i].d= 0.0f;
|
||||||
|
if(m_points[i].a != a) { return false; }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSpline::prep_inner(size_t last, vector<float>& diagonals, vector<float>& results)
|
||||||
|
{
|
||||||
|
for(size_t i= 1; i < last - 1; ++i)
|
||||||
|
{
|
||||||
|
results[i]= 3 * (m_points[i+1].a - m_points[i-1].a);
|
||||||
|
diagonals[i]= 4.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSpline::set_results(size_t last, vector<float>& diagonals, vector<float>& results)
|
||||||
|
{
|
||||||
|
// No more operations left, everything not a diagonal should be zero now.
|
||||||
|
for(size_t i= 0; i < last; ++i)
|
||||||
|
{
|
||||||
|
results[i]/= diagonals[i];
|
||||||
|
}
|
||||||
|
// Now we can go through and set the b, c, d values of each point.
|
||||||
|
// b, c, d values of the last point are not set because they are unused.
|
||||||
|
for(size_t i= 0; i < last; ++i)
|
||||||
|
{
|
||||||
|
size_t next= (i+1) % last;
|
||||||
|
float diff= m_points[next].a - m_points[i].a;
|
||||||
|
m_points[i].b= results[i];
|
||||||
|
m_points[i].c= (3 * diff) - (2 * results[i]) - results[next];
|
||||||
|
m_points[i].d= (2 * -diff) + results[i] + results[next];
|
||||||
|
}
|
||||||
|
// Solving is now complete.
|
||||||
|
}
|
||||||
|
|
||||||
|
float CubicSpline::evaluate(float t, bool loop)
|
||||||
|
{
|
||||||
|
if(loop)
|
||||||
|
{
|
||||||
|
t= fmodf(t, m_points.size());
|
||||||
|
}
|
||||||
|
int flort= static_cast<int>(t);
|
||||||
|
if(flort < 0)
|
||||||
|
{
|
||||||
|
return m_points[0].a;
|
||||||
|
}
|
||||||
|
size_t p= min(static_cast<size_t>(flort), m_points.size()-1);
|
||||||
|
float tfrac= t - static_cast<float>(flort);
|
||||||
|
float tsq= tfrac * tfrac;
|
||||||
|
float tcub= tsq * tfrac;
|
||||||
|
return m_points[p].a + (m_points[p].b * tfrac) +
|
||||||
|
(m_points[p].c * tsq) + (m_points[p].d * tcub);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSpline::set_point(size_t i, float v)
|
||||||
|
{
|
||||||
|
ASSERT_M(i < m_points.size(), "CubicSpline::set_point requires the index to be less than the number of points.");
|
||||||
|
m_points[i].a= v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSpline::resize(size_t s)
|
||||||
|
{
|
||||||
|
m_points.resize(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CubicSpline::size()
|
||||||
|
{
|
||||||
|
return m_points.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CubicSpline::empty()
|
||||||
|
{
|
||||||
|
return m_points.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSplineN::solve()
|
||||||
|
{
|
||||||
|
if(loop)
|
||||||
|
{
|
||||||
|
for(spline_cont_t::iterator spline= m_splines.begin();
|
||||||
|
spline != m_splines.end(); ++spline)
|
||||||
|
{
|
||||||
|
spline->solve_looped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(spline_cont_t::iterator spline= m_splines.begin();
|
||||||
|
spline != m_splines.end(); ++spline)
|
||||||
|
{
|
||||||
|
spline->solve_straight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSplineN::evaluate(float t, vector<float>& v)
|
||||||
|
{
|
||||||
|
for(spline_cont_t::iterator spline= m_splines.begin();
|
||||||
|
spline != m_splines.end(); ++spline)
|
||||||
|
{
|
||||||
|
v.push_back(spline->evaluate(t, loop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSplineN::set_point(size_t i, vector<float> const& v)
|
||||||
|
{
|
||||||
|
ASSERT_M(v.size() == m_splines.size(), "CubicSplineN::set_point requires the passed point to be the same dimension as the spline.");
|
||||||
|
for(size_t n= 0; n < m_splines.size(); ++n)
|
||||||
|
{
|
||||||
|
m_splines[n].set_point(i, v[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSplineN::resize(size_t s)
|
||||||
|
{
|
||||||
|
for(spline_cont_t::iterator spline= m_splines.begin();
|
||||||
|
spline != m_splines.end(); ++spline)
|
||||||
|
{
|
||||||
|
spline->resize(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CubicSplineN::size()
|
||||||
|
{
|
||||||
|
if(!m_splines.empty())
|
||||||
|
{
|
||||||
|
return m_splines[0].size();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CubicSplineN::empty()
|
||||||
|
{
|
||||||
|
return m_splines.empty() || m_splines[0].empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CubicSplineN::redimension(size_t d)
|
||||||
|
{
|
||||||
|
m_splines.resize(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CubicSplineN::dimension()
|
||||||
|
{
|
||||||
|
return m_splines.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001-2006 Chris Danford, Glenn Maynard
|
* Copyright (c) 2001-2006 Chris Danford, Glenn Maynard
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
|||||||
@@ -85,6 +85,43 @@ private:
|
|||||||
RageQuadratic m_Y;
|
RageQuadratic m_Y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CubicSpline
|
||||||
|
{
|
||||||
|
void solve_looped();
|
||||||
|
void solve_straight();
|
||||||
|
float evaluate(float t, bool loop);
|
||||||
|
void set_point(size_t i, float v);
|
||||||
|
void resize(size_t s);
|
||||||
|
size_t size();
|
||||||
|
bool empty();
|
||||||
|
private:
|
||||||
|
bool check_minimum_size();
|
||||||
|
void prep_inner(size_t last, vector<float>& diagonals, vector<float>& results);
|
||||||
|
void set_results(size_t last, vector<float>& diagonals, vector<float>& results);
|
||||||
|
|
||||||
|
struct SplinePoint
|
||||||
|
{
|
||||||
|
float a, b, c, d;
|
||||||
|
};
|
||||||
|
vector<SplinePoint> m_points;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CubicSplineN
|
||||||
|
{
|
||||||
|
void solve();
|
||||||
|
void evaluate(float t, vector<float>& v);
|
||||||
|
void set_point(size_t i, vector<float> const& v);
|
||||||
|
void resize(size_t s);
|
||||||
|
size_t size();
|
||||||
|
void redimension(size_t d);
|
||||||
|
size_t dimension();
|
||||||
|
bool empty();
|
||||||
|
typedef vector<CubicSpline> spline_cont_t;
|
||||||
|
bool loop;
|
||||||
|
private:
|
||||||
|
spline_cont_t m_splines;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user