1import MaskedView from '@react-native-masked-view/masked-view';
2import * as GL from 'expo-gl';
3import React from 'react';
4import { Text, View } from 'react-native';
5
6const vertSrc = `
7attribute vec2 position;
8varying vec2 uv;
9void main() {
10  gl_Position = vec4(position.x, -position.y, 0.0, 1.0);
11  uv = vec2(0.5, 0.5) * (position+vec2(1.0, 1.0));
12}`;
13
14const fragSrc = `
15precision highp float;
16varying vec2 uv;
17void main () {
18  gl_FragColor = vec4(uv.x, uv.y, 0.5, 1.0);
19}`;
20
21interface Props {
22  speed?: number;
23}
24
25export default class GLMaskScreen extends React.Component<Props> {
26  static title = 'MaskedView integration';
27
28  static navigationOptions = {
29    title: 'Mask GLView Example',
30  };
31
32  render() {
33    return (
34      <MaskedView
35        style={{ flex: 1 }}
36        maskElement={
37          <View
38            style={{
39              flex: 1,
40              backgroundColor: 'transparent',
41              justifyContent: 'center',
42            }}>
43            <Text
44              style={{
45                color: 'black',
46                fontSize: 40,
47                fontWeight: 'bold',
48                alignSelf: 'center',
49                backgroundColor: 'transparent',
50              }}>
51              GL IS COOL
52            </Text>
53          </View>
54        }>
55        <GL.GLView style={{ flex: 1 }} onContextCreate={this._onContextCreate} />
56      </MaskedView>
57    );
58  }
59
60  _onContextCreate = (gl: GL.ExpoWebGLRenderingContext) => {
61    // Compile vertex and fragment shader
62    const vert = gl.createShader(gl.VERTEX_SHADER)!;
63    gl.shaderSource(vert, vertSrc);
64    gl.compileShader(vert);
65    const frag = gl.createShader(gl.FRAGMENT_SHADER)!;
66    gl.shaderSource(frag, fragSrc);
67    gl.compileShader(frag);
68
69    // Link together into a program
70    const program = gl.createProgram()!;
71    gl.attachShader(program, vert);
72    gl.attachShader(program, frag);
73    gl.linkProgram(program);
74
75    // Save position attribute
76    const positionAttrib = gl.getAttribLocation(program, 'position');
77
78    // Create buffer
79    const buffer = gl.createBuffer();
80
81    // Animate!
82    let skip = false;
83    const animate = () => {
84      try {
85        if (skip) {
86          // return;
87        }
88
89        // Clear
90        gl.clearColor(0, 0, 1, 1);
91        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
92
93        // Bind buffer, program and position attribute for use
94        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
95        gl.useProgram(program);
96        gl.enableVertexAttribArray(positionAttrib);
97        gl.vertexAttribPointer(positionAttrib, 2, gl.FLOAT, false, 0, 0);
98
99        // Buffer data and draw!
100        const speed = this.props.speed || 1;
101        const a = 0.48 * Math.sin(0.001 * speed * Date.now()) + 0.5;
102        // prettier-ignore
103        const verts = new Float32Array([
104          -a, -a,  a, -a,
105          -a,  a, -a,  a,
106           a, -a,  a,  a,
107         ]);
108        gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
109        gl.drawArrays(gl.TRIANGLES, 0, verts.length / 2);
110
111        // Submit frame
112        gl.flush();
113        gl.endFrameEXP();
114      } finally {
115        skip = !skip;
116        requestAnimationFrame(animate);
117      }
118    };
119    animate();
120  };
121}
122