CubicSpline class created. Temp spline rendering stuff in AMV.

This commit is contained in:
Kyzentun
2014-12-27 21:41:55 -07:00
parent 64d384410c
commit 65187a55c6
9 changed files with 483 additions and 2 deletions
+5
View File
@@ -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.
________________________________________________________________________________
2014/12/26
----------
* [NoteField] Columns turned into actors that can be fetched with
GetColumnActors. [kyzentun]
2014/12/20
----------
* [Preferences] AllowMultipleHighScoreWithSameName, ComboContinuesBetweenSongs
+3
View File
@@ -272,6 +272,7 @@
<Function name='GetDiffuse'/>
<Function name='GetDiffuseAlpha'/>
<Function name='GetEffectDelta'/>
<Function name='GetFakeParent'/>
<Function name='GetGlow'/>
<Function name='GetHAlign'/>
<Function name='GetHeight'/>
@@ -301,6 +302,7 @@
<Function name='Real'/>
<Function name='RealInverse'/>
<Function name='RunCommandsRecursively'/>
<Function name='SetFakeParent'/>
<Function name='SetHeight'/>
<Function name='SetSize'/>
<Function name='SetTextureFiltering'/>
@@ -968,6 +970,7 @@
<Class base='ActorFrame' name='NoteField'>
<Function name='DidHoldNote'/>
<Function name='DidTapNote'/>
<Function name='GetColumnActors'/>
<Function name='SetPressed'/>
<Function name='SetDidHoldNoteCallback'/>
<Function name='SetDidTapNoteCallback'/>
+9
View File
@@ -831,6 +831,12 @@ save yourself some time, copy this for undocumented things:
<Function name='GetParent' return='Actor' arguments=''>
Returns the Actor's parent, or <code>nil</code> if it doesn't have one.
</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=''>
Returns the Actor's visibility.
</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 />
The callback for DidTapNote will not be called.
</Function>
<Function name='GetColumnActors' return='{actor}' arguments=''>
Returns a table of the actors for the columns.
</Function>
<Function name='SetDidHoldNoteCallback' return= '' arguments='function callback'>
Same as SetDidTapNoteCallback, but for hold notes. Uses HoldNoteScore instead of TapNoteScore.
</Function>
+28
View File
@@ -1739,6 +1739,32 @@ public:
pParent->PushSelf(L);
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 )
{
LUA->YieldLua();
@@ -1910,6 +1936,8 @@ public:
ADD_METHOD( GetName );
ADD_METHOD( GetParent );
ADD_METHOD( GetFakeParent );
ADD_METHOD( SetFakeParent );
ADD_METHOD( Draw );
}
+126
View File
@@ -7,6 +7,7 @@
#include "RageLog.h"
#include "RageDisplay.h"
#include "RageTexture.h"
#include "RageTimer.h"
#include "RageUtil.h"
#include "ActorUtil.h"
#include "Foreach.h"
@@ -62,6 +63,9 @@ ActorMultiVertex::ActorMultiVertex()
_EffectMode = EffectMode_Normal;
_TextureMode = TextureMode_Modulate;
_using_spline= false;
_spline.redimension(3);
_spline.loop= false;
}
ActorMultiVertex::~ActorMultiVertex()
@@ -73,6 +77,8 @@ ActorMultiVertex::ActorMultiVertex( const ActorMultiVertex &cpy ):
Actor( cpy )
{
#define CPY(a) a = cpy.a
CPY( _spline );
CPY( _using_spline );
CPY( AMV_Tweens );
CPY( AMV_current );
CPY( AMV_start );
@@ -194,6 +200,75 @@ void ActorMultiVertex::SetVertexCoords( int index, float TexCoordX, float TexCoo
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()
{
Actor::SetGlobalRenderStates(); // set Actor-specified render states
@@ -658,6 +733,48 @@ public:
}
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()
{
@@ -679,6 +796,15 @@ public:
ADD_METHOD( GetCurrFirstToDraw );
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
ADD_METHOD( SetTexture );
ADD_METHOD( GetTexture );
+13
View File
@@ -2,6 +2,7 @@
#include "Actor.h"
#include "RageDisplay.h"
#include "RageMath.h"
#include "RageTextureID.h"
enum DrawMode
@@ -102,11 +103,23 @@ public:
void SetVertexColor( int index , RageColor c );
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 );
private:
RageTexture* _Texture;
CubicSplineN _spline;
bool _using_spline;
vector<RageSpriteVertex> _Vertices;
vector<AMV_TweenState> AMV_Tweens;
AMV_TweenState AMV_current;
+2 -2
View File
@@ -179,7 +179,7 @@ private:
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.
// NoteColumnRenderer exists to hold all the data needed for rendering a
// 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
// ActorProxy because the receptor/ghost actors need to pull in the parent
// state of their rows and the parent state of the column. -Kyz
class NoteColumnRenderer : public ActorFrame
class NoteColumnRenderer : public Actor
{
public:
NoteDisplay* m_displays[PLAYER_INVALID+1];
+260
View File
@@ -5,6 +5,7 @@
*/
#include "global.h"
#include "RageLog.h"
#include "RageMath.h"
#include "RageTypes.h"
#include <float.h>
@@ -695,6 +696,265 @@ void RageBezier2D::SetFromBezier(
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
* All rights reserved.
+37
View File
@@ -85,6 +85,43 @@ private:
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
/*