Team Fortress 2 Source Code as on 22/4/2020
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

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <math.h>
  7. #include <vgui_controls/GraphPanel.h>
  8. #include <vgui/IScheme.h>
  9. #include <vgui/ISurface.h>
  10. #include <vgui/IVGui.h>
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include <tier0/memdbgon.h>
  13. using namespace vgui;
  14. DECLARE_BUILD_FACTORY( GraphPanel );
  15. //-----------------------------------------------------------------------------
  16. // Purpose: Constructor
  17. //-----------------------------------------------------------------------------
  18. GraphPanel::GraphPanel(Panel *parent, const char *name) : BaseClass(parent, name)
  19. {
  20. m_flDomainSize = 100.0f;
  21. m_flLowRange = 0.0f;
  22. m_flHighRange = 1.0f;
  23. m_bUseDynamicRange = true;
  24. m_flMinDomainSize = 0.0f;
  25. m_flMaxDomainSize = 0.0f;
  26. m_bMaxDomainSizeSet = false;
  27. // rendering, need to pull these from scheme/res file
  28. m_iGraphBarWidth = 2;
  29. m_iGraphBarGapWidth = 2;
  30. }
  31. //-----------------------------------------------------------------------------
  32. // Purpose: domain settings (x-axis settings)
  33. //-----------------------------------------------------------------------------
  34. void GraphPanel::SetDisplayDomainSize(float size)
  35. {
  36. m_flDomainSize = size;
  37. // set the max domain size if it hasn't been set yet
  38. if (!m_bMaxDomainSizeSet)
  39. {
  40. SetMaxDomainSize(size);
  41. }
  42. }
  43. //-----------------------------------------------------------------------------
  44. // Purpose: sets the smallest domain that will be displayed
  45. //-----------------------------------------------------------------------------
  46. void GraphPanel::SetMinDomainSize(float size)
  47. {
  48. m_flMinDomainSize = size;
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose: sets the samples to keep
  52. //-----------------------------------------------------------------------------
  53. void GraphPanel::SetMaxDomainSize(float size)
  54. {
  55. m_flMaxDomainSize = size;
  56. m_bMaxDomainSizeSet = true;
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Purpose: range settings (y-axis settings)
  60. //-----------------------------------------------------------------------------
  61. void GraphPanel::SetUseFixedRange(float lowRange, float highRange)
  62. {
  63. m_bUseDynamicRange = false;
  64. m_flLowRange = lowRange;
  65. m_flHighRange = highRange;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose: Sets the graph to dynamically determine the range
  69. //-----------------------------------------------------------------------------
  70. void GraphPanel::SetUseDynamicRange(float *rangeList, int numRanges)
  71. {
  72. m_bUseDynamicRange = true;
  73. m_RangeList.CopyArray(rangeList, numRanges);
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: Gets the currently displayed range
  77. //-----------------------------------------------------------------------------
  78. void GraphPanel::GetDisplayedRange(float &lowRange, float &highRange)
  79. {
  80. lowRange = m_flLowRange;
  81. highRange = m_flHighRange;
  82. }
  83. //-----------------------------------------------------------------------------
  84. // Purpose: adds an item to the end of the list
  85. //-----------------------------------------------------------------------------
  86. void GraphPanel::AddItem(float sampleEnd, float sampleValue)
  87. {
  88. if (m_Samples.Count() && m_Samples[m_Samples.Tail()].value == sampleValue)
  89. {
  90. // collapse identical samples
  91. m_Samples[m_Samples.Tail()].sampleEnd = sampleEnd;
  92. }
  93. else
  94. {
  95. // add to the end of the samples list
  96. Sample_t item;
  97. item.value = sampleValue;
  98. item.sampleEnd = sampleEnd;
  99. m_Samples.AddToTail(item);
  100. }
  101. // see if this frees up any samples past the end
  102. if (m_bMaxDomainSizeSet)
  103. {
  104. float freePoint = sampleEnd - m_flMaxDomainSize;
  105. while (m_Samples[m_Samples.Head()].sampleEnd < freePoint)
  106. {
  107. m_Samples.Remove(m_Samples.Head());
  108. }
  109. }
  110. /*
  111. // see the max number of samples necessary to display this information reasonably precisely
  112. static const int MAX_LIKELY_GRAPH_WIDTH = 800;
  113. int maxSamplesNeeded = 2 * MAX_LIKELY_GRAPH_WIDTH / (m_iGraphBarWidth + m_iGraphBarGapWidth);
  114. if (m_Samples.Count() > 2)
  115. {
  116. // see if we can collapse some items
  117. float highestSample = m_Samples[m_Samples.Tail()].sampleEnd;
  118. // iterate the items
  119. // always keep the head around so we have something to go against
  120. int sampleIndex = m_Samples.Next(m_Samples.Head());
  121. int nextSampleIndex = m_Samples.Next(sampleIndex);
  122. while (m_Samples.IsInList(nextSampleIndex))
  123. {
  124. // calculate what sampling precision is actually needed to display this data
  125. float distanceFromEnd = highestSample - m_Samples[sampleIndex].sampleEnd;
  126. // if (distanceFromEnd < m_flDomainSize)
  127. // break;
  128. //!! this calculation is very incorrect
  129. float minNeededSampleSize = distanceFromEnd / (m_flMinDomainSize * maxSamplesNeeded);
  130. float sampleSize = m_Samples[nextSampleIndex].sampleEnd - m_Samples[sampleIndex].sampleEnd;
  131. if (sampleSize < minNeededSampleSize)
  132. {
  133. // collapse the item into the next index
  134. m_Samples[nextSampleIndex].value = 0.5f * (m_Samples[nextSampleIndex].value + m_Samples[sampleIndex].value);
  135. // remove the item from the list
  136. m_Samples.Remove(sampleIndex);
  137. // move to the next item
  138. sampleIndex = nextSampleIndex;
  139. nextSampleIndex = m_Samples.Next(sampleIndex);
  140. }
  141. else
  142. {
  143. // this item didn't need collapsing, so assume the next item won't
  144. break;
  145. }
  146. }
  147. }
  148. */
  149. InvalidateLayout();
  150. Repaint();
  151. }
  152. //-----------------------------------------------------------------------------
  153. // Purpose: returns number of items that can be displayed
  154. //-----------------------------------------------------------------------------
  155. int GraphPanel::GetVisibleItemCount()
  156. {
  157. return GetWide() / (m_iGraphBarWidth + m_iGraphBarGapWidth);
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose: lays out the graph
  161. //-----------------------------------------------------------------------------
  162. void GraphPanel::PerformLayout()
  163. {
  164. BaseClass::PerformLayout();
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Purpose: draws the graph
  168. //-----------------------------------------------------------------------------
  169. void GraphPanel::Paint()
  170. {
  171. if (!m_Samples.Count())
  172. return;
  173. // walk from right to left drawing the resampled data
  174. int sampleIndex = m_Samples.Tail();
  175. int x = GetWide() - (m_iGraphBarWidth + m_iGraphBarGapWidth);
  176. // calculate how big each sample should be
  177. float sampleSize = m_flDomainSize / GetVisibleItemCount();
  178. // calculate where in the domain we start resampling
  179. float resampleStart = m_Samples[sampleIndex].sampleEnd - sampleSize;
  180. // always resample from a sample point that is a multiple of the sampleSize
  181. resampleStart -= (float)fmod(resampleStart, sampleSize);
  182. // bar size multiplier
  183. float barSizeMultiplier = GetTall() / (m_flHighRange - m_flLowRange);
  184. // set render color
  185. surface()->DrawSetColor(GetFgColor());
  186. // recalculate the sample range for dynamic resizing
  187. float flMinValue = m_Samples[m_Samples.Head()].value;
  188. float flMaxValue = m_Samples[m_Samples.Head()].value;
  189. // iterate the bars to draw
  190. while (x > 0 && m_Samples.IsInList(sampleIndex))
  191. {
  192. // move back the drawing point
  193. x -= (m_iGraphBarWidth + m_iGraphBarGapWidth);
  194. // collect the samples
  195. float value = 0.0f;
  196. float maxValue = 0.0f;
  197. int samplesTouched = 0;
  198. int prevSampleIndex = m_Samples.Previous(sampleIndex);
  199. while (m_Samples.IsInList(prevSampleIndex))
  200. {
  201. // take the value
  202. value += m_Samples[sampleIndex].value;
  203. samplesTouched++;
  204. // do some work to calculate the sample range
  205. if (m_Samples[sampleIndex].value < flMinValue)
  206. {
  207. flMinValue = m_Samples[sampleIndex].value;
  208. }
  209. if (m_Samples[sampleIndex].value > flMaxValue)
  210. {
  211. flMaxValue = m_Samples[sampleIndex].value;
  212. }
  213. if (m_Samples[sampleIndex].value > maxValue)
  214. {
  215. maxValue = m_Samples[sampleIndex].value;
  216. }
  217. if (resampleStart < m_Samples[prevSampleIndex].sampleEnd)
  218. {
  219. // we're out of the sampling range, we need to move on to the next sample
  220. sampleIndex = prevSampleIndex;
  221. prevSampleIndex = m_Samples.Previous(sampleIndex);
  222. }
  223. else
  224. {
  225. // we're done with this resample
  226. // move back the resample start
  227. resampleStart -= sampleSize;
  228. // draw the current item
  229. break;
  230. }
  231. }
  232. // draw the item
  233. // show the max value in the sample, not the average
  234. int size = (int)(maxValue * barSizeMultiplier);
  235. // int size = (int)((value * barSizeMultiplier) / samplesTouched);
  236. surface()->DrawFilledRect(x, GetTall() - size, x + m_iGraphBarWidth, GetTall());
  237. }
  238. // calculate our final range (for use next frame)
  239. if (m_bUseDynamicRange)
  240. {
  241. flMinValue = 0;
  242. // find the range that fits
  243. for (int i = 0; i < m_RangeList.Count(); i++)
  244. {
  245. if (m_RangeList[i] > flMaxValue)
  246. {
  247. flMaxValue = m_RangeList[i];
  248. break;
  249. }
  250. }
  251. m_flLowRange = flMinValue;
  252. m_flHighRange = flMaxValue;
  253. }
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose: sets up colors
  257. //-----------------------------------------------------------------------------
  258. void GraphPanel::ApplySchemeSettings(IScheme *pScheme)
  259. {
  260. BaseClass::ApplySchemeSettings(pScheme);
  261. SetFgColor(GetSchemeColor("GraphPanel.FgColor", pScheme));
  262. SetBgColor(GetSchemeColor("GraphPanel.BgColor", pScheme));
  263. SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
  264. }