/
layers-pass.js
159 lines (133 loc) · 4.77 KB
/
layers-pass.js
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
import GL from '@luma.gl/constants';
import Pass from './pass';
import {clear, setParameters, withParameters, cssToDeviceRatio} from '@luma.gl/core';
export default class LayersPass extends Pass {
render(props) {
const gl = this.gl;
return withParameters(gl, {framebuffer: props.outputBuffer}, () => this.drawLayers(props));
}
// PRIVATE
// Draw a list of layers in a list of viewports
drawLayers(props) {
const {viewports, views, onViewportActive, clearCanvas = true} = props;
const gl = this.gl;
if (clearCanvas) {
clearGLCanvas(gl);
}
const renderStats = [];
viewports.forEach((viewportOrDescriptor, i) => {
// Get a viewport from a viewport descriptor (which can be a plain viewport)
const viewport = viewportOrDescriptor.viewport || viewportOrDescriptor;
const view = views && views[viewport.id];
// Update context to point to this viewport
onViewportActive(viewport);
props.viewport = viewport;
props.view = view;
// render this viewport
const stats = this.drawLayersInViewport(gl, props);
renderStats.push(stats);
});
return renderStats;
}
// Draws a list of layers in one viewport
// TODO - when picking we could completely skip rendering viewports that dont
// intersect with the picking rect
drawLayersInViewport(
gl,
{layers, layerFilter, viewport, view, parameters, pass = 'draw', effects, effectProps}
) {
const glViewport = getGLViewport(gl, {viewport});
if (view && view.props.clear) {
const clearOpts = view.props.clear === true ? {color: true, depth: true} : view.props.clear;
withParameters(
gl,
{
scissorTest: true,
scissor: glViewport
},
() => clear(gl, clearOpts)
);
}
// render layers in normal colors
const renderStatus = {
totalCount: layers.length,
visibleCount: 0,
compositeCount: 0,
pickableCount: 0
};
setParameters(gl, parameters || {});
// render layers in normal colors
layers.forEach((layer, layerIndex) => {
// Check if we should draw layer
const shouldDrawLayer = this.shouldDrawLayer(layer, viewport, layerFilter);
// Calculate stats
if (shouldDrawLayer && layer.props.pickable) {
renderStatus.pickableCount++;
}
if (layer.isComposite) {
renderStatus.compositeCount++;
}
// Draw the layer
if (shouldDrawLayer) {
renderStatus.visibleCount++;
const moduleParameters = this.getModuleParameters(layer, effects, effectProps);
const uniforms = Object.assign({}, layer.context.uniforms, {layerIndex});
const layerParameters = this.getLayerParameters(layer, layerIndex, glViewport, parameters);
layer.drawLayer({
moduleParameters,
uniforms,
parameters: layerParameters
});
}
});
return renderStatus;
}
shouldDrawLayer(layer, viewport, layerFilter) {
let shouldDrawLayer = !layer.isComposite && layer.props.visible;
if (shouldDrawLayer && layerFilter) {
shouldDrawLayer = layerFilter({layer, viewport, isPicking: false});
}
return shouldDrawLayer;
}
getModuleParameters(layer) {
const moduleParameters = Object.assign(Object.create(layer.props), {
viewport: layer.context.viewport,
mousePosition: layer.context.mousePosition,
pickingActive: 0,
devicePixelRatio: cssToDeviceRatio(this.gl)
});
return moduleParameters;
}
getLayerParameters(layer, layerIndex, glViewport, parameters) {
// All parameter resolving is done here instead of the layer
// Blend parameters must not be overridden
const layerParameters = Object.assign({}, layer.props.parameters || {}, parameters);
Object.assign(layerParameters, {
viewport: glViewport
});
return layerParameters;
}
}
// Convert viewport top-left CSS coordinates to bottom up WebGL coordinates
function getGLViewport(gl, {viewport}) {
// TODO - dummy default for node
// Fallback to width/height when clientWidth/clientHeight are 0 or undefined.
const height = gl.canvas ? gl.canvas.clientHeight || gl.canvas.height : 100;
// Convert viewport top-left CSS coordinates to bottom up WebGL coordinates
const dimensions = viewport;
const pixelRatio = cssToDeviceRatio(gl);
return [
dimensions.x * pixelRatio,
(height - dimensions.y - dimensions.height) * pixelRatio,
dimensions.width * pixelRatio,
dimensions.height * pixelRatio
];
}
function clearGLCanvas(gl) {
const width = gl.drawingBufferWidth;
const height = gl.drawingBufferHeight;
// clear depth and color buffers, restoring transparency
withParameters(gl, {viewport: [0, 0, width, height]}, () => {
gl.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT);
});
}