[dasher: 9/28] Refactor control-mode slowdown, optimize Turbo Mode, remove LP_BOOSTFACTOR
- From: Patrick Welche <pwelche src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [dasher: 9/28] Refactor control-mode slowdown, optimize Turbo Mode, remove LP_BOOSTFACTOR
- Date: Tue, 22 Nov 2011 17:03:25 +0000 (UTC)
commit efb1f2308b88e346bfd9e6728d7f524b54653efc
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date: Wed Sep 7 08:41:52 2011 +0100
Refactor control-mode slowdown, optimize Turbo Mode, remove LP_BOOSTFACTOR
Adding CDasherNode::SpeedMul(), using in DynamicFilter::FrameSpeedMul (which
also does slow start + turbo mode), via CDasherModel::Get_node_under_crosshair
(which returns last-output node)
This will cause some minor changes when inside control nodes (e.g. two-push
guide areas being drawn wrong)....
Src/DasherCore/ControlManager.cpp | 11 -------
Src/DasherCore/ControlManager.h | 4 +--
Src/DasherCore/DasherModel.cpp | 15 +++-------
Src/DasherCore/DasherModel.h | 5 +++
Src/DasherCore/DasherNode.h | 11 +++++--
Src/DasherCore/DefaultFilter.cpp | 4 +-
Src/DasherCore/DynamicButtons.cpp | 2 +-
Src/DasherCore/DynamicFilter.cpp | 38 +++++++++++++++++++------
Src/DasherCore/DynamicFilter.h | 20 ++++++++++++-
Src/DasherCore/FrameRate.cpp | 23 +++++----------
Src/DasherCore/FrameRate.h | 23 +++++++---------
Src/DasherCore/OneButtonDynamicFilter.cpp | 2 +-
Src/DasherCore/Parameters.cpp | 1 -
Src/DasherCore/Parameters.h | 2 +-
Src/DasherCore/TwoButtonDynamicFilter.cpp | 14 +++------
Src/DasherCore/TwoButtonDynamicFilter.h | 2 +-
Src/DasherCore/TwoPushDynamicFilter.cpp | 35 +++++++++++++----------
Src/iPhone/Classes/CDasherInterfaceBridge.mm | 2 +-
18 files changed, 116 insertions(+), 98 deletions(-)
---
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index 5e8828b..458a905 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -124,17 +124,6 @@ void CControlBase::CContNode::Output() {
m_pTemplate->happen(this);
}
-void CControlBase::CContNode::Enter() {
- // Slow down to half the speed we were at. This also disables auto-speed-control.
- m_pMgr->SetLongParameter(LP_BOOSTFACTOR, 50);
-}
-
-
-void CControlBase::CContNode::Leave() {
- // Now speed back up, by doubling the speed we were at in control mode
- m_pMgr->SetLongParameter(LP_BOOSTFACTOR, 100);
-}
-
const vector<CControlBase::NodeTemplate *> &CControlParser::parsedNodes() {
return m_vParsed;
}
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index 37c9beb..a07b58f 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -63,6 +63,7 @@ namespace Dasher {
CContNode(CDasherNode *pParent, int iOffset, unsigned int iLbnd, unsigned int iHbnd, NodeTemplate *pTemplate, CControlBase *pMgr);
bool bShove() {return false;}
+ double SpeedMul() {return 0.5;}
///
/// Provide children for the supplied node
///
@@ -72,9 +73,6 @@ namespace Dasher {
virtual void Output();
- virtual void Enter();
- virtual void Leave();
-
private:
NodeTemplate *m_pTemplate;
CControlBase *m_pMgr;
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index 1127e8d..a2d5d63 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -75,8 +75,6 @@ CDasherModel::CDasherModel(CSettingsUser *pCreateFrom)
}
CDasherModel::~CDasherModel() {
- if (m_pLastOutput) m_pLastOutput->Leave();
-
if(oldroots.size() > 0) {
delete oldroots[0];
oldroots.clear();
@@ -203,8 +201,6 @@ void CDasherModel::SetOffset(int iOffset, CAlphabetManager *pMgr, CDasherView *p
// (if we have a root, only rebuild to move location or if bForce says to)
if (m_Root && iOffset == GetOffset() && !bForce) return;
- if (m_pLastOutput) m_pLastOutput->Leave();
-
ClearRootQueue();
delete m_Root;
@@ -215,7 +211,6 @@ void CDasherModel::SetOffset(int iOffset, CAlphabetManager *pMgr, CDasherView *p
// rather than a character node (responsible for the last said preceding character),
// but even so, it seems fair enough to say we've "seen" the root:
m_Root->SetFlag(NF_SEEN, true);
- m_Root->Enter();
// (of course, we don't do Output() - the context contains it already!)
m_pLastOutput = m_Root;
@@ -250,6 +245,10 @@ int CDasherModel::GetOffset() {
return m_pLastOutput ? m_pLastOutput->offset()+1 : m_Root ? m_Root->offset()+1 : 0;
};
+CDasherNode *CDasherModel::Get_node_under_crosshair() {
+ return m_pLastOutput;
+}
+
void CDasherModel::Get_new_root_coords(dasherint X, dasherint Y, dasherint &r1, dasherint &r2, int iSteps, dasherint iMinSize) {
DASHER_ASSERT(m_Root != NULL);
// Avoid X == 0, as this corresponds to infinite zoom
@@ -432,8 +431,6 @@ void CDasherModel::OutputTo(CDasherNode *pNewNode) {
//first, recurse back up to last seen node (must be processed ancestor-first)
if (pNewNode && !pNewNode->GetFlag(NF_SEEN)) {
OutputTo(pNewNode->Parent());
- if (pNewNode->Parent()) pNewNode->Parent()->Leave();
- pNewNode->Enter();
m_pLastOutput = pNewNode;
pNewNode->Output();
@@ -446,12 +443,10 @@ void CDasherModel::OutputTo(CDasherNode *pNewNode) {
// so we should encounter it on the way back out to the root, _before_ null
m_pLastOutput->SetFlag(NF_COMMITTED, false);
m_pLastOutput->Undo();
- m_pLastOutput->Leave(); //Should we? I think so, but the old code didn't...?
m_pLastOutput->SetFlag(NF_SEEN, false);
m_pLastOutput = m_pLastOutput->Parent();
- if (m_pLastOutput) m_pLastOutput->Enter();
- else DASHER_ASSERT (!pNewNode); //both null
+ DASHER_ASSERT(m_pLastOutput || !pNewNode); //if m_pLastOutput null, then pNewNode is too.
}
}
}
diff --git a/Src/DasherCore/DasherModel.h b/Src/DasherCore/DasherModel.h
index 529bab3..78af168 100644
--- a/Src/DasherCore/DasherModel.h
+++ b/Src/DasherCore/DasherModel.h
@@ -154,6 +154,11 @@ class Dasher::CDasherModel: private CSettingsUser, public Observable<CDasherNode
/// @}
+ /// Returns the node that was under the crosshair in the
+ /// last frame that was rendered. (I.e., this is the last
+ /// node output.)
+ CDasherNode *Get_node_under_crosshair();
+
///
/// This is pretty horrible - a rethink of the start/reset mechanism
/// is definitely in order. Used to prevent the root node from being
diff --git a/Src/DasherCore/DasherNode.h b/Src/DasherCore/DasherNode.h
index b48cfb5..4984d60 100644
--- a/Src/DasherCore/DasherNode.h
+++ b/Src/DasherCore/DasherNode.h
@@ -95,6 +95,14 @@ class Dasher::CDasherNode:private NoClones {
/// (Default implementation returns true, subclasses should override if appropriate)
virtual bool bShove() {return true;}
+ ///Multiplier to apply to the speed (in dynamic modes, inc. default mouse
+ /// control) when the crosshair is inside this node (but not inside any child.)
+ /// This creates a sort of "viscosity", i.e. makes some nodes harder to move
+ /// through than others - used to slow down movement inside control nodes,
+ /// making it harder to make mistakes therein. The default just returns 1.0,
+ /// i.e. no change.
+ virtual double SpeedMul() {return 1.0;}
+
inline int offset() const {return m_iOffset;}
CDasherNode *onlyChildRendered; //cache that only one child was rendered (as it filled the screen)
@@ -249,9 +257,6 @@ class Dasher::CDasherNode:private NoClones {
return SymbolProb(0,m_pLabel->m_strText,0.0);
}
- virtual void Enter() {};
- virtual void Leave() {};
-
virtual CDasherNode *RebuildParent() {
return 0;
};
diff --git a/Src/DasherCore/DefaultFilter.cpp b/Src/DasherCore/DefaultFilter.cpp
index 8707e45..300a1b2 100644
--- a/Src/DasherCore/DefaultFilter.cpp
+++ b/Src/DasherCore/DefaultFilter.cpp
@@ -129,13 +129,13 @@ bool CDefaultFilter::Timer(unsigned long Time, CDasherView *pView, CDasherInput
}
}
- double dSpeedMul(SlowStartSpeedMul(Time));
+ double dSpeedMul(FrameSpeedMul(m_pDasherModel, Time));
if (m_bTurbo) dSpeedMul*=1.75;
OneStepTowards(m_pDasherModel, m_iLastX,m_iLastY, Time, dSpeedMul);
bDidSomething = true;
- if (GetLongParameter(LP_BOOSTFACTOR)==100 && dSpeedMul==1.0)
+ if (dSpeedMul==1.0)
m_pAutoSpeedControl->SpeedControl(m_iLastX, m_iLastY, pView);
}
diff --git a/Src/DasherCore/DynamicButtons.cpp b/Src/DasherCore/DynamicButtons.cpp
index f241b1c..109102e 100644
--- a/Src/DasherCore/DynamicButtons.cpp
+++ b/Src/DasherCore/DynamicButtons.cpp
@@ -39,7 +39,7 @@ bool CDynamicButtons::Timer(unsigned long iTime, CDasherView *pDasherView, CDash
}
if (isPaused()) return false;
if (isReversing()) {
- OneStepTowards(m_pDasherModel, 41943,2048, iTime, SlowStartSpeedMul(iTime));
+ OneStepTowards(m_pDasherModel, 41943,2048, iTime, FrameSpeedMul(m_pDasherModel, iTime));
return true;
}
//moving forwards. Check auto speed control...
diff --git a/Src/DasherCore/DynamicFilter.cpp b/Src/DasherCore/DynamicFilter.cpp
index 026f17c..5ebff90 100644
--- a/Src/DasherCore/DynamicFilter.cpp
+++ b/Src/DasherCore/DynamicFilter.cpp
@@ -23,28 +23,48 @@
using namespace Dasher;
-CDynamicFilter::CDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CFrameRate *pFramerate, ModuleID_t iID, const char *szName) : CInputFilter(pInterface, iID, szName), CSettingsUser(pCreator), m_pFramerate(pFramerate) {
+CDynamicFilter::CDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CFrameRate *pFramerate, ModuleID_t iID, const char *szName)
+: CInputFilter(pInterface, iID, szName), CSettingsUser(pCreator),
+m_pFramerate(pFramerate), m_dLastBits(-1) {
}
bool CDynamicFilter::OneStepTowards(CDasherModel *pModel, myint y1, myint y2, unsigned long iTime, double dSpeedMul) {
if (dSpeedMul<=0.0) return false; //going nowhere
m_pFramerate->RecordFrame(iTime); //Hmmm, even if we don't do anything else?
- double dRXMax = m_pFramerate->GetMaxZoomFactor();
- // Adjust for slow start etc. TODO: can we fix to use integer math (or at least no pow?)
- if (dSpeedMul!=1.0) dRXMax=pow(dRXMax, dSpeedMul);
+ //The maximum number of bits we should allow to be entered in this frame:
+ // (after adjusting for slow start, turbo mode, control node slowdown, etc.)
+ double dBits = m_pFramerate->GetMaxBitsPerFrame()*dSpeedMul;
+
+ //Compute max expansion, i.e. the minimum size we should allow the range 0..MAX_Y
+ // to be shrunk down to, for this frame. We cache the most-recent result to
+ // avoid an exp() (and a division): in the majority of cases this doesn't change
+ // between frames, but only does so when the maxbitrate changes, or dspeedmul
+ // changes (e.g. continuously during slow start, or when entering/leaving turbo
+ // mode or a control node).
+ if (dBits != m_dLastBits) m_iLastMinSize = static_cast<myint>(CDasherModel::MAX_Y / exp(m_dLastBits = dBits));
+ //However, note measurements on iPhone suggest even one exp() per frame is not
+ // a significant overhead; so the caching may be unnecessary, but it's easy.
- pModel->OneStepTowards(y1, y2, static_cast<int>(m_pFramerate->Steps() / dSpeedMul), static_cast<myint>(CDasherModel::MAX_Y/dRXMax));
+ //If we wanted to take things further we could generalize this cache to cover
+ // exp()s done in the dynamic button modes too, and thus to allow them to adjust
+ // lag, guide markers, etc., according to the dSpeedMul in use. (And/or
+ // to do slow-start more efficiently by interpolating cache values.)
+ pModel->OneStepTowards(y1, y2,
+ static_cast<int>(m_pFramerate->Steps() / dSpeedMul),
+ m_iLastMinSize);
return true;
}
-double CDynamicFilter::SlowStartSpeedMul(unsigned long iTime) {
+double CDynamicFilter::FrameSpeedMul(CDasherModel *pModel, unsigned long iTime) {
+ CDasherNode *n = pModel->Get_node_under_crosshair();
+ double d = n ? n->SpeedMul() : 1.0;
if(GetBoolParameter(BP_SLOW_START)) {
if ((iTime - m_iStartTime) < GetLongParameter(LP_SLOW_START_TIME))
- return 0.1 * (1 + 9 * ((iTime - m_iStartTime) / static_cast<double>(GetLongParameter(LP_SLOW_START_TIME))));
+ d *= 0.1 * (1 + 9 * ((iTime - m_iStartTime) / static_cast<double>(GetLongParameter(LP_SLOW_START_TIME))));
}
- //no slow start, or finished.
- return 1.0;
+ //else, no slow start, or finished.
+ return d;
}
void CDynamicFilter::Unpause(unsigned long Time) {
diff --git a/Src/DasherCore/DynamicFilter.h b/Src/DasherCore/DynamicFilter.h
index 33791e9..0569a57 100644
--- a/Src/DasherCore/DynamicFilter.h
+++ b/Src/DasherCore/DynamicFilter.h
@@ -40,18 +40,34 @@ class CDynamicFilter : public CInputFilter, public CSettingsUser {
virtual bool supportsPause() {return true;}
protected:
+ ///wraps Model's one-step method to compute the number of steps and minsize
+ /// (from framerate) that the Model requires, from just the frame time and a
+ /// multiplier to speed.
+ /// \param dSpeedMul multiply normal speed of movement by this; 1.0 = normal speed,
+ /// 0.0 = go nowhere. This allows for slow start, turbo mode, control nodes being
+ /// more "viscous", etc. Values <=0.0 will result in no movement
+ /// \return true if dSpeedMul>0.0, false if <=0.0.
bool OneStepTowards(CDasherModel *pModel, myint y1, myint y2, unsigned long iTime, double dSpeedMul);
- double SlowStartSpeedMul(unsigned long iTime);
+
+ ///Calculates a multiplier by which to adjust our speed (for a given frame).
+ /// Defalut implementation implements slow-start (i.e. a multiplier increasing
+ /// from zero to one over the slow-start-time) as well as by checking the speedMul
+ /// of the node under the cursor.
+ virtual double FrameSpeedMul(CDasherModel *pModel, unsigned long iTime);
/// Starts moving. Clears BP_DASHER_PAUSED.
/// (But does nothing if BP_DASHER_PAUSED is currently set).
/// \param Time Time in ms, used to keep a constant frame rate and
/// initialize slow start.
void Unpause(unsigned long iTime);
+
+ CFrameRate * const m_pFramerate;
private:
- CFrameRate *m_pFramerate;
//Time at which Unpause() was called, used for Slow Start.
unsigned long m_iStartTime;
+ //Number of bits (we allowed) to be entered in previous frame - to cache exp()
+ double m_dLastBits;
+ double m_iLastMinSize;
};
}
#endif
diff --git a/Src/DasherCore/FrameRate.cpp b/Src/DasherCore/FrameRate.cpp
index e2b951b..49242bd 100644
--- a/Src/DasherCore/FrameRate.cpp
+++ b/Src/DasherCore/FrameRate.cpp
@@ -11,7 +11,6 @@ CFrameRate::CFrameRate(CSettingsUser *pCreator) :
m_iTime = 0;
//try and carry on from where we left off at last run
- HandleEvent(LP_FRAMERATE);
HandleEvent(LP_MAX_BITRATE);
//calls UpdateSteps(), which sets m_dRXMax and m_iSteps
}
@@ -40,6 +39,7 @@ void CFrameRate::RecordFrame(unsigned long Time)
double dFrNow;
if(m_iTime2 - m_iTime > 0) {
dFrNow = m_iFrames * 1000.0 / (m_iTime2 - m_iTime);
+ //LP_FRAMERATE records a decaying average, smoothed 50:50 with previous value
SetLongParameter(LP_FRAMERATE, long(GetLongParameter(LP_FRAMERATE) + (dFrNow*100))/2);
m_iTime = m_iTime2;
m_iFrames = 0;
@@ -48,7 +48,7 @@ void CFrameRate::RecordFrame(unsigned long Time)
UpdateSteps(dFrNow);
- DASHER_TRACEOUTPUT("Fr %f Steps %d Samples %d Time2 %d rxmax %f\n", dFrNow, m_iSteps, m_iSamples, m_iTime2, m_dRXmax);
+ DASHER_TRACEOUTPUT("Fr %f Steps %d Samples %d Time2 %d maxbits %f\n", dFrNow, m_iSteps, m_iSamples, m_iTime2, m_dFrameBits);
}
}
@@ -56,13 +56,9 @@ void CFrameRate::RecordFrame(unsigned long Time)
void CFrameRate::HandleEvent(int iParameter) {
switch (iParameter) {
- case LP_MAX_BITRATE: // Delibarate fallthrough
- case LP_BOOSTFACTOR:
- m_dMaxbitrate=(GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR)) / 10000.0;
+ case LP_MAX_BITRATE:
UpdateSteps(GetLongParameter(LP_FRAMERATE) / 100.0); //use the decaying average as current
break;
- case LP_FRAMERATE:
- m_dFrDecay = GetLongParameter(LP_FRAMERATE) / 100.0;
}
}
@@ -70,16 +66,13 @@ const double LN2 = log(2.0);
const double STEPS_COEFF = -log(0.2) / LN2;
void CFrameRate::UpdateSteps(double dFrNow) {
+ const double dMaxbitrate = GetLongParameter(LP_MAX_BITRATE) / 100.0;
// Update auxiliary variables - even if we didn't recalc the framerate
// (means we reach sensible values more quickly after first loading)
- m_dRXmax = exp(m_dMaxbitrate * LN2 / dFrNow);
+ m_dFrameBits = dMaxbitrate * LN2 / dFrNow;
- // Note that m_iSteps is smoothed here - 50:50 interpolation with
- // previous value
- m_iSteps = std::max(1,(int)(STEPS_COEFF * m_dFrDecay / m_dMaxbitrate));
-
- // If the framerate slows to < 4 then we end up with steps < 1 !
- if(m_iSteps == 0)
- m_iSteps = 1;
+ //Calculate m_iSteps from the decaying-average framerate, and ensure
+ // it is at least 1 (else, if framerate slows to <4, we get 0 steps!)
+ m_iSteps = std::max(1,(int)(STEPS_COEFF * (GetLongParameter(LP_FRAMERATE)/100.0) / dMaxbitrate));
}
diff --git a/Src/DasherCore/FrameRate.h b/Src/DasherCore/FrameRate.h
index 8f66a6f..31ed87b 100644
--- a/Src/DasherCore/FrameRate.h
+++ b/Src/DasherCore/FrameRate.h
@@ -28,20 +28,20 @@ public:
virtual void HandleEvent(int iParameter);
///The maximum amount by which one frame may zoom in. Used as a hard
- /// upper-bound on the approximate one-step calculation done in DasherModel
- /// to ensure we never exceed the set LP_MAX_BITRATE.
- double GetMaxZoomFactor() {
- return m_dRXmax;
+ /// upper-bound on the speed of movement (however far to RHS the cursor is),
+ /// calculated from the most-recent (instantaneous) framerate rather than
+ /// the decaying average used for the Steps() parameter.
+ double GetMaxBitsPerFrame() {
+ return m_dFrameBits;
}
+ ///The number of frames, in which we will attempt to bring
+ /// the target location (under the cursor, or in dynamic button
+ /// modes) to the crosshair. See DJW thesis.
int Steps() const {
return m_iSteps;
};
- double Bitrate() const {
- return m_dMaxbitrate;
- }
-
///
/// Reset the framerate class
/// TODO: Need to check semantics here
@@ -55,12 +55,9 @@ public:
void RecordFrame(unsigned long Time);
bool OneStepTowards(CDasherModel *pModel, myint y1, myint y2, unsigned long iTime, double dSpeedMul);
- double SlowStartSpeedMul(unsigned long iTime);
private:
- double m_dFrDecay; // current frame rate (cache of LP_FRAMERATE/100.0)
- double m_dMaxbitrate; // the maximum rate of entering information (cache)
- double m_dRXmax; // the maximum zoomin per frame
+ double m_dFrameBits; // the maximum zoomin per frame
///number of frames that have been sampled
int m_iFrames;
///time at which first sampled frame was rendered
@@ -68,7 +65,7 @@ private:
///number of frames over which we will compute average framerate
int m_iSamples;
- int m_iSteps; // the 'Steps' parameter. See djw thesis.
+ int m_iSteps;
///updates m_dRXMax and m_iSteps
/// \param dFrNow current (non-decaying-average) framerate (if available!)
diff --git a/Src/DasherCore/OneButtonDynamicFilter.cpp b/Src/DasherCore/OneButtonDynamicFilter.cpp
index dec1b31..a72a49a 100644
--- a/Src/DasherCore/OneButtonDynamicFilter.cpp
+++ b/Src/DasherCore/OneButtonDynamicFilter.cpp
@@ -109,7 +109,7 @@ void COneButtonDynamicFilter::KeyUp(unsigned long Time, int iId, CDasherView *pD
}
bool COneButtonDynamicFilter::TimerImpl(unsigned long Time, CDasherView *m_pDasherView, CDasherModel *m_pDasherModel, CExpansionPolicy **pol) {
- OneStepTowards(m_pDasherModel, m_iTargetX[m_iTarget], m_iTargetY[m_iTarget], Time, SlowStartSpeedMul(Time));
+ OneStepTowards(m_pDasherModel, m_iTargetX[m_iTarget], m_iTargetY[m_iTarget], Time, FrameSpeedMul(m_pDasherModel, Time));
return true;
}
diff --git a/Src/DasherCore/Parameters.cpp b/Src/DasherCore/Parameters.cpp
index 9be39c1..bf81a98 100644
--- a/Src/DasherCore/Parameters.cpp
+++ b/Src/DasherCore/Parameters.cpp
@@ -108,7 +108,6 @@ const lp_table longparamtable[] = {
#else
{LP_NONLINEAR_X, "NonLinearX", PERS, 5, "Nonlinear compression of X-axis (0 = none, higher = more extreme)"},
#endif
- {LP_BOOSTFACTOR, "BoostFactor", !PERS, 100, "Boost/brake factor (multiplied by 100)"},
{LP_AUTOSPEED_SENSITIVITY, "AutospeedSensitivity", PERS, 100, "Sensitivity of automatic speed control (percent)"},
{LP_SOCKET_PORT, "SocketPort", PERS, 20320, "UDP/TCP socket to use for network socket input"},
{LP_SOCKET_INPUT_X_MIN, "SocketInputXMinTimes1000", PERS, 0, "Bottom of range of X values expected from network input"},
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 0a171bd..2b77da3 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -55,7 +55,7 @@ enum {
LP_LM_WORD_ALPHA, LP_USER_LOG_LEVEL_MASK,
LP_ZOOMSTEPS, LP_B, LP_S, LP_BUTTON_SCAN_TIME, LP_R, LP_RIGHTZOOM,
LP_NODE_BUDGET, LP_OUTLINE_WIDTH, LP_MIN_NODE_SIZE, LP_NONLINEAR_X,
- LP_BOOSTFACTOR, LP_AUTOSPEED_SENSITIVITY, LP_SOCKET_PORT, LP_SOCKET_INPUT_X_MIN, LP_SOCKET_INPUT_X_MAX,
+ LP_AUTOSPEED_SENSITIVITY, LP_SOCKET_PORT, LP_SOCKET_INPUT_X_MIN, LP_SOCKET_INPUT_X_MAX,
LP_SOCKET_INPUT_Y_MIN, LP_SOCKET_INPUT_Y_MAX, LP_INPUT_FILTER,
LP_CIRCLE_PERCENT, LP_TWO_BUTTON_OFFSET, LP_HOLD_TIME, LP_MULTIPRESS_TIME,
LP_SLOW_START_TIME, LP_CONVERSION_ORDER, LP_CONVERSION_TYPE,
diff --git a/Src/DasherCore/TwoButtonDynamicFilter.cpp b/Src/DasherCore/TwoButtonDynamicFilter.cpp
index ad3b4ea..9182827 100644
--- a/Src/DasherCore/TwoButtonDynamicFilter.cpp
+++ b/Src/DasherCore/TwoButtonDynamicFilter.cpp
@@ -51,7 +51,7 @@ static SModuleSettings sSettings[] = {
CTwoButtonDynamicFilter::CTwoButtonDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CFrameRate *pFramerate)
: CButtonMultiPress(pCreator, pInterface, pFramerate, 14, _("Two Button Dynamic Mode")), m_iMouseButton(-1)
{
- //ensure that m_dLagMul is properly initialised
+ //ensure that m_dLagBits is properly initialised
HandleEvent(LP_DYNAMIC_BUTTON_LAG);
}
@@ -118,7 +118,7 @@ void CTwoButtonDynamicFilter::KeyUp(unsigned long Time, int iId, CDasherView *pV
}
bool CTwoButtonDynamicFilter::TimerImpl(unsigned long Time, CDasherView *m_pDasherView, CDasherModel *m_pDasherModel, CExpansionPolicy **pol) {
- OneStepTowards(m_pDasherModel, 100,2048, Time, SlowStartSpeedMul(Time));
+ OneStepTowards(m_pDasherModel, 100,2048, Time, FrameSpeedMul(m_pDasherModel, Time));
return true;
}
@@ -153,7 +153,7 @@ void CTwoButtonDynamicFilter::ActionButton(unsigned long iTime, int iButton, int
return;
}
//fell through to apply offset
- ApplyOffset(pModel,dFactor * GetLongParameter(LP_TWO_BUTTON_OFFSET) * m_dLagMul);
+ ApplyOffset(pModel,dFactor * GetLongParameter(LP_TWO_BUTTON_OFFSET) * exp(m_dLagBits * FrameSpeedMul(pModel, iTime)));
pModel->ResetNats();
if(CUserLogBase *pUserLog=m_pInterface->GetUserLogPtr())
@@ -175,14 +175,10 @@ bool CTwoButtonDynamicFilter::GetMinWidth(int &iMinWidth) {
void CTwoButtonDynamicFilter::HandleEvent(int iParameter)
{
switch (iParameter) {
- case LP_MAX_BITRATE:
- case LP_BOOSTFACTOR: // Deliberate fallthrough
+ case LP_MAX_BITRATE:// Deliberate fallthrough
case LP_DYNAMIC_BUTTON_LAG:
- {
- double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
- m_dLagMul = exp(dMaxRate * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0);
+ m_dLagBits = GetLongParameter(LP_MAX_BITRATE)/100.0 * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0;
//and fallthrough again:
- }
case LP_TWO_BUTTON_OFFSET:
m_bDecorationChanged = true;
}
diff --git a/Src/DasherCore/TwoButtonDynamicFilter.h b/Src/DasherCore/TwoButtonDynamicFilter.h
index d4669b4..ab7fe77 100644
--- a/Src/DasherCore/TwoButtonDynamicFilter.h
+++ b/Src/DasherCore/TwoButtonDynamicFilter.h
@@ -50,7 +50,7 @@ class CTwoButtonDynamicFilter : public CButtonMultiPress {
unsigned int maxClickCount() {return GetBoolParameter(BP_2B_INVERT_DOUBLE) ? 3 : 2;}
virtual bool TimerImpl(unsigned long Time, CDasherView *m_pDasherView, CDasherModel *m_pDasherModel, CExpansionPolicy **pol);
virtual void ActionButton(unsigned long iTime, int iButton, int iType, CDasherModel *pModel);
- double m_dLagMul;
+ double m_dLagBits;
///id of physical key, whose pressing we have emulated, in response
/// to a mouse down event on one or other half of the canvas...
int m_iMouseButton;
diff --git a/Src/DasherCore/TwoPushDynamicFilter.cpp b/Src/DasherCore/TwoPushDynamicFilter.cpp
index e7feef7..059241b 100644
--- a/Src/DasherCore/TwoPushDynamicFilter.cpp
+++ b/Src/DasherCore/TwoPushDynamicFilter.cpp
@@ -135,12 +135,15 @@ m_dLogUpMul = log(dOuter / (double)GetLongParameter(LP_TWO_PUSH_UP));
m_dLogDownMul = log(dOuter / (double)GetLongParameter(LP_TWO_PUSH_DOWN));
//cout << "bitsUp " << m_dLogUpMul << " bitsDown " << m_dLogDownMul << "\n";
} //and fallthrough
- case LP_TWO_PUSH_TOLERANCE:
+ case LP_TWO_PUSH_TOLERANCE: //deliberate fallthrough
case LP_MAX_BITRATE:
- case LP_BOOSTFACTOR: // Deliberate fallthrough
{
-double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
-double dPressBits = dMaxRate * (double) GetLongParameter(LP_TWO_PUSH_TOLERANCE) / 1000.0;
+ //dPressBits just measures the number of bits which would be output in the
+ // tolerance time, at full (100%) speed; note it does not take account of
+ // the SpeedMul (viscosity) of the node under the cursor (or Slow Start, etc.)
+ // - iow, when we are moving slowly for such a reason, we'll be proportionately
+ // _more_ tolerant of user inaccuracy in button pushing...
+double dPressBits = GetLongParameter(LP_MAX_BITRATE)/100.0 * (double) GetLongParameter(LP_TWO_PUSH_TOLERANCE) / 1000.0;
//cout << "Max Bitrate changed - now " << dMaxRate << " user accuracy " << dPressBits;
m_dMinShortTwoPushTime = m_dLogUpMul - dPressBits;
//cout << "bits; minShort " << m_dMinShortTwoPushTime;
@@ -154,16 +157,17 @@ m_dMaxLongTwoPushTime = m_dLogDownMul + dPressBits;
m_bDecorationChanged = true;
} //and fallthrough again
case LP_DYNAMIC_BUTTON_LAG:
- {
- double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
- m_dLagBits = dMaxRate * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0;
+ m_dLagBits = GetLongParameter(LP_MAX_BITRATE)/100.0 * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0;
//cout << " lag (" << m_dLagBits[0] << ", " << m_dLagBits[1] << ", " << m_dLagBits[2] << ", " << m_dLagBits[3] << ")";
+ //these areas should really be calculated using short/long push-times modified by the
+ // current FrameSpeedMul, which we'd have to do every frame. For now I'm not, so the guide
+ // areas will be wrong when the speed multiplier is other than 1.0. TODO reconsider, esp.
+ // wrt. possibly memoizing exp() in CDynamicFilter?
m_aaiGuideAreas[0][0] = 2048 - GetLongParameter(LP_TWO_PUSH_UP)*exp(m_dMaxShortTwoPushTime);
m_aaiGuideAreas[0][1] = 2048 - GetLongParameter(LP_TWO_PUSH_UP)*exp(m_dMinShortTwoPushTime);
m_aaiGuideAreas[1][0] = 2048 + GetLongParameter(LP_TWO_PUSH_DOWN)*exp(m_dMinLongTwoPushTime);
m_aaiGuideAreas[1][1] = 2048 + GetLongParameter(LP_TWO_PUSH_DOWN)*exp(m_dMaxLongTwoPushTime);
break;
- }
}
}
@@ -223,6 +227,7 @@ bool doSet(int &var, const int val)
bool CTwoPushDynamicFilter::TimerImpl(unsigned long iTime, CDasherView *m_pDasherView, CDasherModel *m_pDasherModel, CExpansionPolicy **pol)
{
DASHER_ASSERT(isRunning());
+ const double dSpeedMul(FrameSpeedMul(m_pDasherModel, iTime));
if (m_dNatsSinceFirstPush > -std::numeric_limits<double>::infinity()) // first button has been pushed
{
double dLogGrowth(m_pDasherModel->GetNats() - m_dNatsSinceFirstPush), dOuter(GetLongParameter(LP_TWO_PUSH_OUTER)),
@@ -236,14 +241,14 @@ bool CTwoPushDynamicFilter::TimerImpl(unsigned long iTime, CDasherView *m_pDashe
double dUpBits = (m_dLogUpMul * dOuter + dLogGrowth * dUp) / (dOuter + dUp);
double dDownBits = (m_dLogDownMul * dOuter + dLogGrowth * dDown) / (dOuter + dDown);
- // (note it's actually slightly more complicated even than that, we have to add in m_dLagBits too!)
-
double dUpDist = exp( dUpBits ) * dUp;
double dDownDist = exp( dDownBits ) * dDown;
- m_aiTarget[0] = dUpDist * exp(m_dLagBits);
- m_aiTarget[1] = -dDownDist * exp(m_dLagBits);
- m_bDecorationChanged |= doSet(m_aiMarker[0], 2048 - exp(m_dLagBits + dLogGrowth) * dUp);
- m_bDecorationChanged |= doSet(m_aiMarker[1], 2048 + exp(m_dLagBits + dLogGrowth) * dDown);
+ // (note it's actually slightly more complicated even than that, we have to add in m_dLagBits too!)
+
+ m_aiTarget[0] = dUpDist * exp(m_dLagBits * dSpeedMul);
+ m_aiTarget[1] = -dDownDist * exp(m_dLagBits * dSpeedMul);
+ m_bDecorationChanged |= doSet(m_aiMarker[0], 2048 - exp(m_dLagBits*dSpeedMul + dLogGrowth) * dUp);
+ m_bDecorationChanged |= doSet(m_aiMarker[1], 2048 + exp(m_dLagBits*dSpeedMul + dLogGrowth) * dDown);
if (dLogGrowth > m_dMaxLongTwoPushTime)
{
//cout << " growth " << dLogGrowth << " - reversing\n";
@@ -256,7 +261,7 @@ bool CTwoPushDynamicFilter::TimerImpl(unsigned long iTime, CDasherView *m_pDashe
m_bDecorationChanged |= doSet(m_iActiveMarker, 1 /*down*/);
else m_bDecorationChanged |= doSet(m_iActiveMarker, -1 /*in middle (neither/both) or too short*/);
}
- OneStepTowards(m_pDasherModel, 100, 2048, iTime, SlowStartSpeedMul(iTime));
+ OneStepTowards(m_pDasherModel, 100, 2048, iTime, dSpeedMul);
return true;
}
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.mm b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
index 1b8c3c9..f0f8604 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.mm
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
@@ -186,7 +186,7 @@ void CDasherInterfaceBridge::HandleEvent(int iParameter) {
// user defaults controller which is observing the user defaults and will be notified when
// the parameter is actually written by COSXSettingsStore.
//NSLog(@"CParameterNotificationEvent, m_iParameter: %d", parameterEvent->m_iParameter);
- if (iParameter == LP_MAX_BITRATE || iParameter == LP_BOOSTFACTOR)
+ if (iParameter == LP_MAX_BITRATE)
[dasherApp notifySpeedChange];
else if (iParameter == SP_ALPHABET_ID)
[dasherApp setAlphabet:GetActiveAlphabet()];
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]