expo-gl
Version:
Provides GLView that acts as OpenGL ES render target and gives GL context object implementing WebGL 2.0 specification.
93 lines (80 loc) • 3.44 kB
text/typescript
import GLErrors from './GLErrors';
import { ExpoWebGLRenderingContext, GLLoggingOption } from './GLView.types';
/**
* Maximum length of the strings printed to the console.
*/
const MAX_STRING_LENGTH = 20;
/**
* Sets up `__expoSetLogging` method providing some logging options useful when debugging GL calls.
*/
export function configureLogging(gl: ExpoWebGLRenderingContext): void {
// Enable/disable logging of all GL function calls
let loggingOption = GLLoggingOption.DISABLED;
gl.__expoSetLogging = (option: GLLoggingOption): void => {
// If boolean values are the same, just change the internal value,
// there is no need to wrap/unwrap functions in this case.
if (!loggingOption === !option) {
loggingOption = option;
return;
}
// Turn off logging.
if (option === GLLoggingOption.DISABLED || !option) {
Object.entries(gl).forEach(([key, value]) => {
if (typeof value === 'function' && value.__logWrapper) {
delete gl[key];
}
});
loggingOption = option;
return;
}
// Turn on logging.
Object.entries(Object.getPrototypeOf(gl)).forEach(([key, originalValue]) => {
if (typeof originalValue !== 'function' || key === '__expoSetLogging') {
return;
}
gl[key] = (...args) => {
if (loggingOption & GLLoggingOption.METHOD_CALLS) {
const params = args.map((arg) => {
// If the type is `number`, then try to find name of the constant that has such value,
// so it's easier to read these logs. In some cases it might be misleading
// if the parameter is for example a width or height, so the number is still logged.
if (loggingOption & GLLoggingOption.RESOLVE_CONSTANTS && typeof arg === 'number') {
for (const prop in gl) {
if (gl[prop] === arg) {
return `${arg} (${prop})`;
}
}
}
// Truncate strings so they don't produce too much output and don't block the bridge.
// It mostly applies to shaders which might be very long...
if (loggingOption & GLLoggingOption.TRUNCATE_STRINGS && typeof arg === 'string') {
if (arg.length > MAX_STRING_LENGTH) {
const lastIndex = arg.lastIndexOf(' ', MAX_STRING_LENGTH);
return arg.substr(0, lastIndex >= 0 ? lastIndex : MAX_STRING_LENGTH) + '...';
}
}
// Just return the parameter as a string.
return '' + arg;
});
console.log(`ExpoGL: ${key}(${params.join(', ')})`);
}
const result = originalValue.apply(gl, args);
if (loggingOption & GLLoggingOption.METHOD_CALLS) {
console.log(`ExpoGL: = ${result}`);
}
if (loggingOption & GLLoggingOption.GET_ERRORS && key !== 'getError') {
// @ts-ignore We need to call into the original `getError`.
// eslint-disable-next-line no-proto
const error = gl.__proto__.getError.call(gl);
if (error && error !== gl.NO_ERROR) {
// `console.error` would cause a red screen, so let's just log with red color.
console.log(`\x1b[31mExpoGL: Error ${GLErrors[error]}\x1b[0m`);
}
}
gl[key].__logWrapper = true;
return result;
};
});
loggingOption = option;
};
}