+void SCR_DrawNetGraph_DrawGraph (int graphx, int graphy, int graphwidth, int graphheight, float graphscale, const char *label, float textsize, int packetcounter, netgraphitem_t *netgraph)
+{
+ netgraphitem_t *graph;
+ int j, x, y, numlines;
+ int totalbytes = 0;
+ char bytesstring[128];
+ float g[NETGRAPH_PACKETS][6];
+ float *a;
+ float *b;
+ float vertex3f[(NETGRAPH_PACKETS+2)*5*2*3];
+ float color4f[(NETGRAPH_PACKETS+2)*5*2*4];
+ float *v;
+ float *c;
+ DrawQ_Fill(graphx, graphy, graphwidth, graphheight + textsize * 2, 0, 0, 0, 0.5, 0);
+ // draw the bar graph itself
+ // advance the packet counter because it is the latest packet column being
+ // built up and should come last
+ packetcounter = (packetcounter + 1) % NETGRAPH_PACKETS;
+ memset(g, 0, sizeof(g));
+ for (j = 0;j < NETGRAPH_PACKETS;j++)
+ {
+ graph = netgraph + j;
+ g[j][0] = 1.0f - 0.25f * (realtime - graph->time);
+ g[j][1] = 1.0f;
+ g[j][2] = 1.0f;
+ g[j][3] = 1.0f;
+ g[j][4] = 1.0f;
+ g[j][5] = 1.0f;
+ if (graph->unreliablebytes == NETGRAPH_LOSTPACKET)
+ g[j][1] = 0.00f;
+ else if (graph->unreliablebytes == NETGRAPH_CHOKEDPACKET)
+ g[j][2] = 0.96f;
+ else
+ {
+ g[j][3] = 1.0f - graph->unreliablebytes * graphscale;
+ g[j][4] = g[j][3] - graph->reliablebytes * graphscale;
+ g[j][5] = g[j][4] - graph->ackbytes * graphscale;
+ // count bytes in the last second
+ if (realtime - graph->time < 1.0f)
+ totalbytes += graph->unreliablebytes + graph->reliablebytes + graph->ackbytes;
+ }
+ g[j][1] = bound(0.0f, g[j][1], 1.0f);
+ g[j][2] = bound(0.0f, g[j][2], 1.0f);
+ g[j][3] = bound(0.0f, g[j][3], 1.0f);
+ g[j][4] = bound(0.0f, g[j][4], 1.0f);
+ g[j][5] = bound(0.0f, g[j][5], 1.0f);
+ }
+ // render the lines for the graph
+ numlines = 0;
+ v = vertex3f;
+ c = color4f;
+ for (j = 0;j < NETGRAPH_PACKETS;j++)
+ {
+ a = g[j];
+ b = g[(j+1)%NETGRAPH_PACKETS];
+ if (a[0] < 0.0f || b[0] > 1.0f || b[0] < a[0])
+ continue;
+ VectorSet(v, graphx + graphwidth * a[0], graphy + graphheight * a[2], 0.0f);v += 3;Vector4Set(c, 1.0f, 1.0f, 0.0f, 1.0f);c += 4;
+ VectorSet(v, graphx + graphwidth * b[0], graphy + graphheight * b[2], 0.0f);v += 3;Vector4Set(c, 1.0f, 1.0f, 0.0f, 1.0f);c += 4;
+
+ VectorSet(v, graphx + graphwidth * a[0], graphy + graphheight * a[1], 0.0f);v += 3;Vector4Set(c, 1.0f, 0.0f, 0.0f, 1.0f);c += 4;
+ VectorSet(v, graphx + graphwidth * b[0], graphy + graphheight * b[1], 0.0f);v += 3;Vector4Set(c, 1.0f, 0.0f, 0.0f, 1.0f);c += 4;
+
+ VectorSet(v, graphx + graphwidth * a[0], graphy + graphheight * a[5], 0.0f);v += 3;Vector4Set(c, 0.0f, 1.0f, 0.0f, 1.0f);c += 4;
+ VectorSet(v, graphx + graphwidth * b[0], graphy + graphheight * b[5], 0.0f);v += 3;Vector4Set(c, 0.0f, 1.0f, 0.0f, 1.0f);c += 4;
+
+ VectorSet(v, graphx + graphwidth * a[0], graphy + graphheight * a[4], 0.0f);v += 3;Vector4Set(c, 1.0f, 1.0f, 1.0f, 1.0f);c += 4;
+ VectorSet(v, graphx + graphwidth * b[0], graphy + graphheight * b[4], 0.0f);v += 3;Vector4Set(c, 1.0f, 1.0f, 1.0f, 1.0f);c += 4;
+
+ VectorSet(v, graphx + graphwidth * a[0], graphy + graphheight * a[3], 0.0f);v += 3;Vector4Set(c, 1.0f, 0.5f, 0.0f, 1.0f);c += 4;
+ VectorSet(v, graphx + graphwidth * b[0], graphy + graphheight * b[3], 0.0f);v += 3;Vector4Set(c, 1.0f, 0.5f, 0.0f, 1.0f);c += 4;
+
+ numlines += 5;
+ }
+ if (numlines > 0)
+ DrawQ_Lines(0.0f, numlines, vertex3f, color4f, 0);
+ x = graphx;
+ y = graphy + graphheight;
+ dpsnprintf(bytesstring, sizeof(bytesstring), "%i", totalbytes);
+ DrawQ_String(x, y, label , 0, textsize, textsize, 1.0f, 1.0f, 1.0f, 1.0f, 0, NULL, false, FONT_DEFAULT);y += textsize;
+ DrawQ_String(x, y, bytesstring, 0, textsize, textsize, 1.0f, 1.0f, 1.0f, 1.0f, 0, NULL, false, FONT_DEFAULT);y += textsize;
+}
+
+/*
+==============
+SCR_DrawNetGraph
+==============
+*/
+void SCR_DrawNetGraph (void)
+{
+ int i, separator1, separator2, graphwidth, graphheight, netgraph_x, netgraph_y, textsize, index, netgraphsperrow;
+ float graphscale;
+ netconn_t *c;
+
+ if (cls.state != ca_connected)
+ return;
+ if (!cls.netcon)
+ return;
+ if (!shownetgraph.integer)
+ return;
+
+ separator1 = 2;
+ separator2 = 4;
+ textsize = 8;
+ graphwidth = 120;
+ graphheight = 70;
+ graphscale = 1.0f / 1500.0f;
+
+ netgraphsperrow = (vid_conwidth.integer + separator2) / (graphwidth * 2 + separator1 + separator2);
+ netgraphsperrow = max(netgraphsperrow, 1);
+
+ index = 0;
+ netgraph_x = (vid_conwidth.integer + separator2) - (1 + (index % netgraphsperrow)) * (graphwidth * 2 + separator1 + separator2);
+ netgraph_y = (vid_conheight.integer - 48 - sbar_info_pos.integer + separator2) - (1 + (index / netgraphsperrow)) * (graphheight + textsize + separator2);
+ c = cls.netcon;
+ SCR_DrawNetGraph_DrawGraph(netgraph_x , netgraph_y, graphwidth, graphheight, graphscale, "incoming", textsize, c->incoming_packetcounter, c->incoming_netgraph);
+ SCR_DrawNetGraph_DrawGraph(netgraph_x + graphwidth + separator1, netgraph_y, graphwidth, graphheight, graphscale, "outgoing", textsize, c->outgoing_packetcounter, c->outgoing_netgraph);
+ index++;
+
+ if (sv.active && shownetgraph.integer >= 2)
+ {
+ for (i = 0;i < svs.maxclients;i++)
+ {
+ c = svs.clients[i].netconnection;
+ if (!c)
+ continue;
+ netgraph_x = (vid_conwidth.integer + separator2) - (1 + (index % netgraphsperrow)) * (graphwidth * 2 + separator1 + separator2);
+ netgraph_y = (vid_conheight.integer - 48 + separator2) - (1 + (index / netgraphsperrow)) * (graphheight + textsize + separator2);
+ SCR_DrawNetGraph_DrawGraph(netgraph_x , netgraph_y, graphwidth, graphheight, graphscale, va("%s", svs.clients[i].name), textsize, c->outgoing_packetcounter, c->outgoing_netgraph);
+ SCR_DrawNetGraph_DrawGraph(netgraph_x + graphwidth + separator1, netgraph_y, graphwidth, graphheight, graphscale, "" , textsize, c->incoming_packetcounter, c->incoming_netgraph);
+ index++;
+ }
+ }
+}
+