@@ -8,38 +8,207 @@ import type SymbolBucket from '../data/bucket/symbol_bucket';
8
8
import DepthMode from '../gl/depth_mode' ;
9
9
import StencilMode from '../gl/stencil_mode' ;
10
10
import CullFaceMode from '../gl/cull_face_mode' ;
11
- import { collisionUniformValues } from './program/collision_program' ;
11
+ import { collisionUniformValues , collisionUniformValuesTemp } from './program/collision_program' ;
12
+
13
+ import { StructArrayLayout4i8 , StructArrayLayout3ui6 } from '../data/array_types'
14
+ import { collisionCircleLayoutTemp } from '../data/bucket/symbol_attributes' ;
15
+ import SegmentVector from '../data/segment' ;
16
+ import { mat4 , vec4 } from 'gl-matrix' ;
12
17
13
18
export default drawCollisionDebug ;
14
19
20
+ //const matrixCache = {};
21
+
15
22
function drawCollisionDebugGeometry ( painter : Painter , sourceCache : SourceCache , layer : StyleLayer , coords : Array < OverscaledTileID > , drawCircles : boolean ,
16
23
translate : [ number , number ] , translateAnchor : 'map' | 'viewport' , isText : boolean ) {
17
24
const context = painter . context ;
18
25
const gl = context . gl ;
19
26
const program = drawCircles ? painter . useProgram ( 'collisionCircle' ) : painter . useProgram ( 'collisionBox' ) ;
20
27
28
+ if ( ! drawCircles ) {
29
+ for ( let i = 0 ; i < coords . length ; i ++ ) {
30
+ const coord = coords [ i ] ;
31
+ const tile = sourceCache . getTile ( coord ) ;
32
+ const bucket : ?SymbolBucket = ( tile . getBucket ( layer ) : any ) ;
33
+ if ( ! bucket ) continue ;
34
+ const buffers = drawCircles ? ( isText ? bucket . textCollisionCircle : bucket . iconCollisionCircle ) : ( isText ? bucket . textCollisionBox : bucket . iconCollisionBox ) ;
35
+ if ( ! buffers ) continue ;
36
+ let posMatrix = coord . posMatrix ;
37
+ if ( translate [ 0 ] !== 0 || translate [ 1 ] !== 0 ) {
38
+ posMatrix = painter . translatePosMatrix ( coord . posMatrix , tile , translate , translateAnchor ) ;
39
+ }
40
+ program . draw ( context , drawCircles ? gl . TRIANGLES : gl . LINES ,
41
+ DepthMode . disabled , StencilMode . disabled ,
42
+ painter . colorModeForRenderPass ( ) ,
43
+ CullFaceMode . disabled ,
44
+ collisionUniformValues (
45
+ posMatrix ,
46
+ painter . transform ,
47
+ tile ) ,
48
+ layer . id , buffers . layoutVertexBuffer , buffers . indexBuffer ,
49
+ buffers . segments , null , painter . transform . zoom , null , null ,
50
+ buffers . collisionVertexBuffer ) ;
51
+ }
52
+ }
53
+
54
+ // Render collision circles
55
+ const program2 = painter . useProgram ( 'collisionCircleTemp' ) ;
56
+
57
+ const maxCirclesPerBatch = 4096 ;
58
+ const maxVerticesPerBatch = maxCirclesPerBatch * 4 ;
59
+ const maxIndicesPerBatch = maxCirclesPerBatch * 6 ;
60
+
61
+ if ( ! ( 'vertexBuffer2' in layer ) ) {
62
+ const array = new StructArrayLayout4i8 ( ) ;
63
+
64
+ // use temporary array reserve space for x circles (4 vertex per quad)
65
+ array . resize ( maxVerticesPerBatch ) ;
66
+ array . _trim ( ) ;
67
+
68
+ layer . vertexBuffer2 = context . createVertexBuffer ( array , collisionCircleLayoutTemp . members , true ) ;
69
+ }
70
+
71
+ if ( ! ( 'indexBuffer2' in layer ) ) {
72
+ const array = new StructArrayLayout3ui6 ( ) ;
73
+
74
+ // Pre-generate index buffer for quads
75
+ array . resize ( maxIndicesPerBatch ) ;
76
+ array . _trim ( ) ;
77
+
78
+ for ( let i = 0 ; i < maxCirclesPerBatch ; i ++ ) {
79
+ const idx = i * 6 ;
80
+
81
+ array . uint16 [ idx + 0 ] = i * 4 + 0 ;
82
+ array . uint16 [ idx + 1 ] = i * 4 + 1 ;
83
+ array . uint16 [ idx + 2 ] = i * 4 + 2 ;
84
+ array . uint16 [ idx + 3 ] = i * 4 + 2 ;
85
+ array . uint16 [ idx + 4 ] = i * 4 + 3 ;
86
+ array . uint16 [ idx + 5 ] = i * 4 + 0 ;
87
+ }
88
+
89
+ layer . indexBuffer2 = context . createIndexBuffer ( array , true ) ;
90
+ }
91
+
92
+ let colorFlip = false ;
93
+
94
+ // Gather collision circles of tiles and render them in batches
95
+ const batchVertices = new StructArrayLayout4i8 ( ) ;
96
+ batchVertices . resize ( maxVerticesPerBatch ) ;
97
+ batchVertices . _trim ( ) ;
98
+
99
+ const appendVertex = ( idx , x , y , z , w ) => {
100
+ batchVertices . int16 [ idx * 4 + 0 ] = x ; // anchor center
101
+ batchVertices . int16 [ idx * 4 + 1 ] = y ; // anchor center
102
+ batchVertices . int16 [ idx * 4 + 2 ] = z ; // radius
103
+ batchVertices . int16 [ idx * 4 + 3 ] = w ; // radius
104
+ }
105
+
21
106
for ( let i = 0 ; i < coords . length ; i ++ ) {
22
107
const coord = coords [ i ] ;
23
108
const tile = sourceCache . getTile ( coord ) ;
24
109
const bucket : ?SymbolBucket = ( tile . getBucket ( layer ) : any ) ;
25
110
if ( ! bucket ) continue ;
26
- const buffers = drawCircles ? ( isText ? bucket . textCollisionCircle : bucket . iconCollisionCircle ) : ( isText ? bucket . textCollisionBox : bucket . iconCollisionBox ) ;
27
- if ( ! buffers ) continue ;
111
+
112
+ const arr = bucket . collisionCircleArrayTemp ;
113
+
114
+ if ( ! arr . length )
115
+ continue ;
116
+
117
+ // Collision circle rendering is a little more complex now that they're stored in screen coordinates.
118
+ // Screen space positions of previous frames can be reused by transforming them first to tile space and
119
+ // then to the new clip space. Depth information of vertices is not preserved during circle generation
120
+ // so it has to be reconstructed in vertex shader
28
121
let posMatrix = coord . posMatrix ;
29
122
if ( translate [ 0 ] !== 0 || translate [ 1 ] !== 0 ) {
30
123
posMatrix = painter . translatePosMatrix ( coord . posMatrix , tile , translate , translateAnchor ) ;
31
124
}
32
- program . draw ( context , drawCircles ? gl . TRIANGLES : gl . LINES ,
33
- DepthMode . disabled , StencilMode . disabled ,
34
- painter . colorModeForRenderPass ( ) ,
35
- CullFaceMode . disabled ,
36
- collisionUniformValues (
37
- posMatrix ,
38
- painter . transform ,
39
- tile ) ,
40
- layer . id , buffers . layoutVertexBuffer , buffers . indexBuffer ,
41
- buffers . segments , null , painter . transform . zoom , null , null ,
42
- buffers . collisionVertexBuffer ) ;
125
+
126
+ let prevInvPosMatrix = posMatrix ;
127
+
128
+ if ( 'posMatrixCircles' in bucket ) {
129
+ prevInvPosMatrix = mat4 . invert ( [ ] , bucket [ 'posMatrixCircles' ] ) ;
130
+ } else {
131
+ prevInvPosMatrix = mat4 . invert ( [ ] , posMatrix ) ;
132
+ }
133
+
134
+ const uniforms = collisionUniformValuesTemp ( painter . transform . glCoordMatrix , prevInvPosMatrix ,
135
+ posMatrix , [ painter . transform . width , painter . transform . height ] ) ;
136
+
137
+ // Upload and render quads in batches
138
+ let batchVertexIdx = 0 ;
139
+ let vertexOffset = 0 ;
140
+
141
+ while ( vertexOffset < arr . length ) {
142
+ const verticesLeft = arr . length - vertexOffset ;
143
+ const vertexSpaceLeftInBatch = maxVerticesPerBatch - batchVertexIdx ;
144
+ const batchSize = Math . min ( verticesLeft , vertexSpaceLeftInBatch ) ;
145
+
146
+ for ( let vIdx = vertexOffset ; vIdx < vertexOffset + batchSize ; vIdx += 4 ) {
147
+ const r = arr [ vIdx + 2 ] ;
148
+ appendVertex ( batchVertexIdx + 0 , arr [ vIdx + 0 ] , arr [ vIdx + 1 ] , - r , - r ) ;
149
+ appendVertex ( batchVertexIdx + 1 , arr [ vIdx + 0 ] , arr [ vIdx + 1 ] , - r , r ) ;
150
+ appendVertex ( batchVertexIdx + 2 , arr [ vIdx + 0 ] , arr [ vIdx + 1 ] , r , r ) ;
151
+ appendVertex ( batchVertexIdx + 3 , arr [ vIdx + 0 ] , arr [ vIdx + 1 ] , r , - r ) ;
152
+
153
+ batchVertexIdx += 4 ;
154
+ }
155
+
156
+ vertexOffset += batchSize ;
157
+
158
+ // TODO: Proper buffer orphaning. This might currently cause CPU-GPU sync!
159
+ if ( batchVertexIdx == maxVerticesPerBatch ) {
160
+ // Render the batch
161
+ layer . vertexBuffer2 . updateData ( batchVertices , 0 ) ;
162
+
163
+ program2 . draw (
164
+ context ,
165
+ gl . TRIANGLES ,
166
+ DepthMode . disabled ,
167
+ StencilMode . disabled ,
168
+ painter . colorModeForRenderPass ( ) ,
169
+ CullFaceMode . disabled ,
170
+ uniforms ,
171
+ layer . id ,
172
+ layer . vertexBuffer2 , // layoutVertexBuffer
173
+ layer . indexBuffer2 , // indexbuffer,
174
+ SegmentVector . simpleSegment ( 0 , 0 , batchVertexIdx , batchVertexIdx / 2 ) ,
175
+ null ,
176
+ painter . transform . zoom ,
177
+ null ,
178
+ null , // vertexBuffer
179
+ null // vertexBuffer
180
+ ) ;
181
+
182
+ batchVertexIdx = 0 ;
183
+ }
184
+ }
185
+
186
+ // Render the leftover branch
187
+ if ( batchVertexIdx ) {
188
+ // Render the batch
189
+ layer . vertexBuffer2 . updateData ( batchVertices , 0 ) ;
190
+
191
+ program2 . draw (
192
+ context ,
193
+ gl . TRIANGLES ,
194
+ DepthMode . disabled ,
195
+ StencilMode . disabled ,
196
+ painter . colorModeForRenderPass ( ) ,
197
+ CullFaceMode . disabled ,
198
+ uniforms ,
199
+ layer . id ,
200
+ layer . vertexBuffer2 , // layoutVertexBuffer
201
+ layer . indexBuffer2 , // indexbuffer,
202
+ SegmentVector . simpleSegment ( 0 , 0 , batchVertexIdx , batchVertexIdx / 2 ) ,
203
+ null ,
204
+ painter . transform . zoom ,
205
+ null ,
206
+ null , // vertexBuffer
207
+ null // vertexBuffer
208
+ ) ;
209
+
210
+ batchVertexIdx = 0 ;
211
+ }
43
212
}
44
213
}
45
214
0 commit comments