Spaces:
Sleeping
Sleeping
File size: 6,412 Bytes
9a14526 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 | // @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<number>,
circleOffset: number,
transform: mat4,
invTransform: mat4
};
let quadTriangles: ?QuadTriangleArray;
function drawCollisionDebug(painter: Painter, sourceCache: SourceCache, layer: StyleLayer, coords: Array<OverscaledTileID>, translate: [number, number], translateAnchor: 'map' | 'viewport', isText: boolean) {
const context = painter.context;
const gl = context.gl;
const program = painter.useProgram('collisionBox');
const tileBatches: Array<TileBatch> = [];
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<number> = 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;
}
|