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  `