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 || option === GLLoggingOption.DISABLED) { Object.entries(gl).forEach(([key, value]) => { if (typeof value === 'function' && value.original) { gl[key] = value.original; } }); loggingOption = option; return; } // Turn on logging. Object.entries(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`. const error = gl.getError.original.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`); } } return result; }; gl[key].original = originalValue; }); loggingOption = option; }; }