ddnet/src/engine/client/graph.cpp

210 lines
5.6 KiB
C++
Raw Normal View History

/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <engine/graphics.h>
#include <engine/textrender.h>
#include "graph.h"
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
CGraph::CGraph(int MaxEntries) :
m_Entries(MaxEntries * (sizeof(SEntry) + 2 * CRingBufferBase::ITEM_SIZE), CRingBufferBase::FLAG_RECYCLE)
{
}
void CGraph::Init(float Min, float Max)
{
SetMin(Min);
SetMax(Max);
}
void CGraph::SetMin(float Min)
{
m_MinRange = m_Min = Min;
}
void CGraph::SetMax(float Max)
{
m_MaxRange = m_Max = Max;
}
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
void CGraph::Scale(int64_t WantedTotalTime)
{
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
// Scale X axis for wanted total time
if(m_Entries.First() != nullptr)
{
const int64_t EndTime = m_Entries.Last()->m_Time;
bool ScaleTotalTime = false;
m_pFirstScaled = nullptr;
if(m_Entries.First()->m_Time >= EndTime - WantedTotalTime)
{
m_pFirstScaled = m_Entries.First();
}
else
{
m_pFirstScaled = m_Entries.Last();
while(m_pFirstScaled)
{
SEntry *pPrev = m_Entries.Prev(m_pFirstScaled);
if(pPrev == nullptr)
break;
if(pPrev->m_Time < EndTime - WantedTotalTime)
{
// Scale based on actual total time instead of based on wanted total time,
// to avoid flickering last segment due to rounding errors.
ScaleTotalTime = true;
break;
}
m_pFirstScaled = pPrev;
}
}
m_RenderedTotalTime = ScaleTotalTime ? (EndTime - m_pFirstScaled->m_Time) : WantedTotalTime;
// Ensure that color is applied to first line segment
if(m_pFirstScaled)
{
m_pFirstScaled->m_ApplyColor = true;
SEntry *pNext = m_Entries.Next(m_pFirstScaled);
if(pNext != nullptr)
{
pNext->m_ApplyColor = true;
}
}
}
else
{
m_pFirstScaled = nullptr;
m_RenderedTotalTime = 0;
}
// Scale Y axis
m_Min = m_MinRange;
m_Max = m_MaxRange;
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
for(SEntry *pEntry = m_pFirstScaled; pEntry != nullptr; pEntry = m_Entries.Next(pEntry))
{
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
if(pEntry->m_Value > m_Max)
m_Max = pEntry->m_Value;
else if(pEntry->m_Value < m_Min)
m_Min = pEntry->m_Value;
}
}
void CGraph::Add(float Value, ColorRGBA Color)
{
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
InsertAt(time_get(), Value, Color);
}
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
void CGraph::InsertAt(int64_t Time, float Value, ColorRGBA Color)
{
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
SEntry *pEntry = m_Entries.Allocate(sizeof(SEntry));
pEntry->m_Time = Time;
pEntry->m_Value = Value;
pEntry->m_Color = Color;
// Determine whether the line (pPrev, pEntry) has different
// vertex colors than the line (pPrevPrev, pPrev).
SEntry *pPrev = m_Entries.Prev(pEntry);
if(pPrev == nullptr)
{
pEntry->m_ApplyColor = true;
}
else
{
SEntry *pPrevPrev = m_Entries.Prev(pPrev);
if(pPrevPrev == nullptr)
{
pEntry->m_ApplyColor = true;
}
else
{
pEntry->m_ApplyColor = Color != pPrev->m_Color || pPrev->m_Color != pPrevPrev->m_Color;
}
}
}
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
void CGraph::Render(IGraphics *pGraphics, ITextRender *pTextRender, float x, float y, float w, float h, const char *pDescription)
{
pGraphics->TextureClear();
pGraphics->QuadsBegin();
pGraphics->SetColor(0.0f, 0.0f, 0.0f, 0.75f);
IGraphics::CQuadItem QuadItem(x, y, w, h);
pGraphics->QuadsDrawTL(&QuadItem, 1);
pGraphics->QuadsEnd();
pGraphics->LinesBegin();
pGraphics->SetColor(0.95f, 0.95f, 0.95f, 1.0f);
IGraphics::CLineItem LineItem(x, y + h / 2, x + w, y + h / 2);
pGraphics->LinesDraw(&LineItem, 1);
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
pGraphics->SetColor(0.5f, 0.5f, 0.5f, 0.75f);
IGraphics::CLineItem aLineItems[2] = {
IGraphics::CLineItem(x, y + (h * 3) / 4, x + w, y + (h * 3) / 4),
IGraphics::CLineItem(x, y + h / 4, x + w, y + h / 4)};
pGraphics->LinesDraw(aLineItems, std::size(aLineItems));
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
if(m_pFirstScaled != nullptr)
{
Add time scale to debug graphs for constant scrolling speed Store X value (time) for all graph entries in addition to the Y value (FPS, prediction margin etc.). The `CGraph::Add` function adds values to the graph at the current time. The `CGraph::InsertAt` function allows specifying arbitrary X values, as long as the values are inserted in increasing order. The entries are kept in a ringbuffer and old entries are recycled when it's full. The size of the ringbuffer is configurable for each graph, as the FPS graph needs significantly more buffer because values are added more often. The scrolling speed of the graphs is fixed by specifying the maximum size of the window of values which should be displayed. For this purpose, a parameter is added to the `CGraph::Scale` function to specify the size of the window which should be rendered in the `CGraph::Render` function. For the FPS graph only the last second is rendered, so small spikes are still noticeable. For prediction and gametime margin graphs the last five seconds are rendered, which should result in a similar scrolling speed as before this change. The debug tuning graph is a special case, where the X values set manually and fixed to 0-127, same as before, instead of being based on the current time. The graph rendering is made much more efficient by precalculating when the vertex colors need to be updated, to avoid all unnecessary calls to `SetColorVertex`. Additionally, line items are bundled together in an array to avoid calling `LinesDraw` for every individual line item.
2024-01-02 22:46:52 +00:00
IGraphics::CLineItem aValueLineItems[128];
size_t NumValueLineItems = 0;
const int64_t StartTime = m_pFirstScaled->m_Time;
SEntry *pEntry0 = m_pFirstScaled;
int a0 = round_to_int((pEntry0->m_Time - StartTime) * w / m_RenderedTotalTime);
int v0 = round_to_int((pEntry0->m_Value - m_Min) * h / (m_Max - m_Min));
while(pEntry0 != nullptr)
{
SEntry *pEntry1 = m_Entries.Next(pEntry0);
if(pEntry1 == nullptr)
break;
const int a1 = round_to_int((pEntry1->m_Time - StartTime) * w / m_RenderedTotalTime);
const int v1 = round_to_int((pEntry1->m_Value - m_Min) * h / (m_Max - m_Min));
if(pEntry1->m_ApplyColor)
{
if(NumValueLineItems)
{
pGraphics->LinesDraw(aValueLineItems, NumValueLineItems);
NumValueLineItems = 0;
}
IGraphics::CColorVertex aColorVertices[2] = {
IGraphics::CColorVertex(0, pEntry0->m_Color.r, pEntry0->m_Color.g, pEntry0->m_Color.b, pEntry0->m_Color.a),
IGraphics::CColorVertex(1, pEntry1->m_Color.r, pEntry1->m_Color.g, pEntry1->m_Color.b, pEntry1->m_Color.a)};
pGraphics->SetColorVertex(aColorVertices, std::size(aColorVertices));
}
if(NumValueLineItems == std::size(aValueLineItems))
{
pGraphics->LinesDraw(aValueLineItems, NumValueLineItems);
NumValueLineItems = 0;
}
aValueLineItems[NumValueLineItems] = IGraphics::CLineItem(x + a0, y + h - v0, x + a1, y + h - v1);
++NumValueLineItems;
pEntry0 = pEntry1;
a0 = a1;
v0 = v1;
}
if(NumValueLineItems)
{
pGraphics->LinesDraw(aValueLineItems, NumValueLineItems);
}
}
pGraphics->LinesEnd();
const float FontSize = 12.0f;
const float Spacing = 2.0f;
pTextRender->Text(x + Spacing, y + h - FontSize - Spacing, FontSize, pDescription);
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "%.2f", m_Max);
pTextRender->Text(x + w - pTextRender->TextWidth(FontSize, aBuf) - Spacing, y + Spacing, FontSize, aBuf);
str_format(aBuf, sizeof(aBuf), "%.2f", m_Min);
pTextRender->Text(x + w - pTextRender->TextWidth(FontSize, aBuf) - Spacing, y + h - FontSize - Spacing, FontSize, aBuf);
}