Ticket #3403: 3403_charts.3.patch
File 3403_charts.3.patch, 18.4 KB (added by , 7 years ago) |
---|
-
binaries/data/mods/public/gui/summary/summary.js
35 35 var g_GameData; 36 36 var g_ResourceData = new Resources(); 37 37 38 var g_Charts = ["population", "explored"]; 39 38 40 function selectPanel(panel) 39 41 { 40 42 // TODO: move panel buttons to a custom parent object … … 47 49 48 50 adjustTabDividers(panel.size); 49 51 50 updatePanelData(g_ScorePanelsData[panel.name.substr(0, panel.name.length - "PanelButton".length)]); 52 let generalPanel = Engine.GetGUIObjectByName("generalPanel"); 53 let chartsPanel = Engine.GetGUIObjectByName("chartsPanel"); 54 if (panel.name != "chartsPanelButton") 55 { 56 generalPanel.hidden = false; 57 chartsPanel.hidden = true; 58 updatePanelData(g_ScorePanelsData[panel.name.substr(0, panel.name.length - "PanelButton".length)]); 59 } 60 else 61 { 62 generalPanel.hidden = true; 63 chartsPanel.hidden = false; 64 updateCharts(); 65 } 51 66 } 52 67 68 function initCharts() 69 { 70 let player_colors = []; 71 for (let i = 0; i < g_PlayerCount; ++i) 72 { 73 let playerState = g_GameData.sim.playerStates[i+1]; 74 player_colors.push( 75 Math.floor(playerState.color.r * 255) + " " + 76 Math.floor(playerState.color.g * 255) + " " + 77 Math.floor(playerState.color.b * 255) 78 ); 79 } 80 for (let i = 0; i < g_Charts.length; ++i) 81 { 82 let chart = Engine.GetGUIObjectByName(g_Charts[i] + "Chart"); 83 chart.series_color = player_colors; 84 } 85 } 86 87 function updateCharts() 88 { 89 for (let i = 0; i < g_Charts.length; ++i) 90 { 91 let chart = Engine.GetGUIObjectByName(g_Charts[i] + "Chart"); 92 let series = []; 93 for (let j = 0; j < g_PlayerCount; ++j) 94 { 95 let playerState = g_GameData.sim.playerStates[j+1]; 96 series.push(playerState.statistics.sequences[g_Charts[i]]); 97 } 98 chart.series = series; 99 } 100 } 101 53 102 function adjustTabDividers(tabSize) 54 103 { 55 104 let leftSpacer = Engine.GetGUIObjectByName("tabDividerLeft"); … … 266 315 g_WithoutTeam -= g_Teams[i] ? g_Teams[i] : 0; 267 316 } 268 317 318 initCharts(); 319 269 320 selectPanel(Engine.GetGUIObjectByName("scorePanelButton")); 270 321 } -
binaries/data/mods/public/gui/summary/summary.xml
98 98 </object> 99 99 </object> 100 100 101 <object name="chartsPanelButton" type="button" sprite="BackgroundTab" style="TabButton" size="762 92 880 120"> 102 <action on="Press">selectPanel(this);</action> 103 <object type="text" style="ModernLabelText" ghost="true"> 104 <translatableAttribute id="caption">Charts</translatableAttribute> 105 </object> 106 </object> 107 101 108 <object name="generalPanel" type="image" sprite="ForegroundBody" size="20 120 100%-20 100%-54"> 102 109 <object size="0 0 100% 100%-50"> 103 110 <object name="playerNameHeading" type="text" style="ModernLeftTabLabelText"> … … 151 158 </repeat> 152 159 </object> 153 160 </object> 161 162 <object name="chartsPanel" type="image" sprite="ForegroundBody" size="20 120 100%-20 100%-54"> 163 <object 164 name="populationChartCaption" 165 type="text" 166 style="ModernTabLabelText" 167 size="20 20 50%-20 40" 168 > 169 <translatableAttribute id="caption">Population</translatableAttribute> 170 </object> 171 <object 172 name="populationChart" 173 type="chart" 174 ghost="true" 175 size="20 60 50%-20 50%-20" 176 /> 177 <object 178 name="exploredChartCaption" 179 type="text" 180 style="ModernTabLabelText" 181 size="50%+20 20 100%-20 40" 182 > 183 <translatableAttribute id="caption">Explored</translatableAttribute> 184 </object> 185 <object 186 name="exploredChart" 187 type="chart" 188 ghost="true" 189 size="50%+20 60 100%-20 50%-20" 190 /> 191 </object> 154 192 155 193 <object type="button" name="replayButton" style="ModernButtonRed" size="100%-310 100%-48 100%-170 100%-20"> 156 194 <translatableAttribute id="caption">Replay</translatableAttribute> -
binaries/data/mods/public/simulation/components/StatisticsTracker.js
1 1 function StatisticsTracker() {} 2 2 3 const UPDATE_SEQUENCE_INTERVAL = 30000; // 30 seconds 4 3 5 StatisticsTracker.prototype.Schema = 4 6 "<a:component type='system'/><empty/>"; 5 7 … … 142 144 this.lootCollected = 0; 143 145 this.peakPercentMapControlled = 0; 144 146 this.teamPeakPercentMapControlled = 0; 147 148 this.sequences = { 149 "population": [], 150 "explored": [] 151 }; 152 153 let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 154 if (!cmpTimer) 155 return; 156 this.updateTimer = cmpTimer.SetInterval( 157 this.entity, IID_StatisticsTracker, "updateSequences", 0, UPDATE_SEQUENCE_INTERVAL, { 158 "startTime": cmpTimer.GetTime() 159 } 160 ); 145 161 }; 146 162 147 163 /** … … 191 207 "percentMapControlled": this.GetPercentMapControlled(), 192 208 "teamPercentMapControlled": this.GetTeamPercentMapControlled(), 193 209 "peakPercentMapControlled": this.peakPercentMapControlled, 194 "teamPeakPercentMapControlled": this.teamPeakPercentMapControlled 210 "teamPeakPercentMapControlled": this.teamPeakPercentMapControlled, 211 "sequences": this.sequences 195 212 }; 196 213 }; 197 214 … … 492 509 this.teamPeakPercentMapControlled = newPercent; 493 510 }; 494 511 512 StatisticsTracker.prototype.updateSequences = function(data) 513 { 514 let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); 515 if (!cmpTimer) 516 return; 517 let deltaTime = (cmpTimer.GetTime() - data["startTime"]) / 1000; 518 519 let cmpPlayer = Engine.QueryInterface(this.entity, IID_Player); 520 if (!cmpPlayer) 521 return; 522 this.sequences.population.push([deltaTime, cmpPlayer.GetPopulationCount()]); 523 524 let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 525 if (!cmpRangeManager) 526 return; 527 this.sequences.explored.push([ 528 deltaTime, 529 cmpRangeManager.GetPercentMapExplored(cmpPlayer.GetPlayerID()) 530 ]); 531 } 532 495 533 Engine.RegisterComponentType(IID_StatisticsTracker, "StatisticsTracker", StatisticsTracker); -
source/gui/CChart.cpp
1 /* Copyright (C) 2016 Wildfire Games. 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include "precompiled.h" 19 #include "CChart.h" 20 21 #include "graphics/ShaderManager.h" 22 #include "lib/ogl.h" 23 #include "ps/CLogger.h" 24 #include "renderer/Renderer.h" 25 26 #include <cmath> 27 28 CChart::CChart() 29 { 30 AddSetting(GUIST_CGUIList, "series_color"); 31 AddSetting(GUIST_CGUISeries, "series"); 32 } 33 34 CChart::~CChart() 35 { 36 } 37 38 void CChart::HandleMessage(SGUIMessage& Message) 39 { 40 // TODO: implement zoom 41 } 42 43 void CChart::Draw() 44 { 45 PROFILE3("render chart"); 46 47 if (!GetGUI()) 48 return; 49 50 UpdateSeries(); 51 52 const float bz = GetBufferedZ(); 53 CRect rect = GetChartRect(); 54 const float width = rect.GetWidth(); 55 const float height = rect.GetHeight(); 56 57 if (m_Series.empty()) 58 return; 59 60 // Disable depth updates to prevent apparent z-fighting-related issues 61 // with some drivers causing units to get drawn behind the texture. 62 glDepthMask(0); 63 64 // Setup the render state 65 CMatrix3D transform = GetDefaultGuiMatrix(); 66 CShaderDefines lineDefines; 67 CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid, g_Renderer.GetSystemShaderDefines(), lineDefines); 68 tech->BeginPass(); 69 CShaderProgramPtr shader = tech->GetShader(); 70 shader->Uniform(str_transform, transform); 71 72 CVector2D leftBottom, rightTop; 73 leftBottom = rightTop = m_Series[0].m_Points[0]; 74 for (const CChartSerie& item : m_Series) 75 for (const CVector2D& point : item.m_Points) 76 { 77 if (point.X < leftBottom.X) 78 leftBottom.X = point.X; 79 if (point.Y < leftBottom.Y) 80 leftBottom.Y = point.Y; 81 82 if (point.X > rightTop.X) 83 rightTop.X = point.X; 84 if (point.Y > rightTop.Y) 85 rightTop.Y = point.Y; 86 } 87 88 CVector2D scale(width / (rightTop.X - leftBottom.X), height / (rightTop.Y - leftBottom.Y)); 89 90 for (const CChartSerie& item : m_Series) 91 { 92 if (item.m_Points.empty()) 93 continue; 94 95 std::vector<float> vertices; 96 for (const CVector2D& point : item.m_Points) 97 { 98 vertices.push_back(rect.left + (point.X - leftBottom.X) * scale.X); 99 vertices.push_back(rect.bottom - (point.Y - leftBottom.Y) * scale.Y); 100 vertices.push_back(bz + 0.5f); 101 } 102 shader->Uniform(str_color, item.m_Color); 103 shader->VertexPointer(3, GL_FLOAT, 0, &vertices[0]); 104 shader->AssertPointersBound(); 105 106 glEnable(GL_LINE_SMOOTH); 107 glLineWidth(1.1f); 108 if (!g_Renderer.m_SkipSubmit) 109 glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3); 110 glLineWidth(1.0f); 111 glDisable(GL_LINE_SMOOTH); 112 } 113 114 tech->EndPass(); 115 116 // Reset depth mask 117 glDepthMask(1); 118 } 119 120 CRect CChart::GetChartRect() const 121 { 122 return m_CachedActualSize; 123 } 124 125 void CChart::UpdateSeries() 126 { 127 CGUISeries* pSeries; 128 GUI<CGUISeries>::GetSettingPointer(this, "series", pSeries); 129 130 CGUIList* pSeriesColor; 131 GUI<CGUIList>::GetSettingPointer(this, "series_color", pSeriesColor); 132 133 m_Series.clear(); 134 for (size_t i = 0; i < pSeries->m_Series.size(); ++i) 135 { 136 m_Series.resize(m_Series.size() + 1); 137 CChartSerie& serie = m_Series.back(); 138 139 if (i < pSeriesColor->m_Items.size() && !GUI<int>::ParseColor(pSeriesColor->m_Items[i].GetOriginalString(), serie.m_Color, 0)) 140 LOGWARNING("GUI: Error parsing 'series_color' (\"%s\")", utf8_from_wstring(pSeriesColor->m_Items[i].GetOriginalString())); 141 142 for (size_t j = 0; j < pSeries->m_Series[i].size(); ++j) 143 serie.m_Points.push_back(pSeries->m_Series[i][j]); 144 } 145 } -
source/gui/CChart.h
1 /* Copyright (C) 2016 Wildfire Games. 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef INCLUDED_CCHART 19 #define INCLUDED_CCHART 20 21 #include "GUI.h" 22 #include "graphics/Color.h" 23 #include "maths/Vector2D.h" 24 #include <vector> 25 26 /** 27 * Represents a serie of chart. 28 */ 29 struct CChartSerie 30 { 31 CStr m_Id; 32 CColor m_Color; 33 std::vector<CVector2D> m_Points; 34 }; 35 36 /** 37 * Chart for a data visualization as lines or points 38 * 39 * @see IGUIObject 40 */ 41 class CChart : public IGUIObject 42 { 43 GUI_OBJECT(CChart) 44 45 public: 46 CChart(); 47 virtual ~CChart(); 48 49 protected: 50 /** 51 * @see IGUIObject#HandleMessage() 52 */ 53 virtual void HandleMessage(SGUIMessage& Message); 54 55 /** 56 * Draws the Chart 57 */ 58 virtual void Draw(); 59 60 virtual CRect GetChartRect() const; 61 62 void UpdateSeries(); 63 64 std::vector<CChartSerie> m_Series; 65 }; 66 67 #endif // INCLUDED_CCHART -
source/gui/CGUI.cpp
24 24 25 25 // Types - when including them into the engine. 26 26 #include "CButton.h" 27 #include "CChart.h" 27 28 #include "CCheckBox.h" 28 29 #include "CDropDown.h" 29 30 #include "CImage.h" … … 312 313 AddObjectType("olist", &COList::ConstructObject); 313 314 AddObjectType("dropdown", &CDropDown::ConstructObject); 314 315 AddObjectType("tooltip", &CTooltip::ConstructObject); 316 AddObjectType("chart", &CChart::ConstructObject); 315 317 } 316 318 317 319 void CGUI::Draw() -
source/gui/CGUISeries.h
1 /* Copyright (C) 2016 Wildfire Games. 2 * This file is part of 0 A.D. 3 * 4 * 0 A.D. is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * 0 A.D. is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 19 #ifndef INCLUDED_CGUISERIES 20 #define INCLUDED_CGUISERIES 21 22 #include "GUItext.h" 23 #include "maths/Vector2D.h" 24 25 26 class CGUISeries 27 { 28 public: 29 std::vector<std::vector<CVector2D>> m_Series; 30 }; 31 32 #endif -
source/gui/GUI.h
40 40 #include "ps/CStr.h" 41 41 42 42 #include "CGUIList.h" 43 #include "CGUISeries.h" 43 44 #include "GUIbase.h" 44 45 #include "GUItext.h" 45 46 #include "GUIutil.h" -
source/gui/GUItypes.h
1 /* Copyright (C) 20 09Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 40 40 TYPE(EVAlign) 41 41 TYPE(CPos) 42 42 TYPE(CGUIList) 43 TYPE(CGUISeries) -
source/gui/GUIutil.cpp
253 253 return false; 254 254 } 255 255 256 template <> 257 bool __ParseString<CGUISeries>(const CStrW& UNUSED(Value), CGUISeries& UNUSED(Output)) 258 { 259 return false; 260 } 256 261 257 262 //-------------------------------------------------------- 258 263 -
source/gui/scripting/JSInterface_IGUIObject.cpp
1 /* Copyright (C) 201 5Wildfire Games.1 /* Copyright (C) 2016 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 298 298 break; 299 299 } 300 300 301 case GUIST_CGUISeries: 302 { 303 CGUISeries value; 304 GUI<CGUISeries>::GetSetting(e, propName, value); 305 306 JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); 307 vp.setObject(*obj); 308 309 for (u32 i = 0; i < value.m_Series.size(); ++i) 310 { 311 JS::RootedObject inner_obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); 312 for (u32 j = 0; j < value.m_Series[i].size(); ++j) 313 { 314 JS::RootedObject val(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty())); 315 316 JS::RootedValue val_x(cx), val_y(cx); 317 ScriptInterface::ToJSVal(cx, &val_x, value.m_Series[i][j].X); 318 ScriptInterface::ToJSVal(cx, &val_y, value.m_Series[i][j].Y); 319 JS_SetElement(cx, val, 0, val_x); 320 JS_SetElement(cx, val, 1, val_y); 321 322 JS_SetElement(cx, inner_obj, j, val); 323 } 324 JS_SetElement(cx, obj, i, inner_obj); 325 } 326 327 break; 328 } 329 301 330 default: 302 331 JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str()); 303 332 DEBUG_WARN_ERR(ERR::LOGIC); … … 588 617 break; 589 618 } 590 619 620 case GUIST_CGUISeries: 621 { 622 u32 length; 623 if (!vp.isObject() || !JS_GetArrayLength(cx, vpObj, &length)) 624 { 625 JS_ReportError(cx, "Table only accepts a GUITable object"); 626 return false; 627 } 628 629 CGUISeries series; 630 series.m_Series.resize(length); 631 for (u32 i = 0; i < length; ++i) 632 { 633 JS::RootedValue serie_value(cx); 634 if (!JS_GetElement(cx, vpObj, i, &serie_value)) 635 { 636 JS_ReportError(cx, "Failed to get a serie"); 637 return false; 638 } 639 640 JS::RootedObject serie(cx, serie_value.toObjectOrNull()); 641 u32 serie_length; 642 if (!JS_GetArrayLength(cx, serie, &serie_length)) 643 { 644 JS_ReportError(cx, "Series only accepts a serie"); 645 return false; 646 } 647 648 series.m_Series[i].resize(serie_length); 649 for (u32 j = 0; j < serie_length; ++j) 650 { 651 JS::RootedValue element_value(cx); 652 if (!JS_GetElement(cx, serie, j, &element_value)) 653 { 654 JS_ReportError(cx, "Failed to get a serie element"); 655 return false; 656 } 657 658 JS::RootedObject element(cx, element_value.toObjectOrNull()); 659 u32 element_length; 660 if (!JS_GetArrayLength(cx, element, &element_length) || length < 2) 661 { 662 JS_ReportError(cx, "Failed to get a serie element size"); 663 return false; 664 } 665 666 JS::RootedValue element_x(cx), element_y(cx); 667 if (!JS_GetElement(cx, element, 0, &element_x) || !JS_GetElement(cx, element, 1, &element_y)) 668 { 669 JS_ReportError(cx, "Failed to get a serie element values"); 670 return false; 671 } 672 673 if (!ScriptInterface::FromJSVal(cx, element_x, series.m_Series[i][j].X) || 674 !ScriptInterface::FromJSVal(cx, element_y, series.m_Series[i][j].Y)) 675 return false; 676 } 677 } 678 679 GUI<CGUISeries>::SetSetting(e, propName, series); 680 break; 681 } 682 591 683 default: 592 684 JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str()); 593 685 break;