1 | import { NativeModulesProxy, UnavailabilityError, requireNativeViewManager, CodedError, } from '@unimodules/core';
|
2 | import * as React from 'react';
|
3 | import { Platform, View, findNodeHandle } from 'react-native';
|
4 | import { configureLogging } from './GLUtils';
|
5 | const packageJSON = require('../package.json');
|
6 | const { ExponentGLObjectManager, ExponentGLViewManager } = NativeModulesProxy;
|
7 | const NativeView = requireNativeViewManager('ExponentGLView');
|
8 |
|
9 |
|
10 |
|
11 | export class GLView extends React.Component {
|
12 | constructor() {
|
13 | super(...arguments);
|
14 | this.nativeRef = null;
|
15 | this._setNativeRef = (nativeRef) => {
|
16 | if (this.props.nativeRef_EXPERIMENTAL) {
|
17 | this.props.nativeRef_EXPERIMENTAL(nativeRef);
|
18 | }
|
19 | this.nativeRef = nativeRef;
|
20 | };
|
21 | this._onSurfaceCreate = ({ nativeEvent: { exglCtxId } }) => {
|
22 | const gl = getGl(exglCtxId);
|
23 | this.exglCtxId = exglCtxId;
|
24 | if (this.props.onContextCreate) {
|
25 | this.props.onContextCreate(gl);
|
26 | }
|
27 | };
|
28 | }
|
29 | static async createContextAsync() {
|
30 | const { exglCtxId } = await ExponentGLObjectManager.createContextAsync();
|
31 | return getGl(exglCtxId);
|
32 | }
|
33 | static async destroyContextAsync(exgl) {
|
34 | const exglCtxId = getContextId(exgl);
|
35 | return ExponentGLObjectManager.destroyContextAsync(exglCtxId);
|
36 | }
|
37 | static async takeSnapshotAsync(exgl, options = {}) {
|
38 | const exglCtxId = getContextId(exgl);
|
39 | return ExponentGLObjectManager.takeSnapshotAsync(exglCtxId, options);
|
40 | }
|
41 | render() {
|
42 | const { onContextCreate,
|
43 | msaaSamples, ...viewProps } = this.props;
|
44 | return (React.createElement(View, Object.assign({}, viewProps),
|
45 | React.createElement(NativeView, { ref: this._setNativeRef, style: {
|
46 | flex: 1,
|
47 | ...(Platform.OS === 'ios'
|
48 | ? {
|
49 | backgroundColor: 'transparent',
|
50 | }
|
51 | : {}),
|
52 | }, onSurfaceCreate: this._onSurfaceCreate, msaaSamples: Platform.OS === 'ios' ? msaaSamples : undefined })));
|
53 | }
|
54 | async startARSessionAsync() {
|
55 | if (!ExponentGLViewManager.startARSessionAsync) {
|
56 | throw new UnavailabilityError('expo-gl', 'startARSessionAsync');
|
57 | }
|
58 | return await ExponentGLViewManager.startARSessionAsync(findNodeHandle(this.nativeRef));
|
59 | }
|
60 | async createCameraTextureAsync(cameraRefOrHandle) {
|
61 | if (!ExponentGLObjectManager.createCameraTextureAsync) {
|
62 | throw new UnavailabilityError('expo-gl', 'createCameraTextureAsync');
|
63 | }
|
64 | const { exglCtxId } = this;
|
65 | if (!exglCtxId) {
|
66 | throw new Error("GLView's surface is not created yet!");
|
67 | }
|
68 | const cameraTag = findNodeHandle(cameraRefOrHandle);
|
69 | const { exglObjId } = await ExponentGLObjectManager.createCameraTextureAsync(exglCtxId, cameraTag);
|
70 | return new WebGLTexture(exglObjId);
|
71 | }
|
72 | async destroyObjectAsync(glObject) {
|
73 | if (!ExponentGLObjectManager.destroyObjectAsync) {
|
74 | throw new UnavailabilityError('expo-gl', 'destroyObjectAsync');
|
75 | }
|
76 | return await ExponentGLObjectManager.destroyObjectAsync(glObject.id);
|
77 | }
|
78 | async takeSnapshotAsync(options = {}) {
|
79 | if (!GLView.takeSnapshotAsync) {
|
80 | throw new UnavailabilityError('expo-gl', 'takeSnapshotAsync');
|
81 | }
|
82 | const { exglCtxId } = this;
|
83 | return await GLView.takeSnapshotAsync(exglCtxId, options);
|
84 | }
|
85 | }
|
86 | GLView.defaultProps = {
|
87 | msaaSamples: 4,
|
88 | };
|
89 | GLView.NativeView = NativeView;
|
90 |
|
91 | class WebGLRenderingContext {
|
92 | }
|
93 | class WebGL2RenderingContext extends WebGLRenderingContext {
|
94 | }
|
95 | const idToObject = {};
|
96 | export class WebGLObject {
|
97 | constructor(id) {
|
98 | if (idToObject[id]) {
|
99 | throw new Error(`WebGL object with underlying EXGLObjectId '${id}' already exists!`);
|
100 | }
|
101 | this.id = id;
|
102 | }
|
103 | toString() {
|
104 | return `[${this.constructor.name} ${this.id}]`;
|
105 | }
|
106 | }
|
107 | const wrapObject = (type, id) => {
|
108 | const found = idToObject[id];
|
109 | if (found) {
|
110 | return found;
|
111 | }
|
112 | return (idToObject[id] = new type(id));
|
113 | };
|
114 | const objectId = (obj) => obj && obj.id;
|
115 | class WebGLBuffer extends WebGLObject {
|
116 | }
|
117 | class WebGLFramebuffer extends WebGLObject {
|
118 | }
|
119 | class WebGLProgram extends WebGLObject {
|
120 | }
|
121 | class WebGLRenderbuffer extends WebGLObject {
|
122 | }
|
123 | class WebGLShader extends WebGLObject {
|
124 | }
|
125 | class WebGLTexture extends WebGLObject {
|
126 | }
|
127 | class WebGLUniformLocation {
|
128 | constructor(id) {
|
129 | this.id = id;
|
130 | }
|
131 | toString() {
|
132 | return `[${this.constructor.name} ${this.id}]`;
|
133 | }
|
134 | }
|
135 | class WebGLActiveInfo {
|
136 | constructor(obj) {
|
137 | Object.assign(this, obj);
|
138 | }
|
139 | toString() {
|
140 | return `[${this.constructor.name} ${JSON.stringify(this)}]`;
|
141 | }
|
142 | }
|
143 | class WebGLShaderPrecisionFormat {
|
144 | constructor(obj) {
|
145 | Object.assign(this, obj);
|
146 | }
|
147 | toString() {
|
148 | return `[${this.constructor.name} ${JSON.stringify(this)}]`;
|
149 | }
|
150 | }
|
151 |
|
152 | class WebGLQuery extends WebGLObject {
|
153 | }
|
154 | class WebGLSampler extends WebGLObject {
|
155 | }
|
156 | class WebGLSync extends WebGLObject {
|
157 | }
|
158 | class WebGLTransformFeedback extends WebGLObject {
|
159 | }
|
160 | class WebGLVertexArrayObject extends WebGLObject {
|
161 | }
|
162 |
|
163 |
|
164 | const wrapMethods = gl => {
|
165 | const wrap = (methodNames, wrapper) => (Array.isArray(methodNames) ? methodNames : [methodNames]).forEach(methodName => (gl[methodName] = wrapper(gl[methodName])));
|
166 |
|
167 | const getParameterTypes = {
|
168 | [gl.ARRAY_BUFFER_BINDING]: WebGLBuffer,
|
169 | [gl.COPY_READ_BUFFER_BINDING]: WebGLBuffer,
|
170 | [gl.COPY_WRITE_BUFFER_BINDING]: WebGLBuffer,
|
171 | [gl.CURRENT_PROGRAM]: WebGLProgram,
|
172 | [gl.DRAW_FRAMEBUFFER_BINDING]: WebGLFramebuffer,
|
173 | [gl.ELEMENT_ARRAY_BUFFER_BINDING]: WebGLBuffer,
|
174 | [gl.READ_FRAMEBUFFER_BINDING]: WebGLFramebuffer,
|
175 | [gl.RENDERBUFFER_BINDING]: WebGLRenderbuffer,
|
176 | [gl.SAMPLER_BINDING]: WebGLSampler,
|
177 | [gl.TEXTURE_BINDING_2D_ARRAY]: WebGLTexture,
|
178 | [gl.TEXTURE_BINDING_2D]: WebGLTexture,
|
179 | [gl.TEXTURE_BINDING_3D]: WebGLTexture,
|
180 | [gl.TEXTURE_BINDING_CUBE_MAP]: WebGLTexture,
|
181 | [gl.TRANSFORM_FEEDBACK_BINDING]: WebGLTransformFeedback,
|
182 | [gl.TRANSFORM_FEEDBACK_BUFFER_BINDING]: WebGLBuffer,
|
183 | [gl.UNIFORM_BUFFER_BINDING]: WebGLBuffer,
|
184 | [gl.VERTEX_ARRAY_BINDING]: WebGLVertexArrayObject,
|
185 | };
|
186 | wrap('getParameter', orig => pname => {
|
187 | let ret = orig.call(gl, pname);
|
188 | if (pname === gl.VERSION) {
|
189 |
|
190 | ret = `WebGL 2.0 (Expo-${Platform.OS}-${packageJSON.version}) (${ret})`;
|
191 | }
|
192 | const type = getParameterTypes[pname];
|
193 | return type ? wrapObject(type, ret) : ret;
|
194 | });
|
195 |
|
196 | wrap('bindBuffer', orig => (target, buffer) => orig.call(gl, target, buffer && buffer.id));
|
197 | wrap('createBuffer', orig => () => wrapObject(WebGLBuffer, orig.call(gl)));
|
198 | wrap('deleteBuffer', orig => buffer => orig.call(gl, buffer && buffer.id));
|
199 | wrap('isBuffer', orig => buffer => buffer instanceof WebGLBuffer && orig.call(gl, buffer.id));
|
200 |
|
201 | wrap('bindFramebuffer', orig => (target, framebuffer) => orig.call(gl, target, framebuffer && framebuffer.id));
|
202 | wrap('createFramebuffer', orig => () => wrapObject(WebGLFramebuffer, orig.call(gl)));
|
203 | wrap('deleteFramebuffer', orig => framebuffer => orig.call(gl, framebuffer && framebuffer.id));
|
204 | wrap('framebufferRenderbuffer', orig => (target, attachment, rbtarget, rb) => orig.call(gl, target, attachment, rbtarget, rb && rb.id));
|
205 | wrap('framebufferTexture2D', orig => (target, attachment, textarget, tex, level) => orig.call(gl, target, attachment, textarget, tex && tex.id, level));
|
206 | wrap('isFramebuffer', orig => framebuffer => framebuffer instanceof WebGLFramebuffer && orig.call(gl, framebuffer.id));
|
207 | wrap('framebufferTextureLayer', orig => (target, attachment, texture, level, layer) => {
|
208 | return orig.call(gl, target, attachment, objectId(texture), level, layer);
|
209 | });
|
210 |
|
211 | wrap('bindRenderbuffer', orig => (target, renderbuffer) => orig.call(gl, target, renderbuffer && renderbuffer.id));
|
212 | wrap('createRenderbuffer', orig => () => wrapObject(WebGLRenderbuffer, orig.call(gl)));
|
213 | wrap('deleteRenderbuffer', orig => renderbuffer => orig.call(gl, renderbuffer && renderbuffer.id));
|
214 | wrap('isRenderbuffer', orig => renderbuffer => renderbuffer instanceof WebGLRenderbuffer && orig.call(gl, renderbuffer.id));
|
215 |
|
216 | wrap('bindTexture', orig => (target, texture) => orig.call(gl, target, texture && texture.id));
|
217 | wrap('createTexture', orig => () => wrapObject(WebGLTexture, orig.call(gl)));
|
218 | wrap('deleteTexture', orig => texture => orig.call(gl, texture && texture.id));
|
219 | wrap('isTexture', orig => texture => texture instanceof WebGLTexture && orig.call(gl, texture.id));
|
220 |
|
221 | wrap('attachShader', orig => (program, shader) => orig.call(gl, program && program.id, shader && shader.id));
|
222 | wrap('bindAttribLocation', orig => (program, index, name) => orig.call(gl, program && program.id, index, name));
|
223 | wrap('compileShader', orig => shader => orig.call(gl, shader && shader.id));
|
224 | wrap('createProgram', orig => () => wrapObject(WebGLProgram, orig.call(gl)));
|
225 | wrap('createShader', orig => type => wrapObject(WebGLShader, orig.call(gl, type)));
|
226 | wrap('deleteProgram', orig => program => orig.call(gl, program && program.id));
|
227 | wrap('deleteShader', orig => shader => orig.call(gl, shader && shader.id));
|
228 | wrap('detachShader', orig => (program, shader) => orig.call(gl, program && program.id, shader && shader.id));
|
229 | wrap('getAttachedShaders', orig => program => orig.call(gl, program && program.id).map(id => wrapObject(WebGLShader, id)));
|
230 | wrap('getProgramParameter', orig => (program, pname) => orig.call(gl, program && program.id, pname));
|
231 | wrap('getProgramInfoLog', orig => program => orig.call(gl, program && program.id));
|
232 | wrap('getShaderParameter', orig => (shader, pname) => orig.call(gl, shader && shader.id, pname));
|
233 | wrap('getShaderPrecisionFormat', orig => (shadertype, precisiontype) => new WebGLShaderPrecisionFormat(orig.call(gl, shadertype, precisiontype)));
|
234 | wrap('getShaderInfoLog', orig => shader => orig.call(gl, shader && shader.id));
|
235 | wrap('getShaderSource', orig => shader => orig.call(gl, shader && shader.id));
|
236 | wrap('linkProgram', orig => program => orig.call(gl, program && program.id));
|
237 | wrap('shaderSource', orig => (shader, source) => orig.call(gl, shader && shader.id, source));
|
238 | wrap('useProgram', orig => program => orig.call(gl, program && program.id));
|
239 | wrap('validateProgram', orig => program => orig.call(gl, program && program.id));
|
240 | wrap('isShader', orig => shader => shader instanceof WebGLShader && orig.call(gl, shader.id));
|
241 | wrap('isProgram', orig => program => program instanceof WebGLProgram && orig.call(gl, program.id));
|
242 | wrap('getFragDataLocation', orig => program => orig.call(gl, objectId(program)));
|
243 |
|
244 | wrap('getActiveAttrib', orig => (program, index) => new WebGLActiveInfo(orig.call(gl, program && program.id, index)));
|
245 | wrap('getActiveUniform', orig => (program, index) => new WebGLActiveInfo(orig.call(gl, program && program.id, index)));
|
246 | wrap('getAttribLocation', orig => (program, name) => orig.call(gl, program && program.id, name));
|
247 | wrap('getUniform', orig => (program, location) => orig.call(gl, program && program.id, location && location.id));
|
248 | wrap('getUniformLocation', orig => (program, name) => new WebGLUniformLocation(orig.call(gl, program && program.id, name)));
|
249 | wrap(['uniform1f', 'uniform1i', 'uniform1ui'], orig => (loc, x) => orig.call(gl, objectId(loc), x));
|
250 | wrap(['uniform2f', 'uniform2i', 'uniform2ui'], orig => (loc, x, y) => orig.call(gl, objectId(loc), x, y));
|
251 | wrap(['uniform3f', 'uniform3i', 'uniform3ui'], orig => (loc, x, y, z) => orig.call(gl, objectId(loc), x, y, z));
|
252 | wrap(['uniform4f', 'uniform4i', 'uniform4ui'], orig => (loc, x, y, z, w) => orig.call(gl, objectId(loc), x, y, z, w));
|
253 | wrap(['uniform1fv', 'uniform2fv', 'uniform3fv', 'uniform4fv'], orig => (loc, val) => orig.call(gl, objectId(loc), new Float32Array(val)));
|
254 | wrap(['uniform1iv', 'uniform2iv', 'uniform3iv', 'uniform4iv'], orig => (loc, val) => orig.call(gl, objectId(loc), new Int32Array(val)));
|
255 | wrap(['uniform1uiv', 'uniform2uiv', 'uniform3uiv', 'uniform4uiv'], orig => (loc, val) => orig.call(gl, objectId(loc), new Uint32Array(val)));
|
256 | wrap([
|
257 | 'uniformMatrix2fv',
|
258 | 'uniformMatrix3fv',
|
259 | 'uniformMatrix4fv',
|
260 | 'uniformMatrix3x2fv',
|
261 | 'uniformMatrix4x2fv',
|
262 | 'uniformMatrix2x3fv',
|
263 | 'uniformMatrix4x3fv',
|
264 | 'uniformMatrix2x4fv',
|
265 | 'uniformMatrix3x4fv',
|
266 | ], orig => (loc, transpose, val) => orig.call(gl, loc && loc.id, transpose, new Float32Array(val)));
|
267 | wrap(['vertexAttrib1fv', 'vertexAttrib2fv', 'vertexAttrib3fv', 'vertexAttrib4fv'], orig => (index, val) => orig.call(gl, index, new Float32Array(val)));
|
268 | wrap('vertexAttribI4iv', orig => (index, val) => orig.call(gl, index, new Int32Array(val)));
|
269 | wrap('vertexAttribI4uiv', orig => (index, val) => orig.call(gl, index, new Uint32Array(val)));
|
270 |
|
271 | wrap('createQuery', orig => () => wrapObject(WebGLQuery, orig.call(gl)));
|
272 | wrap('deleteQuery', orig => query => orig.call(gl, objectId(query)));
|
273 | wrap('beginQuery', orig => (target, query) => orig.call(gl, target, objectId(query)));
|
274 | wrap('getQuery', orig => (target, pname) => {
|
275 | const id = orig.call(gl, target, pname);
|
276 | return id ? wrapObject(WebGLQuery, id) : id;
|
277 | });
|
278 | wrap('getQueryParameter', orig => (query, pname) => orig.call(gl, objectId(query), pname));
|
279 |
|
280 | wrap('bindSampler', orig => (unit, sampler) => orig.call(gl, unit, objectId(sampler)));
|
281 | wrap('createSampler', orig => () => wrapObject(WebGLSampler, orig.call(gl)));
|
282 | wrap('deleteSampler', orig => sampler => orig.call(gl, objectId(sampler)));
|
283 | wrap('isSampler', orig => sampler => sampler instanceof WebGLSampler && orig.call(gl, sampler.id));
|
284 | wrap(['samplerParameteri', 'samplerParameterf'], orig => (sampler, pname, param) => {
|
285 | return orig.call(gl, objectId(sampler), pname, param);
|
286 | });
|
287 | wrap('getSamplerParameter', orig => (sampler, pname) => {
|
288 | return orig.call(gl, objectId(sampler), pname);
|
289 | });
|
290 |
|
291 | wrap('bindTransformFeedback', orig => (target, transformFeedback) => {
|
292 | return orig.call(gl, target, objectId(transformFeedback));
|
293 | });
|
294 | wrap('createTransformFeedback', orig => () => wrapObject(WebGLTransformFeedback, orig.call(gl)));
|
295 | wrap('deleteTransformFeedback', orig => transformFeedback => {
|
296 | return orig.call(gl, objectId(transformFeedback));
|
297 | });
|
298 | wrap('transformFeedbackVaryings', orig => (program, varyings, bufferMode) => {
|
299 | return orig.call(gl, objectId(program), varyings, bufferMode);
|
300 | });
|
301 | wrap('getTransformFeedbackVarying', orig => (program, index) => {
|
302 | return new WebGLActiveInfo(orig.call(gl, objectId(program), index));
|
303 | });
|
304 |
|
305 | wrap(['bindBufferBase', 'bindBufferRange'], orig => (target, index, buffer, ...rest) => {
|
306 | return orig.call(gl, target, index, objectId(buffer), ...rest);
|
307 | });
|
308 | wrap('getUniformIndices', orig => (program, uniformNames) => {
|
309 |
|
310 | const uintArray = orig.call(gl, objectId(program), uniformNames);
|
311 | return Array.from(uintArray);
|
312 | });
|
313 | wrap('getActiveUniforms', orig => (program, uniformIndices, pname) => {
|
314 |
|
315 | const intArray = orig.call(gl, objectId(program), new Uint32Array(uniformIndices), pname);
|
316 | const boolResult = pname === gl.UNIFORM_IS_ROW_MAJOR;
|
317 | const arr = Array.from(intArray);
|
318 | return boolResult ? arr.map(val => !!val) : arr;
|
319 | });
|
320 | wrap('getUniformBlockIndex', orig => (program, uniformBlockName) => orig.call(gl, objectId(program), uniformBlockName));
|
321 | wrap('getActiveUniformBlockName', orig => (program, uniformBlockIndex) => orig.call(gl, objectId(program), uniformBlockIndex));
|
322 | wrap('uniformBlockBinding', orig => (program, uniformBlockIndex, uniformBlockBinding) => {
|
323 | return orig.call(gl, objectId(program), uniformBlockIndex, uniformBlockBinding);
|
324 | });
|
325 |
|
326 | wrap('bindVertexArray', orig => vertexArray => orig.call(gl, vertexArray && vertexArray.id));
|
327 | wrap('createVertexArray', orig => () => wrapObject(WebGLVertexArrayObject, orig.call(gl)));
|
328 | wrap('deleteVertexArray', orig => vertexArray => orig.call(gl, vertexArray && vertexArray.id));
|
329 | wrap('isVertexArray', orig => vertexArray => vertexArray instanceof WebGLVertexArrayObject && orig.call(gl, vertexArray.id));
|
330 | };
|
331 |
|
332 | const getGl = (exglCtxId) => {
|
333 | if (!global.__EXGLContexts) {
|
334 | throw new CodedError('ERR_GL_NOT_AVAILABLE', 'GL is currently not available. (Have you enabled remote debugging? GL is not available while debugging remotely.)');
|
335 | }
|
336 | const gl = global.__EXGLContexts[exglCtxId];
|
337 | gl.__exglCtxId = exglCtxId;
|
338 | delete global.__EXGLContexts[exglCtxId];
|
339 |
|
340 | const glesVersion = gl.getParameter(gl.VERSION);
|
341 | const supportsWebGL2 = parseFloat(glesVersion.split(/[^\d.]+/g).join(' ')) >= 3.0;
|
342 | const prototype = supportsWebGL2
|
343 | ? global.WebGL2RenderingContext.prototype
|
344 | : global.WebGLRenderingContext.prototype;
|
345 | if (Object.setPrototypeOf) {
|
346 | Object.setPrototypeOf(gl, prototype);
|
347 | }
|
348 | else {
|
349 |
|
350 |
|
351 | gl.__proto__ = prototype;
|
352 | }
|
353 | wrapMethods(gl);
|
354 |
|
355 | gl.canvas = null;
|
356 |
|
357 |
|
358 | const viewport = gl.getParameter(gl.VIEWPORT);
|
359 | gl.drawingBufferWidth = viewport[2];
|
360 | gl.drawingBufferHeight = viewport[3];
|
361 | configureLogging(gl);
|
362 | return gl;
|
363 | };
|
364 | const getContextId = (exgl) => {
|
365 | const exglCtxId = exgl && typeof exgl === 'object' ? exgl.__exglCtxId : exgl;
|
366 | if (!exglCtxId || typeof exglCtxId !== 'number') {
|
367 | throw new Error(`Invalid EXGLContext id: ${String(exglCtxId)}`);
|
368 | }
|
369 | return exglCtxId;
|
370 | };
|
371 | global.WebGLRenderingContext = WebGLRenderingContext;
|
372 | global.WebGL2RenderingContext = WebGL2RenderingContext;
|
373 | global.WebGLObject = WebGLObject;
|
374 | global.WebGLBuffer = WebGLBuffer;
|
375 | global.WebGLFramebuffer = WebGLFramebuffer;
|
376 | global.WebGLProgram = WebGLProgram;
|
377 | global.WebGLRenderbuffer = WebGLRenderbuffer;
|
378 | global.WebGLShader = WebGLShader;
|
379 | global.WebGLTexture = WebGLTexture;
|
380 | global.WebGLUniformLocation = WebGLUniformLocation;
|
381 | global.WebGLActiveInfo = WebGLActiveInfo;
|
382 | global.WebGLShaderPrecisionFormat = WebGLShaderPrecisionFormat;
|
383 | global.WebGLQuery = WebGLQuery;
|
384 | global.WebGLSampler = WebGLSampler;
|
385 | global.WebGLSync = WebGLSync;
|
386 | global.WebGLTransformFeedback = WebGLTransformFeedback;
|
387 | global.WebGLVertexArrayObject = WebGLVertexArrayObject;
|
388 |
|
\ | No newline at end of file |