github.com/as/shiny@v0.8.2/driver/gldriver/texture.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 "encoding/binary" 11 "image" 12 "image/color" 13 "image/draw" 14 15 "github.com/as/shiny/gl" 16 "github.com/as/shiny/screen" 17 ) 18 19 type textureImpl struct { 20 w *windowImpl 21 id gl.Texture 22 fb gl.Framebuffer 23 size image.Point 24 } 25 26 func (t *textureImpl) Size() image.Point { return t.size } 27 func (t *textureImpl) Bounds() image.Rectangle { return image.Rectangle{Max: t.size} } 28 29 func (t *textureImpl) Release() { 30 t.w.glctxMu.Lock() 31 defer t.w.glctxMu.Unlock() 32 33 if t.fb.Value != 0 { 34 t.w.glctx.DeleteFramebuffer(t.fb) 35 t.fb = gl.Framebuffer{} 36 } 37 t.w.glctx.DeleteTexture(t.id) 38 t.id = gl.Texture{} 39 } 40 41 func (t *textureImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle) { 42 buf := src.(*bufferImpl) 43 44 // src2dst is added to convert from the src coordinate space to the dst 45 // coordinate space. It is subtracted to convert the other way. 46 src2dst := dp.Sub(sr.Min) 47 48 // Clip to the source. 49 sr = sr.Intersect(buf.Bounds()) 50 51 // Clip to the destination. 52 dr := sr.Add(src2dst) 53 dr = dr.Intersect(t.Bounds()) 54 if dr.Empty() { 55 return 56 } 57 58 // Bring dr.Min in dst-space back to src-space to get the pixel buffer offset. 59 pix := buf.rgba.Pix[buf.rgba.PixOffset(dr.Min.X-src2dst.X, dr.Min.Y-src2dst.Y):] 60 61 t.w.glctxMu.Lock() 62 defer t.w.glctxMu.Unlock() 63 64 t.w.glctx.BindTexture(gl.TEXTURE_2D, t.id) 65 66 width := dr.Dx() 67 if width*4 == buf.rgba.Stride { 68 t.w.glctx.TexSubImage2D(gl.TEXTURE_2D, 0, dr.Min.X, dr.Min.Y, width, dr.Dy(), gl.RGBA, gl.UNSIGNED_BYTE, pix) 69 return 70 } 71 // TODO: can we use GL_UNPACK_ROW_LENGTH with glPixelStorei for stride in 72 // ES 3.0, instead of uploading the pixels row-by-row? 73 for y, p := dr.Min.Y, 0; y < dr.Max.Y; y++ { 74 t.w.glctx.TexSubImage2D(gl.TEXTURE_2D, 0, dr.Min.X, y, width, 1, gl.RGBA, gl.UNSIGNED_BYTE, pix[p:]) 75 p += buf.rgba.Stride 76 } 77 } 78 79 func (t *textureImpl) Fill(dr image.Rectangle, src color.Color, op draw.Op) { 80 minX := float64(dr.Min.X) 81 minY := float64(dr.Min.Y) 82 maxX := float64(dr.Max.X) 83 maxY := float64(dr.Max.Y) 84 mvp := calcMVP( 85 t.size.X, t.size.Y, 86 minX, minY, 87 maxX, minY, 88 minX, maxY, 89 ) 90 91 glctx := t.w.glctx 92 93 t.w.glctxMu.Lock() 94 defer t.w.glctxMu.Unlock() 95 96 create := t.fb.Value == 0 97 if create { 98 //t.fb = glctx.CreateFramebuffer() 99 } 100 glctx.BindFramebuffer(gl.FRAMEBUFFER, t.fb) 101 if create { 102 glctx.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, t.id, 0) 103 } 104 105 glctx.Viewport(0, 0, t.size.X, t.size.Y) 106 doFill(t.w.s, t.w.glctx, mvp, src, op) 107 108 // We can't restore the GL state (i.e. bind the back buffer, also known as 109 // gl.Framebuffer{Value: 0}) right away, since we don't necessarily know 110 // the right viewport size yet. It is valid to call textureImpl.Fill before 111 // we've gotten our first size.Event. We bind it lazily instead. 112 //t.w.backBufferBound = false 113 } 114 115 var quadCoords = f32Bytes(binary.LittleEndian, 116 0, 0, // top left 117 1, 0, // top right 118 0, 1, // bottom left 119 1, 1, // bottom right 120 ) 121 122 const textureVertexSrc = `#version 100 123 uniform mat3 mvp; 124 uniform mat3 uvp; 125 attribute vec3 pos; 126 attribute vec2 inUV; 127 varying vec2 uv; 128 void main() { 129 vec3 p = pos; 130 p.z = 1.0; 131 gl_Position = vec4(mvp * p, 1); 132 uv = (uvp * vec3(inUV, 1)).xy; 133 } 134 ` 135 136 const textureFragmentSrc = `#version 100 137 precision mediump float; 138 varying vec2 uv; 139 uniform sampler2D sample; 140 void main() { 141 gl_FragColor = texture2D(sample, uv); 142 } 143 ` 144 145 const fillVertexSrc = `#version 100 146 uniform mat3 mvp; 147 attribute vec3 pos; 148 void main() { 149 vec3 p = pos; 150 p.z = 1.0; 151 gl_Position = vec4(mvp * p, 1); 152 } 153 ` 154 155 const fillFragmentSrc = `#version 100 156 precision mediump float; 157 uniform vec4 color; 158 void main() { 159 gl_FragColor = color; 160 } 161 `