viewer/frozenbufferset.js
import {AbstractBufferSet} from "./abstractbufferset.js";
import {Utils} from "./utils.js";
import {AvlTree} from "./collections/avltree.js";
/**
* @ignore
*/
export class FrozenBufferSet extends AbstractBufferSet {
constructor(
viewer,
originalBuffer,
positionBuffer, normalBuffer, colorBuffer, pickColorBuffer, indexBuffer, lineIndexBuffer,
color, colorHash,
nrIndices, nrLineIndices, nrNormals, nrPositions, nrColors,
vao, vaoPick, lineRenderVao,
hasTransparency, hasTwoSidedTriangles, reuse, owner, manager,
// only in case of reuse
roid, uniqueModelId)
{
super(viewer, true);
if (originalBuffer) {
this.uniqueIdToIndex = originalBuffer.uniqueIdToIndex;
this.uniqueIdSet = originalBuffer.uniqueIdSet;
}
// @todo make these something like LRU caches?
this.visibleRanges = new Map();
this.lineIndexBuffers = new Map();
this.positionBuffer = positionBuffer;
this.normalBuffer = normalBuffer;
this.colorBuffer = colorBuffer;
this.pickColorBuffer = pickColorBuffer;
this.indexBuffer = indexBuffer;
this.lineIndexBuffer = lineIndexBuffer;
this.color = color;
this.colorHash = colorHash;
this.nrIndices = nrIndices;
this.nrLineIndices = nrLineIndices;
this.nrNormals = nrNormals;
this.nrPositions = nrPositions;
this.nrColors = nrColors;
this.vao = vao;
this.vaoPick = vaoPick;
this.lineRenderVao = lineRenderVao;
this.hasTransparency = hasTransparency;
this.hasTwoSidedTriangles = hasTwoSidedTriangles;
this.reuse = reuse;
this.owner = owner;
this.manager = manager;
this.roid = roid;
this.uniqueModelId = uniqueModelId;
this.indexType = indexBuffer.attrib_type;
this.instanceMatricesBuffer = null;
this.instanceNormalMatricesBuffer = null;
this.instancePickColorsBuffer = null;
}
update(nrIndices, nrPositions, nrNormals, nrColors) {
this.nrIndices = nrIndices;
this.nrNormals = nrNormals;
this.nrPositions = nrPositions;
this.nrColors = nrColors;
this.dirty = true;
}
finalize() {
}
// Sets reuse instances
setObjects(gl, objects) {
this.objects = objects;
this.reuse = true;
const N = this.nrProcessedMatrices = objects.length;
var instanceMatrices = new Float32Array(N * 16);
var instanceNormalMatrices = new Float32Array(N * 9);
var instancePickColors = new Uint8Array(N * 4);
for (var index=0; index<objects.length; index++) {
let object = objects[index];
instanceMatrices.set(object.matrix, index * 16);
instanceNormalMatrices.set(object.normalMatrix, index * 9);
instancePickColors.set(this.viewer.getPickColor(object.uniqueId), index * 4);
}
if (this.instanceMatricesBuffer === null) {
this.instanceMatricesBuffer = Utils.createBuffer(gl, instanceMatrices, null, null, 16);
this.instanceNormalMatricesBuffer = Utils.createBuffer(gl, instanceNormalMatrices, null, null, 9);
this.instancePickColorsBuffer = Utils.createBuffer(gl, instancePickColors, null, null, 4);
} else {
let arrays = [instanceMatrices, instanceNormalMatrices, instancePickColors];
let buffers = [this.instanceMatricesBuffer, this.instanceNormalMatricesBuffer, this.instancePickColorsBuffer];
var restoreArrayBinding = gl.getParameter(gl.ARRAY_BUFFER_BINDING);
arrays.forEach(function(a, idx) {
let b = buffers[idx];
gl.bindBuffer(gl.ARRAY_BUFFER, b);
gl.bufferData(gl.ARRAY_BUFFER, a, gl.STATIC_DRAW, 0);
});
gl.bindBuffer(gl.ARRAY_BUFFER, restoreArrayBinding);
}
}
copyEmpty() {
let b = new FrozenBufferSet(
this.viewer,
null,
// multiply
this.positionBuffer,
this.normalBuffer,
this.colorBuffer,
this.pickColorBuffer,
this.indexBuffer,
this.lineIndexBuffer,
null,
null,
this.indexBuffer.N,
this.lineIndexBuffer ? this.lineIndexBuffer.N : 0,
this.normalBuffer.N,
this.positionBuffer.N,
this.colorBuffer.N,
// vaos
null,
null,
null,
this.hasTransparency,
this.hasTwoSidedTriangles,
this.reuse,
this.owner,
this.manager,
this.roid,
this.uniqueModelId
);
b.uniqueIdToIndex = new AvlTree(this.viewer.inverseUniqueIdCompareFunction);
return b;
}
buildVao(gl, settings, programInfo, pickProgramInfo, lineProgramInfo) {
let bindLocationPairs = (locations) => {
for (let [location, buffer] of locations) {
gl.bindBuffer(buffer.gl_type, buffer);
let fn = buffer.attrib_type == gl.FLOAT
? gl.vertexAttribPointer
: gl.vertexAttribIPointer;
fn.bind(gl)(location, buffer.components, buffer.attrib_type, buffer.normalize, buffer.stride, buffer.offset);
gl.enableVertexAttribArray(location);
}
};
// Regular drawing VAO
var vao = this.vao = gl.createVertexArray();
gl.bindVertexArray(vao);
let locations = [
[programInfo.attribLocations.vertexPosition, this.positionBuffer],
[programInfo.attribLocations.vertexNormal, this.normalBuffer]
];
if (!settings.useObjectColors) {
locations.push([programInfo.attribLocations.vertexColor, this.colorBuffer]);
}
bindLocationPairs(locations);
if (this.instanceMatricesBuffer) {
gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceMatricesBuffer);
for (let i = 0; i < 4; ++i) {
gl.enableVertexAttribArray(programInfo.attribLocations.instanceMatrices + i);
gl.vertexAttribPointer(programInfo.attribLocations.instanceMatrices + i, 4, gl.FLOAT, false, 64, 16 * i);
gl.vertexAttribDivisor(programInfo.attribLocations.instanceMatrices + i, 1);
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceNormalMatricesBuffer);
for (let i = 0; i < 3; ++i) {
gl.enableVertexAttribArray(programInfo.attribLocations.instanceNormalMatrices + i);
gl.vertexAttribPointer(programInfo.attribLocations.instanceNormalMatrices + i, 3, gl.FLOAT, false, 36, 12 * i);
gl.vertexAttribDivisor(programInfo.attribLocations.instanceNormalMatrices + i, 1);
}
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
gl.bindVertexArray(null);
// Line render drawing VAO
var lineRenderVao = this.lineRenderVao = gl.createVertexArray();
gl.bindVertexArray(lineRenderVao);
locations = [
[lineProgramInfo.attribLocations.vertexPosition, this.positionBuffer]
];
bindLocationPairs(locations);
if (this.instanceMatricesBuffer) {
gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceMatricesBuffer);
for (let i = 0; i < 4; ++i) {
gl.enableVertexAttribArray(lineProgramInfo.attribLocations.instanceMatrices + i);
gl.vertexAttribPointer(lineProgramInfo.attribLocations.instanceMatrices + i, 4, gl.FLOAT, false, 64, 16 * i);
gl.vertexAttribDivisor(lineProgramInfo.attribLocations.instanceMatrices + i, 1);
}
if (lineProgramInfo.attribLocations.instanceNormalMatrices) {
// Line renders do not use normals
gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceNormalMatricesBuffer);
for (let i = 0; i < 3; ++i) {
gl.enableVertexAttribArray(lineProgramInfo.attribLocations.instanceNormalMatrices + i);
gl.vertexAttribPointer(lineProgramInfo.attribLocations.instanceNormalMatrices + i, 3, gl.FLOAT, false, 36, 12 * i);
gl.vertexAttribDivisor(lineProgramInfo.attribLocations.instanceNormalMatrices + i, 1);
}
}
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.lineIndexBuffer);
gl.bindVertexArray(null);
// Picking VAO
var vaoPick = this.vaoPick = gl.createVertexArray();
gl.bindVertexArray(vaoPick);
locations = [[pickProgramInfo.attribLocations.vertexPosition, this.positionBuffer]];
if (this.pickColorBuffer) {
locations.push([pickProgramInfo.attribLocations.vertexPickColor, this.pickColorBuffer]);
}
bindLocationPairs(locations);
if (this.instanceMatricesBuffer) {
gl.bindBuffer(gl.ARRAY_BUFFER, this.instanceMatricesBuffer);
for (let i = 0; i < 4; ++i) {
gl.enableVertexAttribArray(pickProgramInfo.attribLocations.instanceMatrices + i);
gl.vertexAttribPointer(pickProgramInfo.attribLocations.instanceMatrices + i, 4, gl.FLOAT, false, 64, 16 * i);
gl.vertexAttribDivisor(pickProgramInfo.attribLocations.instanceMatrices + i, 1);
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.instancePickColorsBuffer);
gl.enableVertexAttribArray(pickProgramInfo.attribLocations.instancePickColors);
gl.vertexAttribIPointer(pickProgramInfo.attribLocations.instancePickColors, 4, gl.UNSIGNED_BYTE, false, 0, 0);
gl.vertexAttribDivisor(pickProgramInfo.attribLocations.instancePickColors, 1);
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
gl.bindVertexArray(null);
}
}