Ticket #3403: 3403_charts.2.patch

File 3403_charts.2.patch, 18.3 KB (added by Vladislav Belov, 7 years ago)

Adds charts

  • binaries/data/mods/public/gui/summary/summary.js

     
    3535var g_GameData;
    3636var g_ResourceData = new Resources();
    3737
     38var g_Charts = ["population", "explored"];
     39
    3840function selectPanel(panel)
    3941{
    4042    // TODO: move panel buttons to a custom parent object
     
    4749
    4850    adjustTabDividers(panel.size);
    4951
    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    }
    5166}
    5267
     68function 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.list_color = player_colors;
     84    }
     85}
     86
     87function updateCharts()
     88{
     89    for (let i = 0; i < g_Charts.length; ++i)
     90    {
     91        let chart = Engine.GetGUIObjectByName(g_Charts[i] + "Chart");
     92        let table_x = [];
     93        let table_y = [];
     94        for (let j = 0; j < g_PlayerCount; ++j)
     95        {
     96            let playerState = g_GameData.sim.playerStates[j+1];
     97            let list_x = [];
     98            let list_y = [];
     99            for (let k = 0; k < playerState.statistics.sequences[g_Charts[i]].length; ++k)
     100            {
     101                list_x.push(playerState.statistics.sequences[g_Charts[i]][k][0]);
     102                list_y.push(playerState.statistics.sequences[g_Charts[i]][k][1]);
     103            }
     104            table_x.push(list_x);
     105            table_y.push(list_y);
     106        }
     107        chart.table_x = table_x;
     108        chart.table_y = table_y;
     109    }
     110}
     111
    53112function adjustTabDividers(tabSize)
    54113{
    55114    let leftSpacer = Engine.GetGUIObjectByName("tabDividerLeft");
     
    266325            g_WithoutTeam -= g_Teams[i] ? g_Teams[i] : 0;
    267326    }
    268327
     328    initCharts();
     329
    269330    selectPanel(Engine.GetGUIObjectByName("scorePanelButton"));
    270331}
  • binaries/data/mods/public/gui/summary/summary.xml

     
    9898            </object>
    9999        </object>
    100100
     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
    101108        <object name="generalPanel" type="image" sprite="ForegroundBody" size="20 120 100%-20 100%-54">
    102109            <object size="0 0 100% 100%-50">
    103110                <object name="playerNameHeading" type="text" style="ModernLeftTabLabelText">
     
    151158                </repeat>
    152159            </object>
    153160        </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>
    154192
    155193        <object type="button" name="replayButton" style="ModernButtonRed" size="100%-310 100%-48 100%-170 100%-20">
    156194            <translatableAttribute id="caption">Replay</translatableAttribute>
  • binaries/data/mods/public/simulation/components/StatisticsTracker.js

     
    11function StatisticsTracker() {}
    22
     3const UPDATE_SEQUENCE_INTERVAL = 30000; // 30 seconds
     4
    35StatisticsTracker.prototype.Schema =
    46    "<a:component type='system'/><empty/>";
    57
     
    142144    this.lootCollected = 0;
    143145    this.peakPercentMapControlled = 0;
    144146    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, "updateSequneces", 0, UPDATE_SEQUENCE_INTERVAL, {
     158            "startTime": cmpTimer.GetTime()
     159        }
     160    );
    145161};
    146162
    147163/**
     
    191207        "percentMapControlled": this.GetPercentMapControlled(),
    192208        "teamPercentMapControlled": this.GetTeamPercentMapControlled(),
    193209        "peakPercentMapControlled": this.peakPercentMapControlled,
    194         "teamPeakPercentMapControlled": this.teamPeakPercentMapControlled
     210        "teamPeakPercentMapControlled": this.teamPeakPercentMapControlled,
     211        "sequences": this.sequences
    195212    };
    196213};
    197214
     
    492509        this.teamPeakPercentMapControlled = newPercent;
    493510};
    494511
     512StatisticsTracker.prototype.updateSequneces = 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
    495533Engine.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
     28CChart::CChart()
     29{
     30    AddSetting(GUIST_CGUIList, "list_color");
     31    AddSetting(GUIST_CGUITable, "table_x");
     32    AddSetting(GUIST_CGUITable, "table_y");
     33}
     34
     35CChart::~CChart()
     36{
     37}
     38
     39void CChart::HandleMessage(SGUIMessage& Message)
     40{
     41    // TODO: implement zoom
     42}
     43
     44void CChart::Draw()
     45{
     46    PROFILE3("render chart");
     47
     48    if (!GetGUI())
     49        return;
     50
     51    UpdateItems();
     52
     53    const float bz = GetBufferedZ();
     54    CRect rect = GetChartRect();
     55    const float width = rect.GetWidth();
     56    const float height = rect.GetHeight();
     57
     58    if (m_Items.empty())
     59        return;
     60
     61    // Disable depth updates to prevent apparent z-fighting-related issues
     62    //  with some drivers causing units to get drawn behind the texture.
     63    glDepthMask(0);
     64
     65    // Setup the render state
     66    CMatrix3D transform = GetDefaultGuiMatrix();
     67    CShaderDefines lineDefines;
     68    CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid, g_Renderer.GetSystemShaderDefines(), lineDefines);
     69    tech->BeginPass();
     70    CShaderProgramPtr shader = tech->GetShader();
     71    shader->Uniform(str_transform, transform);
     72
     73    CVector2D leftBottom, rightTop;
     74    leftBottom = rightTop = m_Items[0].m_Points[0];
     75    for (const CChartItem& item : m_Items)
     76        for (const CVector2D& point : item.m_Points)
     77        {
     78            if (point.X < leftBottom.X)
     79                leftBottom.X = point.X;
     80            if (point.Y < leftBottom.Y)
     81                leftBottom.Y = point.Y;
     82
     83            if (point.X > rightTop.X)
     84                rightTop.X = point.X;
     85            if (point.Y > rightTop.Y)
     86                rightTop.Y = point.Y;
     87        }
     88
     89    CVector2D scale(width / (rightTop.X - leftBottom.X), height / (rightTop.Y - leftBottom.Y));
     90
     91    for (const CChartItem& item : m_Items)
     92    {
     93        if (item.m_Points.empty())
     94            continue;
     95
     96        std::vector<float> vertices;
     97        for (const CVector2D& point : item.m_Points)
     98        {
     99            vertices.push_back(rect.left + (point.X - leftBottom.X) * scale.X);
     100            vertices.push_back(rect.bottom - (point.Y - leftBottom.Y) * scale.Y);
     101            vertices.push_back(bz + 0.5f);
     102        }
     103        shader->Uniform(str_color, item.m_Color);
     104        shader->VertexPointer(3, GL_FLOAT, 0, &vertices[0]);
     105        shader->AssertPointersBound();
     106
     107        glEnable(GL_LINE_SMOOTH);
     108        glLineWidth(1.1f);
     109        if (!g_Renderer.m_SkipSubmit)
     110            glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3);
     111        glLineWidth(1.0f);
     112        glDisable(GL_LINE_SMOOTH);
     113    }
     114
     115    tech->EndPass();
     116
     117    // Reset depth mask
     118    glDepthMask(1);
     119}
     120
     121CRect CChart::GetChartRect() const
     122{
     123    return m_CachedActualSize;
     124}
     125
     126void CChart::UpdateItems()
     127{
     128    CGUITable* pTableX;
     129    CGUITable* pTableY;
     130    GUI<CGUITable>::GetSettingPointer(this, "table_x", pTableX);
     131    GUI<CGUITable>::GetSettingPointer(this, "table_y", pTableY);
     132
     133    CGUIList* pListColor;
     134    GUI<CGUIList>::GetSettingPointer(this, "list_color", pListColor);
     135
     136    m_Items.clear();
     137    for (size_t i = 0; i < std::min(pTableX->m_Items.size(), pTableY->m_Items.size()); ++i)
     138    {
     139        m_Items.resize(m_Items.size() + 1);
     140        CChartItem& item = m_Items.back();
     141
     142        if (i < pListColor->m_Items.size() && !GUI<int>::ParseColor(pListColor->m_Items[i].GetOriginalString(), item.m_Color, 0))
     143            LOGWARNING("GUI: Error parsing 'list_color' (\"%s\")", utf8_from_wstring(pListColor->m_Items[i].GetOriginalString()));
     144
     145        for (size_t j = 0; j < std::min(pTableX->m_Items[i].size(), pTableY->m_Items[i].size()); ++j)
     146        {
     147            item.m_Points.push_back(CVector2D(
     148                pTableX->m_Items[i][j].GetOriginalString().ToFloat(),
     149                pTableY->m_Items[i][j].GetOriginalString().ToFloat()
     150            ));
     151        }
     152    }
     153}
  • 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 an item of chart.
     28*/
     29struct CChartItem
     30{
     31    CStr m_Id;
     32    CColor m_Color;
     33    std::vector<CVector2D> m_Points;
     34};
     35
     36/**
     37* Chart for a data visualization
     38*
     39* @see IGUIObject
     40*/
     41class CChart : public IGUIObject
     42{
     43    GUI_OBJECT(CChart)
     44
     45public:
     46    CChart();
     47    virtual ~CChart();
     48
     49protected:
     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 UpdateItems();
     63
     64    std::vector<CChartItem> m_Items;
     65};
     66
     67#endif // INCLUDED_CCHART
  • source/gui/CGUI.cpp

     
    2424
    2525// Types - when including them into the engine.
    2626#include "CButton.h"
     27#include "CChart.h"
    2728#include "CCheckBox.h"
    2829#include "CDropDown.h"
    2930#include "CImage.h"
     
    312313    AddObjectType("olist",          &COList::ConstructObject);
    313314    AddObjectType("dropdown",       &CDropDown::ConstructObject);
    314315    AddObjectType("tooltip",        &CTooltip::ConstructObject);
     316    AddObjectType("chart",          &CChart::ConstructObject);
    315317}
    316318
    317319void CGUI::Draw()
  • source/gui/CGUITable.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_CGUITABLE
     20#define INCLUDED_CGUITABLE
     21
     22#include "GUItext.h"
     23
     24class CGUITable
     25{
     26public:
     27    /**
     28    * List of items (as text), the post-processed result is stored in
     29    *  the IGUITextOwner structure of this class.
     30    */
     31    std::vector<std::vector<CGUIString>> m_Items;
     32};
     33
     34#endif
  • source/gui/GUI.h

     
    4040#include "ps/CStr.h"
    4141
    4242#include "CGUIList.h"
     43#include "CGUITable.h"
    4344#include "GUIbase.h"
    4445#include "GUItext.h"
    4546#include "GUIutil.h"
  • source/gui/GUItypes.h

     
    1 /* Copyright (C) 2009 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    4040TYPE(EVAlign)
    4141TYPE(CPos)
    4242TYPE(CGUIList)
     43TYPE(CGUITable)
  • source/gui/GUIutil.cpp

     
    253253    return false;
    254254}
    255255
     256template <>
     257bool __ParseString<CGUITable>(const CStrW& UNUSED(Value), CGUITable& UNUSED(Output))
     258{
     259    return false;
     260}
    256261
    257262//--------------------------------------------------------
    258263
  • source/gui/scripting/JSInterface_IGUIObject.cpp

     
    1 /* Copyright (C) 2015 Wildfire Games.
     1/* Copyright (C) 2016 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
    44 * 0 A.D. is free software: you can redistribute it and/or modify
     
    298298            break;
    299299        }
    300300
     301        case GUIST_CGUITable:
     302        {
     303            CGUITable value;
     304            GUI<CGUITable>::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_Items.size(); ++i)
     310            {
     311                JS::RootedObject inner_obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty()));
     312                for (u32 j = 0; j < value.m_Items[i].size(); ++j)
     313                {
     314                    JS::RootedValue val(cx);
     315                    ScriptInterface::ToJSVal(cx, &val, value.m_Items[i][j].GetOriginalString());
     316                    JS_SetElement(cx, inner_obj, j, val);
     317                }
     318                JS_SetElement(cx, obj, i, inner_obj);
     319            }
     320
     321            break;
     322        }
     323
    301324        default:
    302325            JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str());
    303326            DEBUG_WARN_ERR(ERR::LOGIC);
     
    588611        break;
    589612    }
    590613
     614    case GUIST_CGUITable:
     615    {
     616        u32 row_length;
     617        if (!vp.isObject() || !JS_GetArrayLength(cx, vpObj, &row_length))
     618        {
     619            JS_ReportError(cx, "Table only accepts a GUITable object");
     620            return false;
     621        }
     622
     623        CGUITable table;
     624        table.m_Items.resize(row_length);
     625        for (u32 i = 0; i < row_length; ++i)
     626        {
     627            JS::RootedValue column_value(cx);
     628            if (!JS_GetElement(cx, vpObj, i, &column_value))
     629            {
     630                JS_ReportError(cx, "Failed to get table column");
     631                return false;
     632            }
     633            JS::RootedObject column(cx, column_value.toObjectOrNull());
     634            u32 column_length;
     635            if (!JS_GetArrayLength(cx, column, &column_length))
     636            {
     637                JS_ReportError(cx, "Table row only accepts a table column");
     638                return false;
     639            }
     640
     641            table.m_Items[i].resize(column_length);
     642            for (u32 j = 0; j < column_length; ++j)
     643            {
     644                JS::RootedValue element(cx);
     645                if (!JS_GetElement(cx, column, j, &element))
     646                {
     647                    JS_ReportError(cx, "Failed to get list element");
     648                    return false;
     649                }
     650
     651                std::wstring value;
     652                if (!ScriptInterface::FromJSVal(cx, element, value))
     653                    return false;
     654
     655                table.m_Items[i][j].SetValue(value);
     656            }
     657        }
     658
     659        GUI<CGUITable>::SetSetting(e, propName, table);
     660        break;
     661    }
     662
    591663    default:
    592664        JS_ReportError(cx, "Setting '%s' uses an unimplemented type", propName.c_str());
    593665        break;