UNPKG

@openhps/core

Version:

Open Hybrid Positioning System - Core component

328 lines (321 loc) 12.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebGLBindingStates = WebGLBindingStates; var _constants = require("../../constants.js"); function WebGLBindingStates(gl, attributes) { const maxVertexAttributes = gl.getParameter(gl.MAX_VERTEX_ATTRIBS); const bindingStates = {}; const defaultState = createBindingState(null); let currentState = defaultState; let forceUpdate = false; function setup(object, material, program, geometry, index) { let updateBuffers = false; const state = getBindingState(geometry, program, material); if (currentState !== state) { currentState = state; bindVertexArrayObject(currentState.object); } updateBuffers = needsUpdate(object, geometry, program, index); if (updateBuffers) saveCache(object, geometry, program, index); if (index !== null) { attributes.update(index, gl.ELEMENT_ARRAY_BUFFER); } if (updateBuffers || forceUpdate) { forceUpdate = false; setupVertexAttributes(object, material, program, geometry); if (index !== null) { gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, attributes.get(index).buffer); } } } function createVertexArrayObject() { return gl.createVertexArray(); } function bindVertexArrayObject(vao) { return gl.bindVertexArray(vao); } function deleteVertexArrayObject(vao) { return gl.deleteVertexArray(vao); } function getBindingState(geometry, program, material) { const wireframe = material.wireframe === true; let programMap = bindingStates[geometry.id]; if (programMap === undefined) { programMap = {}; bindingStates[geometry.id] = programMap; } let stateMap = programMap[program.id]; if (stateMap === undefined) { stateMap = {}; programMap[program.id] = stateMap; } let state = stateMap[wireframe]; if (state === undefined) { state = createBindingState(createVertexArrayObject()); stateMap[wireframe] = state; } return state; } function createBindingState(vao) { const newAttributes = []; const enabledAttributes = []; const attributeDivisors = []; for (let i = 0; i < maxVertexAttributes; i++) { newAttributes[i] = 0; enabledAttributes[i] = 0; attributeDivisors[i] = 0; } return { // for backward compatibility on non-VAO support browser geometry: null, program: null, wireframe: false, newAttributes: newAttributes, enabledAttributes: enabledAttributes, attributeDivisors: attributeDivisors, object: vao, attributes: {}, index: null }; } function needsUpdate(object, geometry, program, index) { const cachedAttributes = currentState.attributes; const geometryAttributes = geometry.attributes; let attributesNum = 0; const programAttributes = program.getAttributes(); for (const name in programAttributes) { const programAttribute = programAttributes[name]; if (programAttribute.location >= 0) { const cachedAttribute = cachedAttributes[name]; let geometryAttribute = geometryAttributes[name]; if (geometryAttribute === undefined) { if (name === 'instanceMatrix' && object.instanceMatrix) geometryAttribute = object.instanceMatrix; if (name === 'instanceColor' && object.instanceColor) geometryAttribute = object.instanceColor; } if (cachedAttribute === undefined) return true; if (cachedAttribute.attribute !== geometryAttribute) return true; if (geometryAttribute && cachedAttribute.data !== geometryAttribute.data) return true; attributesNum++; } } if (currentState.attributesNum !== attributesNum) return true; if (currentState.index !== index) return true; return false; } function saveCache(object, geometry, program, index) { const cache = {}; const attributes = geometry.attributes; let attributesNum = 0; const programAttributes = program.getAttributes(); for (const name in programAttributes) { const programAttribute = programAttributes[name]; if (programAttribute.location >= 0) { let attribute = attributes[name]; if (attribute === undefined) { if (name === 'instanceMatrix' && object.instanceMatrix) attribute = object.instanceMatrix; if (name === 'instanceColor' && object.instanceColor) attribute = object.instanceColor; } const data = {}; data.attribute = attribute; if (attribute && attribute.data) { data.data = attribute.data; } cache[name] = data; attributesNum++; } } currentState.attributes = cache; currentState.attributesNum = attributesNum; currentState.index = index; } function initAttributes() { const newAttributes = currentState.newAttributes; for (let i = 0, il = newAttributes.length; i < il; i++) { newAttributes[i] = 0; } } function enableAttribute(attribute) { enableAttributeAndDivisor(attribute, 0); } function enableAttributeAndDivisor(attribute, meshPerAttribute) { const newAttributes = currentState.newAttributes; const enabledAttributes = currentState.enabledAttributes; const attributeDivisors = currentState.attributeDivisors; newAttributes[attribute] = 1; if (enabledAttributes[attribute] === 0) { gl.enableVertexAttribArray(attribute); enabledAttributes[attribute] = 1; } if (attributeDivisors[attribute] !== meshPerAttribute) { gl.vertexAttribDivisor(attribute, meshPerAttribute); attributeDivisors[attribute] = meshPerAttribute; } } function disableUnusedAttributes() { const newAttributes = currentState.newAttributes; const enabledAttributes = currentState.enabledAttributes; for (let i = 0, il = enabledAttributes.length; i < il; i++) { if (enabledAttributes[i] !== newAttributes[i]) { gl.disableVertexAttribArray(i); enabledAttributes[i] = 0; } } } function vertexAttribPointer(index, size, type, normalized, stride, offset, integer) { if (integer === true) { gl.vertexAttribIPointer(index, size, type, stride, offset); } else { gl.vertexAttribPointer(index, size, type, normalized, stride, offset); } } function setupVertexAttributes(object, material, program, geometry) { initAttributes(); const geometryAttributes = geometry.attributes; const programAttributes = program.getAttributes(); const materialDefaultAttributeValues = material.defaultAttributeValues; for (const name in programAttributes) { const programAttribute = programAttributes[name]; if (programAttribute.location >= 0) { let geometryAttribute = geometryAttributes[name]; if (geometryAttribute === undefined) { if (name === 'instanceMatrix' && object.instanceMatrix) geometryAttribute = object.instanceMatrix; if (name === 'instanceColor' && object.instanceColor) geometryAttribute = object.instanceColor; } if (geometryAttribute !== undefined) { const normalized = geometryAttribute.normalized; const size = geometryAttribute.itemSize; const attribute = attributes.get(geometryAttribute); // TODO Attribute may not be available on context restore if (attribute === undefined) continue; const buffer = attribute.buffer; const type = attribute.type; const bytesPerElement = attribute.bytesPerElement; // check for integer attributes const integer = type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === _constants.IntType; if (geometryAttribute.isInterleavedBufferAttribute) { const data = geometryAttribute.data; const stride = data.stride; const offset = geometryAttribute.offset; if (data.isInstancedInterleavedBuffer) { for (let i = 0; i < programAttribute.locationSize; i++) { enableAttributeAndDivisor(programAttribute.location + i, data.meshPerAttribute); } if (object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined) { geometry._maxInstanceCount = data.meshPerAttribute * data.count; } } else { for (let i = 0; i < programAttribute.locationSize; i++) { enableAttribute(programAttribute.location + i); } } gl.bindBuffer(gl.ARRAY_BUFFER, buffer); for (let i = 0; i < programAttribute.locationSize; i++) { vertexAttribPointer(programAttribute.location + i, size / programAttribute.locationSize, type, normalized, stride * bytesPerElement, (offset + size / programAttribute.locationSize * i) * bytesPerElement, integer); } } else { if (geometryAttribute.isInstancedBufferAttribute) { for (let i = 0; i < programAttribute.locationSize; i++) { enableAttributeAndDivisor(programAttribute.location + i, geometryAttribute.meshPerAttribute); } if (object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined) { geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count; } } else { for (let i = 0; i < programAttribute.locationSize; i++) { enableAttribute(programAttribute.location + i); } } gl.bindBuffer(gl.ARRAY_BUFFER, buffer); for (let i = 0; i < programAttribute.locationSize; i++) { vertexAttribPointer(programAttribute.location + i, size / programAttribute.locationSize, type, normalized, size * bytesPerElement, size / programAttribute.locationSize * i * bytesPerElement, integer); } } } else if (materialDefaultAttributeValues !== undefined) { const value = materialDefaultAttributeValues[name]; if (value !== undefined) { switch (value.length) { case 2: gl.vertexAttrib2fv(programAttribute.location, value); break; case 3: gl.vertexAttrib3fv(programAttribute.location, value); break; case 4: gl.vertexAttrib4fv(programAttribute.location, value); break; default: gl.vertexAttrib1fv(programAttribute.location, value); } } } } } disableUnusedAttributes(); } function dispose() { reset(); for (const geometryId in bindingStates) { const programMap = bindingStates[geometryId]; for (const programId in programMap) { const stateMap = programMap[programId]; for (const wireframe in stateMap) { deleteVertexArrayObject(stateMap[wireframe].object); delete stateMap[wireframe]; } delete programMap[programId]; } delete bindingStates[geometryId]; } } function releaseStatesOfGeometry(geometry) { if (bindingStates[geometry.id] === undefined) return; const programMap = bindingStates[geometry.id]; for (const programId in programMap) { const stateMap = programMap[programId]; for (const wireframe in stateMap) { deleteVertexArrayObject(stateMap[wireframe].object); delete stateMap[wireframe]; } delete programMap[programId]; } delete bindingStates[geometry.id]; } function releaseStatesOfProgram(program) { for (const geometryId in bindingStates) { const programMap = bindingStates[geometryId]; if (programMap[program.id] === undefined) continue; const stateMap = programMap[program.id]; for (const wireframe in stateMap) { deleteVertexArrayObject(stateMap[wireframe].object); delete stateMap[wireframe]; } delete programMap[program.id]; } } function reset() { resetDefaultState(); forceUpdate = true; if (currentState === defaultState) return; currentState = defaultState; bindVertexArrayObject(currentState.object); } // for backward-compatibility function resetDefaultState() { defaultState.geometry = null; defaultState.program = null; defaultState.wireframe = false; } return { setup: setup, reset: reset, resetDefaultState: resetDefaultState, dispose: dispose, releaseStatesOfGeometry: releaseStatesOfGeometry, releaseStatesOfProgram: releaseStatesOfProgram, initAttributes: initAttributes, enableAttribute: enableAttribute, disableUnusedAttributes: disableUnusedAttributes }; }