github.com/as/shiny@v0.8.2/driver/gldriver/screen.go (about) 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 // +build darwin 6 7 package gldriver 8 9 import ( 10 "fmt" 11 "image" 12 "sync" 13 14 "github.com/as/shiny/gl" 15 "github.com/as/shiny/screen" 16 ) 17 18 var theScreen = &screenImpl{} 19 20 type screenImpl struct { 21 texture struct { 22 program gl.Program 23 pos gl.Attrib 24 mvp gl.Uniform 25 uvp gl.Uniform 26 inUV gl.Attrib 27 sample gl.Uniform 28 quad gl.Buffer 29 } 30 fill struct { 31 program gl.Program 32 pos gl.Attrib 33 mvp gl.Uniform 34 color gl.Uniform 35 quad gl.Buffer 36 } 37 38 mu sync.Mutex 39 window *windowImpl 40 } 41 42 func (s *screenImpl) NewBuffer(size image.Point) (retBuf screen.Buffer, retErr error) { 43 m := image.NewRGBA(image.Rectangle{Max: size}) 44 return &bufferImpl{ 45 buf: m.Pix, 46 rgba: *m, 47 size: size, 48 }, nil 49 } 50 51 func (s *screenImpl) NewTexture(size image.Point) (screen.Texture, error) { 52 // TODO: can we compile these programs eagerly instead of lazily? 53 54 // Find a GL context for this texture. 55 // TODO: this might be correct. Some GL objects can be shared 56 // across contexts. But this needs a review of the spec to make 57 // sure it's correct, and some testing would be nice. 58 w := s.window 59 if w == nil { 60 return nil, fmt.Errorf("gldriver: no window available") 61 } 62 63 w.glctxMu.Lock() 64 defer w.glctxMu.Unlock() 65 glctx := w.glctx 66 if glctx == nil { 67 return nil, fmt.Errorf("gldriver: no GL context available") 68 } 69 70 if !glctx.IsProgram(s.texture.program) { 71 p, err := compileProgram(glctx, textureVertexSrc, textureFragmentSrc) 72 if err != nil { 73 return nil, err 74 } 75 s.texture.program = p 76 s.texture.pos = glctx.GetAttribLocation(p, "pos") 77 s.texture.mvp = glctx.GetUniformLocation(p, "mvp") 78 s.texture.uvp = glctx.GetUniformLocation(p, "uvp") 79 s.texture.inUV = glctx.GetAttribLocation(p, "inUV") 80 s.texture.sample = glctx.GetUniformLocation(p, "sample") 81 s.texture.quad = glctx.CreateBuffer() 82 83 glctx.BindBuffer(gl.ARRAY_BUFFER, s.texture.quad) 84 glctx.BufferData(gl.ARRAY_BUFFER, quadCoords, gl.STATIC_DRAW) 85 } 86 87 t := &textureImpl{ 88 w: w, 89 id: glctx.CreateTexture(), 90 size: size, 91 } 92 93 glctx.BindTexture(gl.TEXTURE_2D, t.id) 94 glctx.TexImage2D(gl.TEXTURE_2D, 0, size.X, size.Y, gl.RGBA, gl.UNSIGNED_BYTE, nil) 95 glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 96 glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 97 glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) 98 glctx.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) 99 100 return t, nil 101 } 102 103 func optsSize(opts *screen.NewWindowOptions) (width, height int) { 104 width, height = 1024, 768 105 if opts != nil { 106 if opts.Width > 0 { 107 width = opts.Width 108 } 109 if opts.Height > 0 { 110 height = opts.Height 111 } 112 } 113 return width, height 114 } 115 116 func (s *screenImpl) NewWindow(opts *screen.NewWindowOptions) (screen.Window, error) { 117 id, err := newWindow(opts) 118 if err != nil { 119 return nil, err 120 } 121 w := &windowImpl{ 122 s: s, 123 id: id, 124 publish: make(chan struct{}), 125 publishDone: make(chan screen.PublishResult), 126 drawDone: make(chan struct{}), 127 } 128 initWindow(w) 129 130 if s.window != nil { 131 panic("newwindow") 132 } 133 s.window = w 134 showWindow(w) 135 return w, nil 136 }