maplibre-gl
Version:
BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
139 lines (120 loc) • 4.18 kB
text/typescript
import {warnOnce} from '../util/util';
import {register} from '../util/web_worker_transfer';
import type {VertexArrayObject} from '../render/vertex_array_object';
import type {StructArray} from '../util/struct_array';
/**
* @internal
* A single segment of a vector
*/
export type Segment = {
sortKey?: number;
vertexOffset: number;
primitiveOffset: number;
vertexLength: number;
primitiveLength: number;
vaos: {[_: string]: VertexArrayObject};
};
/**
* @internal
* Used for calculations on vector segments
*/
export class SegmentVector {
static MAX_VERTEX_ARRAY_LENGTH: number;
segments: Array<Segment>;
private _forceNewSegmentOnNextPrepare: boolean = false;
constructor(segments: Array<Segment> = []) {
this.segments = segments;
}
/**
* Returns the last segment if `numVertices` fits into it.
* If there are no segments yet or `numVertices` doesn't fit into the last one, creates a new empty segment and returns it.
*/
prepareSegment(
numVertices: number,
layoutVertexArray: StructArray,
indexArray: StructArray,
sortKey?: number
): Segment {
const lastSegment: Segment = this.segments[this.segments.length - 1];
if (numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH) {
warnOnce(`Max vertices per segment is ${SegmentVector.MAX_VERTEX_ARRAY_LENGTH}: bucket requested ${numVertices}. Consider using the \`fillLargeMeshArrays\` function if you require meshes with more than ${SegmentVector.MAX_VERTEX_ARRAY_LENGTH} vertices.`);
}
if (this._forceNewSegmentOnNextPrepare || !lastSegment || lastSegment.vertexLength + numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH || lastSegment.sortKey !== sortKey) {
return this.createNewSegment(layoutVertexArray, indexArray, sortKey);
} else {
return lastSegment;
}
}
/**
* Creates a new empty segment and returns it.
*/
createNewSegment(
layoutVertexArray: StructArray,
indexArray: StructArray,
sortKey?: number
): Segment {
const segment: Segment = {
vertexOffset: layoutVertexArray.length,
primitiveOffset: indexArray.length,
vertexLength: 0,
primitiveLength: 0,
vaos: {}
};
if (sortKey !== undefined) {
segment.sortKey = sortKey;
}
// If this was set, we have no need to create a new segment on next prepareSegment call,
// since this function already created a new, empty segment.
this._forceNewSegmentOnNextPrepare = false;
this.segments.push(segment);
return segment;
}
/**
* Returns the last segment, or creates a new segments if there are no segments yet.
*/
getOrCreateLatestSegment(
layoutVertexArray: StructArray,
indexArray: StructArray,
sortKey?: number
): Segment {
return this.prepareSegment(0, layoutVertexArray, indexArray, sortKey);
}
/**
* Causes the next call to {@link prepareSegment} to always return a new segment,
* not reusing the current segment even if the new geometry would fit it.
*/
forceNewSegmentOnNextPrepare() {
this._forceNewSegmentOnNextPrepare = true;
}
get() {
return this.segments;
}
destroy() {
for (const segment of this.segments) {
for (const k in segment.vaos) {
segment.vaos[k].destroy();
}
}
}
static simpleSegment(
vertexOffset: number,
primitiveOffset: number,
vertexLength: number,
primitiveLength: number
): SegmentVector {
return new SegmentVector([{
vertexOffset,
primitiveOffset,
vertexLength,
primitiveLength,
vaos: {},
sortKey: 0
}]);
}
}
/**
* The maximum size of a vertex array. This limit is imposed by WebGL's 16 bit
* addressing of vertex buffers.
*/
SegmentVector.MAX_VERTEX_ARRAY_LENGTH = Math.pow(2, 16) - 1;
register('SegmentVector', SegmentVector);