| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // Package gldriver provides an OpenGL driver for accessing a screen. |
| package gldriver // import "golang.org/x/exp/shiny/driver/gldriver" |
| |
| import ( |
| "encoding/binary" |
| "fmt" |
| "math" |
| |
| "golang.org/x/exp/shiny/driver/internal/errscreen" |
| "golang.org/x/exp/shiny/screen" |
| "golang.org/x/image/math/f64" |
| "golang.org/x/mobile/gl" |
| ) |
| |
| // Main is called by the program's main function to run the graphical |
| // application. |
| // |
| // It calls f on the Screen, possibly in a separate goroutine, as some OS- |
| // specific libraries require being on 'the main thread'. It returns when f |
| // returns. |
| func Main(f func(screen.Screen)) { |
| if err := main(f); err != nil { |
| f(errscreen.Stub(err)) |
| } |
| } |
| |
| func mul(a, b f64.Aff3) f64.Aff3 { |
| return f64.Aff3{ |
| a[0]*b[0] + a[1]*b[3], |
| a[0]*b[1] + a[1]*b[4], |
| a[0]*b[2] + a[1]*b[5] + a[2], |
| |
| a[3]*b[0] + a[4]*b[3], |
| a[3]*b[1] + a[4]*b[4], |
| a[3]*b[2] + a[4]*b[5] + a[5], |
| } |
| } |
| |
| // writeAff3 must only be called while holding windowImpl.glctxMu. |
| func writeAff3(glctx gl.Context, u gl.Uniform, a f64.Aff3) { |
| var m [9]float32 |
| m[0*3+0] = float32(a[0*3+0]) |
| m[0*3+1] = float32(a[1*3+0]) |
| m[0*3+2] = 0 |
| m[1*3+0] = float32(a[0*3+1]) |
| m[1*3+1] = float32(a[1*3+1]) |
| m[1*3+2] = 0 |
| m[2*3+0] = float32(a[0*3+2]) |
| m[2*3+1] = float32(a[1*3+2]) |
| m[2*3+2] = 1 |
| glctx.UniformMatrix3fv(u, m[:]) |
| } |
| |
| // f32Bytes returns the byte representation of float32 values in the given byte |
| // order. byteOrder must be either binary.BigEndian or binary.LittleEndian. |
| func f32Bytes(byteOrder binary.ByteOrder, values ...float32) []byte { |
| le := false |
| switch byteOrder { |
| case binary.BigEndian: |
| case binary.LittleEndian: |
| le = true |
| default: |
| panic(fmt.Sprintf("invalid byte order %v", byteOrder)) |
| } |
| |
| b := make([]byte, 4*len(values)) |
| for i, v := range values { |
| u := math.Float32bits(v) |
| if le { |
| b[4*i+0] = byte(u >> 0) |
| b[4*i+1] = byte(u >> 8) |
| b[4*i+2] = byte(u >> 16) |
| b[4*i+3] = byte(u >> 24) |
| } else { |
| b[4*i+0] = byte(u >> 24) |
| b[4*i+1] = byte(u >> 16) |
| b[4*i+2] = byte(u >> 8) |
| b[4*i+3] = byte(u >> 0) |
| } |
| } |
| return b |
| } |
| |
| // compileProgram must only be called while holding windowImpl.glctxMu. |
| func compileProgram(glctx gl.Context, vSrc, fSrc string) (gl.Program, error) { |
| program := glctx.CreateProgram() |
| if program.Value == 0 { |
| return gl.Program{}, fmt.Errorf("gldriver: no programs available") |
| } |
| |
| vertexShader, err := compileShader(glctx, gl.VERTEX_SHADER, vSrc) |
| if err != nil { |
| return gl.Program{}, err |
| } |
| fragmentShader, err := compileShader(glctx, gl.FRAGMENT_SHADER, fSrc) |
| if err != nil { |
| glctx.DeleteShader(vertexShader) |
| return gl.Program{}, err |
| } |
| |
| glctx.AttachShader(program, vertexShader) |
| glctx.AttachShader(program, fragmentShader) |
| glctx.LinkProgram(program) |
| |
| // Flag shaders for deletion when program is unlinked. |
| glctx.DeleteShader(vertexShader) |
| glctx.DeleteShader(fragmentShader) |
| |
| if glctx.GetProgrami(program, gl.LINK_STATUS) == 0 { |
| defer glctx.DeleteProgram(program) |
| return gl.Program{}, fmt.Errorf("gldriver: program compile: %s", glctx.GetProgramInfoLog(program)) |
| } |
| return program, nil |
| } |
| |
| // compileShader must only be called while holding windowImpl.glctxMu. |
| func compileShader(glctx gl.Context, shaderType gl.Enum, src string) (gl.Shader, error) { |
| shader := glctx.CreateShader(shaderType) |
| if shader.Value == 0 { |
| return gl.Shader{}, fmt.Errorf("gldriver: could not create shader (type %v)", shaderType) |
| } |
| glctx.ShaderSource(shader, src) |
| glctx.CompileShader(shader) |
| if glctx.GetShaderi(shader, gl.COMPILE_STATUS) == 0 { |
| defer glctx.DeleteShader(shader) |
| return gl.Shader{}, fmt.Errorf("gldriver: shader compile: %s", glctx.GetShaderInfoLog(shader)) |
| } |
| return shader, nil |
| } |