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