|
|
@@ -0,0 +1,459 @@
|
|
|
+package gui
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "github.com/g3n/engine/core"
|
|
|
+ "github.com/g3n/engine/geometry"
|
|
|
+ "github.com/g3n/engine/gls"
|
|
|
+ "github.com/g3n/engine/graphic"
|
|
|
+ "github.com/g3n/engine/material"
|
|
|
+ "github.com/g3n/engine/math32"
|
|
|
+ "github.com/g3n/engine/renderer/shader"
|
|
|
+)
|
|
|
+
|
|
|
+func init() {
|
|
|
+ shader.AddShader("shaderChartVertex", shaderChartVertex)
|
|
|
+ shader.AddShader("shaderChartFrag", shaderChartFrag)
|
|
|
+ shader.AddProgram("shaderChart", "shaderChartVertex", "shaderChartFrag")
|
|
|
+}
|
|
|
+
|
|
|
+// ChartLine implements a panel which can contain several line charts
|
|
|
+type ChartLine struct {
|
|
|
+ Panel // Embedded panel
|
|
|
+ grid *ChartGrid // Optional chart grid
|
|
|
+ baseX float32 // NDC x coordinate for y axis
|
|
|
+ baseY float32 // NDC y coordinate for x axis
|
|
|
+ scaleX *ChartScaleX // X scale objet
|
|
|
+ firstX float32 // First value for X label
|
|
|
+ stepX float32 // Step value for X label
|
|
|
+ formatX string // Format for X labels
|
|
|
+ scaleY *ChartScaleY // Y scale objet
|
|
|
+ graphs []*LineGraph // Array of line graphs
|
|
|
+}
|
|
|
+
|
|
|
+// NewChartLine creates and returns a new line chart panel with
|
|
|
+// the specified dimensions in pixels.
|
|
|
+func NewChartLine(width, height float32) *ChartLine {
|
|
|
+
|
|
|
+ cl := new(ChartLine)
|
|
|
+ cl.Panel.Initialize(width, height)
|
|
|
+ cl.baseX = 0.1
|
|
|
+ cl.baseY = -0.9
|
|
|
+ cl.firstX = 0.0
|
|
|
+ cl.stepX = 1.0
|
|
|
+ cl.formatX = "%2.1f"
|
|
|
+ return cl
|
|
|
+}
|
|
|
+
|
|
|
+// SetGrid sets the line chart grid with the specified number of
|
|
|
+// grid lines and color
|
|
|
+func (cl *ChartLine) SetGrid(xcount, ycount int, color *math32.Color) {
|
|
|
+
|
|
|
+ if cl.grid != nil {
|
|
|
+ cl.Node.Remove(cl.grid)
|
|
|
+ cl.grid.Dispose()
|
|
|
+ }
|
|
|
+ cl.grid = NewChartGrid(&cl.Panel, xcount, ycount, color)
|
|
|
+ cl.Node.Add(cl.grid)
|
|
|
+}
|
|
|
+
|
|
|
+// SetScaleX sets the line chart x scale number of lines and color
|
|
|
+func (cl *ChartLine) SetScaleX(lines int, color *math32.Color) {
|
|
|
+
|
|
|
+ if cl.scaleX != nil {
|
|
|
+ cl.Node.Remove(cl.scaleX)
|
|
|
+ cl.scaleX.Dispose()
|
|
|
+ }
|
|
|
+ cl.scaleX = newChartScaleX(cl, lines, color)
|
|
|
+ cl.Node.Add(cl.scaleX)
|
|
|
+}
|
|
|
+
|
|
|
+// SetScaleY sets the line chart y scale number of lines and color
|
|
|
+func (cl *ChartLine) SetScaleY(lines int, color *math32.Color) {
|
|
|
+
|
|
|
+ if cl.scaleY != nil {
|
|
|
+ cl.Node.Remove(cl.scaleY)
|
|
|
+ cl.scaleY.Dispose()
|
|
|
+ }
|
|
|
+ cl.scaleY = newChartScaleY(cl, lines, color)
|
|
|
+ cl.Node.Add(cl.scaleY)
|
|
|
+}
|
|
|
+
|
|
|
+// AddLine adds a line graph to the chart
|
|
|
+func (cl *ChartLine) AddGraph(name, title string, color *math32.Color, data []float32) {
|
|
|
+
|
|
|
+ graph := newLineGraph(&cl.Panel, name, title, color, data)
|
|
|
+ cl.graphs = append(cl.graphs, graph)
|
|
|
+ cl.Node.Add(graph)
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+// ChartScaleX
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+type ChartScaleX struct {
|
|
|
+ graphic.Graphic // It is a Graphic
|
|
|
+ chart *ChartLine // Container chart
|
|
|
+ modelMatrixUni gls.UniformMatrix4f // Model matrix uniform
|
|
|
+}
|
|
|
+
|
|
|
+func newChartScaleX(chart *ChartLine, lines int, color *math32.Color) *ChartScaleX {
|
|
|
+
|
|
|
+ sx := new(ChartScaleX)
|
|
|
+ sx.chart = chart
|
|
|
+
|
|
|
+ // Generates grid lines using Normalized Device Coordinates and
|
|
|
+ // considering that the parent panel model coordinates are:
|
|
|
+ // 0,0,0 1,0,0
|
|
|
+ // +---------------+
|
|
|
+ // | |
|
|
|
+ // | |
|
|
|
+ // +---------------+
|
|
|
+ // 0,-1,0 1,-1,0
|
|
|
+ positions := math32.NewArrayF32(0, 0)
|
|
|
+
|
|
|
+ // Appends scaleX bottom horizontal base line
|
|
|
+ positions.Append(
|
|
|
+ 0, chart.baseY, 0, color.R, color.G, color.B, // line start vertex and color
|
|
|
+ 1, chart.baseY, 0, color.R, color.G, color.B, // line end vertex and color
|
|
|
+ )
|
|
|
+ // Appends scale X vertical lines
|
|
|
+ step := 1 / (float32(lines) + 1)
|
|
|
+ for i := 1; i < lines+1; i++ {
|
|
|
+ nx := float32(i) * step
|
|
|
+ positions.Append(
|
|
|
+ nx, 0, 0, color.R, color.G, color.B, // line start vertex and color
|
|
|
+ nx, chart.baseY, 0, color.R, color.G, color.B, // line end vertex and color
|
|
|
+ )
|
|
|
+ l := NewLabel(fmt.Sprintf(sx.chart.formatX, float32(i)))
|
|
|
+ px, py := ndc2pix(&sx.chart.Panel, nx, chart.baseY)
|
|
|
+ l.SetPosition(px, py)
|
|
|
+ sx.chart.Add(l)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Creates geometry using one interlaced VBO
|
|
|
+ geom := geometry.NewGeometry()
|
|
|
+ geom.AddVBO(gls.NewVBO().
|
|
|
+ AddAttrib("VertexPosition", 3).
|
|
|
+ AddAttrib("VertexColor", 3).
|
|
|
+ SetBuffer(positions),
|
|
|
+ )
|
|
|
+
|
|
|
+ // Creates material
|
|
|
+ mat := material.NewMaterial()
|
|
|
+ mat.SetLineWidth(1.0)
|
|
|
+ mat.SetShader("shaderChart")
|
|
|
+
|
|
|
+ // Initializes the grid graphic
|
|
|
+ sx.Graphic.Init(geom, gls.LINES)
|
|
|
+ sx.AddMaterial(sx, mat, 0, 0)
|
|
|
+ sx.modelMatrixUni.Init("ModelMatrix")
|
|
|
+
|
|
|
+ return sx
|
|
|
+}
|
|
|
+
|
|
|
+// Converts panel ndc coordinates to relative pixels inside panel
|
|
|
+func ndc2pix(p *Panel, nx, ny float32) (px, py float32) {
|
|
|
+
|
|
|
+ w := p.ContentWidth()
|
|
|
+ h := p.ContentHeight()
|
|
|
+ return w * nx, -h * ny
|
|
|
+}
|
|
|
+
|
|
|
+// RenderSetup is called by the renderer before drawing this graphic
|
|
|
+// Calculates the model matrix and transfer to OpenGL.
|
|
|
+func (sx *ChartScaleX) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
|
|
|
+
|
|
|
+ // Set this model matrix the same as the chart panel
|
|
|
+ var mm math32.Matrix4
|
|
|
+ sx.chart.SetModelMatrix(gs, &mm)
|
|
|
+
|
|
|
+ // Sets and transfer the model matrix uniform
|
|
|
+ sx.modelMatrixUni.SetMatrix4(&mm)
|
|
|
+ sx.modelMatrixUni.Transfer(gs)
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+// ChartScaleY
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+type ChartScaleY struct {
|
|
|
+ graphic.Graphic // It is a Graphic
|
|
|
+ chart *ChartLine // Container chart
|
|
|
+ modelMatrixUni gls.UniformMatrix4f // Model matrix uniform
|
|
|
+}
|
|
|
+
|
|
|
+func newChartScaleY(chart *ChartLine, lines int, color *math32.Color) *ChartScaleY {
|
|
|
+
|
|
|
+ sy := new(ChartScaleY)
|
|
|
+ sy.chart = chart
|
|
|
+
|
|
|
+ // Generates grid lines using Normalized Device Coordinates and
|
|
|
+ // considering that the parent panel model coordinates are:
|
|
|
+ // 0,0,0 1,0,0
|
|
|
+ // +---------------+
|
|
|
+ // | |
|
|
|
+ // | |
|
|
|
+ // +---------------+
|
|
|
+ // 0,-1,0 1,-1,0
|
|
|
+ positions := math32.NewArrayF32(0, 0)
|
|
|
+
|
|
|
+ // Appends scaleY left vertical axis line
|
|
|
+ positions.Append(
|
|
|
+ chart.baseX, 0, 0, color.R, color.G, color.B, // line start vertex and color
|
|
|
+ chart.baseX, -1, 0, color.R, color.G, color.B, // line end vertex and color
|
|
|
+ )
|
|
|
+ // Appends scale horizontal lines starting from baseX
|
|
|
+ step := 1 / (float32(lines) + 1)
|
|
|
+ for i := 1; i < lines+1; i++ {
|
|
|
+ ny := -float32(i) * step
|
|
|
+ positions.Append(
|
|
|
+ chart.baseX, ny, 0, color.R, color.G, color.B, // line start vertex and color
|
|
|
+ 1, ny, 0, color.R, color.G, color.B, // line end vertex and color
|
|
|
+ )
|
|
|
+ // l := NewLabel(fmt.Sprintf(sx.chart.formatX, float32(i)))
|
|
|
+ // px, py := ndc2pix(&sx.chart.Panel, nx, baseY)
|
|
|
+ // l.SetPosition(px, py)
|
|
|
+ // sx.chart.Add(l)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Creates geometry using one interlaced VBO
|
|
|
+ geom := geometry.NewGeometry()
|
|
|
+ geom.AddVBO(gls.NewVBO().
|
|
|
+ AddAttrib("VertexPosition", 3).
|
|
|
+ AddAttrib("VertexColor", 3).
|
|
|
+ SetBuffer(positions),
|
|
|
+ )
|
|
|
+
|
|
|
+ // Creates material
|
|
|
+ mat := material.NewMaterial()
|
|
|
+ mat.SetLineWidth(1.0)
|
|
|
+ mat.SetShader("shaderChart")
|
|
|
+
|
|
|
+ // Initializes the grid graphic
|
|
|
+ sy.Graphic.Init(geom, gls.LINES)
|
|
|
+ sy.AddMaterial(sy, mat, 0, 0)
|
|
|
+ sy.modelMatrixUni.Init("ModelMatrix")
|
|
|
+
|
|
|
+ return sy
|
|
|
+}
|
|
|
+
|
|
|
+// RenderSetup is called by the renderer before drawing this graphic
|
|
|
+// Calculates the model matrix and transfer to OpenGL.
|
|
|
+func (sy *ChartScaleY) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
|
|
|
+
|
|
|
+ // Set this model matrix the same as the chart panel
|
|
|
+ var mm math32.Matrix4
|
|
|
+ sy.chart.SetModelMatrix(gs, &mm)
|
|
|
+
|
|
|
+ // Sets and transfer the model matrix uniform
|
|
|
+ sy.modelMatrixUni.SetMatrix4(&mm)
|
|
|
+ sy.modelMatrixUni.Transfer(gs)
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+// ChartGrid
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+
|
|
|
+// ChartGrid implements a 2D grid used inside charts
|
|
|
+type ChartGrid struct {
|
|
|
+ graphic.Graphic // It is a Graphic
|
|
|
+ chart *Panel // Container chart
|
|
|
+ modelMatrixUni gls.UniformMatrix4f // Model matrix uniform
|
|
|
+}
|
|
|
+
|
|
|
+// NewChartGrid creates and returns a pointer to a chart grid graphic for the
|
|
|
+// specified parent chart and with the specified number of grid lines and color.
|
|
|
+func NewChartGrid(chart *Panel, xcount, ycount int, color *math32.Color) *ChartGrid {
|
|
|
+
|
|
|
+ cg := new(ChartGrid)
|
|
|
+ cg.chart = chart
|
|
|
+
|
|
|
+ // Generates grid lines using Normalized Device Coordinates and
|
|
|
+ // considering that the parent panel model coordinates are:
|
|
|
+ // 0,0,0 1,0,0
|
|
|
+ // +---------------+
|
|
|
+ // | |
|
|
|
+ // | |
|
|
|
+ // +---------------+
|
|
|
+ // 0,-1,0 1,-1,0
|
|
|
+ positions := math32.NewArrayF32(0, 0)
|
|
|
+ xstep := 1 / (float32(xcount) + 1)
|
|
|
+ for xi := 1; xi < xcount+1; xi++ {
|
|
|
+ posx := float32(xi) * xstep
|
|
|
+ positions.Append(
|
|
|
+ posx, 0, 0, color.R, color.G, color.B, // line start vertex and color
|
|
|
+ posx, -1, 0, color.R, color.G, color.B, // line end vertex and color
|
|
|
+ )
|
|
|
+ }
|
|
|
+ ystep := 1 / (float32(ycount) + 1)
|
|
|
+ for yi := 1; yi < ycount+1; yi++ {
|
|
|
+ posy := -float32(yi) * ystep
|
|
|
+ positions.Append(
|
|
|
+ 0, posy, 0, color.R, color.G, color.B, // line start vertex and color
|
|
|
+ 1, posy, 0, color.R, color.G, color.B, // line end vertex and color
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
+ // Creates geometry using one interlaced VBO
|
|
|
+ geom := geometry.NewGeometry()
|
|
|
+ geom.AddVBO(
|
|
|
+ gls.NewVBO().
|
|
|
+ AddAttrib("VertexPosition", 3).
|
|
|
+ AddAttrib("VertexColor", 3).
|
|
|
+ SetBuffer(positions),
|
|
|
+ )
|
|
|
+
|
|
|
+ // Creates material
|
|
|
+ mat := material.NewMaterial()
|
|
|
+ mat.SetLineWidth(1.0)
|
|
|
+ mat.SetShader("shaderChart")
|
|
|
+
|
|
|
+ // Initializes the grid graphic
|
|
|
+ cg.Graphic.Init(geom, gls.LINES)
|
|
|
+ cg.AddMaterial(cg, mat, 0, 0)
|
|
|
+ cg.modelMatrixUni.Init("ModelMatrix")
|
|
|
+ return cg
|
|
|
+}
|
|
|
+
|
|
|
+// RenderSetup is called by the renderer before drawing this graphic
|
|
|
+// Calculates the model matrix and transfer to OpenGL.
|
|
|
+func (cg *ChartGrid) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
|
|
|
+
|
|
|
+ // Set this model matrix the same as the chart panel
|
|
|
+ var mm math32.Matrix4
|
|
|
+ cg.chart.SetModelMatrix(gs, &mm)
|
|
|
+
|
|
|
+ // Sets and transfer the model matrix uniform
|
|
|
+ cg.modelMatrixUni.SetMatrix4(&mm)
|
|
|
+ cg.modelMatrixUni.Transfer(gs)
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+// LineGraph
|
|
|
+//
|
|
|
+//
|
|
|
+//
|
|
|
+
|
|
|
+// LineGraph implemens a 2D line graph
|
|
|
+type LineGraph struct {
|
|
|
+ graphic.Graphic // It is a Graphic
|
|
|
+ chart *Panel // Container chart
|
|
|
+ modelMatrixUni gls.UniformMatrix4f // Model matrix uniform
|
|
|
+ name string // Name id
|
|
|
+ title string // Title string
|
|
|
+ color *math32.Color // Line color
|
|
|
+ data []float32 // Data
|
|
|
+}
|
|
|
+
|
|
|
+// newLineGraph creates and returns a pointer to a line graph graphic for the
|
|
|
+// specified parent chart
|
|
|
+func newLineGraph(chart *Panel, name, title string, color *math32.Color, data []float32) *LineGraph {
|
|
|
+
|
|
|
+ lg := new(LineGraph)
|
|
|
+ lg.chart = chart
|
|
|
+ lg.name = name
|
|
|
+ lg.title = title
|
|
|
+ lg.color = color
|
|
|
+ lg.data = data
|
|
|
+
|
|
|
+ // Generates graph lines using Normalized Device Coordinates and
|
|
|
+ // considering that the parent panel model coordinates are:
|
|
|
+ // 0,0,0 1,0,0
|
|
|
+ // +---------------+
|
|
|
+ // | |
|
|
|
+ // | |
|
|
|
+ // +---------------+
|
|
|
+ // 0,-1,0 1,-1,0
|
|
|
+ positions := math32.NewArrayF32(0, 0)
|
|
|
+ for i := 0; i < len(data); i++ {
|
|
|
+ px := float32(i) / float32(len(data))
|
|
|
+ py := -1 + data[i]
|
|
|
+ positions.Append(px, py, 0, color.R, color.G, color.B)
|
|
|
+ }
|
|
|
+
|
|
|
+ // Creates geometry using one interlaced VBO
|
|
|
+ geom := geometry.NewGeometry()
|
|
|
+ geom.AddVBO(gls.NewVBO().
|
|
|
+ AddAttrib("VertexPosition", 3).
|
|
|
+ AddAttrib("VertexColor", 3).
|
|
|
+ SetBuffer(positions),
|
|
|
+ )
|
|
|
+
|
|
|
+ // Creates material
|
|
|
+ mat := material.NewMaterial()
|
|
|
+ mat.SetLineWidth(2.5)
|
|
|
+ mat.SetShader("shaderChart")
|
|
|
+
|
|
|
+ // Initializes the graphic
|
|
|
+ lg.Graphic.Init(geom, gls.LINE_STRIP)
|
|
|
+ lg.AddMaterial(lg, mat, 0, 0)
|
|
|
+ lg.modelMatrixUni.Init("ModelMatrix")
|
|
|
+
|
|
|
+ return lg
|
|
|
+}
|
|
|
+
|
|
|
+// RenderSetup is called by the renderer before drawing this graphic
|
|
|
+// Calculates the model matrix and transfer to OpenGL.
|
|
|
+func (lg *LineGraph) RenderSetup(gs *gls.GLS, rinfo *core.RenderInfo) {
|
|
|
+
|
|
|
+ // Set this graphic model matrix the same as the container chart panel
|
|
|
+ var mm math32.Matrix4
|
|
|
+ lg.chart.SetModelMatrix(gs, &mm)
|
|
|
+
|
|
|
+ // Sets and transfer the model matrix uniform
|
|
|
+ lg.modelMatrixUni.SetMatrix4(&mm)
|
|
|
+ lg.modelMatrixUni.Transfer(gs)
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+// Vertex Shader template
|
|
|
+//
|
|
|
+const shaderChartVertex = `
|
|
|
+#version {{.Version}}
|
|
|
+
|
|
|
+// Vertex attributes
|
|
|
+{{template "attributes" .}}
|
|
|
+
|
|
|
+// Input uniforms
|
|
|
+uniform mat4 ModelMatrix;
|
|
|
+
|
|
|
+// Outputs for fragment shader
|
|
|
+out vec3 Color;
|
|
|
+
|
|
|
+void main() {
|
|
|
+
|
|
|
+ Color = VertexColor;
|
|
|
+
|
|
|
+ // Set position
|
|
|
+ vec4 pos = vec4(VertexPosition.xyz, 1);
|
|
|
+ gl_Position = ModelMatrix * pos;
|
|
|
+}
|
|
|
+`
|
|
|
+
|
|
|
+//
|
|
|
+// Fragment Shader template
|
|
|
+//
|
|
|
+const shaderChartFrag = `
|
|
|
+#version {{.Version}}
|
|
|
+
|
|
|
+in vec3 Color;
|
|
|
+out vec4 FragColor;
|
|
|
+
|
|
|
+void main() {
|
|
|
+
|
|
|
+ FragColor = vec4(Color, 1.0);
|
|
|
+}
|
|
|
+`
|