package.src.render.draw_collision_debug.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mapbox-gl Show documentation
Show all versions of mapbox-gl Show documentation
A WebGL interactive maps library
The newest version!
// @flow
import type Painter from './painter';
import type SourceCache from '../source/source_cache';
import type StyleLayer from '../style/style_layer';
import type {OverscaledTileID} from '../source/tile_id';
import type SymbolBucket from '../data/bucket/symbol_bucket';
import DepthMode from '../gl/depth_mode';
import StencilMode from '../gl/stencil_mode';
import CullFaceMode from '../gl/cull_face_mode';
import {collisionUniformValues, collisionCircleUniformValues} from './program/collision_program';
import {QuadTriangleArray, CollisionCircleLayoutArray} from '../data/array_types';
import {collisionCircleLayout} from '../data/bucket/symbol_attributes';
import SegmentVector from '../data/segment';
import {mat4} from 'gl-matrix';
import VertexBuffer from '../gl/vertex_buffer';
import IndexBuffer from '../gl/index_buffer';
export default drawCollisionDebug;
type TileBatch = {
circleArray: Array,
circleOffset: number,
transform: mat4,
invTransform: mat4
};
let quadTriangles: ?QuadTriangleArray;
function drawCollisionDebug(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array, translate: [number, number], translateAnchor: 'map' | 'viewport', isText: boolean) {
const context = painter.context;
const gl = context.gl;
const program = painter.useProgram('collisionBox');
const tileBatches: Array = [];
let circleCount = 0;
let circleOffset = 0;
for (let i = 0; i < coords.length; i++) {
const coord = coords[i];
const tile = sourceCache.getTile(coord);
const bucket: ?SymbolBucket = (tile.getBucket(layer): any);
if (!bucket) continue;
let posMatrix = coord.posMatrix;
if (translate[0] !== 0 || translate[1] !== 0) {
posMatrix = painter.translatePosMatrix(coord.posMatrix, tile, translate, translateAnchor);
}
const buffers = isText ? bucket.textCollisionBox : bucket.iconCollisionBox;
// Get collision circle data of this bucket
const circleArray: Array = bucket.collisionCircleArray;
if (circleArray.length > 0) {
// We need to know the projection matrix that was used for projecting collision circles to the screen.
// This might vary between buckets as the symbol placement is a continous process. This matrix is
// required for transforming points from previous screen space to the current one
const invTransform = mat4.create();
const transform = posMatrix;
mat4.mul(invTransform, bucket.placementInvProjMatrix, painter.transform.glCoordMatrix);
mat4.mul(invTransform, invTransform, bucket.placementViewportMatrix);
tileBatches.push({
circleArray,
circleOffset,
transform,
invTransform
});
circleCount += circleArray.length / 4; // 4 values per circle
circleOffset = circleCount;
}
if (!buffers) continue;
program.draw(context, gl.LINES,
DepthMode.disabled, StencilMode.disabled,
painter.colorModeForRenderPass(),
CullFaceMode.disabled,
collisionUniformValues(
posMatrix,
painter.transform,
tile),
layer.id, buffers.layoutVertexBuffer, buffers.indexBuffer,
buffers.segments, null, painter.transform.zoom, null, null,
buffers.collisionVertexBuffer);
}
if (!isText || !tileBatches.length) {
return;
}
// Render collision circles
const circleProgram = painter.useProgram('collisionCircle');
// Construct vertex data
const vertexData = new CollisionCircleLayoutArray();
vertexData.resize(circleCount * 4);
vertexData._trim();
let vertexOffset = 0;
for (const batch of tileBatches) {
for (let i = 0; i < batch.circleArray.length / 4; i++) {
const circleIdx = i * 4;
const x = batch.circleArray[circleIdx + 0];
const y = batch.circleArray[circleIdx + 1];
const radius = batch.circleArray[circleIdx + 2];
const collision = batch.circleArray[circleIdx + 3];
// 4 floats per vertex, 4 vertices per quad
vertexData.emplace(vertexOffset++, x, y, radius, collision, 0);
vertexData.emplace(vertexOffset++, x, y, radius, collision, 1);
vertexData.emplace(vertexOffset++, x, y, radius, collision, 2);
vertexData.emplace(vertexOffset++, x, y, radius, collision, 3);
}
}
if (!quadTriangles || quadTriangles.length < circleCount * 2) {
quadTriangles = createQuadTriangles(circleCount);
}
const indexBuffer: IndexBuffer = context.createIndexBuffer(quadTriangles, true);
const vertexBuffer: VertexBuffer = context.createVertexBuffer(vertexData, collisionCircleLayout.members, true);
// Render batches
for (const batch of tileBatches) {
const uniforms = collisionCircleUniformValues(
batch.transform,
batch.invTransform,
painter.transform
);
circleProgram.draw(
context,
gl.TRIANGLES,
DepthMode.disabled,
StencilMode.disabled,
painter.colorModeForRenderPass(),
CullFaceMode.disabled,
uniforms,
layer.id,
vertexBuffer,
indexBuffer,
SegmentVector.simpleSegment(0, batch.circleOffset * 2, batch.circleArray.length, batch.circleArray.length / 2),
null,
painter.transform.zoom,
null,
null,
null);
}
vertexBuffer.destroy();
indexBuffer.destroy();
}
function createQuadTriangles(quadCount: number): QuadTriangleArray {
const triCount = quadCount * 2;
const array = new QuadTriangleArray();
array.resize(triCount);
array._trim();
// Two triangles and 4 vertices per quad.
for (let i = 0; i < triCount; i++) {
const idx = i * 6;
array.uint16[idx + 0] = i * 4 + 0;
array.uint16[idx + 1] = i * 4 + 1;
array.uint16[idx + 2] = i * 4 + 2;
array.uint16[idx + 3] = i * 4 + 2;
array.uint16[idx + 4] = i * 4 + 3;
array.uint16[idx + 5] = i * 4 + 0;
}
return array;
}