xref: /expo/apps/test-suite/tests/GLView.js (revision bb8f4f99)
1'use strict';
2import { Platform } from '@unimodules/core';
3import { Asset } from 'expo-asset';
4import { GLView } from 'expo-gl';
5import React from 'react';
6
7import { mountAndWaitFor } from './helpers';
8
9export const name = 'GLView';
10const style = { width: 200, height: 200 };
11
12export async function test(
13  { it, describe, beforeAll, jasmine, afterAll, expect, afterEach, beforeEach },
14  { setPortalChild, cleanupPortal }
15) {
16  let instance = null;
17  let originalTimeout;
18
19  const refSetter = ref => {
20    instance = ref;
21  };
22
23  beforeAll(async () => {
24    originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
25    jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout * 3;
26  });
27
28  afterAll(() => {
29    jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
30  });
31
32  afterEach(async () => {
33    instance = null;
34    await cleanupPortal();
35  });
36
37  function getContextAsync() {
38    return new Promise(async resolve => {
39      await mountAndWaitFor(
40        <GLView onContextCreate={context => resolve(context)} ref={refSetter} style={style} />,
41        'onContextCreate',
42        setPortalChild
43      );
44    });
45  }
46
47  describe('GLView', () => {
48    it('gets a valid context', async () => {
49      const context = await getContextAsync();
50      expect(context instanceof WebGLRenderingContext).toBe(true);
51    });
52
53    it('takes a snapshot', async () => {
54      await getContextAsync();
55
56      const snapshot = await instance.takeSnapshotAsync({ format: 'png' });
57      expect(snapshot).toBeDefined();
58      if (Platform.OS === 'web') {
59        expect(snapshot.uri instanceof Blob).toBe(true);
60      } else {
61        expect(snapshot.uri).toMatch(/^file:\/\//);
62        expect(snapshot.localUri).toMatch(/^file:\/\//);
63      }
64    });
65
66    describe('context', () => {
67      const vertexShader = `
68        precision highp float;
69        attribute vec2 position;
70        varying vec2 uv;
71        void main () {
72          uv = position;
73          gl_Position = vec4(1.0 - 2.0 * position, 0, 1);
74        }`;
75      const fragShader = `
76        precision highp float;
77    uniform sampler2D texture;
78    varying vec2 uv;
79    void main () {
80      gl_FragColor = texture2D(texture, vec2(uv.x, uv.y));
81    }
82        `;
83      it('has Expo methods', async () => {
84        const context = await getContextAsync();
85        expect(typeof context.endFrameEXP).toBe('function');
86      });
87      it('clears to blue without throwing', async () => {
88        const gl = await getContextAsync();
89        gl.clearColor(0, 0, 1, 1);
90        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
91        gl.endFrameEXP();
92      });
93
94      it(`draws a texture`, async () => {
95        const gl = await getContextAsync();
96
97        const vert = gl.createShader(gl.VERTEX_SHADER);
98        gl.shaderSource(vert, vertexShader);
99        gl.compileShader(vert);
100        const frag = gl.createShader(gl.FRAGMENT_SHADER);
101        gl.shaderSource(frag, fragShader);
102        gl.compileShader(frag);
103
104        const program = gl.createProgram();
105        gl.attachShader(program, vert);
106        gl.attachShader(program, frag);
107        gl.linkProgram(program);
108        gl.useProgram(program);
109
110        const buffer = gl.createBuffer();
111        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
112        const verts = new Float32Array([-2, 0, 0, -2, 2, 2]);
113        gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
114        const positionAttrib = gl.getAttribLocation(program, 'position');
115        gl.enableVertexAttribArray(positionAttrib);
116        gl.vertexAttribPointer(positionAttrib, 2, gl.FLOAT, false, 0, 0);
117
118        const asset = Asset.fromModule(require('../assets/qrcode_expo.jpg'));
119        await asset.downloadAsync();
120        const texture = gl.createTexture();
121        gl.activeTexture(gl.TEXTURE0);
122        gl.bindTexture(gl.TEXTURE_2D, texture);
123        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
124        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
125        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, asset);
126        gl.uniform1i(gl.getUniformLocation(program, 'texture'), 0);
127
128        gl.clearColor(0, 0, 1, 1);
129        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
130        gl.drawArrays(gl.TRIANGLES, 0, verts.length / 2);
131        gl.endFrameEXP();
132      });
133
134      it(`draws a texture with a TypedArray`, async () => {
135        const gl = await getContextAsync();
136
137        const vert = gl.createShader(gl.VERTEX_SHADER);
138        gl.shaderSource(vert, vertexShader);
139
140        gl.compileShader(vert);
141        const frag = gl.createShader(gl.FRAGMENT_SHADER);
142        gl.shaderSource(frag, fragShader);
143        gl.compileShader(frag);
144
145        const program = gl.createProgram();
146        gl.attachShader(program, vert);
147        gl.attachShader(program, frag);
148        gl.linkProgram(program);
149        gl.useProgram(program);
150
151        const buffer = gl.createBuffer();
152        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
153        const verts = new Float32Array([-2, 0, 0, -2, 2, 2]);
154        gl.bufferData(gl.ARRAY_BUFFER, verts, gl.STATIC_DRAW);
155        const positionAttrib = gl.getAttribLocation(program, 'position');
156        gl.enableVertexAttribArray(positionAttrib);
157        gl.vertexAttribPointer(positionAttrib, 2, gl.FLOAT, false, 0, 0);
158
159        const texture = gl.createTexture();
160        gl.activeTexture(gl.TEXTURE0);
161        gl.bindTexture(gl.TEXTURE_2D, texture);
162        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
163        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
164
165        // Use below to test using a `TypedArray` parameter
166        gl.texSubImage2D(
167          gl.TEXTURE_2D,
168          0,
169          32,
170          32,
171          2,
172          2,
173          gl.RGBA,
174          gl.UNSIGNED_BYTE,
175          new Uint8Array([255, 0, 0, 255, 0, 255, 0, 255, 0, 0, 255, 255, 128, 128, 0, 255])
176        );
177
178        gl.uniform1i(gl.getUniformLocation(program, 'texture'), 0);
179
180        gl.clearColor(0, 0, 1, 1);
181        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
182        gl.drawArrays(gl.TRIANGLES, 0, verts.length / 2);
183        gl.endFrameEXP();
184      });
185    });
186
187    describe('static', () => {
188      it('creates a static context', async () => {
189        const context = await GLView.createContextAsync();
190        expect(context instanceof WebGLRenderingContext).toBe(true);
191      });
192
193      it('takes a snapshot', async () => {
194        const context = await getContextAsync();
195
196        const snapshot = await GLView.takeSnapshotAsync(context, { format: 'png' });
197        expect(snapshot).toBeDefined();
198
199        if (Platform.OS === 'web') {
200          expect(snapshot.uri instanceof Blob).toBe(true);
201        } else {
202          expect(snapshot.uri).toMatch(/^file:\/\//);
203          expect(snapshot.localUri).toMatch(/^file:\/\//);
204        }
205      });
206    });
207  });
208}
209