diff --git a/Docs/Changelog_sm5.txt b/Docs/Changelog_sm5.txt
index 49c0335c11..33512ebde7 100644
--- a/Docs/Changelog_sm5.txt
+++ b/Docs/Changelog_sm5.txt
@@ -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
diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml
index 53d2d79fd4..590bfa43f0 100644
--- a/Docs/Luadoc/Lua.xml
+++ b/Docs/Luadoc/Lua.xml
@@ -272,6 +272,7 @@
+
@@ -301,6 +302,7 @@
+
@@ -968,6 +970,7 @@
+
diff --git a/Docs/Luadoc/LuaDocumentation.xml b/Docs/Luadoc/LuaDocumentation.xml
index fa8011dbe4..f7cb109daa 100644
--- a/Docs/Luadoc/LuaDocumentation.xml
+++ b/Docs/Luadoc/LuaDocumentation.xml
@@ -831,6 +831,12 @@ save yourself some time, copy this for undocumented things:
Returns the Actor's parent, or nil if it doesn't have one.
+
+ Returns the Actor's fake parent, or nil if it doesn't have one.
+
+
+ Sets the Actor's fake parent to p, or clears it if p is nil.
+
Returns the Actor's visibility.
@@ -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.
The callback for DidTapNote will not be called.
+
+ Returns a table of the actors for the columns.
+
Same as SetDidTapNoteCallback, but for hold notes. Uses HoldNoteScore instead of TapNoteScore.
diff --git a/src/Actor.cpp b/src/Actor.cpp
index 318e06e8ab..d2ab5487a9 100644
--- a/src/Actor.cpp
+++ b/src/Actor.cpp
@@ -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::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 );
}
diff --git a/src/ActorMultiVertex.cpp b/src/ActorMultiVertex.cpp
index c569eb3d7a..7d1b48c0ae 100644
--- a/src/ActorMultiVertex.cpp
+++ b/src/ActorMultiVertex.cpp
@@ -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 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(_spline.size()-1) / static_cast(num_verts-1);
+ if(_spline.loop)
+ {
+ conversion= static_cast(_spline.size()) / static_cast(num_verts-1);
+ }
+ for(size_t i= 0; i < num_verts; ++i)
+ {
+ float t= i * conversion;
+ vector 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(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 );
diff --git a/src/ActorMultiVertex.h b/src/ActorMultiVertex.h
index 176d2a7cad..ce340215ef 100644
--- a/src/ActorMultiVertex.h
+++ b/src/ActorMultiVertex.h
@@ -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 _Vertices;
vector AMV_Tweens;
AMV_TweenState AMV_current;
diff --git a/src/NoteDisplay.h b/src/NoteDisplay.h
index 3487be8d6c..ade622f321 100644
--- a/src/NoteDisplay.h
+++ b/src/NoteDisplay.h
@@ -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];
diff --git a/src/RageMath.cpp b/src/RageMath.cpp
index dd209974cc..8baf3b5403 100644
--- a/src/RageMath.cpp
+++ b/src/RageMath.cpp
@@ -5,6 +5,7 @@
*/
#include "global.h"
+#include "RageLog.h"
#include "RageMath.h"
#include "RageTypes.h"
#include
@@ -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 results(m_points.size());
+ vector 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 results(m_points.size());
+ vector 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& diagonals, vector& 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& diagonals, vector& 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(t);
+ if(flort < 0)
+ {
+ return m_points[0].a;
+ }
+ size_t p= min(static_cast(flort), m_points.size()-1);
+ float tfrac= t - static_cast(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& 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 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.
diff --git a/src/RageMath.h b/src/RageMath.h
index 4e56aac737..4565fc80fb 100644
--- a/src/RageMath.h
+++ b/src/RageMath.h
@@ -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& diagonals, vector& results);
+ void set_results(size_t last, vector& diagonals, vector& results);
+
+ struct SplinePoint
+ {
+ float a, b, c, d;
+ };
+ vector m_points;
+};
+
+struct CubicSplineN
+{
+ void solve();
+ void evaluate(float t, vector& v);
+ void set_point(size_t i, vector const& v);
+ void resize(size_t s);
+ size_t size();
+ void redimension(size_t d);
+ size_t dimension();
+ bool empty();
+ typedef vector spline_cont_t;
+ bool loop;
+private:
+ spline_cont_t m_splines;
+};
+
#endif
/*