Selaa lähdekoodia

gui chart dev

leonsal 8 vuotta sitten
vanhempi
commit
26986926c0
1 muutettua tiedostoa jossa 459 lisäystä ja 0 poistoa
  1. 459 0
      gui/chart.go

+ 459 - 0
gui/chart.go

@@ -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);
+}
+`