twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

texture.go (3798B)


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