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