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