gldriver.go (3820B)
1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package gldriver provides an OpenGL driver for accessing a screen. 6 package gldriver // import "golang.org/x/exp/shiny/driver/gldriver" 7 8 import ( 9 "encoding/binary" 10 "fmt" 11 "math" 12 13 "golang.org/x/exp/shiny/driver/internal/errscreen" 14 "golang.org/x/exp/shiny/screen" 15 "golang.org/x/image/math/f64" 16 "golang.org/x/mobile/gl" 17 ) 18 19 // Main is called by the program's main function to run the graphical 20 // application. 21 // 22 // It calls f on the Screen, possibly in a separate goroutine, as some OS- 23 // specific libraries require being on 'the main thread'. It returns when f 24 // returns. 25 func Main(f func(screen.Screen)) { 26 if err := main(f); err != nil { 27 f(errscreen.Stub(err)) 28 } 29 } 30 31 func mul(a, b f64.Aff3) f64.Aff3 { 32 return f64.Aff3{ 33 a[0]*b[0] + a[1]*b[3], 34 a[0]*b[1] + a[1]*b[4], 35 a[0]*b[2] + a[1]*b[5] + a[2], 36 37 a[3]*b[0] + a[4]*b[3], 38 a[3]*b[1] + a[4]*b[4], 39 a[3]*b[2] + a[4]*b[5] + a[5], 40 } 41 } 42 43 // writeAff3 must only be called while holding windowImpl.glctxMu. 44 func writeAff3(glctx gl.Context, u gl.Uniform, a f64.Aff3) { 45 var m [9]float32 46 m[0*3+0] = float32(a[0*3+0]) 47 m[0*3+1] = float32(a[1*3+0]) 48 m[0*3+2] = 0 49 m[1*3+0] = float32(a[0*3+1]) 50 m[1*3+1] = float32(a[1*3+1]) 51 m[1*3+2] = 0 52 m[2*3+0] = float32(a[0*3+2]) 53 m[2*3+1] = float32(a[1*3+2]) 54 m[2*3+2] = 1 55 glctx.UniformMatrix3fv(u, m[:]) 56 } 57 58 // f32Bytes returns the byte representation of float32 values in the given byte 59 // order. byteOrder must be either binary.BigEndian or binary.LittleEndian. 60 func f32Bytes(byteOrder binary.ByteOrder, values ...float32) []byte { 61 le := false 62 switch byteOrder { 63 case binary.BigEndian: 64 case binary.LittleEndian: 65 le = true 66 default: 67 panic(fmt.Sprintf("invalid byte order %v", byteOrder)) 68 } 69 70 b := make([]byte, 4*len(values)) 71 for i, v := range values { 72 u := math.Float32bits(v) 73 if le { 74 b[4*i+0] = byte(u >> 0) 75 b[4*i+1] = byte(u >> 8) 76 b[4*i+2] = byte(u >> 16) 77 b[4*i+3] = byte(u >> 24) 78 } else { 79 b[4*i+0] = byte(u >> 24) 80 b[4*i+1] = byte(u >> 16) 81 b[4*i+2] = byte(u >> 8) 82 b[4*i+3] = byte(u >> 0) 83 } 84 } 85 return b 86 } 87 88 // compileProgram must only be called while holding windowImpl.glctxMu. 89 func compileProgram(glctx gl.Context, vSrc, fSrc string) (gl.Program, error) { 90 program := glctx.CreateProgram() 91 if program.Value == 0 { 92 return gl.Program{}, fmt.Errorf("gldriver: no programs available") 93 } 94 95 vertexShader, err := compileShader(glctx, gl.VERTEX_SHADER, vSrc) 96 if err != nil { 97 return gl.Program{}, err 98 } 99 fragmentShader, err := compileShader(glctx, gl.FRAGMENT_SHADER, fSrc) 100 if err != nil { 101 glctx.DeleteShader(vertexShader) 102 return gl.Program{}, err 103 } 104 105 glctx.AttachShader(program, vertexShader) 106 glctx.AttachShader(program, fragmentShader) 107 glctx.LinkProgram(program) 108 109 // Flag shaders for deletion when program is unlinked. 110 glctx.DeleteShader(vertexShader) 111 glctx.DeleteShader(fragmentShader) 112 113 if glctx.GetProgrami(program, gl.LINK_STATUS) == 0 { 114 defer glctx.DeleteProgram(program) 115 return gl.Program{}, fmt.Errorf("gldriver: program compile: %s", glctx.GetProgramInfoLog(program)) 116 } 117 return program, nil 118 } 119 120 // compileShader must only be called while holding windowImpl.glctxMu. 121 func compileShader(glctx gl.Context, shaderType gl.Enum, src string) (gl.Shader, error) { 122 shader := glctx.CreateShader(shaderType) 123 if shader.Value == 0 { 124 return gl.Shader{}, fmt.Errorf("gldriver: could not create shader (type %v)", shaderType) 125 } 126 glctx.ShaderSource(shader, src) 127 glctx.CompileShader(shader) 128 if glctx.GetShaderi(shader, gl.COMPILE_STATUS) == 0 { 129 defer glctx.DeleteShader(shader) 130 return gl.Shader{}, fmt.Errorf("gldriver: shader compile: %s", glctx.GetShaderInfoLog(shader)) 131 } 132 return shader, nil 133 }