Moved note column splines into tween state. Renamed size/dimension spline lua functions to get/set convention. Added make_camel_aliases to 01 alias.lua to make the CamelCase aliases required by shakesoda for consistency.

This commit is contained in:
Kyzentun
2015-01-04 06:10:21 -07:00
parent 6c722df0c6
commit 703b423dd4
8 changed files with 340 additions and 60 deletions
+24
View File
@@ -43,6 +43,30 @@ function math.round(n)
end
end
function split(delimiter, text)
local list = {}
local pos = 1
while 1 do
local first,last = string.find(text, delimiter, pos)
if first then
table.insert(list, string.sub(text, pos, first-1))
pos = last+1
else
table.insert(list, string.sub(text, pos))
break
end
end
return list
end
function join(delimiter, list)
local ret = list[1]
for i = 2,table.getn(list) do
ret = ret .. delimiter .. list[i]
end
return ret or ""
end
-- (c) 2006 Glenn Maynard
-- All rights reserved.
--
+56
View File
@@ -24,6 +24,62 @@ _safe = {
--[[ compatibility aliases ]]
function alias_one(class, main_name, alt_name)
if type(main_name) ~= "string" then
lua.ReportScriptError("Name of function to make an alias for must be a string.")
return
end
if type(alt_name) ~= "string" then
lua.ReportScriptError("Alias name of function must be a string.")
return
end
class[alt_name]= class[main_name]
end
function alias_set(class, set)
assert(type(class) == "table" and type(set) == "table",
"alias_set must be passed a class and a set of names to make alieases.")
for i, fun in ipairs(set) do
if type(fun) == "table" then
local main_name= fun[1]
if type(set[2]) == "table" then
for n, alt_name in ipairs(set[2]) do
alias_one(class, main_name, alt_name)
end
elseif type(set[2]) == "string" then
alias_one(class, main_name, set[2])
end
else
lua.ReportScriptError("alias entry " .. i .. " in set passed to " ..
"alias_set is not a table.")
end
end
end
function make_camel_aliases(class)
local name_list= {}
for name, fun in pairs(class) do
if type(fun) == "function" and type(name) == "string" then
name_list[#name_list+1]= name
end
end
for i, name in ipairs(name_list) do
local words= split("_", name)
for o, w in ipairs(words) do
words[o]= w:sub(1,1):upper() .. w:sub(2)
end
local camel_name= join("", words)
if name ~= camel_name then
alias_one(class, name, camel_name)
end
end
end
make_camel_aliases(CubicSplineN)
make_camel_aliases(NCSplineHandler)
make_camel_aliases(NoteColumnRenderer)
make_camel_aliases(NoteField)
--[[ ActorScroller: all of these got renamed, so alias the lowercase ones if
themes are going to look for them. ]]
ActorScroller.getsecondtodestination = ActorScroller.GetSecondsToDestination
-24
View File
@@ -29,30 +29,6 @@ function TableStringLookup(t, group)
return ret
end
function split(delimiter, text)
local list = {}
local pos = 1
while 1 do
local first,last = string.find(text, delimiter, pos)
if first then
table.insert(list, string.sub(text, pos, first-1))
pos = last+1
else
table.insert(list, string.sub(text, pos))
break
end
end
return list
end
function join(delimiter, list)
local ret = list[1]
for i = 2,table.getn(list) do
ret = ret .. delimiter .. list[i]
end
return ret or ""
end
function wrap(val,n)
local x = val
Trace( "wrap "..x.." "..n )
+115 -10
View File
@@ -494,7 +494,7 @@ void CubicSpline::set_coefficients(size_t i, float b, float c, float d)
m_points[i].d= d;
}
void CubicSpline::get_coefficients(size_t i, float& b, float& c, float& d)
void CubicSpline::get_coefficients(size_t i, float& b, float& c, float& d) const
{
ASSERT_M(i < m_points.size(), "CubicSpline: point index must be less than the number of points.");
b= m_points[i].b;
@@ -502,6 +502,20 @@ void CubicSpline::get_coefficients(size_t i, float& b, float& c, float& d)
d= m_points[i].d;
}
void CubicSpline::set_point_and_coefficients(size_t i, float a, float b,
float c, float d)
{
set_coefficients(i, b, c, d);
m_points[i].a= a;
}
void CubicSpline::get_point_and_coefficients(size_t i, float& a, float& b,
float& c, float& d) const
{
get_coefficients(i, b, c, d);
a= m_points[i].a;
}
void CubicSpline::resize(size_t s)
{
m_points.resize(s);
@@ -517,6 +531,96 @@ bool CubicSpline::empty() const
return m_points.empty();
}
void CubicSplineN::weighted_average(CubicSplineN& out,
CubicSplineN const& from, CubicSplineN const& to, float between)
{
ASSERT_M(out.dimension() == from.dimension() &&
to.dimension() == from.dimension(),
"Cannot tween splines of different dimensions.");
#define BOOLS_FROM_CLOSEST(closest) \
out.set_loop(closest.get_loop()); \
out.set_polygonal(closest.get_polygonal());
if(between >= 0.5f)
{
BOOLS_FROM_CLOSEST(to);
}
else
{
BOOLS_FROM_CLOSEST(from);
}
#undef BOOLS_FROM_CLOSEST
// Behavior for splines of different sizes: Use a size between the two.
// Points that exist in both will be averaged.
// Points that only exist in one will come only from that one.
size_t const from_size= from.size();
size_t const to_size= to.size();
size_t out_size= to_size;
size_t limit= to_size;
if(from_size < to_size)
{
out_size= from_size + static_cast<size_t>(
static_cast<float>(to_size - from_size) * between);
}
else if(to_size < from_size)
{
limit= from_size;
out_size= to_size + static_cast<size_t>(
static_cast<float>(from_size - to_size) * between);
}
CLAMP(out_size, 0, limit);
out.resize(out_size);
for(size_t spli= 0; spli < out.m_splines.size(); ++spli)
{
for(size_t p= 0; p < out_size; ++p)
{
float fc[4]= {0.0f, 0.0f, 0.0f, 0.0f};
float tc[4]= {0.0f, 0.0f, 0.0f, 0.0f};
if(p < from_size)
{
from.m_splines[spli].get_point_and_coefficients(p, fc[0], fc[1],
fc[2], fc[3]);
}
if(p < to_size)
{
to.m_splines[spli].get_point_and_coefficients(p, tc[0], tc[1],
tc[2], tc[3]);
}
else
{
for(int i= 0; i < 4; ++i)
{
tc[i]= fc[i];
}
}
if(p >= from_size)
{
for(int i= 0; i < 4; ++i)
{
fc[i]= tc[i];
}
}
float oc[4]= {0.0f, 0.0f, 0.0f, 0.0f};
for(int i= 0; i < 4; ++i)
{
oc[i]= lerp(between, fc[i], tc[i]);
}
out.m_splines[spli].set_point_and_coefficients(p, oc[0], oc[1], oc[2],
oc[3]);
}
}
// The spline is not solved after averaging because my testing showed that
// it is unnecessary.
// My testing method was this:
// Spline A is generated by lerping all points and coefficients.
// Spline B is generated by lerping all points then solving.
// The coefficients for Spline A and Spline B are identical to 5 to 9
// significant digits. Thus, solving is unnecessary.
// Additionally, solving would require a mechanism to disable solving for
// the people that wish to set their own coefficients instead of solving.
// -Kyz
}
void CubicSplineN::solve()
{
if(!m_dirty) { return; }
@@ -655,7 +759,7 @@ void CubicSplineN::set_##name(bool b) \
m_dirty= true; \
member= b; \
} \
bool CubicSplineN::get_##name() \
bool CubicSplineN::get_##name() const \
{ \
return member; \
}
@@ -728,6 +832,7 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
{
ret.push_back(0.0f);
}
ret.resize(limit);
}
static void set_point_from_stack(T* p, lua_State* L, size_t i, int s)
{
@@ -802,7 +907,7 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
lua_pushnumber(L, p->size() - 1 + p->get_loop());
return 1;
}
static int resize(T* p, lua_State* L)
static int set_size(T* p, lua_State* L)
{
int siz= IArg(1);
if(siz < 0)
@@ -812,12 +917,12 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
p->resize(static_cast<size_t>(siz));
COMMON_RETURN_SELF;
}
static int size(T* p, lua_State* L)
static int get_size(T* p, lua_State* L)
{
lua_pushnumber(L, p->size());
return 1;
}
static int redimension(T* p, lua_State* L)
static int set_dimension(T* p, lua_State* L)
{
if(p->m_owned_by_actor)
{
@@ -832,7 +937,7 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
p->redimension(static_cast<size_t>(dim));
COMMON_RETURN_SELF;
}
static int dimension(T* p, lua_State* L)
static int get_dimension(T* p, lua_State* L)
{
lua_pushnumber(L, p->dimension());
return 1;
@@ -880,10 +985,10 @@ struct LunaCubicSplineN : Luna<CubicSplineN>
ADD_METHOD(set_spatial_extent);
ADD_METHOD(get_spatial_extent);
ADD_METHOD(get_max_t);
ADD_METHOD(resize);
ADD_METHOD(size);
ADD_METHOD(redimension);
ADD_METHOD(dimension);
ADD_METHOD(set_size);
ADD_METHOD(get_size);
ADD_METHOD(set_dimension);
ADD_METHOD(get_dimension);
ADD_METHOD(empty);
ADD_METHOD(set_loop);
ADD_METHOD(get_loop);
+8 -4
View File
@@ -18,7 +18,9 @@ CubicSpline() :m_spatial_extent(0.0f) {}
float evaluate_third_derivative(float t, bool loop) const;
void set_point(size_t i, float v);
void set_coefficients(size_t i, float b, float c, float d);
void get_coefficients(size_t i, float& b, float& c, float& d);
void get_coefficients(size_t i, float& b, float& c, float& d) const;
void set_point_and_coefficients(size_t i, float a, float b, float c, float d);
void get_point_and_coefficients(size_t i, float& a, float& b, float& c, float& d) const;
void resize(size_t s);
size_t size() const;
bool empty() const;
@@ -40,6 +42,8 @@ struct CubicSplineN
CubicSplineN()
:m_owned_by_actor(false), m_loop(false), m_polygonal(false), m_dirty(true)
{}
static void weighted_average(CubicSplineN& out, CubicSplineN const& from,
CubicSplineN const& to, float between);
void solve();
void evaluate(float t, vector<float>& v) const;
void evaluate_derivative(float t, vector<float>& v) const;
@@ -59,11 +63,11 @@ struct CubicSplineN
bool empty() const;
typedef vector<CubicSpline> spline_cont_t;
void set_loop(bool l);
bool get_loop();
bool get_loop() const;
void set_polygonal(bool p);
bool get_polygonal();
bool get_polygonal() const;
void set_dirty(bool d);
bool get_dirty();
bool get_dirty() const;
bool m_owned_by_actor;
void PushSelf(lua_State* L);
+93 -16
View File
@@ -325,6 +325,25 @@ void NCSplineHandler::EvalForReceptor(float song_beat, vector<float>& ret) const
m_spline.evaluate(t_value, ret);
}
void NCSplineHandler::MakeWeightedAverage(NCSplineHandler& out,
NCSplineHandler const& from, NCSplineHandler const& to, float between)
{
#define BOOLS_FROM_CLOSEST(closest) \
out.m_spline_mode= closest.m_spline_mode; \
out.m_subtract_song_beat_from_curr= closest.m_subtract_song_beat_from_curr;
if(between >= 0.5f)
{
BOOLS_FROM_CLOSEST(to);
}
else
{
BOOLS_FROM_CLOSEST(from);
}
#undef BOOLS_FROM_CLOSEST
CubicSplineN::weighted_average(out.m_spline, from.m_spline, to.m_spline,
between);
}
void NoteColumnRenderArgs::spae_pos_for_beat(PlayerState const* state,
float beat, float y_offset, float y_reverse_offset,
vector<float>& sp_pos, vector<float>& ae_pos) const
@@ -1346,7 +1365,7 @@ void NoteColumnRenderer::UpdateReceptorGhostStuff(Actor* receptor) const
vector<float> ae_pos(3, 0.0f);
vector<float> ae_rot(3, 0.0f);
vector<float> ae_zoom(3, 0.0f);
switch(m_pos_handler.m_spline_mode)
switch(NCR_current.m_pos_handler.m_spline_mode)
{
case NCSM_Disabled:
ArrowEffects::GetXYZPos(player_state, m_column, 0, m_field_render_args->reverse_offset_pixels, ae_pos);
@@ -1358,13 +1377,13 @@ void NoteColumnRenderer::UpdateReceptorGhostStuff(Actor* receptor) const
break;
case NCSM_Offset:
ArrowEffects::GetXYZPos(player_state, m_column, 0, m_field_render_args->reverse_offset_pixels, ae_pos);
m_pos_handler.EvalForReceptor(song_beat, sp_pos);
NCR_current.m_pos_handler.EvalForReceptor(song_beat, sp_pos);
break;
case NCSM_Position:
m_pos_handler.EvalForReceptor(song_beat, sp_pos);
NCR_current.m_pos_handler.EvalForReceptor(song_beat, sp_pos);
break;
}
switch(m_rot_handler.m_spline_mode)
switch(NCR_current.m_rot_handler.m_spline_mode)
{
case NCSM_Disabled:
ae_rot[2]= ArrowEffects::ReceptorGetRotationZ(player_state);
@@ -1373,13 +1392,13 @@ void NoteColumnRenderer::UpdateReceptorGhostStuff(Actor* receptor) const
break;
case NCSM_Offset:
ae_rot[2]= ArrowEffects::ReceptorGetRotationZ(player_state);
m_rot_handler.EvalForReceptor(song_beat, sp_rot);
NCR_current.m_rot_handler.EvalForReceptor(song_beat, sp_rot);
break;
case NCSM_Position:
m_rot_handler.EvalForReceptor(song_beat, sp_rot);
NCR_current.m_rot_handler.EvalForReceptor(song_beat, sp_rot);
break;
}
switch(m_zoom_handler.m_spline_mode)
switch(NCR_current.m_zoom_handler.m_spline_mode)
{
case NCSM_Disabled:
ae_zoom[0]= ae_zoom[1]= ae_zoom[2]= ArrowEffects::GetZoom(player_state);
@@ -1388,10 +1407,10 @@ void NoteColumnRenderer::UpdateReceptorGhostStuff(Actor* receptor) const
break;
case NCSM_Offset:
ae_zoom[0]= ae_zoom[1]= ae_zoom[2]= ArrowEffects::GetZoom(player_state);
m_zoom_handler.EvalForReceptor(song_beat, sp_zoom);
NCR_current.m_zoom_handler.EvalForReceptor(song_beat, sp_zoom);
break;
case NCSM_Position:
m_zoom_handler.EvalForReceptor(song_beat, sp_zoom);
NCR_current.m_zoom_handler.EvalForReceptor(song_beat, sp_zoom);
break;
}
m_column_render_args.SetPRZForActor(receptor, sp_pos, ae_pos, sp_rot, ae_rot, sp_zoom, ae_zoom);
@@ -1400,9 +1419,9 @@ void NoteColumnRenderer::UpdateReceptorGhostStuff(Actor* receptor) const
void NoteColumnRenderer::DrawPrimitives()
{
m_column_render_args.song_beat= m_field_render_args->player_state->GetDisplayedPosition().m_fSongBeatVisible;
m_column_render_args.pos_handler= &m_pos_handler;
m_column_render_args.rot_handler= &m_rot_handler;
m_column_render_args.zoom_handler= &m_zoom_handler;
m_column_render_args.pos_handler= &NCR_current.m_pos_handler;
m_column_render_args.rot_handler= &NCR_current.m_rot_handler;
m_column_render_args.zoom_handler= &NCR_current.m_zoom_handler;
m_field_render_args->first_beat= NoteRowToBeat(m_field_render_args->first_row);
m_field_render_args->last_beat= NoteRowToBeat(m_field_render_args->last_row);
bool any_upcoming= false;
@@ -1461,6 +1480,64 @@ void NoteColumnRenderer::DrawPrimitives()
m_field_render_args->receptor_row->SetNoteUpcoming(m_column, any_upcoming);
}
void NoteColumnRenderer::SetCurrentTweenStart()
{
NCR_start= NCR_current;
}
void NoteColumnRenderer::EraseHeadTween()
{
NCR_current= NCR_Tweens[0];
NCR_Tweens.erase(NCR_Tweens.begin());
}
void NoteColumnRenderer::UpdatePercentThroughTween(float between)
{
NCR_TweenState::MakeWeightedAverage(NCR_current, NCR_start, NCR_Tweens[0],
between);
}
void NoteColumnRenderer::BeginTweening(float time, ITween* interp)
{
Actor::BeginTweening(time, interp);
if(!NCR_Tweens.empty())
{
NCR_Tweens.push_back(NCR_Tweens.back());
}
else
{
NCR_Tweens.push_back(NCR_current);
}
}
void NoteColumnRenderer::StopTweening()
{
NCR_Tweens.clear();
Actor::StopTweening();
}
void NoteColumnRenderer::FinishTweening()
{
if(!NCR_Tweens.empty())
{
NCR_current= NCR_DestTweenState();
}
Actor::FinishTweening();
}
void NoteColumnRenderer::NCR_TweenState::MakeWeightedAverage(
NCR_TweenState& out, NCR_TweenState const& from, NCR_TweenState const& to,
float between)
{
#define WEIGHT_FOR_ME(me) \
NCSplineHandler::MakeWeightedAverage(out.me, from.me, to.me, between);
WEIGHT_FOR_ME(m_pos_handler);
WEIGHT_FOR_ME(m_rot_handler);
WEIGHT_FOR_ME(m_zoom_handler);
#undef WEIGHT_FOR_ME
}
#include "LuaBinding.h"
struct LunaNCSplineHandler : Luna<NCSplineHandler>
@@ -1518,12 +1595,12 @@ struct LunaNoteColumnRenderer : Luna<NoteColumnRenderer>
#define GET_HANDLER(member, name) \
static int name(T* p, lua_State* L) \
{ \
p->member.PushSelf(L); \
p->member->PushSelf(L); \
return 1; \
}
GET_HANDLER(m_pos_handler, get_pos_handler);
GET_HANDLER(m_rot_handler, get_rot_handler);
GET_HANDLER(m_zoom_handler, get_zoom_handler);
GET_HANDLER(GetPosHandler(), get_pos_handler);
GET_HANDLER(GetRotHandler(), get_rot_handler);
GET_HANDLER(GetZoomHandler(), get_zoom_handler);
#undef GET_HANDLER
LunaNoteColumnRenderer()
+38 -6
View File
@@ -136,6 +136,8 @@ struct NCSplineHandler
void EvalForBeat(float song_beat, float note_beat, vector<float>& ret) const;
void EvalDerivForBeat(float song_beat, float note_beat, vector<float>& ret) const;
void EvalForReceptor(float song_beat, vector<float>& ret) const;
static void MakeWeightedAverage(NCSplineHandler& out,
NCSplineHandler const& from, NCSplineHandler const& to, float between);
CubicSplineN m_spline;
NoteColumnSplineMode m_spline_mode;
@@ -263,12 +265,6 @@ struct NoteColumnRenderer : public Actor
NoteFieldRenderArgs* m_field_render_args;
NoteColumnRenderArgs m_column_render_args;
int m_column;
// m_column_render_args has pointers to these fields that are updated
// every frame instead of using m_column_render_args directly so that they
// can be moved into a tween state later. -Kyz
NCSplineHandler m_pos_handler;
NCSplineHandler m_rot_handler;
NCSplineHandler m_zoom_handler;
// UpdateReceptorGhostStuff takes care of the logic for making the ghost
// and receptor positions follow the splines. It's called by their row
@@ -276,6 +272,42 @@ struct NoteColumnRenderer : public Actor
void UpdateReceptorGhostStuff(Actor* receptor) const;
virtual void DrawPrimitives();
virtual void PushSelf(lua_State* L);
struct NCR_TweenState
{
NCSplineHandler m_pos_handler;
NCSplineHandler m_rot_handler;
NCSplineHandler m_zoom_handler;
static void MakeWeightedAverage(NCR_TweenState& out,
NCR_TweenState const& from, NCR_TweenState const& to, float between);
bool operator==(NCR_TweenState const& other) const;
bool operator!=(NCR_TweenState const& other) const { return !operator==(other); }
};
NCR_TweenState& NCR_DestTweenState()
{
if(NCR_Tweens.empty())
{ return NCR_current; }
else
{ return NCR_Tweens.back(); }
}
NCR_TweenState const& NCR_DestTweenState() const { return const_cast<NoteColumnRenderer*>(this)->NCR_DestTweenState(); }
virtual void SetCurrentTweenStart();
virtual void EraseHeadTween();
virtual void UpdatePercentThroughTween(float between);
virtual void BeginTweening(float time, ITween* interp);
virtual void StopTweening();
virtual void FinishTweening();
NCSplineHandler* GetPosHandler() { return &NCR_DestTweenState().m_pos_handler; }
NCSplineHandler* GetRotHandler() { return &NCR_DestTweenState().m_rot_handler; }
NCSplineHandler* GetZoomHandler() { return &NCR_DestTweenState().m_zoom_handler; }
private:
vector<NCR_TweenState> NCR_Tweens;
NCR_TweenState NCR_current;
NCR_TweenState NCR_start;
};
#endif
+6
View File
@@ -61,6 +61,12 @@ inline bool CLAMP( unsigned &x, unsigned l, unsigned h )
else if (x < l) { x = l; return true; }
return false;
}
inline bool CLAMP( size_t &x, size_t l, size_t h )
{
if (x > h) { x = h; return true; }
else if (x < l) { x = l; return true; }
return false;
}
inline bool CLAMP( float &x, float l, float h )
{
if (x > h) { x = h; return true; }