From ea2494a0839ec02d3889a405306009c2f4f9aea7 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 30 Oct 2013 00:37:11 -0700
Subject: stats now autoscale back down in range, instead of sticking at high
 water mark

---
 indra/llui/llstatbar.cpp | 132 ++++++++++++++++++++---------------------------
 indra/llui/llstatbar.h   |  30 ++++++-----
 2 files changed, 73 insertions(+), 89 deletions(-)

(limited to 'indra')

diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp
index 2b325c27f0..bfdc6571c2 100755
--- a/indra/llui/llstatbar.cpp
+++ b/indra/llui/llstatbar.cpp
@@ -176,8 +176,8 @@ LLStatBar::LLStatBar(const Params& p)
 :	LLView(p),
 	mLabel(p.label),
 	mUnitLabel(p.unit_label),
-	mMinBar(llmin(p.bar_min, p.bar_max)),
-	mMaxBar(llmax(p.bar_max, p.bar_min)),
+	mTargetMinBar(llmin(p.bar_min, p.bar_max)),
+	mTargetMaxBar(llmax(p.bar_max, p.bar_min)),
 	mCurMaxBar(p.bar_max),
     mCurMinBar(0),
 	mDecimalDigits(p.decimal_digits),
@@ -189,15 +189,18 @@ LLStatBar::LLStatBar(const Params& p)
 	mOrientation(p.orientation),
 	mAutoScaleMax(!p.bar_max.isProvided()),
 	mAutoScaleMin(!p.bar_min.isProvided()),
-	mTickValue(p.tick_spacing),
+	mTickSpacing(p.tick_spacing),
 	mLastDisplayValue(0.f),
 	mStatType(STAT_NONE)
 {
+	mFloatingTargetMinBar = mTargetMinBar;
+	mFloatingTargetMaxBar = mTargetMaxBar;
+
 	mStat.valid = NULL;
 	// tick value will be automatically calculated later
 	if (!p.tick_spacing.isProvided() && p.bar_min.isProvided() && p.bar_max.isProvided())
 	{
-		mTickValue = calc_tick_value(mMinBar, mMaxBar);
+		mTickSpacing = calc_tick_value(mTargetMinBar, mTargetMaxBar);
 	}
 
 	setStat(p.stat);
@@ -259,12 +262,12 @@ BOOL LLStatBar::handleMouseDown(S32 x, S32 y, MASK mask)
 template<typename T>
 S32 calc_num_rapid_changes(LLTrace::PeriodicRecording& periodic_recording, const T& stat, const F32Seconds time_period)
 {
-	F32Seconds	elapsed_time,
-				time_since_value_changed;
-	S32 num_rapid_changes = 0;
-	const F32Seconds	RAPID_CHANGE_THRESHOLD = F32Seconds(0.3f);
+	F32Seconds			elapsed_time,
+						time_since_value_changed;
+	S32					num_rapid_changes			= 0;
+	const F32Seconds	RAPID_CHANGE_THRESHOLD		= F32Seconds(0.3f);
+	F64					last_value					= periodic_recording.getPrevRecording(1).getLastValue(stat);
 
-	F64 last_value = periodic_recording.getPrevRecording(1).getLastValue(stat);
 	for (S32 i = 2; i < periodic_recording.getNumRecordedPeriods(); i++)
 	{
 		LLTrace::Recording& recording = periodic_recording.getPrevRecording(i);
@@ -284,32 +287,6 @@ S32 calc_num_rapid_changes(LLTrace::PeriodicRecording& periodic_recording, const
 	return num_rapid_changes;
 }
 
-S32 calc_num_rapid_changes(LLTrace::PeriodicRecording& periodic_recording, const LLTrace::StatType<LLTrace::CountAccumulator>& stat, const F32Seconds time_period)
-{
-	F32Seconds	elapsed_time,
-				time_since_value_changed;
-	S32 num_rapid_changes = 0;
-
-	F64 last_value = periodic_recording.getPrevRecording(1).getSum(stat);
-	for (S32 i = 1; i < periodic_recording.getNumRecordedPeriods(); i++)
-	{
-		LLTrace::Recording& recording = periodic_recording.getPrevRecording(i);
-		F64 cur_value = recording.getSum(stat);
-
-		if (last_value != cur_value)
-		{
-			if (time_since_value_changed < RAPID_CHANGE_THRESHOLD) num_rapid_changes++;
-			time_since_value_changed = (F32Seconds)0;	
-		}
-		last_value = cur_value;
-
-		elapsed_time += recording.getDuration();
-		if (elapsed_time > time_period) break;
-	}
-
-	return num_rapid_changes;
-}
-
 void LLStatBar::draw()
 {
 	LLLocalClipRect _(getLocalRect());
@@ -318,16 +295,16 @@ void LLStatBar::draw()
 	LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); 
 
 	std::string unit_label;
-	F32 current			= 0, 
-		min				= 0, 
-		max				= 0,
-		mean			= 0,
-		display_value	= 0;
-	S32 num_frames		= mDisplayHistory 
-						? mNumHistoryFrames 
-						: mNumShortHistoryFrames;
-	S32 num_rapid_changes = 0;
-	S32 decimal_digits = mDecimalDigits;
+	F32			current			= 0, 
+				min				= 0, 
+				max				= 0,
+				mean			= 0,
+				display_value	= 0;
+	S32			num_frames		= mDisplayHistory 
+								? mNumHistoryFrames 
+								: mNumShortHistoryFrames;
+	S32			num_rapid_changes = 0;
+	S32			decimal_digits = mDecimalDigits;
 
 	switch(mStatType)
 	{
@@ -414,8 +391,8 @@ void LLStatBar::draw()
 		bar_rect.mBottom = llmin(bar_rect.mTop - 5, 20);
 	}
 
-	mCurMaxBar = LLSmoothInterpolation::lerp(mCurMaxBar, mMaxBar, 0.05f);
-	mCurMinBar = LLSmoothInterpolation::lerp(mCurMinBar, mMinBar, 0.05f);
+	mCurMaxBar = LLSmoothInterpolation::lerp(mCurMaxBar, mTargetMaxBar, 0.05f);
+	mCurMinBar = LLSmoothInterpolation::lerp(mCurMinBar, mTargetMinBar, 0.05f);
 
 	// rate limited updates
 	if (mLastDisplayValueTimer.getElapsedTimeF32() < MEAN_VALUE_UPDATE_TIME)
@@ -429,7 +406,6 @@ void LLStatBar::draw()
 	drawLabelAndValue(display_value, unit_label, bar_rect, decimal_digits);
 	mLastDisplayValue = display_value;
 
-
 	if (mDisplayBar && mStat.valid)
 	{
 		// Draw the tick marks.
@@ -607,9 +583,11 @@ void LLStatBar::setStat(const std::string& stat_name)
 
 void LLStatBar::setRange(F32 bar_min, F32 bar_max)
 {
-	mMinBar		= llmin(bar_min, bar_max);
-	mMaxBar		= llmax(bar_min, bar_max);
-	mTickValue	= calc_tick_value(mMinBar, mMaxBar);
+	mTargetMinBar		= llmin(bar_min, bar_max);
+	mTargetMaxBar		= llmax(bar_min, bar_max);
+	mFloatingTargetMinBar = mTargetMinBar;
+	mFloatingTargetMaxBar = mTargetMaxBar;
+	mTickSpacing	= calc_tick_value(mTargetMinBar, mTargetMaxBar);
 }
 
 LLRect LLStatBar::getRequiredRect()
@@ -660,21 +638,24 @@ void LLStatBar::drawLabelAndValue( F32 value, std::string &label, LLRect &bar_re
 
 void LLStatBar::drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect )
 {
-	if ((mAutoScaleMax && max >= mCurMaxBar)|| (mAutoScaleMin && min <= mCurMinBar))
+	if (mAutoScaleMax || mAutoScaleMin)
 	{
-		F32 range_min = mAutoScaleMin ? llmin(mMinBar, min) : mMinBar;
-		F32 range_max = mAutoScaleMax ? llmax(mMaxBar, max) : mMaxBar;
+		F32 u = LLSmoothInterpolation::getInterpolant(10.f);
+		mFloatingTargetMinBar = llmin(min, lerp(mFloatingTargetMinBar, min, u));
+		mFloatingTargetMaxBar = llmax(max, lerp(mFloatingTargetMaxBar, max, u));
+		F32 range_min = mAutoScaleMin ? mFloatingTargetMinBar : mTargetMinBar;
+		F32 range_max = mAutoScaleMax ? mFloatingTargetMaxBar : mTargetMaxBar;
 		F32 tick_value = 0.f;
 		calc_auto_scale_range(range_min, range_max, tick_value);
-		if (mAutoScaleMin) { mMinBar = range_min; }
-		if (mAutoScaleMax) { mMaxBar = range_max; }
+		if (mAutoScaleMin) { mTargetMinBar = range_min; }
+		if (mAutoScaleMax) { mTargetMaxBar = range_max; }
 		if (mAutoScaleMin && mAutoScaleMax)
 		{
-			mTickValue = tick_value;
+			mTickSpacing = tick_value;
 		}
 		else
 		{
-			mTickValue = calc_tick_value(mMinBar, mMaxBar);
+			mTickSpacing = calc_tick_value(mTargetMinBar, mTargetMaxBar);
 		}
 	}
 
@@ -682,7 +663,7 @@ void LLStatBar::drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect )
 	// ensure ticks always hit 0
 	S32 last_tick = S32_MIN;
 	S32 last_label = S32_MIN;
-	if (mTickValue > 0.f && value_scale > 0.f)
+	if (mTickSpacing > 0.f && value_scale > 0.f)
 	{
 		const S32 MIN_TICK_SPACING  = mOrientation == HORIZONTAL ? 20 : 30;
 		const S32 MIN_LABEL_SPACING = mOrientation == HORIZONTAL ? 30 : 60;
@@ -690,17 +671,18 @@ void LLStatBar::drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect )
 		const S32 TICK_WIDTH = 1;
 
 		F32 start = mCurMinBar < 0.f
-			? llceil(-mCurMinBar / mTickValue) * -mTickValue
+			? llceil(-mCurMinBar / mTickSpacing) * -mTickSpacing
 			: 0.f;
-		for (F32 tick_value = start; ;tick_value += mTickValue)
+		for (F32 tick_value = start; ;tick_value += mTickSpacing)
 		{
-			const S32 begin = llfloor((tick_value - mCurMinBar)*value_scale);
-			const S32 end = begin + TICK_WIDTH;
-			if (begin < last_tick + MIN_TICK_SPACING)
+			// clamp to S32_MAX / 2 to avoid floating point to integer overflow resulting in S32_MIN
+			const S32 tick_begin = llfloor(llmin((F32)(S32_MAX / 2), (tick_value - mCurMinBar)*value_scale));
+			const S32 tick_end = tick_begin + TICK_WIDTH;
+			if (tick_begin < last_tick + MIN_TICK_SPACING)
 			{
 				continue;
 			}
-			last_tick = begin;
+			last_tick = tick_begin;
 
 			S32 decimal_digits = mDecimalDigits;
 			if (is_approx_equal((F32)(S32)tick_value, tick_value))
@@ -711,25 +693,25 @@ void LLStatBar::drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect )
 			S32 tick_label_width = LLFontGL::getFontMonospace()->getWidth(tick_label);
 			if (mOrientation == HORIZONTAL)
 			{
-				if (begin > last_label + MIN_LABEL_SPACING)
+				if (tick_begin > last_label + MIN_LABEL_SPACING)
 				{
-					gl_rect_2d(bar_rect.mLeft, end, bar_rect.mRight - TICK_LENGTH, begin, LLColor4(1.f, 1.f, 1.f, 0.25f));
-					LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, bar_rect.mRight, begin,
+					gl_rect_2d(bar_rect.mLeft, tick_end, bar_rect.mRight - TICK_LENGTH, tick_begin, LLColor4(1.f, 1.f, 1.f, 0.25f));
+					LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, bar_rect.mRight, tick_begin,
 						LLColor4(1.f, 1.f, 1.f, 0.5f),
 						LLFontGL::LEFT, LLFontGL::VCENTER);
-					last_label = begin;
+					last_label = tick_begin;
 				}
 				else
 				{
-					gl_rect_2d(bar_rect.mLeft, end, bar_rect.mRight - TICK_LENGTH/2, begin, LLColor4(1.f, 1.f, 1.f, 0.1f));
+					gl_rect_2d(bar_rect.mLeft, tick_end, bar_rect.mRight - TICK_LENGTH/2, tick_begin, LLColor4(1.f, 1.f, 1.f, 0.1f));
 				}
 			}
 			else
 			{
-				if (begin > last_label + MIN_LABEL_SPACING)
+				if (tick_begin > last_label + MIN_LABEL_SPACING)
 				{
-					gl_rect_2d(begin, bar_rect.mTop, end, bar_rect.mBottom - TICK_LENGTH, LLColor4(1.f, 1.f, 1.f, 0.25f));
-					S32 label_pos = begin - llround((F32)tick_label_width * ((F32)begin / (F32)bar_rect.getWidth()));
+					gl_rect_2d(tick_begin, bar_rect.mTop, tick_end, bar_rect.mBottom - TICK_LENGTH, LLColor4(1.f, 1.f, 1.f, 0.25f));
+					S32 label_pos = tick_begin - llround((F32)tick_label_width * ((F32)tick_begin / (F32)bar_rect.getWidth()));
 					LLFontGL::getFontMonospace()->renderUTF8(tick_label, 0, label_pos, bar_rect.mBottom - TICK_LENGTH,
 						LLColor4(1.f, 1.f, 1.f, 0.5f),
 						LLFontGL::LEFT, LLFontGL::TOP);
@@ -737,10 +719,10 @@ void LLStatBar::drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect )
 				}
 				else
 				{
-					gl_rect_2d(begin, bar_rect.mTop, end, bar_rect.mBottom - TICK_LENGTH/2, LLColor4(1.f, 1.f, 1.f, 0.1f));
+					gl_rect_2d(tick_begin, bar_rect.mTop, tick_end, bar_rect.mBottom - TICK_LENGTH/2, LLColor4(1.f, 1.f, 1.f, 0.1f));
 				}
 			}
-			// always draw one tick value past end, so we can see part of the text, if possible
+			// always draw one tick value past tick_end, so we can see part of the text, if possible
 			if (tick_value > mCurMaxBar)
 			{
 				break;
diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h
index 57e492bc80..89d7ff24ed 100755
--- a/indra/llui/llstatbar.h
+++ b/indra/llui/llstatbar.h
@@ -44,13 +44,12 @@ public:
 								bar_max,
 								tick_spacing;
 
-		Optional<U32>			decimal_digits;
-
 		Optional<bool>			show_bar,
 								show_history,
 								scale_range;
 
-		Optional<S32>			num_frames,
+		Optional<S32>			decimal_digits,
+								num_frames,
 								num_frames_short,
 								max_height;
 		Optional<std::string>	stat;
@@ -67,7 +66,7 @@ public:
 	void setStat(const std::string& stat_name);
 
 	void setRange(F32 bar_min, F32 bar_max);
-	void getRange(F32& bar_min, F32& bar_max) { bar_min = mMinBar; bar_max = mMaxBar; }
+	void getRange(F32& bar_min, F32& bar_max) { bar_min = mTargetMinBar; bar_max = mTargetMaxBar; }
 	
 	/*virtual*/ LLRect getRequiredRect();	// Return the height of this object, given the set options.
 
@@ -75,20 +74,18 @@ private:
 	void drawLabelAndValue( F32 mean, std::string &unit_label, LLRect &bar_rect, S32 decimal_digits );
 	void drawTicks( F32 min, F32 max, F32 value_scale, LLRect &bar_rect );
 
-	F32          mMinBar,
-				 mMaxBar,
+	F32          mTargetMinBar,
+				 mTargetMaxBar,
+				 mFloatingTargetMinBar,
+				 mFloatingTargetMaxBar,
 				 mCurMaxBar,
 				 mCurMinBar,
-				 mLabelSpacing;
-	F32			 mTickValue;
-	U32          mDecimalDigits;
-	S32			 mNumHistoryFrames,
+				 mLabelSpacing,
+				 mTickSpacing;
+	S32          mDecimalDigits,
+				 mNumHistoryFrames,
 				 mNumShortHistoryFrames;
 	S32			 mMaxHeight;
-	bool         mDisplayBar,			// Display the bar graph.
-				 mDisplayHistory,
-				 mAutoScaleMax,
-				 mAutoScaleMin;
 	EOrientation mOrientation;
 	F32			 mLastDisplayValue;
 	LLFrameTimer mLastDisplayValueTimer;
@@ -113,6 +110,11 @@ private:
 
 	LLUIString   mLabel;
 	std::string  mUnitLabel;
+
+	bool         mDisplayBar,			// Display the bar graph.
+				 mDisplayHistory,
+				 mAutoScaleMax,
+				 mAutoScaleMin;
 };
 
 #endif
-- 
cgit v1.2.3