Esempio n. 1
0
void Painter::renderLine(LineBucket& bucket, const StyleLayer &layer_desc, const TileID& id, const mat4 &matrix) {
    // Abort early.
    if (pass == RenderPass::Opaque) return;
    if (!bucket.hasData()) return;

    depthMask(false);

    const auto &properties = layer_desc.getProperties<LineProperties>();
    const auto &layout = bucket.layout;

    // the distance over which the line edge fades out.
    // Retina devices need a smaller distance to avoid aliasing.
    float antialiasing = 1 / state.getPixelRatio();

    float blur = properties.blur + antialiasing;
    float edgeWidth = properties.width / 2.0;
    float inset = -1;
    float offset = 0;
    float shift = 0;

    if (properties.gap_width != 0) {
        inset = properties.gap_width / 2.0 + antialiasing * 0.5;
        edgeWidth = properties.width;

        // shift outer lines half a pixel towards the middle to eliminate the crack
        offset = inset - antialiasing / 2.0;
    }

    float outset = offset + edgeWidth + antialiasing / 2.0 + shift;

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

    float ratio = state.getPixelRatio();
    mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor);

    depthRange(strata, 1.0f);

    if (properties.dash_array.from.size()) {

        useProgram(linesdfShader->program);

        linesdfShader->u_matrix = vtxMatrix;
        linesdfShader->u_exmatrix = extrudeMatrix;
        linesdfShader->u_linewidth = {{ outset, inset }};
        linesdfShader->u_ratio = ratio;
        linesdfShader->u_blur = blur;
        linesdfShader->u_color = color;

        LinePatternPos posA = lineAtlas.getDashPosition(properties.dash_array.from, layout.cap == CapType::Round);
        LinePatternPos posB = lineAtlas.getDashPosition(properties.dash_array.to, layout.cap == CapType::Round);
        lineAtlas.bind();

        float patternratio = std::pow(2.0, std::floor(std::log2(state.getScale())) - id.z) / 8.0;
        float scaleXA = patternratio / posA.width / properties.dash_line_width / properties.dash_array.fromScale;
        float scaleYA = -posA.height / 2.0;
        float scaleXB = patternratio / posB.width / properties.dash_line_width / properties.dash_array.toScale;
        float scaleYB = -posB.height / 2.0;

        linesdfShader->u_patternscale_a = {{ scaleXA, scaleYA }};
        linesdfShader->u_tex_y_a = posA.y;
        linesdfShader->u_patternscale_b = {{ scaleXB, scaleYB }};
        linesdfShader->u_tex_y_b = posB.y;
        linesdfShader->u_image = 0;
        linesdfShader->u_sdfgamma = lineAtlas.width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * state.getPixelRatio()) / 2;
        linesdfShader->u_mix = properties.dash_array.t;

        bucket.drawLineSDF(*linesdfShader);

    } else if (properties.image.from.size()) {
        SpriteAtlasPosition imagePosA = spriteAtlas.getPosition(properties.image.from, true);
        SpriteAtlasPosition imagePosB = spriteAtlas.getPosition(properties.image.to, true);

        float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z);

        useProgram(linepatternShader->program);

        linepatternShader->u_matrix = vtxMatrix;
        linepatternShader->u_exmatrix = extrudeMatrix;
        linepatternShader->u_linewidth = {{ outset, inset }};
        linepatternShader->u_ratio = ratio;
        linepatternShader->u_blur = blur;

        linepatternShader->u_pattern_size_a = {{imagePosA.size[0] * factor * properties.image.fromScale, imagePosA.size[1]}};
        linepatternShader->u_pattern_tl_a = imagePosA.tl;
        linepatternShader->u_pattern_br_a = imagePosA.br;
        linepatternShader->u_pattern_size_b = {{imagePosB.size[0] * factor * properties.image.toScale, imagePosB.size[1]}};
        linepatternShader->u_pattern_tl_b = imagePosB.tl;
        linepatternShader->u_pattern_br_b = imagePosB.br;
        linepatternShader->u_fade = properties.image.t;
        linepatternShader->u_opacity = properties.opacity;

        MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0));
        spriteAtlas.bind(true);
        MBGL_CHECK_ERROR(glDepthRange(strata + strata_epsilon, 1.0f));  // may or may not matter

        bucket.drawLinePatterns(*linepatternShader);

    } else {
        useProgram(lineShader->program);

        lineShader->u_matrix = vtxMatrix;
        lineShader->u_exmatrix = extrudeMatrix;
        lineShader->u_linewidth = {{ outset, inset }};
        lineShader->u_ratio = ratio;
        lineShader->u_blur = blur;

        lineShader->u_color = color;

        bucket.drawLines(*lineShader);
    }
}
void Painter::renderLine(LineBucket& bucket, const LineLayer& layer, const TileID& id, const mat4& matrix) {
    // Abort early.
    if (pass == RenderPass::Opaque) return;

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

    const auto& properties = layer.paint;
    const auto& layout = bucket.layout;

    // the distance over which the line edge fades out.
    // Retina devices need a smaller distance to avoid aliasing.
    float antialiasing = 1.0 / data.pixelRatio;

    float blur = properties.blur + antialiasing;
    float edgeWidth = properties.width / 2.0;
    float inset = -1;
    float offset = 0;
    float shift = 0;

    if (properties.gapWidth != 0) {
        inset = properties.gapWidth / 2.0 + antialiasing * 0.5;
        edgeWidth = properties.width;

        // shift outer lines half a pixel towards the middle to eliminate the crack
        offset = inset - antialiasing / 2.0;
    }

    float outset = offset + edgeWidth + antialiasing / 2.0 + shift;

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

    float ratio = state.getScale() / std::pow(2, id.z) / 8.0 * id.overscaling;

    mat2 antialiasingMatrix;
    matrix::identity(antialiasingMatrix);
    matrix::scale(antialiasingMatrix, antialiasingMatrix, 1.0, std::cos(state.getPitch()));
    matrix::rotate(antialiasingMatrix, antialiasingMatrix, state.getAngle());

    // calculate how much longer the real world distance is at the top of the screen
    // than at the middle of the screen.
    float topedgelength = std::sqrt(std::pow(state.getHeight(), 2) / 4  * (1 + std::pow(state.getAltitude(), 2)));
    float x = state.getHeight() / 2.0f * std::tan(state.getPitch());
    float extra = (topedgelength + x) / topedgelength - 1;

    mat4 vtxMatrix = translatedMatrix(matrix, properties.translate, id, properties.translateAnchor);

    setDepthSublayer(0);

    if (!properties.dasharray.value.from.empty()) {

        config.program = linesdfShader->program;

        linesdfShader->u_matrix = vtxMatrix;
        linesdfShader->u_exmatrix = extrudeMatrix;
        linesdfShader->u_linewidth = {{ outset, inset }};
        linesdfShader->u_ratio = ratio;
        linesdfShader->u_blur = blur;
        linesdfShader->u_color = color;

        LinePatternPos posA = lineAtlas->getDashPosition(properties.dasharray.value.from, layout.cap == CapType::Round);
        LinePatternPos posB = lineAtlas->getDashPosition(properties.dasharray.value.to, layout.cap == CapType::Round);
        lineAtlas->bind();

        float patternratio = std::pow(2.0, std::floor(::log2(state.getScale())) - id.z) / 8.0 * id.overscaling;
        float scaleXA = patternratio / posA.width / properties.dashLineWidth / properties.dasharray.value.fromScale;
        float scaleYA = -posA.height / 2.0;
        float scaleXB = patternratio / posB.width / properties.dashLineWidth / properties.dasharray.value.toScale;
        float scaleYB = -posB.height / 2.0;

        linesdfShader->u_patternscale_a = {{ scaleXA, scaleYA }};
        linesdfShader->u_tex_y_a = posA.y;
        linesdfShader->u_patternscale_b = {{ scaleXB, scaleYB }};
        linesdfShader->u_tex_y_b = posB.y;
        linesdfShader->u_image = 0;
        linesdfShader->u_sdfgamma = lineAtlas->width / (properties.dashLineWidth * std::min(posA.width, posB.width) * 256.0 * data.pixelRatio) / 2;
        linesdfShader->u_mix = properties.dasharray.value.t;
        linesdfShader->u_extra = extra;
        linesdfShader->u_antialiasingmatrix = antialiasingMatrix;

        bucket.drawLineSDF(*linesdfShader);

    } else if (!properties.pattern.value.from.empty()) {
        mapbox::util::optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(properties.pattern.value.from, true);
        mapbox::util::optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(properties.pattern.value.to, true);
        
        if (!imagePosA || !imagePosB)
            return;

        float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z) * id.overscaling;

        config.program = linepatternShader->program;

        linepatternShader->u_matrix = vtxMatrix;
        linepatternShader->u_exmatrix = extrudeMatrix;
        linepatternShader->u_linewidth = {{ outset, inset }};
        linepatternShader->u_ratio = ratio;
        linepatternShader->u_blur = blur;

        linepatternShader->u_pattern_size_a = {{(*imagePosA).size[0] * factor * properties.pattern.value.fromScale, (*imagePosA).size[1]}};
        linepatternShader->u_pattern_tl_a = (*imagePosA).tl;
        linepatternShader->u_pattern_br_a = (*imagePosA).br;
        linepatternShader->u_pattern_size_b = {{(*imagePosB).size[0] * factor * properties.pattern.value.toScale, (*imagePosB).size[1]}};
        linepatternShader->u_pattern_tl_b = (*imagePosB).tl;
        linepatternShader->u_pattern_br_b = (*imagePosB).br;
        linepatternShader->u_fade = properties.pattern.value.t;
        linepatternShader->u_opacity = properties.opacity;
        linepatternShader->u_extra = extra;
        linepatternShader->u_antialiasingmatrix = antialiasingMatrix;

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

        bucket.drawLinePatterns(*linepatternShader);

    } else {
        config.program = lineShader->program;

        lineShader->u_matrix = vtxMatrix;
        lineShader->u_exmatrix = extrudeMatrix;
        lineShader->u_linewidth = {{ outset, inset }};
        lineShader->u_ratio = ratio;
        lineShader->u_blur = blur;
        lineShader->u_extra = extra;
        lineShader->u_antialiasingmatrix = antialiasingMatrix;

        lineShader->u_color = color;

        bucket.drawLines(*lineShader);
    }
}
Esempio n. 3
0
void Painter::renderLine(LineBucket& bucket,
                         const LineLayer& layer,
                         const UnwrappedTileID& tileID,
                         const mat4& matrix) {
    // Abort early.
    if (pass == RenderPass::Opaque) return;

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

    const auto& properties = layer.impl->paint;
    const auto& layout = bucket.layout;

    // the distance over which the line edge fades out.
    // Retina devices need a smaller distance to avoid aliasing.
    float antialiasing = 1.0 / frame.pixelRatio;

    bool wireframe = frame.debugOptions & MapDebugOptions::Wireframe;

    float blur = properties.lineBlur + antialiasing;

    Color color = Color::white();
    float opacity = 1.0f;
    if (!wireframe) {
        color = properties.lineColor;
        opacity = properties.lineOpacity;
    }

    const float ratio = 1.0 / tileID.pixelsToTileUnits(1.0, state.getZoom());

    mat2 antialiasingMatrix;
    matrix::identity(antialiasingMatrix);
    matrix::scale(antialiasingMatrix, antialiasingMatrix, 1.0, std::cos(state.getPitch()));
    matrix::rotate(antialiasingMatrix, antialiasingMatrix, state.getAngle());

    // calculate how much longer the real world distance is at the top of the screen
    // than at the middle of the screen.
    float topedgelength = std::sqrt(std::pow(state.getHeight(), 2.0f) / 4.0f  * (1.0f + std::pow(state.getAltitude(), 2.0f)));
    float x = state.getHeight() / 2.0f * std::tan(state.getPitch());
    float extra = (topedgelength + x) / topedgelength - 1.0f;

    mat4 vtxMatrix =
        translatedMatrix(matrix, properties.lineTranslate, tileID, properties.lineTranslateAnchor);

    setDepthSublayer(0);

    if (!properties.lineDasharray.value.from.empty()) {

        config.program = linesdfShader->getID();

        linesdfShader->u_matrix = vtxMatrix;
        linesdfShader->u_linewidth = properties.lineWidth / 2;
        linesdfShader->u_gapwidth = properties.lineGapWidth / 2;
        linesdfShader->u_antialiasing = antialiasing / 2;
        linesdfShader->u_ratio = ratio;
        linesdfShader->u_blur = blur;
        linesdfShader->u_color = color;
        linesdfShader->u_opacity = opacity;

        LinePatternPos posA = lineAtlas->getDashPosition(properties.lineDasharray.value.from, layout.lineCap == LineCapType::Round, store);
        LinePatternPos posB = lineAtlas->getDashPosition(properties.lineDasharray.value.to, layout.lineCap == LineCapType::Round, store);

        const float widthA = posA.width * properties.lineDasharray.value.fromScale * layer.impl->dashLineWidth;
        const float widthB = posB.width * properties.lineDasharray.value.toScale * layer.impl->dashLineWidth;

        float scaleXA = 1.0 / tileID.pixelsToTileUnits(widthA, state.getIntegerZoom());
        float scaleYA = -posA.height / 2.0;
        float scaleXB = 1.0 / tileID.pixelsToTileUnits(widthB, state.getIntegerZoom());
        float scaleYB = -posB.height / 2.0;

        linesdfShader->u_patternscale_a = {{ scaleXA, scaleYA }};
        linesdfShader->u_tex_y_a = posA.y;
        linesdfShader->u_patternscale_b = {{ scaleXB, scaleYB }};
        linesdfShader->u_tex_y_b = posB.y;
        linesdfShader->u_sdfgamma = lineAtlas->width / (std::min(widthA, widthB) * 256.0 * frame.pixelRatio) / 2;
        linesdfShader->u_mix = properties.lineDasharray.value.t;
        linesdfShader->u_extra = extra;
        linesdfShader->u_offset = -properties.lineOffset;
        linesdfShader->u_antialiasingmatrix = antialiasingMatrix;

        linesdfShader->u_image = 0;
        config.activeTexture = GL_TEXTURE0;
        lineAtlas->bind(store);

        bucket.drawLineSDF(*linesdfShader, store);

    } else if (!properties.linePattern.value.from.empty()) {
        optional<SpriteAtlasPosition> imagePosA = spriteAtlas->getPosition(properties.linePattern.value.from, true);
        optional<SpriteAtlasPosition> imagePosB = spriteAtlas->getPosition(properties.linePattern.value.to, true);
        
        if (!imagePosA || !imagePosB)
            return;

        config.program = linepatternShader->getID();

        linepatternShader->u_matrix = vtxMatrix;
        linepatternShader->u_linewidth = properties.lineWidth / 2;
        linepatternShader->u_gapwidth = properties.lineGapWidth / 2;
        linepatternShader->u_antialiasing = antialiasing / 2;
        linepatternShader->u_ratio = ratio;
        linepatternShader->u_blur = blur;

        linepatternShader->u_pattern_size_a = {{
            tileID.pixelsToTileUnits((*imagePosA).size[0] * properties.linePattern.value.fromScale, state.getIntegerZoom()),
            (*imagePosA).size[1]
        }};
        linepatternShader->u_pattern_tl_a = (*imagePosA).tl;
        linepatternShader->u_pattern_br_a = (*imagePosA).br;

        linepatternShader->u_pattern_size_b = {{
            tileID.pixelsToTileUnits((*imagePosB).size[0] * properties.linePattern.value.toScale, state.getIntegerZoom()),
            (*imagePosB).size[1]
        }};
        linepatternShader->u_pattern_tl_b = (*imagePosB).tl;
        linepatternShader->u_pattern_br_b = (*imagePosB).br;

        linepatternShader->u_fade = properties.linePattern.value.t;
        linepatternShader->u_opacity = properties.lineOpacity;
        linepatternShader->u_extra = extra;
        linepatternShader->u_offset = -properties.lineOffset;
        linepatternShader->u_antialiasingmatrix = antialiasingMatrix;

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

        bucket.drawLinePatterns(*linepatternShader, store);

    } else {
        config.program = lineShader->getID();

        lineShader->u_matrix = vtxMatrix;
        lineShader->u_linewidth = properties.lineWidth / 2;
        lineShader->u_gapwidth = properties.lineGapWidth / 2;
        lineShader->u_antialiasing = antialiasing / 2;
        lineShader->u_ratio = ratio;
        lineShader->u_blur = blur;
        lineShader->u_extra = extra;
        lineShader->u_offset = -properties.lineOffset;
        lineShader->u_antialiasingmatrix = antialiasingMatrix;

        lineShader->u_color = color;
        lineShader->u_opacity = opacity;

        bucket.drawLines(*lineShader, store);
    }
}