blob: 37eb4674e75620991be8c161dbfb8f0c6aea1d12 [file] [log] [blame]
David Crawshawcabcb382015-07-30 14:52:09 -04001// 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.
Nigel Taoad7d0ec2016-02-04 09:20:54 +11006package gldriver // import "golang.org/x/exp/shiny/driver/gldriver"
David Crawshawcabcb382015-07-30 14:52:09 -04007
8import (
David Crawshaw6d4148d2015-08-01 10:13:44 -04009 "encoding/binary"
10 "fmt"
David Crawshaw6d4148d2015-08-01 10:13:44 -040011 "math"
David Crawshawcabcb382015-07-30 14:52:09 -040012
Nigel Taoffc53912015-08-20 12:08:26 +100013 "golang.org/x/exp/shiny/driver/internal/errscreen"
David Crawshawcabcb382015-07-30 14:52:09 -040014 "golang.org/x/exp/shiny/screen"
David Crawshaw6d4148d2015-08-01 10:13:44 -040015 "golang.org/x/image/math/f64"
16 "golang.org/x/mobile/gl"
David Crawshawcabcb382015-07-30 14:52:09 -040017)
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.
25func Main(f func(screen.Screen)) {
26 if err := main(f); err != nil {
Nigel Taoffc53912015-08-20 12:08:26 +100027 f(errscreen.Stub(err))
David Crawshawcabcb382015-07-30 14:52:09 -040028 }
29}
30
David Crawshaw6d4148d2015-08-01 10:13:44 -040031func 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
David Crawshawb80da082015-09-23 22:43:36 -040043// writeAff3 must only be called while holding windowImpl.glctxMu.
David Crawshaw82ea2f52015-09-23 19:37:56 -040044func writeAff3(glctx gl.Context, u gl.Uniform, a f64.Aff3) {
David Crawshaw6d4148d2015-08-01 10:13:44 -040045 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
David Crawshaw82ea2f52015-09-23 19:37:56 -040055 glctx.UniformMatrix3fv(u, m[:])
David Crawshaw6d4148d2015-08-01 10:13:44 -040056}
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.
60func 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
David Crawshawb80da082015-09-23 22:43:36 -040088// compileProgram must only be called while holding windowImpl.glctxMu.
David Crawshaw82ea2f52015-09-23 19:37:56 -040089func compileProgram(glctx gl.Context, vSrc, fSrc string) (gl.Program, error) {
90 program := glctx.CreateProgram()
David Crawshaw6d4148d2015-08-01 10:13:44 -040091 if program.Value == 0 {
92 return gl.Program{}, fmt.Errorf("gldriver: no programs available")
93 }
94
David Crawshaw82ea2f52015-09-23 19:37:56 -040095 vertexShader, err := compileShader(glctx, gl.VERTEX_SHADER, vSrc)
David Crawshaw6d4148d2015-08-01 10:13:44 -040096 if err != nil {
97 return gl.Program{}, err
98 }
David Crawshaw82ea2f52015-09-23 19:37:56 -040099 fragmentShader, err := compileShader(glctx, gl.FRAGMENT_SHADER, fSrc)
David Crawshaw6d4148d2015-08-01 10:13:44 -0400100 if err != nil {
David Crawshaw82ea2f52015-09-23 19:37:56 -0400101 glctx.DeleteShader(vertexShader)
David Crawshaw6d4148d2015-08-01 10:13:44 -0400102 return gl.Program{}, err
103 }
104
David Crawshaw82ea2f52015-09-23 19:37:56 -0400105 glctx.AttachShader(program, vertexShader)
106 glctx.AttachShader(program, fragmentShader)
107 glctx.LinkProgram(program)
David Crawshaw6d4148d2015-08-01 10:13:44 -0400108
109 // Flag shaders for deletion when program is unlinked.
David Crawshaw82ea2f52015-09-23 19:37:56 -0400110 glctx.DeleteShader(vertexShader)
111 glctx.DeleteShader(fragmentShader)
David Crawshaw6d4148d2015-08-01 10:13:44 -0400112
David Crawshaw82ea2f52015-09-23 19:37:56 -0400113 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))
David Crawshaw6d4148d2015-08-01 10:13:44 -0400116 }
117 return program, nil
118}
119
David Crawshawb80da082015-09-23 22:43:36 -0400120// compileShader must only be called while holding windowImpl.glctxMu.
David Crawshaw82ea2f52015-09-23 19:37:56 -0400121func compileShader(glctx gl.Context, shaderType gl.Enum, src string) (gl.Shader, error) {
122 shader := glctx.CreateShader(shaderType)
David Crawshaw6d4148d2015-08-01 10:13:44 -0400123 if shader.Value == 0 {
124 return gl.Shader{}, fmt.Errorf("gldriver: could not create shader (type %v)", shaderType)
125 }
David Crawshaw82ea2f52015-09-23 19:37:56 -0400126 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))
David Crawshaw6d4148d2015-08-01 10:13:44 -0400131 }
132 return shader, nil
133}