1 | 'use strict';
|
2 |
|
3 | import React, { PropTypes } from 'react';
|
4 | import { View, Platform, requireNativeComponent } from 'react-native';
|
5 |
|
6 | import * as Constants from './Constants';
|
7 |
|
8 |
|
9 |
|
10 |
|
11 | export default class GLView extends React.Component {
|
12 | static propTypes = {
|
13 |
|
14 |
|
15 |
|
16 | onContextCreate: PropTypes.func,
|
17 |
|
18 |
|
19 | msaaSamples: PropTypes.number,
|
20 |
|
21 | ...View.propTypes,
|
22 | }
|
23 |
|
24 | static defaultProps = {
|
25 | msaaSamples: 4,
|
26 | };
|
27 |
|
28 | render() {
|
29 |
|
30 | const { onContextCreate, msaaSamples, ...viewProps } = this.props;
|
31 |
|
32 |
|
33 |
|
34 | return (
|
35 | <View {...viewProps}>
|
36 | <GLView.NativeView
|
37 | style={{ flex: 1, backgroundColor: 'transparent' }}
|
38 | onSurfaceCreate={this._onSurfaceCreate}
|
39 | msaaSamples={Platform.OS === 'ios' ? msaaSamples : undefined}
|
40 | />
|
41 | </View>
|
42 | );
|
43 | }
|
44 |
|
45 | _onSurfaceCreate = ({ nativeEvent: { exglCtxId } }) => {
|
46 | const gl = getGl(exglCtxId);
|
47 | if (this.props.onContextCreate) {
|
48 | this.props.onContextCreate(gl);
|
49 | }
|
50 | }
|
51 |
|
52 | static NativeView = requireNativeComponent('ExponentGLView', GLView, {
|
53 | nativeOnly: { onSurfaceCreate: true },
|
54 | });
|
55 | }
|
56 |
|
57 |
|
58 |
|
59 |
|
60 | global.WebGLRenderingContext = class WebGLRenderingContext {};
|
61 |
|
62 | global.WebGLObject = class WebGLObject {
|
63 | constructor (id) {
|
64 | this.id = id;
|
65 | }
|
66 | toString() {
|
67 | return `[WebGLObject ${this.id}]`;
|
68 | }
|
69 | }
|
70 | global.WebGLBuffer = class WebGLBuffer extends WebGLObject {}
|
71 | global.WebGLFramebuffer = class WebGLFramebuffer extends WebGLObject {}
|
72 | global.WebGLProgram = class WebGLProgram extends WebGLObject {}
|
73 | global.WebGLRenderbuffer = class WebGLRenderbuffer extends WebGLObject {}
|
74 | global.WebGLShader = class WebGLShader extends WebGLObject {}
|
75 | global.WebGLTexture = class WebGLTexture extends WebGLObject {}
|
76 |
|
77 | const idToObject = {};
|
78 | const wrapObject = (type, id) => {
|
79 | const found = idToObject[id];
|
80 | if (found) {
|
81 | return found;
|
82 | }
|
83 | return idToObject[id] = new type(id);
|
84 | }
|
85 |
|
86 | global.WebGLUniformLocation = class WebGLUniformLocation {
|
87 | constructor (id) {
|
88 | this.id = id;
|
89 | }
|
90 | }
|
91 |
|
92 | global.WebGLActiveInfo = class WebGLActiveInfo {
|
93 | constructor (obj) {
|
94 | Object.assign(this, obj);
|
95 | }
|
96 | }
|
97 | global.WebGLShaderPrecisionFormat = class WebGLShaderPrecisionFormat {
|
98 | constructor (obj) {
|
99 | Object.assign(this, obj);
|
100 | }
|
101 | }
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | const wrapMethods = (gl) => {
|
107 | const wrap = (methodNames, wrapper) =>
|
108 | (Array.isArray(methodNames) ? methodNames : [methodNames]).forEach(
|
109 | (methodName) => gl[methodName] = wrapper(gl[methodName]));
|
110 |
|
111 |
|
112 | const getParameterTypes = {
|
113 | [gl.ARRAY_BUFFER_BINDING]: WebGLBuffer,
|
114 | [gl.ELEMENT_ARRAY_BUFFER_BINDING]: WebGLBuffer,
|
115 | [gl.CURRENT_PROGRAM]: WebGLProgram,
|
116 | [gl.FRAMEBUFFER_BINDING]: WebGLFramebuffer,
|
117 | [gl.RENDERBUFFER_BINDING]: WebGLRenderbuffer,
|
118 | [gl.TEXTURE_BINDING_2D]: WebGLTexture,
|
119 | [gl.TEXTURE_BINDING_CUBE_MAP]: WebGLTexture,
|
120 | };
|
121 | wrap('getParameter', (orig) => (pname) => {
|
122 | let ret = orig.call(gl, pname);
|
123 | if (pname === gl.VERSION) {
|
124 |
|
125 | ret = `WebGL 1.0 (Expo-${Platform.OS}-${Constants.expoVersion}) (${ret})`;
|
126 | }
|
127 | const type = getParameterTypes[pname];
|
128 | return type ? wrapObject(type, ret) : ret;
|
129 | });
|
130 |
|
131 |
|
132 | wrap('bindBuffer', (orig) => (target, buffer) =>
|
133 | orig.call(gl, target, buffer && buffer.id));
|
134 | wrap('createBuffer', (orig) => () =>
|
135 | wrapObject(WebGLBuffer, orig.call(gl)));
|
136 | wrap('deleteBuffer', (orig) => (buffer) =>
|
137 | orig.call(gl, buffer && buffer.id));
|
138 | wrap('isBuffer', (orig) => (buffer) =>
|
139 | buffer instanceof WebGLBuffer && orig.call(gl, buffer.id));
|
140 |
|
141 |
|
142 | wrap('bindFramebuffer', (orig) => (target, framebuffer) =>
|
143 | orig.call(gl, target, framebuffer && framebuffer.id));
|
144 | wrap('createFramebuffer', (orig) => () =>
|
145 | wrapObject(WebGLFramebuffer, orig.call(gl)));
|
146 | wrap('deleteFramebuffer', (orig) => (framebuffer) =>
|
147 | orig.call(gl, framebuffer && framebuffer.id));
|
148 | wrap('framebufferRenderbuffer', (orig) => (target, attachment, rbtarget, rb) =>
|
149 | orig.call(gl, target, attachment, rbtarget, rb && rb.id));
|
150 | wrap('framebufferTexture2D', (orig) => (target, attachment, textarget, tex, level) =>
|
151 | orig.call(gl, target, attachment, textarget, tex && tex.id, level));
|
152 | wrap('isFramebuffer', (orig) => (framebuffer) =>
|
153 | framebuffer instanceof WebGLFramebuffer && orig.call(gl, framebuffer.id));
|
154 |
|
155 |
|
156 | wrap('bindRenderbuffer', (orig) => (target, renderbuffer) =>
|
157 | orig.call(gl, target, renderbuffer && renderbuffer.id));
|
158 | wrap('createRenderbuffer', (orig) => () =>
|
159 | wrapObject(WebGLRenderbuffer, orig.call(gl)));
|
160 | wrap('deleteRenderbuffer', (orig) => (renderbuffer) =>
|
161 | orig.call(gl, renderbuffer && renderbuffer.id));
|
162 | wrap('isRenderbuffer', (orig) => (renderbuffer) =>
|
163 | renderbuffer instanceof WebGLRenderbuffer && orig.call(gl, renderbuffer.id));
|
164 |
|
165 |
|
166 | wrap('bindTexture', (orig) => (target, texture) =>
|
167 | orig.call(gl, target, texture && texture.id));
|
168 | wrap('createTexture', (orig) => () =>
|
169 | wrapObject(WebGLTexture, orig.call(gl)));
|
170 | wrap('deleteTexture', (orig) => (texture) =>
|
171 | orig.call(gl, texture && texture.id));
|
172 | wrap('isTexture', (orig) => (texture) =>
|
173 | texture instanceof WebGLTexture && orig.call(gl, texture.id));
|
174 |
|
175 |
|
176 | wrap('attachShader', (orig) => (program, shader) =>
|
177 | orig.call(gl, program && program.id, shader && shader.id));
|
178 | wrap('bindAttribLocation', (orig) => (program, index, name) =>
|
179 | orig.call(gl, program && program.id, index, name));
|
180 | wrap('compileShader', (orig) => (shader) =>
|
181 | orig.call(gl, shader && shader.id));
|
182 | wrap('createProgram', (orig) => () =>
|
183 | wrapObject(WebGLProgram, orig.call(gl)));
|
184 | wrap('createShader', (orig) => (type) =>
|
185 | wrapObject(WebGLShader, orig.call(gl, type)));
|
186 | wrap('deleteProgram', (orig) => (program) =>
|
187 | orig.call(gl, program && program.id));
|
188 | wrap('deleteShader', (orig) => (shader) =>
|
189 | orig.call(gl, shader && shader.id));
|
190 | wrap('detachShader', (orig) => (program, shader) =>
|
191 | orig.call(gl, program && program.id, shader && shader.id));
|
192 | wrap('getAttachedShaders', (orig) => (program) =>
|
193 | orig.call(gl, program && program.id).map((id) => wrapObject(WebGLShader, id)));
|
194 | wrap('getProgramParameter', (orig) => (program, pname) =>
|
195 | orig.call(gl, program && program.id, pname));
|
196 | wrap('getProgramInfoLog', (orig) => (program) =>
|
197 | orig.call(gl, program && program.id));
|
198 | wrap('getShaderParameter', (orig) => (shader, pname) =>
|
199 | orig.call(gl, shader && shader.id, pname));
|
200 | wrap('getShaderPrecisionFormat', (orig) => (shadertype, precisiontype) =>
|
201 | new WebGLShaderPrecisionFormat(orig.call(gl, shadertype, precisiontype)))
|
202 | wrap('getShaderInfoLog', (orig) => (shader) =>
|
203 | orig.call(gl, shader && shader.id));
|
204 | wrap('getShaderSource', (orig) => (shader) =>
|
205 | orig.call(gl, shader && shader.id));
|
206 | wrap('linkProgram', (orig) => (program) =>
|
207 | orig.call(gl, program && program.id));
|
208 | wrap('shaderSource', (orig) => (shader, source) =>
|
209 | orig.call(gl, shader && shader.id, source));
|
210 | wrap('useProgram', (orig) => (program) =>
|
211 | orig.call(gl, program && program.id));
|
212 | wrap('validateProgram', (orig) => (program) =>
|
213 | orig.call(gl, program && program.id));
|
214 | wrap('isShader', (orig) => (shader) =>
|
215 | shader instanceof WebGLShader && orig.call(gl, shader.id));
|
216 | wrap('isProgram', (orig) => (program) =>
|
217 | program instanceof WebGLProgram && orig.call(gl, program.id));
|
218 |
|
219 |
|
220 | wrap('getActiveAttrib', (orig) => (program, index) =>
|
221 | new WebGLActiveInfo(orig.call(gl, program && program.id, index)));
|
222 | wrap('getActiveUniform', (orig) => (program, index) =>
|
223 | new WebGLActiveInfo(orig.call(gl, program && program.id, index)));
|
224 | wrap('getAttribLocation', (orig) => (program, name) =>
|
225 | orig.call(gl, program && program.id, name));
|
226 | wrap('getUniform', (orig) => (program, location) =>
|
227 | orig.call(gl, program && program.id, location && location.id));
|
228 | wrap('getUniformLocation', (orig) => (program, name) =>
|
229 | new WebGLUniformLocation(orig.call(gl, program && program.id, name)));
|
230 | wrap(['uniform1f', 'uniform1i'], (orig) => (loc, x) =>
|
231 | orig.call(gl, loc && loc.id, x));
|
232 | wrap(['uniform2f', 'uniform2i'], (orig) => (loc, x, y) =>
|
233 | orig.call(gl, loc && loc.id, x, y));
|
234 | wrap(['uniform3f', 'uniform3i'], (orig) => (loc, x, y, z) =>
|
235 | orig.call(gl, loc && loc.id, x, y, z));
|
236 | wrap(['uniform4f', 'uniform4i'], (orig) => (loc, x, y, z, w) =>
|
237 | orig.call(gl, loc && loc.id, x, y, z, w));
|
238 | wrap(['uniform1fv', 'uniform2fv', 'uniform3fv', 'uniform4fv'],
|
239 | (orig) => (loc, val) => orig.call(gl, loc && loc.id, new Float32Array(val)));
|
240 | wrap(['uniform1iv', 'uniform2iv', 'uniform3iv', 'uniform4iv'],
|
241 | (orig) => (loc, val) => orig.call(gl, loc && loc.id, new Int32Array(val)));
|
242 | wrap(['uniformMatrix2fv', 'uniformMatrix3fv', 'uniformMatrix4fv'],
|
243 | (orig) => (loc, transpose, val) =>
|
244 | orig.call(gl, loc && loc.id, transpose, new Float32Array(val)));
|
245 | wrap(['vertexAttrib1fv', 'vertexAttrib2fv', 'vertexAttrib3fv', 'vertexAttrib4fv'],
|
246 | (orig) => (index, val) => orig.call(gl, index, new Float32Array(val)));
|
247 | }
|
248 |
|
249 |
|
250 | const getGl = (exglCtxId) => {
|
251 | const gl = global.__EXGLContexts[exglCtxId];
|
252 | delete global.__EXGLContexts[exglCtxId];
|
253 | if (Object.setPrototypeOf) {
|
254 | Object.setPrototypeOf(gl, global.WebGLRenderingContext.prototype);
|
255 | } else {
|
256 | gl.__proto__ = global.WebGLRenderingContext.prototype;
|
257 | }
|
258 |
|
259 | wrapMethods(gl);
|
260 |
|
261 |
|
262 | gl.canvas = null;
|
263 |
|
264 |
|
265 |
|
266 | const viewport = gl.getParameter(gl.VIEWPORT);
|
267 | gl.drawingBufferWidth = viewport[2];
|
268 | gl.drawingBufferHeight = viewport[3];
|
269 |
|
270 |
|
271 | let enableLogging = false;
|
272 | Object.defineProperty(gl, 'enableLogging', {
|
273 | configurable: true,
|
274 | get() {
|
275 | return enableLogging;
|
276 | },
|
277 | set(enable) {
|
278 | if (enable === enableLogging) {
|
279 | return;
|
280 | }
|
281 | if (enable) {
|
282 | Object.keys(gl).forEach((key) => {
|
283 | if (typeof gl[key] === 'function') {
|
284 | const original = gl[key];
|
285 | gl[key] = (...args) => {
|
286 | console.log(`EXGL: ${key}(${args.join(', ')})`);
|
287 | const r = original.apply(gl, args);
|
288 | console.log(`EXGL: = ${r}`);
|
289 | return r;
|
290 | };
|
291 | gl[key].original = original;
|
292 | }
|
293 | });
|
294 | } else {
|
295 | Object.keys(gl).forEach((key) => {
|
296 | if (typeof gl[key] === 'function' && gl[key].original) {
|
297 | gl[key] = gl[key].original;
|
298 | }
|
299 | });
|
300 | }
|
301 | enableLogging = enable;
|
302 | },
|
303 | });
|
304 |
|
305 | return gl;
|
306 | };
|