예제 #1
0
TEST(Buckets, FillBucket) {
    HeadlessBackend backend({ 512, 256 });
    BackendScope scope { backend };

    gl::Context context;
    FillBucket bucket { { {0, 0, 0}, MapMode::Static, 1.0 }, {} };
    ASSERT_FALSE(bucket.hasData());
    ASSERT_FALSE(bucket.needsUpload());

    GeometryCollection polygon { { { 0, 0 }, { 0, 1 }, { 1, 1 } } };
    bucket.addFeature(StubGeometryTileFeature { {}, FeatureType::Polygon, polygon, properties }, polygon);
    ASSERT_TRUE(bucket.hasData());
    ASSERT_TRUE(bucket.needsUpload());

    bucket.upload(context);
    ASSERT_FALSE(bucket.needsUpload());
}
예제 #2
0
void Painter::renderFill(FillBucket& bucket, const FillLayer& layer, const TileID& id, const mat4& matrix) {
    const FillPaintProperties& properties = layer.properties;
    mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor);

    Color fill_color = properties.fill_color;
    fill_color[0] *= properties.opacity;
    fill_color[1] *= properties.opacity;
    fill_color[2] *= properties.opacity;
    fill_color[3] *= properties.opacity;

    Color stroke_color = properties.stroke_color;
    if (stroke_color[3] < 0) {
        stroke_color = fill_color;
    } else {
        stroke_color[0] *= properties.opacity;
        stroke_color[1] *= properties.opacity;
        stroke_color[2] *= properties.opacity;
        stroke_color[3] *= properties.opacity;
    }

    const bool pattern = !properties.image.from.empty();

    bool outline = properties.antialias && !pattern && stroke_color != fill_color;
    bool fringeline = properties.antialias && !pattern && stroke_color == fill_color;

    config.stencilTest = true;
    config.depthTest = true;

    // Because we're drawing top-to-bottom, and we update the stencil mask
    // befrom, we have to draw the outline first (!)
    if (outline && pass == RenderPass::Translucent) {
        config.program = outlineShader->program;
        outlineShader->u_matrix = vtxMatrix;
        config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!

        outlineShader->u_color = stroke_color;

        // Draw the entire line
        outlineShader->u_world = {{
            static_cast<float>(frame.framebufferSize[0]),
            static_cast<float>(frame.framebufferSize[1])
        }};
        setDepthSublayer(0);
        bucket.drawVertices(*outlineShader);
    }

    if (pattern) {
        // Image fill.
        if (pass == RenderPass::Translucent) {

            const SpriteAtlasPosition posA = spriteAtlas->getPosition(properties.image.from, true);
            const SpriteAtlasPosition posB = spriteAtlas->getPosition(properties.image.to, true);
            float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z) / id.overscaling;

            mat3 patternMatrixA;
            matrix::identity(patternMatrixA);
            matrix::scale(patternMatrixA, patternMatrixA,
                    1.0f / (posA.size[0] * factor * properties.image.fromScale),
                    1.0f / (posA.size[1] * factor * properties.image.fromScale));
            mat3 patternMatrixB;
            matrix::identity(patternMatrixB);
            matrix::scale(patternMatrixB, patternMatrixB,
                    1.0f / (posB.size[0] * factor * properties.image.toScale),
                    1.0f / (posB.size[1] * factor * properties.image.toScale));

            config.program = patternShader->program;
            patternShader->u_matrix = vtxMatrix;
            patternShader->u_pattern_tl_a = posA.tl;
            patternShader->u_pattern_br_a = posA.br;
            patternShader->u_pattern_tl_b = posB.tl;
            patternShader->u_pattern_br_b = posB.br;
            patternShader->u_opacity = properties.opacity;
            patternShader->u_image = 0;
            patternShader->u_mix = properties.image.t;
            patternShader->u_patternmatrix_a = patternMatrixA;
            patternShader->u_patternmatrix_b = patternMatrixB;

            MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
            spriteAtlas->bind(true);

            // Draw the actual triangles into the color & stencil buffer.
            config.depthMask = GL_TRUE;
            setDepthSublayer(0);
            bucket.drawElements(*patternShader);
        }
    }
    else {
        // No image fill.
        if ((fill_color[3] >= 1.0f) == (pass == RenderPass::Opaque)) {
            // Only draw the fill when it's either opaque and we're drawing opaque
            // fragments or when it's translucent and we're drawing translucent
            // fragments
            // Draw filling rectangle.
            config.program = plainShader->program;
            plainShader->u_matrix = vtxMatrix;
            plainShader->u_color = fill_color;

            // Draw the actual triangles into the color & stencil buffer.
            config.depthMask = GL_TRUE;
            setDepthSublayer(1);
            bucket.drawElements(*plainShader);
        }
    }

    // Because we're drawing top-to-bottom, and we update the stencil mask
    // below, we have to draw the outline first (!)
    if (fringeline && pass == RenderPass::Translucent) {
        config.program = outlineShader->program;
        outlineShader->u_matrix = vtxMatrix;
        config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!

        outlineShader->u_color = fill_color;

        // Draw the entire line
        outlineShader->u_world = {{
            static_cast<float>(frame.framebufferSize[0]),
            static_cast<float>(frame.framebufferSize[1])
        }};

        setDepthSublayer(2);
        bucket.drawVertices(*outlineShader);
    }
}
예제 #3
0
void Painter::renderFill(FillBucket& bucket,
                         const FillLayer& layer,
                         const UnwrappedTileID& tileID,
                         const mat4& matrix) {
    const FillPaintProperties& properties = layer.paint;
    mat4 vtxMatrix =
        translatedMatrix(matrix, properties.fillTranslate, tileID, properties.fillTranslateAnchor);

    Color fill_color = properties.fillColor;
    float opacity = properties.fillOpacity;

    Color stroke_color = properties.fillOutlineColor;
    if (stroke_color[3] < 0) {
        stroke_color = fill_color;
    }

    bool pattern = !properties.fillPattern.value.from.empty();
    bool outline = properties.fillAntialias && !pattern && stroke_color != fill_color;
    bool fringeline = properties.fillAntialias && !pattern && stroke_color == fill_color;

    bool wireframe = frame.debugOptions & MapDebugOptions::Wireframe;
    if (wireframe) {
        fill_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
        stroke_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
        opacity = 1.0f;
        pattern = false;
        outline = true;
        fringeline = true;
    }

    config.stencilOp.reset();
    config.stencilTest = GL_TRUE;
    config.depthFunc.reset();
    config.depthTest = GL_TRUE;
    config.depthMask = GL_TRUE;

    // Because we're drawing top-to-bottom, and we update the stencil mask
    // befrom, we have to draw the outline first (!)
    if (outline && pass == RenderPass::Translucent) {
        config.program = outlineShader->getID();
        outlineShader->u_matrix = vtxMatrix;
        config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!

        outlineShader->u_color = stroke_color;
        outlineShader->u_opacity = opacity;

        // Draw the entire line
        outlineShader->u_world = {{
            static_cast<float>(frame.framebufferSize[0]),
            static_cast<float>(frame.framebufferSize[1])
        }};
        setDepthSublayer(0);
        bucket.drawVertices(*outlineShader, store);
    }

    if (pattern) {
        optional<SpriteAtlasPosition> posA = spriteAtlas->getPosition(properties.fillPattern.value.from, true);
        optional<SpriteAtlasPosition> posB = spriteAtlas->getPosition(properties.fillPattern.value.to, true);

        // Image fill.
        if (pass == RenderPass::Translucent && posA && posB) {
            config.program = patternShader->getID();
            patternShader->u_matrix = vtxMatrix;
            patternShader->u_pattern_tl_a = (*posA).tl;
            patternShader->u_pattern_br_a = (*posA).br;
            patternShader->u_pattern_tl_b = (*posB).tl;
            patternShader->u_pattern_br_b = (*posB).br;
            patternShader->u_opacity = properties.fillOpacity;
            patternShader->u_image = 0;
            patternShader->u_mix = properties.fillPattern.value.t;

            std::array<int, 2> imageSizeScaledA = {{
                (int)((*posA).size[0] * properties.fillPattern.value.fromScale),
                (int)((*posA).size[1] * properties.fillPattern.value.fromScale)
            }};
            std::array<int, 2> imageSizeScaledB = {{
                (int)((*posB).size[0] * properties.fillPattern.value.toScale),
                (int)((*posB).size[1] * properties.fillPattern.value.toScale)
            }};

            patternShader->u_patternscale_a = {
                { 1.0f / tileID.pixelsToTileUnits(imageSizeScaledA[0], state.getIntegerZoom()),
                  1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom()) }
            };
            patternShader->u_patternscale_b = {
                { 1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[0], state.getIntegerZoom()),
                  1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom()) }
            };

            float offsetAx = (std::fmod(util::tileSize, imageSizeScaledA[0]) * tileID.canonical.x) /
                             (float)imageSizeScaledA[0];
            float offsetAy = (std::fmod(util::tileSize, imageSizeScaledA[1]) * tileID.canonical.y) /
                             (float)imageSizeScaledA[1];

            float offsetBx = (std::fmod(util::tileSize, imageSizeScaledB[0]) * tileID.canonical.x) /
                             (float)imageSizeScaledB[0];
            float offsetBy = (std::fmod(util::tileSize, imageSizeScaledB[1]) * tileID.canonical.y) /
                             (float)imageSizeScaledB[1];

            patternShader->u_offset_a = std::array<float, 2>{{offsetAx, offsetAy}};
            patternShader->u_offset_b = std::array<float, 2>{{offsetBx, offsetBy}};

            config.activeTexture = GL_TEXTURE0;
            spriteAtlas->bind(true, store);

            // Draw the actual triangles into the color & stencil buffer.
            setDepthSublayer(0);
            bucket.drawElements(*patternShader, store);

            if (properties.fillAntialias && stroke_color == fill_color) {
                config.program = outlinePatternShader->getID();
                outlinePatternShader->u_matrix = vtxMatrix;
                config.lineWidth = 2.0f;

                // Draw the entire line
                outlinePatternShader->u_world = {{
                    static_cast<float>(frame.framebufferSize[0]),
                    static_cast<float>(frame.framebufferSize[1])
                }};

                outlinePatternShader->u_pattern_tl_a = (*posA).tl;
                outlinePatternShader->u_pattern_br_a = (*posA).br;
                outlinePatternShader->u_pattern_tl_b = (*posB).tl;
                outlinePatternShader->u_pattern_br_b = (*posB).br;
                outlinePatternShader->u_opacity = properties.fillOpacity;
                outlinePatternShader->u_image = 0;
                outlinePatternShader->u_mix = properties.fillPattern.value.t;

                outlinePatternShader->u_patternscale_a = {{
                    1.0f / tileID.pixelsToTileUnits(imageSizeScaledA[0], state.getIntegerZoom()),
                    1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom())
                }};
                outlinePatternShader->u_patternscale_b = {{
                    1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[0], state.getIntegerZoom()),
                    1.0f / tileID.pixelsToTileUnits(imageSizeScaledB[1], state.getIntegerZoom())
                }};

                outlinePatternShader->u_offset_a = std::array<float, 2>{{offsetAx, offsetAy}};
                outlinePatternShader->u_offset_b = std::array<float, 2>{{offsetBx, offsetBy}};

                config.activeTexture = GL_TEXTURE0;
                spriteAtlas->bind(true, store);

                setDepthSublayer(2);
                bucket.drawVertices(*outlinePatternShader, store);
            }
        }
    } else if (!wireframe) {
        // No image fill.
        if ((fill_color[3] >= 1.0f && opacity >= 1.0f) == (pass == RenderPass::Opaque)) {
            // Only draw the fill when it's either opaque and we're drawing opaque
            // fragments or when it's translucent and we're drawing translucent
            // fragments
            // Draw filling rectangle.
            config.program = plainShader->getID();
            plainShader->u_matrix = vtxMatrix;
            plainShader->u_color = fill_color;
            plainShader->u_opacity = opacity;

            // Draw the actual triangles into the color & stencil buffer.
            setDepthSublayer(1);
            bucket.drawElements(*plainShader, store);
        }
    }

    // Because we're drawing top-to-bottom, and we update the stencil mask
    // below, we have to draw the outline first (!)
    if (fringeline && pass == RenderPass::Translucent) {
        config.program = outlineShader->getID();
        outlineShader->u_matrix = vtxMatrix;
        config.lineWidth = 2.0f; // This is always fixed and does not depend on the pixelRatio!

        outlineShader->u_color = fill_color;
        outlineShader->u_opacity = opacity;

        // Draw the entire line
        outlineShader->u_world = {{
            static_cast<float>(frame.framebufferSize[0]),
            static_cast<float>(frame.framebufferSize[1])
        }};

        setDepthSublayer(2);
        bucket.drawVertices(*outlineShader, store);
    }
}