#include #include #include #include #include #include #include #include #include #include #include namespace mbgl { using namespace style; namespace { inline const RasterLayer::Impl& impl_cast(const Immutable& impl) { assert(impl->getTypeInfo() == RasterLayer::Impl::staticTypeInfo()); return static_cast(*impl); } } // namespace RenderRasterLayer::RenderRasterLayer(Immutable _impl) : RenderLayer(makeMutable(std::move(_impl))), unevaluated(impl_cast(baseImpl).paint.untransitioned()) {} RenderRasterLayer::~RenderRasterLayer() = default; void RenderRasterLayer::transition(const TransitionParameters& parameters) { unevaluated = impl_cast(baseImpl).paint.transitioned(parameters, std::move(unevaluated)); } void RenderRasterLayer::evaluate(const PropertyEvaluationParameters& parameters) { auto properties = makeMutable( staticImmutableCast(baseImpl), unevaluated.evaluate(parameters)); passes = properties->evaluated.get() > 0 ? RenderPass::Translucent : RenderPass::None; properties->renderPasses = mbgl::underlying_type(passes); evaluatedProperties = std::move(properties); } bool RenderRasterLayer::hasTransition() const { return unevaluated.hasTransition(); } bool RenderRasterLayer::hasCrossfade() const { return false; } static float saturationFactor(float saturation) { if (saturation > 0) { return 1 - 1 / (1.001 - saturation); } else { return -saturation; } } static float contrastFactor(float contrast) { if (contrast > 0) { return 1 / (1 - contrast); } else { return 1 + contrast; } } static std::array spinWeights(float spin) { spin *= util::DEG2RAD; float s = std::sin(spin); float c = std::cos(spin); std::array spin_weights = {{ (2 * c + 1) / 3, (-std::sqrt(3.0f) * s - c + 1) / 3, (std::sqrt(3.0f) * s - c + 1) / 3 }}; return spin_weights; } void RenderRasterLayer::prepare(const LayerPrepareParameters& params) { renderTiles = params.source->getRenderTiles(); imageData = params.source->getImageRenderData(); // It is possible image data is not available until the source loads it. assert(renderTiles || imageData || !params.source->isEnabled()); } void RenderRasterLayer::render(PaintParameters& parameters) { if (parameters.pass != RenderPass::Translucent || (!renderTiles && !imageData)) { return; } const auto& evaluated = static_cast(*evaluatedProperties).evaluated; RasterProgram::Binders paintAttributeData{ evaluated, 0 }; auto draw = [&] (const mat4& matrix, const auto& vertexBuffer, const auto& indexBuffer, const auto& segments, const auto& textureBindings, const std::string& drawScopeID) { auto& programInstance = parameters.programs.getRasterLayerPrograms().raster; const auto allUniformValues = RasterProgram::computeAllUniformValues( RasterProgram::LayoutUniformValues{ uniforms::matrix::Value(matrix), uniforms::opacity::Value(evaluated.get()), uniforms::fade_t::Value(1), uniforms::brightness_low::Value(evaluated.get()), uniforms::brightness_high::Value(evaluated.get()), uniforms::saturation_factor::Value(saturationFactor(evaluated.get())), uniforms::contrast_factor::Value(contrastFactor(evaluated.get())), uniforms::spin_weights::Value(spinWeights(evaluated.get())), uniforms::buffer_scale::Value(1.0f), uniforms::scale_parent::Value(1.0f), uniforms::tl_parent::Value(std::array{{0.0f, 0.0f}}), }, paintAttributeData, evaluated, parameters.state.getZoom()); const auto allAttributeBindings = RasterProgram::computeAllAttributeBindings(vertexBuffer, paintAttributeData, evaluated); checkRenderability(parameters, RasterProgram::activeBindingCount(allAttributeBindings)); programInstance.draw( parameters.context, *parameters.renderPass, gfx::Triangles(), parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly), gfx::StencilMode::disabled(), parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), indexBuffer, segments, allUniformValues, allAttributeBindings, textureBindings, getID() + "/" + drawScopeID ); }; const gfx::TextureFilterType filter = evaluated.get() == RasterResamplingType::Nearest ? gfx::TextureFilterType::Nearest : gfx::TextureFilterType::Linear; if (imageData && !imageData->bucket->needsUpload()) { RasterBucket& bucket = *imageData->bucket; assert(bucket.texture); size_t i = 0; for (const auto& matrix_ : imageData->matrices) { draw(matrix_, *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, RasterProgram::TextureBindings{ textures::image0::Value{bucket.texture->getResource(), filter}, textures::image1::Value{bucket.texture->getResource(), filter}, }, std::to_string(i++)); } } else if (renderTiles) { for (const RenderTile& tile : *renderTiles) { auto* bucket_ = tile.getBucket(*baseImpl); if (!bucket_) { continue; } auto& bucket = static_cast(*bucket_); if (!bucket.hasData()) continue; assert(bucket.texture); if (bucket.vertexBuffer && bucket.indexBuffer) { // Draw only the parts of the tile that aren't drawn by another tile in the layer. draw(parameters.matrixForTile(tile.id, !parameters.state.isChanging()), *bucket.vertexBuffer, *bucket.indexBuffer, bucket.segments, RasterProgram::TextureBindings{ textures::image0::Value{bucket.texture->getResource(), filter}, textures::image1::Value{bucket.texture->getResource(), filter}, }, "image"); } else { // Draw the full tile. if (bucket.segments.empty()) { // Copy over the segments so that we can create our own DrawScopes. bucket.segments = RenderStaticData::rasterSegments(); } draw(parameters.matrixForTile(tile.id, !parameters.state.isChanging()), *parameters.staticData.rasterVertexBuffer, *parameters.staticData.quadTriangleIndexBuffer, bucket.segments, RasterProgram::TextureBindings{ textures::image0::Value{bucket.texture->getResource(), filter}, textures::image1::Value{bucket.texture->getResource(), filter}, }, "image"); } } } } } // namespace mbgl