You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
308 lines
9.3 KiB
308 lines
9.3 KiB
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================//
|
|
|
|
#include <math.h>
|
|
|
|
#include <vgui_controls/GraphPanel.h>
|
|
#include <vgui/IScheme.h>
|
|
#include <vgui/ISurface.h>
|
|
#include <vgui/IVGui.h>
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include <tier0/memdbgon.h>
|
|
|
|
using namespace vgui;
|
|
|
|
DECLARE_BUILD_FACTORY( GraphPanel );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Constructor
|
|
//-----------------------------------------------------------------------------
|
|
GraphPanel::GraphPanel(Panel *parent, const char *name) : BaseClass(parent, name)
|
|
{
|
|
m_flDomainSize = 100.0f;
|
|
m_flLowRange = 0.0f;
|
|
m_flHighRange = 1.0f;
|
|
m_bUseDynamicRange = true;
|
|
m_flMinDomainSize = 0.0f;
|
|
m_flMaxDomainSize = 0.0f;
|
|
m_bMaxDomainSizeSet = false;
|
|
|
|
// rendering, need to pull these from scheme/res file
|
|
m_iGraphBarWidth = 2;
|
|
m_iGraphBarGapWidth = 2;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: domain settings (x-axis settings)
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::SetDisplayDomainSize(float size)
|
|
{
|
|
m_flDomainSize = size;
|
|
|
|
// set the max domain size if it hasn't been set yet
|
|
if (!m_bMaxDomainSizeSet)
|
|
{
|
|
SetMaxDomainSize(size);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sets the smallest domain that will be displayed
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::SetMinDomainSize(float size)
|
|
{
|
|
m_flMinDomainSize = size;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sets the samples to keep
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::SetMaxDomainSize(float size)
|
|
{
|
|
m_flMaxDomainSize = size;
|
|
m_bMaxDomainSizeSet = true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: range settings (y-axis settings)
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::SetUseFixedRange(float lowRange, float highRange)
|
|
{
|
|
m_bUseDynamicRange = false;
|
|
m_flLowRange = lowRange;
|
|
m_flHighRange = highRange;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Sets the graph to dynamically determine the range
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::SetUseDynamicRange(float *rangeList, int numRanges)
|
|
{
|
|
m_bUseDynamicRange = true;
|
|
m_RangeList.CopyArray(rangeList, numRanges);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Gets the currently displayed range
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::GetDisplayedRange(float &lowRange, float &highRange)
|
|
{
|
|
lowRange = m_flLowRange;
|
|
highRange = m_flHighRange;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: adds an item to the end of the list
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::AddItem(float sampleEnd, float sampleValue)
|
|
{
|
|
if (m_Samples.Count() && m_Samples[m_Samples.Tail()].value == sampleValue)
|
|
{
|
|
// collapse identical samples
|
|
m_Samples[m_Samples.Tail()].sampleEnd = sampleEnd;
|
|
}
|
|
else
|
|
{
|
|
// add to the end of the samples list
|
|
Sample_t item;
|
|
item.value = sampleValue;
|
|
item.sampleEnd = sampleEnd;
|
|
m_Samples.AddToTail(item);
|
|
}
|
|
|
|
// see if this frees up any samples past the end
|
|
if (m_bMaxDomainSizeSet)
|
|
{
|
|
float freePoint = sampleEnd - m_flMaxDomainSize;
|
|
while (m_Samples[m_Samples.Head()].sampleEnd < freePoint)
|
|
{
|
|
m_Samples.Remove(m_Samples.Head());
|
|
}
|
|
}
|
|
|
|
/*
|
|
// see the max number of samples necessary to display this information reasonably precisely
|
|
static const int MAX_LIKELY_GRAPH_WIDTH = 800;
|
|
int maxSamplesNeeded = 2 * MAX_LIKELY_GRAPH_WIDTH / (m_iGraphBarWidth + m_iGraphBarGapWidth);
|
|
if (m_Samples.Count() > 2)
|
|
{
|
|
// see if we can collapse some items
|
|
float highestSample = m_Samples[m_Samples.Tail()].sampleEnd;
|
|
|
|
// iterate the items
|
|
// always keep the head around so we have something to go against
|
|
int sampleIndex = m_Samples.Next(m_Samples.Head());
|
|
int nextSampleIndex = m_Samples.Next(sampleIndex);
|
|
|
|
while (m_Samples.IsInList(nextSampleIndex))
|
|
{
|
|
// calculate what sampling precision is actually needed to display this data
|
|
float distanceFromEnd = highestSample - m_Samples[sampleIndex].sampleEnd;
|
|
|
|
// if (distanceFromEnd < m_flDomainSize)
|
|
// break;
|
|
|
|
//!! this calculation is very incorrect
|
|
float minNeededSampleSize = distanceFromEnd / (m_flMinDomainSize * maxSamplesNeeded);
|
|
float sampleSize = m_Samples[nextSampleIndex].sampleEnd - m_Samples[sampleIndex].sampleEnd;
|
|
|
|
if (sampleSize < minNeededSampleSize)
|
|
{
|
|
// collapse the item into the next index
|
|
m_Samples[nextSampleIndex].value = 0.5f * (m_Samples[nextSampleIndex].value + m_Samples[sampleIndex].value);
|
|
|
|
// remove the item from the list
|
|
m_Samples.Remove(sampleIndex);
|
|
|
|
// move to the next item
|
|
sampleIndex = nextSampleIndex;
|
|
nextSampleIndex = m_Samples.Next(sampleIndex);
|
|
}
|
|
else
|
|
{
|
|
// this item didn't need collapsing, so assume the next item won't
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
InvalidateLayout();
|
|
Repaint();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: returns number of items that can be displayed
|
|
//-----------------------------------------------------------------------------
|
|
int GraphPanel::GetVisibleItemCount()
|
|
{
|
|
return GetWide() / (m_iGraphBarWidth + m_iGraphBarGapWidth);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: lays out the graph
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::PerformLayout()
|
|
{
|
|
BaseClass::PerformLayout();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: draws the graph
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::Paint()
|
|
{
|
|
if (!m_Samples.Count())
|
|
return;
|
|
|
|
// walk from right to left drawing the resampled data
|
|
int sampleIndex = m_Samples.Tail();
|
|
int x = GetWide() - (m_iGraphBarWidth + m_iGraphBarGapWidth);
|
|
|
|
// calculate how big each sample should be
|
|
float sampleSize = m_flDomainSize / GetVisibleItemCount();
|
|
|
|
// calculate where in the domain we start resampling
|
|
float resampleStart = m_Samples[sampleIndex].sampleEnd - sampleSize;
|
|
// always resample from a sample point that is a multiple of the sampleSize
|
|
resampleStart -= (float)fmod(resampleStart, sampleSize);
|
|
|
|
// bar size multiplier
|
|
float barSizeMultiplier = GetTall() / (m_flHighRange - m_flLowRange);
|
|
|
|
// set render color
|
|
surface()->DrawSetColor(GetFgColor());
|
|
|
|
// recalculate the sample range for dynamic resizing
|
|
float flMinValue = m_Samples[m_Samples.Head()].value;
|
|
float flMaxValue = m_Samples[m_Samples.Head()].value;
|
|
|
|
// iterate the bars to draw
|
|
while (x > 0 && m_Samples.IsInList(sampleIndex))
|
|
{
|
|
// move back the drawing point
|
|
x -= (m_iGraphBarWidth + m_iGraphBarGapWidth);
|
|
|
|
// collect the samples
|
|
float value = 0.0f;
|
|
float maxValue = 0.0f;
|
|
int samplesTouched = 0;
|
|
int prevSampleIndex = m_Samples.Previous(sampleIndex);
|
|
while (m_Samples.IsInList(prevSampleIndex))
|
|
{
|
|
// take the value
|
|
value += m_Samples[sampleIndex].value;
|
|
samplesTouched++;
|
|
|
|
// do some work to calculate the sample range
|
|
if (m_Samples[sampleIndex].value < flMinValue)
|
|
{
|
|
flMinValue = m_Samples[sampleIndex].value;
|
|
}
|
|
if (m_Samples[sampleIndex].value > flMaxValue)
|
|
{
|
|
flMaxValue = m_Samples[sampleIndex].value;
|
|
}
|
|
if (m_Samples[sampleIndex].value > maxValue)
|
|
{
|
|
maxValue = m_Samples[sampleIndex].value;
|
|
}
|
|
|
|
if (resampleStart < m_Samples[prevSampleIndex].sampleEnd)
|
|
{
|
|
// we're out of the sampling range, we need to move on to the next sample
|
|
sampleIndex = prevSampleIndex;
|
|
prevSampleIndex = m_Samples.Previous(sampleIndex);
|
|
}
|
|
else
|
|
{
|
|
// we're done with this resample
|
|
// move back the resample start
|
|
resampleStart -= sampleSize;
|
|
// draw the current item
|
|
break;
|
|
}
|
|
}
|
|
|
|
// draw the item
|
|
// show the max value in the sample, not the average
|
|
int size = (int)(maxValue * barSizeMultiplier);
|
|
// int size = (int)((value * barSizeMultiplier) / samplesTouched);
|
|
surface()->DrawFilledRect(x, GetTall() - size, x + m_iGraphBarWidth, GetTall());
|
|
}
|
|
|
|
// calculate our final range (for use next frame)
|
|
if (m_bUseDynamicRange)
|
|
{
|
|
flMinValue = 0;
|
|
|
|
// find the range that fits
|
|
for (int i = 0; i < m_RangeList.Count(); i++)
|
|
{
|
|
if (m_RangeList[i] > flMaxValue)
|
|
{
|
|
flMaxValue = m_RangeList[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
m_flLowRange = flMinValue;
|
|
m_flHighRange = flMaxValue;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sets up colors
|
|
//-----------------------------------------------------------------------------
|
|
void GraphPanel::ApplySchemeSettings(IScheme *pScheme)
|
|
{
|
|
BaseClass::ApplySchemeSettings(pScheme);
|
|
|
|
SetFgColor(GetSchemeColor("GraphPanel.FgColor", pScheme));
|
|
SetBgColor(GetSchemeColor("GraphPanel.BgColor", pScheme));
|
|
SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
|
|
}
|