
// CommonStrokeTessellatorEvalMain.hpp - tessellator evaluation stage for polar stroking evaluation routines

#ifndef __CommonStrokeTessellatorEvalMain_hpp__
#define __CommonStrokeTessellatorEvalMain_hpp__

#include "CommonStrokeTessellatorPrivate.hpp"

// Used by evalRib to handle a mitered join that needs its offset adjusted.
void StrokeTessellatorMETHOD adjustOffsetForMiter(uint i, INOUTPARAM(vec2) effective_offset) CONST
{
    // Miter joins (-1 for miter revert, -2 for miter truncate) identified
    // by negative max_join_steps uniform.
    CONST bool treat_as_miter = (link_state[3] != 0);
    if (treat_as_miter) {
        CONST uint steps = Steps();
        // At this point steps should be one of 1 (bevel) or 2 (miter) or 3 (miter truncate).
        assert(steps == /*bevel*/1 || steps == /*miter*/2 || steps == /*miter truncate*/3);
        // If a middle positition treated as a miter...
        if ((i > 0) && (i < steps)) {
            // At this point steps should be either 2 (miter) or 3 (miter truncate).
            assert(steps == /*miter*/2 || steps == /*miter truncate*/3);
            assert(i == 1 || i == 2);
            // Replace with two between points with cp[1] and cp[2] if truncated miter
            // Replace with single between point with cp[1] if non-truncated miter
            effective_offset = cp[i].xy;
        } else {
            // A miter that reverts to a bevel needs no effective offset adjustment.
        }
    }
}

// Used by evalRib to write segment information, as for arc length texture coordinate generation.
void StrokeTessellatorMETHOD writeSegmentInfo(uint rib_index, float t, CPtype p, vec2 normal, float height)
{
#if ARC_LENGTH_TEXGEN
    CONST float total_dist = processArcLength(rib_index, t, p, normal);
    CONST float scaled_total_dist = arc_length_texgen_scale * total_dist;
    pervertex_arc_length = scaled_total_dist;
#endif
}

void StrokeTessellatorMETHOD evalRib(RibIndexResult rib)
{
    CONST ParametricDirection pd = evalRibIndex(rib.i);
    CONST vec2 normal = pd.normal;
    vec2 effective_offset = normal;  // Offset might not be a normal in join and cap cases.
    float radius = stroke_radius;  // Allows forcing radius to zero later.

    if (results) {
        stashParametricT(rib.i, pd.t);
        stashTheta(rib.i, pd.theta);
        stashNormal(rib.i, pd.normal);
        stashOffset(rib.i, normal);
    }

    CONST bool is_join_or_cap = IsJoinOrCap();
    CPtype p;
    if (is_join_or_cap) {
        // The join position is always at cp[0].
        p = cp[0];
        CONST bool is_round_join = (link_state[1] == 2);
        if (is_round_join && draw_inside_of_round_joins != 0) {
            // Reverse the radius value signs to indicate is a round join for later frieze height conversion.
            pervertex_radius = vec2(radius, -radius);
        } else {
            adjustOffsetForMiter(rib.i, effective_offset);
            CONST bool square = (link_state[3] < 0);
            CONST uint orientationBitMask = OrientationBitMask();
            pervertex_radius[0] = 0;
            if (square || (orientationBitMask != 0)) {
                pervertex_radius[1] = radius;
            } else {
                pervertex_radius[1] = -radius;
            }
        }
    } else {
        p = evalSegmentPosition(pd);
        pervertex_radius = vec2(-radius, radius);
    }

    CONST float dontcare = 0;
    writeSegmentInfo(rib.i, pd.t, p, effective_offset, dontcare);

    pervertex_offset = effective_offset;
    pervertex_p = p;
    pervertex_t = pd.t;
}

#endif // __CommonStrokeTessellatorEvalMain_hpp__
