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
15namespace mbgl {
16
17using namespace style;
18RenderHillshadeLayer::RenderHillshadeLayer(Immutable<style::HillshadeLayer::Impl> _impl)
19 : RenderLayer(style::LayerType::Hillshade, _impl),
20 unevaluated(impl().paint.untransitioned()) {
21}
22
23const style::HillshadeLayer::Impl& RenderHillshadeLayer::impl() const {
24 return static_cast<const style::HillshadeLayer::Impl&>(*baseImpl);
25}
26
27std::unique_ptr<Bucket> RenderHillshadeLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
28 assert(false);
29 return nullptr;
30}
31
32const 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
38const 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
44void RenderHillshadeLayer::transition(const TransitionParameters& parameters) {
45 unevaluated = impl().paint.transitioned(parameters, prior: std::move(unevaluated));
46}
47
48void 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
55bool RenderHillshadeLayer::hasTransition() const {
56 return unevaluated.hasTransition();
57}
58
59void 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

source code of qtlocation/src/3rdparty/mapbox-gl-native/src/mbgl/renderer/layers/render_hillshade_layer.cpp