void RenderTile::finishRender(PaintParameters& parameters) { if (!used || parameters.debugOptions == MapDebugOptions::NoDebug) return; static const style::Properties<>::PossiblyEvaluated properties {}; static const DebugProgram::PaintPropertyBinders paintAttributeData(properties, 0); auto& program = parameters.programs.debug; if (parameters.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) { if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() || tile.debugBucket->complete != tile.isComplete() || !(tile.debugBucket->modified == tile.modified) || !(tile.debugBucket->expires == tile.expires) || tile.debugBucket->debugMode != parameters.debugOptions) { tile.debugBucket = std::make_unique<DebugBucket>( tile.id, tile.isRenderable(), tile.isComplete(), tile.modified, tile.expires, parameters.debugOptions, parameters.context); } const auto allAttributeBindings = program.computeAllAttributeBindings( *tile.debugBucket->vertexBuffer, paintAttributeData, properties ); program.draw( parameters.context, gl::Lines { 4.0f * parameters.pixelRatio }, gl::DepthMode::disabled(), parameters.stencilModeForClipping(clip), gl::ColorMode::unblended(), gl::CullFaceMode::disabled(), *tile.debugBucket->indexBuffer, tile.debugBucket->segments, program.computeAllUniformValues( DebugProgram::UniformValues { uniforms::u_matrix::Value( matrix ), uniforms::u_color::Value( Color::white() ) }, paintAttributeData, properties, parameters.state.getZoom() ), allAttributeBindings, "debug" ); program.draw( parameters.context, gl::Lines { 2.0f * parameters.pixelRatio }, gl::DepthMode::disabled(), parameters.stencilModeForClipping(clip), gl::ColorMode::unblended(), gl::CullFaceMode::disabled(), *tile.debugBucket->indexBuffer, tile.debugBucket->segments, program.computeAllUniformValues( DebugProgram::UniformValues { uniforms::u_matrix::Value( matrix ), uniforms::u_color::Value( Color::black() ) }, paintAttributeData, properties, parameters.state.getZoom() ), allAttributeBindings, "debug" ); } if (parameters.debugOptions & MapDebugOptions::TileBorders) { parameters.programs.debug.draw( parameters.context, gl::LineStrip { 4.0f * parameters.pixelRatio }, gl::DepthMode::disabled(), parameters.stencilModeForClipping(clip), gl::ColorMode::unblended(), gl::CullFaceMode::disabled(), parameters.staticData.tileBorderIndexBuffer, parameters.staticData.tileBorderSegments, program.computeAllUniformValues( DebugProgram::UniformValues { uniforms::u_matrix::Value( matrix ), uniforms::u_color::Value( Color::red() ) }, paintAttributeData, properties, parameters.state.getZoom() ), program.computeAllAttributeBindings( parameters.staticData.tileVertexBuffer, paintAttributeData, properties ), "debug" ); } }
void RenderHeatmapLayer::render(PaintParameters& parameters, RenderSource*) { if (parameters.pass == RenderPass::Opaque) { return; } if (parameters.pass == RenderPass::Pass3D) { const auto& viewportSize = parameters.staticData.backendSize; const auto size = Size{viewportSize.width / 4, viewportSize.height / 4}; if (!renderTexture || renderTexture->getSize() != size) { if (parameters.context.supportsHalfFloatTextures) { renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::HalfFloat); try { renderTexture->bind(); } catch (const std::runtime_error& ex) { // can't render to a half-float texture; falling back to unsigned byte one renderTexture = nullopt; parameters.context.supportsHalfFloatTextures = false; } } if (!parameters.context.supportsHalfFloatTextures || !renderTexture) { renderTexture = OffscreenTexture(parameters.context, size, gl::TextureType::UnsignedByte); renderTexture->bind(); } } else { renderTexture->bind(); } if (!colorRampTexture) { colorRampTexture = parameters.context.createTexture(colorRamp, 1, gl::TextureType::UnsignedByte); } parameters.context.clear(Color{ 0.0f, 0.0f, 0.0f, 1.0f }, {}, {}); for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket<HeatmapBucket>(*baseImpl); if (!bucket_) { continue; } HeatmapBucket& bucket = *bucket_; const auto extrudeScale = tile.id.pixelsToTileUnits(1, parameters.state.getZoom()); const auto stencilMode = parameters.mapMode != MapMode::Continuous ? parameters.stencilModeForClipping(tile.clip) : gl::StencilMode::disabled(); const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); auto& programInstance = parameters.programs.heatmap.get(evaluated); const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapProgram::UniformValues { uniforms::u_intensity::Value( evaluated.get<style::HeatmapIntensity>() ), uniforms::u_matrix::Value( tile.matrix ), uniforms::heatmap::u_extrude_scale::Value( extrudeScale ) }, paintPropertyBinders, evaluated, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( *bucket.vertexBuffer, paintPropertyBinders, evaluated ); checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, gl::Triangles(), parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly), stencilMode, gl::ColorMode::additive(), gl::CullFaceMode::disabled(), *bucket.indexBuffer, bucket.segments, allUniformValues, allAttributeBindings, getID() ); } } else if (parameters.pass == RenderPass::Translucent) { parameters.context.bindTexture(renderTexture->getTexture(), 0, gl::TextureFilter::Linear); parameters.context.bindTexture(*colorRampTexture, 1, gl::TextureFilter::Linear); const auto& size = parameters.staticData.backendSize; mat4 viewportMat; matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); const Properties<>::PossiblyEvaluated properties; const HeatmapTextureProgram::PaintPropertyBinders paintAttributeData{ properties, 0 }; auto& programInstance = parameters.programs.heatmapTexture; const auto allUniformValues = programInstance.computeAllUniformValues( HeatmapTextureProgram::UniformValues{ uniforms::u_matrix::Value( viewportMat ), uniforms::u_world::Value( size ), uniforms::u_image::Value( 0 ), uniforms::u_color_ramp::Value( 1 ), uniforms::u_opacity::Value( evaluated.get<HeatmapOpacity>() ) }, paintAttributeData, properties, parameters.state.getZoom() ); const auto allAttributeBindings = programInstance.computeAllAttributeBindings( parameters.staticData.extrusionTextureVertexBuffer, paintAttributeData, properties ); checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, gl::Triangles(), gl::DepthMode::disabled(), gl::StencilMode::disabled(), parameters.colorModeForRenderPass(), gl::CullFaceMode::disabled(), parameters.staticData.quadTriangleIndexBuffer, parameters.staticData.extrusionTextureSegments, allUniformValues, allAttributeBindings, getID() ); } }
void RenderFillLayer::render(PaintParameters& parameters, RenderSource*) { if (evaluated.get<FillPattern>().from.empty()) { for (const RenderTile& tile : renderTiles) { assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl))); FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)); auto draw = [&] (auto& program, const auto& drawMode, const auto& depthMode, const auto& indexBuffer, const auto& segments) { program.get(evaluated).draw( parameters.context, drawMode, depthMode, parameters.stencilModeForClipping(tile.clip), parameters.colorModeForRenderPass(), FillProgram::UniformValues { uniforms::u_matrix::Value{ tile.translatedMatrix(evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), parameters.state) }, uniforms::u_world::Value{ parameters.context.viewport.getCurrentValue().size }, }, *bucket.vertexBuffer, indexBuffer, segments, bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(), getID() ); }; // Only draw the fill when it's opaque and we're drawing opaque fragments, // or when it's translucent and we're drawing translucent fragments. if ((evaluated.get<FillColor>().constantOr(Color()).a >= 1.0f && evaluated.get<FillOpacity>().constantOr(0) >= 1.0f) == (parameters.pass == RenderPass::Opaque)) { draw(parameters.programs.fill, gl::Triangles(), parameters.depthModeForSublayer(1, parameters.pass == RenderPass::Opaque ? gl::DepthMode::ReadWrite : gl::DepthMode::ReadOnly), *bucket.triangleIndexBuffer, bucket.triangleSegments); } if (evaluated.get<FillAntialias>() && parameters.pass == RenderPass::Translucent) { draw(parameters.programs.fillOutline, gl::Lines{ 2.0f }, parameters.depthModeForSublayer( unevaluated.get<FillOutlineColor>().isUndefined() ? 2 : 0, gl::DepthMode::ReadOnly), *bucket.lineIndexBuffer, bucket.lineSegments); } } } else { if (parameters.pass != RenderPass::Translucent) { return; } optional<ImagePosition> imagePosA = parameters.imageManager.getPattern(evaluated.get<FillPattern>().from); optional<ImagePosition> imagePosB = parameters.imageManager.getPattern(evaluated.get<FillPattern>().to); if (!imagePosA || !imagePosB) { return; } parameters.imageManager.bind(parameters.context, 0); for (const RenderTile& tile : renderTiles) { assert(dynamic_cast<FillBucket*>(tile.tile.getBucket(*baseImpl))); FillBucket& bucket = *reinterpret_cast<FillBucket*>(tile.tile.getBucket(*baseImpl)); auto draw = [&] (auto& program, const auto& drawMode, const auto& depthMode, const auto& indexBuffer, const auto& segments) { program.get(evaluated).draw( parameters.context, drawMode, depthMode, parameters.stencilModeForClipping(tile.clip), parameters.colorModeForRenderPass(), FillPatternUniforms::values( tile.translatedMatrix(evaluated.get<FillTranslate>(), evaluated.get<FillTranslateAnchor>(), parameters.state), parameters.context.viewport.getCurrentValue().size, parameters.imageManager.getPixelSize(), *imagePosA, *imagePosB, evaluated.get<FillPattern>(), tile.id, parameters.state ), *bucket.vertexBuffer, indexBuffer, segments, bucket.paintPropertyBinders.at(getID()), evaluated, parameters.state.getZoom(), getID() ); }; draw(parameters.programs.fillPattern, gl::Triangles(), parameters.depthModeForSublayer(1, gl::DepthMode::ReadWrite), *bucket.triangleIndexBuffer, bucket.triangleSegments); if (evaluated.get<FillAntialias>() && unevaluated.get<FillOutlineColor>().isUndefined()) { draw(parameters.programs.fillOutlinePattern, gl::Lines { 2.0f }, parameters.depthModeForSublayer(2, gl::DepthMode::ReadOnly), *bucket.lineIndexBuffer, bucket.lineSegments); } } } }