1import * as GL from 'expo-gl'; 2import mat4 from 'gl-mat4'; 3import hsv2rgb from 'hsv2rgb'; 4import React from 'react'; 5import { ActivityIndicator, InteractionManager, StyleSheet, View } from 'react-native'; 6import REGL from 'regl'; 7 8const NUM_POINTS = 1e4; 9const VERT_SIZE = 4 * (4 + 4 + 3); 10 11export default class BasicScene extends React.Component { 12 static title = 'GLView example'; 13 static navigationOptions = { 14 title: 'GLView example', 15 }; 16 17 state = { 18 transitionIsComplete: false, 19 }; 20 21 componentDidMount() { 22 InteractionManager.runAfterInteractions(() => { 23 this.setState({ transitionIsComplete: true }); 24 }); 25 } 26 27 render() { 28 if (!this.state.transitionIsComplete) { 29 return ( 30 <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> 31 <ActivityIndicator /> 32 </View> 33 ); 34 } 35 36 return <GL.GLView style={StyleSheet.absoluteFill} onContextCreate={this._onContextCreate} />; 37 } 38 39 _onContextCreate = (gl: GL.ExpoWebGLRenderingContext) => { 40 const regl = REGL({ gl }); 41 42 const pointBuffer = regl.buffer( 43 Array(NUM_POINTS) 44 .fill(0) 45 .map(() => { 46 const color = hsv2rgb(Math.random() * 360, 0.6, 1); 47 return [ 48 // freq 49 Math.random() * 10, 50 Math.random() * 10, 51 Math.random() * 10, 52 Math.random() * 10, 53 // phase 54 2.0 * Math.PI * Math.random(), 55 2.0 * Math.PI * Math.random(), 56 2.0 * Math.PI * Math.random(), 57 2.0 * Math.PI * Math.random(), 58 // color 59 color[0] / 255, 60 color[1] / 255, 61 color[2] / 255, 62 ]; 63 }) 64 ); 65 66 const drawParticles = regl({ 67 vert: ` 68 precision highp float; 69 attribute vec4 freq, phase; 70 attribute vec3 color; 71 uniform float time; 72 uniform mat4 view, projection; 73 varying vec3 fragColor; 74 void main() { 75 vec3 position = 8.0 * cos(freq.xyz * time + phase.xyz); 76 gl_PointSize = 10.0 * (1.0 + cos(freq.w * time + phase.w)); 77 gl_Position = projection * view * vec4(position, 1); 78 fragColor = color; 79 }`, 80 81 frag: ` 82 precision lowp float; 83 varying vec3 fragColor; 84 void main() { 85 if (length(gl_PointCoord.xy - 0.5) > 0.5) { 86 discard; 87 } 88 gl_FragColor = vec4(fragColor, 1); 89 }`, 90 91 attributes: { 92 freq: { 93 buffer: pointBuffer, 94 stride: VERT_SIZE, 95 offset: 0, 96 }, 97 phase: { 98 buffer: pointBuffer, 99 stride: VERT_SIZE, 100 offset: 16, 101 }, 102 color: { 103 buffer: pointBuffer, 104 stride: VERT_SIZE, 105 offset: 32, 106 }, 107 }, 108 109 uniforms: { 110 view: ({ time: t }: { time: number }) => { 111 t = t * 0.1; 112 return mat4.lookAt([], [30 * Math.cos(t), 2.5, 30 * Math.sin(t)], [0, 0, 0], [0, 1, 0]); 113 }, 114 projection: mat4.perspective( 115 [], 116 Math.PI / 4, 117 gl.drawingBufferWidth / gl.drawingBufferHeight, 118 0.01, 119 1000 120 ), 121 time: ({ time }: { time: number }) => time * 0.1, 122 }, 123 124 count: NUM_POINTS, 125 126 primitive: 'points', 127 }); 128 129 const frame = () => { 130 regl.poll(); 131 regl.clear({ 132 color: [0, 0, 0, 1], 133 depth: 1, 134 }); 135 136 drawParticles(); 137 138 gl.flush(); 139 gl.endFrameEXP(); 140 requestAnimationFrame(frame); 141 }; 142 frame(); 143 }; 144} 145