@luma.gl/gltools
Version:
WebGL2 API Polyfills for WebGL1 WebGLRenderingContext
167 lines (136 loc) • 4.04 kB
JavaScript
import { GL_PARAMETER_DEFAULTS, GL_HOOKED_SETTERS } from './webgl-parameter-tables';
import { setParameters, getParameters } from './unified-parameter-api';
import { assert } from '../utils/assert';
import { deepArrayEqual } from '../utils/utils';
function installGetterOverride(gl, functionName) {
const originalGetterFunc = gl[functionName].bind(gl);
gl[functionName] = function get() {
const pname = arguments.length <= 0 ? undefined : arguments[0];
if (!(pname in gl.state.cache)) {
return originalGetterFunc(...arguments);
}
return gl.state.enable ? gl.state.cache[pname] : originalGetterFunc(...arguments);
};
Object.defineProperty(gl[functionName], 'name', {
value: "".concat(functionName, "-from-cache"),
configurable: false
});
}
function installSetterSpy(gl, functionName, setter) {
const originalSetterFunc = gl[functionName].bind(gl);
gl[functionName] = function set() {
for (var _len = arguments.length, params = new Array(_len), _key = 0; _key < _len; _key++) {
params[_key] = arguments[_key];
}
const {
valueChanged,
oldValue
} = setter(gl.state._updateCache, ...params);
if (valueChanged) {
originalSetterFunc(...params);
}
return oldValue;
};
Object.defineProperty(gl[functionName], 'name', {
value: "".concat(functionName, "-to-cache"),
configurable: false
});
}
function installProgramSpy(gl) {
const originalUseProgram = gl.useProgram.bind(gl);
gl.useProgram = function useProgramLuma(handle) {
if (gl.state.program !== handle) {
originalUseProgram(handle);
gl.state.program = handle;
}
};
}
class GLState {
constructor(gl) {
let {
copyState = false,
log = () => {}
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
this.gl = gl;
this.program = null;
this.stateStack = [];
this.enable = true;
this.cache = copyState ? getParameters(gl) : Object.assign({}, GL_PARAMETER_DEFAULTS);
this.log = log;
this._updateCache = this._updateCache.bind(this);
Object.seal(this);
}
push() {
let values = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
this.stateStack.push({});
}
pop() {
assert(this.stateStack.length > 0);
const oldValues = this.stateStack[this.stateStack.length - 1];
setParameters(this.gl, oldValues);
this.stateStack.pop();
}
_updateCache(values) {
let valueChanged = false;
let oldValue;
const oldValues = this.stateStack.length > 0 && this.stateStack[this.stateStack.length - 1];
for (const key in values) {
assert(key !== undefined);
const value = values[key];
const cached = this.cache[key];
if (!deepArrayEqual(value, cached)) {
valueChanged = true;
oldValue = cached;
if (oldValues && !(key in oldValues)) {
oldValues[key] = cached;
}
this.cache[key] = value;
}
}
return {
valueChanged,
oldValue
};
}
}
export function trackContextState(gl) {
let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
const {
enable = true,
copyState
} = options;
assert(copyState !== undefined);
if (!gl.state) {
const {
polyfillContext
} = globalThis;
if (polyfillContext) {
polyfillContext(gl);
}
gl.state = new GLState(gl, {
copyState
});
installProgramSpy(gl);
for (const key in GL_HOOKED_SETTERS) {
const setter = GL_HOOKED_SETTERS[key];
installSetterSpy(gl, key, setter);
}
installGetterOverride(gl, 'getParameter');
installGetterOverride(gl, 'isEnabled');
}
gl.state.enable = enable;
return gl;
}
export function pushContextState(gl) {
if (!gl.state) {
trackContextState(gl, {
copyState: false
});
}
gl.state.push();
}
export function popContextState(gl) {
assert(gl.state);
gl.state.pop();
}
//# sourceMappingURL=track-context-state.js.map