1 | #include <mbgl/renderer/layers/render_hillshade_layer.hpp> |
2 | #include <mbgl/renderer/buckets/hillshade_bucket.hpp> |
3 | #include <mbgl/renderer/render_tile.hpp> |
4 | #include <mbgl/renderer/sources/render_raster_dem_source.hpp> |
5 | #include <mbgl/renderer/paint_parameters.hpp> |
6 | #include <mbgl/renderer/render_static_data.hpp> |
7 | #include <mbgl/programs/programs.hpp> |
8 | #include <mbgl/programs/hillshade_program.hpp> |
9 | #include <mbgl/programs/hillshade_prepare_program.hpp> |
10 | #include <mbgl/tile/tile.hpp> |
11 | #include <mbgl/style/layers/hillshade_layer_impl.hpp> |
12 | #include <mbgl/util/geo.hpp> |
13 | #include <mbgl/util/offscreen_texture.hpp> |
14 | |
15 | namespace mbgl { |
16 | |
17 | using namespace style; |
18 | RenderHillshadeLayer::RenderHillshadeLayer(Immutable<style::HillshadeLayer::Impl> _impl) |
19 | : RenderLayer(style::LayerType::Hillshade, _impl), |
20 | unevaluated(impl().paint.untransitioned()) { |
21 | } |
22 | |
23 | const style::HillshadeLayer::Impl& RenderHillshadeLayer::impl() const { |
24 | return static_cast<const style::HillshadeLayer::Impl&>(*baseImpl); |
25 | } |
26 | |
27 | std::unique_ptr<Bucket> RenderHillshadeLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const { |
28 | assert(false); |
29 | return nullptr; |
30 | } |
31 | |
32 | const std::array<float, 2> RenderHillshadeLayer::getLatRange(const UnwrappedTileID& id) { |
33 | const LatLng latlng0 = LatLng(id); |
34 | const LatLng latlng1 = LatLng(UnwrappedTileID(id.canonical.z, id.canonical.x, id.canonical.y + 1)); |
35 | return {._M_elems: { (float)latlng0.latitude(), (float)latlng1.latitude() }}; |
36 | } |
37 | |
38 | const std::array<float, 2> RenderHillshadeLayer::getLight(const PaintParameters& parameters){ |
39 | float azimuthal = evaluated.get<HillshadeIlluminationDirection>() * util::DEG2RAD; |
40 | if (evaluated.get<HillshadeIlluminationAnchor>() == HillshadeIlluminationAnchorType::Viewport) azimuthal = azimuthal - parameters.state.getAngle(); |
41 | return {._M_elems: {evaluated.get<HillshadeExaggeration>(), azimuthal}}; |
42 | } |
43 | |
44 | void RenderHillshadeLayer::transition(const TransitionParameters& parameters) { |
45 | unevaluated = impl().paint.transitioned(parameters, prior: std::move(unevaluated)); |
46 | } |
47 | |
48 | void RenderHillshadeLayer::evaluate(const PropertyEvaluationParameters& parameters) { |
49 | evaluated = unevaluated.evaluate(parameters); |
50 | passes = (evaluated.get<style::HillshadeExaggeration >() > 0) |
51 | ? (RenderPass::Translucent | RenderPass::Pass3D) |
52 | : RenderPass::None; |
53 | } |
54 | |
55 | bool RenderHillshadeLayer::hasTransition() const { |
56 | return unevaluated.hasTransition(); |
57 | } |
58 | |
59 | void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src) { |
60 | if (parameters.pass != RenderPass::Translucent && parameters.pass != RenderPass::Pass3D) |
61 | return; |
62 | |
63 | RenderRasterDEMSource* demsrc = dynamic_cast<RenderRasterDEMSource*>(src); |
64 | const uint8_t TERRAIN_RGB_MAXZOOM = 15; |
65 | const uint8_t maxzoom = demsrc != nullptr ? demsrc->getMaxZoom() : TERRAIN_RGB_MAXZOOM; |
66 | |
67 | auto draw = [&] (const mat4& matrix, |
68 | const auto& vertexBuffer, |
69 | const auto& indexBuffer, |
70 | const auto& segments, |
71 | const UnwrappedTileID& id) { |
72 | auto& programInstance = parameters.programs.hillshade; |
73 | |
74 | const HillshadeProgram::PaintPropertyBinders paintAttributeData{ evaluated, 0 }; |
75 | |
76 | const auto allUniformValues = programInstance.computeAllUniformValues( |
77 | uniformValues: HillshadeProgram::UniformValues { |
78 | uniforms::u_matrix::Value{ matrix }, |
79 | uniforms::u_image::Value{ 0 }, |
80 | uniforms::u_highlight::Value{ evaluated.get<HillshadeHighlightColor>() }, |
81 | uniforms::u_shadow::Value{ evaluated.get<HillshadeShadowColor>() }, |
82 | uniforms::u_accent::Value{ evaluated.get<HillshadeAccentColor>() }, |
83 | uniforms::u_light::Value{ getLight(parameters) }, |
84 | uniforms::u_latrange::Value{ getLatRange(id) }, |
85 | }, |
86 | paintPropertyBinders: paintAttributeData, |
87 | currentProperties: evaluated, |
88 | currentZoom: parameters.state.getZoom() |
89 | ); |
90 | const auto allAttributeBindings = programInstance.computeAllAttributeBindings( |
91 | layoutVertexBuffer: vertexBuffer, |
92 | paintPropertyBinders: paintAttributeData, |
93 | currentProperties: evaluated |
94 | ); |
95 | |
96 | checkRenderability(parameters, activeBindingCount: programInstance.activeBindingCount(allAttributeBindings)); |
97 | |
98 | programInstance.draw( |
99 | parameters.context, |
100 | gl::Triangles(), |
101 | parameters.depthModeForSublayer(n: 0, gl::DepthMode::ReadOnly), |
102 | gl::StencilMode::disabled(), |
103 | parameters.colorModeForRenderPass(), |
104 | indexBuffer, |
105 | segments, |
106 | allUniformValues, |
107 | allAttributeBindings, |
108 | getID() |
109 | ); |
110 | }; |
111 | |
112 | mat4 mat; |
113 | matrix::ortho(out&: mat, left: 0, right: util::EXTENT, bottom: -util::EXTENT, top: 0, near: 0, far: 1); |
114 | matrix::translate(out&: mat, a: mat, x: 0, y: -util::EXTENT, z: 0); |
115 | |
116 | for (const RenderTile& tile : renderTiles) { |
117 | auto bucket_ = tile.tile.getBucket<HillshadeBucket>(layer: *baseImpl); |
118 | if (!bucket_) { |
119 | continue; |
120 | } |
121 | HillshadeBucket& bucket = *bucket_; |
122 | |
123 | if (!bucket.hasData()){ |
124 | continue; |
125 | } |
126 | |
127 | if (!bucket.isPrepared() && parameters.pass == RenderPass::Pass3D) { |
128 | const uint16_t tilesize = bucket.getDEMData().dim; |
129 | OffscreenTexture view(parameters.context, { tilesize, tilesize }); |
130 | view.bind(); |
131 | |
132 | parameters.context.bindTexture(*bucket.dem, 0, gl::TextureFilter::Nearest, gl::TextureMipMap::No, wrapX: gl::TextureWrap::Clamp, wrapY: gl::TextureWrap::Clamp); |
133 | const Properties<>::PossiblyEvaluated properties; |
134 | const HillshadePrepareProgram::PaintPropertyBinders paintAttributeData{ properties, 0 }; |
135 | |
136 | auto& programInstance = parameters.programs.hillshadePrepare; |
137 | |
138 | const auto allUniformValues = programInstance.computeAllUniformValues( |
139 | uniformValues: HillshadePrepareProgram::UniformValues { |
140 | uniforms::u_matrix::Value { mat }, |
141 | uniforms::u_dimension::Value { {._M_elems: {uint16_t(tilesize * 2), uint16_t(tilesize * 2) }} }, |
142 | uniforms::u_zoom::Value{ float(tile.id.canonical.z) }, |
143 | uniforms::u_maxzoom::Value{ float(maxzoom) }, |
144 | uniforms::u_image::Value{ 0 } |
145 | }, |
146 | paintPropertyBinders: paintAttributeData, |
147 | currentProperties: properties, |
148 | currentZoom: parameters.state.getZoom() |
149 | ); |
150 | const auto allAttributeBindings = programInstance.computeAllAttributeBindings( |
151 | layoutVertexBuffer: parameters.staticData.rasterVertexBuffer, |
152 | paintPropertyBinders: paintAttributeData, |
153 | currentProperties: properties |
154 | ); |
155 | |
156 | checkRenderability(parameters, activeBindingCount: programInstance.activeBindingCount(allAttributeBindings)); |
157 | |
158 | programInstance.draw( |
159 | context&: parameters.context, |
160 | drawMode: gl::Triangles(), |
161 | depthMode: parameters.depthModeForSublayer(n: 0, gl::DepthMode::ReadOnly), |
162 | stencilMode: gl::StencilMode::disabled(), |
163 | colorMode: parameters.colorModeForRenderPass(), |
164 | indexBuffer: parameters.staticData.quadTriangleIndexBuffer, |
165 | segments: parameters.staticData.rasterSegments, |
166 | allUniformValues, |
167 | allAttributeBindings, |
168 | layerID: getID() |
169 | ); |
170 | bucket.texture = std::move(view.getTexture()); |
171 | bucket.setPrepared(true); |
172 | } else if (parameters.pass == RenderPass::Translucent) { |
173 | assert(bucket.texture); |
174 | parameters.context.bindTexture(*bucket.texture, 0, gl::TextureFilter::Linear, gl::TextureMipMap::No, wrapX: gl::TextureWrap::Clamp, wrapY: gl::TextureWrap::Clamp); |
175 | |
176 | if (bucket.vertexBuffer && bucket.indexBuffer && !bucket.segments.empty()) { |
177 | // Draw only the parts of the tile that aren't drawn by another tile in the layer. |
178 | draw(parameters.matrixForTile(tile.id, aligned: true), |
179 | *bucket.vertexBuffer, |
180 | *bucket.indexBuffer, |
181 | bucket.segments, |
182 | tile.id); |
183 | } else { |
184 | // Draw the full tile. |
185 | draw(parameters.matrixForTile(tile.id, aligned: true), |
186 | parameters.staticData.rasterVertexBuffer, |
187 | parameters.staticData.quadTriangleIndexBuffer, |
188 | parameters.staticData.rasterSegments, |
189 | tile.id); |
190 | } |
191 | } |
192 | |
193 | |
194 | } |
195 | } |
196 | |
197 | } // namespace mbgl |
198 | |