
// CommonStrokeTessellatorTangentChangeMap.hpp - theta map

#ifndef __CommonStrokeTessellatorTangentChangeMap_hpp__
#define __CommonStrokeTessellatorTangentChangeMap_hpp__

#include "CommonStrokeTessellatorPrivate.hpp"
#include "CommonStrokeTessellatorTypes.hpp"  // for ThetaPosition
#include "CommonStrokeTessellatorEvalPosition.hpp" // for evalQuadraticBezierPosition & evalCubicBezierPosition
#include "CommonStrokeTessellatorEval.hpp" // for evalDeltaStepRibIndex

#include <Cg/floor.hpp>

STATIC CONST float bogus_unreferenced_value = -666;

bool StrokeTessellatorMETHOD LinkTypeIsCurved(int link_type) CONST
{
    if (link_type < LT_NO_CAP) {
        if (link_type == LT_JOIN) {
            if (max_join_steps == uint(LT_HEMICIRCLE_CAP)) {
                return true;
            } else {
                // Faceted joins: miter truncate, miter revert, none, bevel, triangular.
                assert(max_join_steps >= -2 && max_join_steps <= 2);
                return false;
            }
        } else {
            assert(link_type == LT_QUADRATIC_SEGMENT || link_type == LT_CUBIC_SEGMENT);
            return true;
        }
    } else {
        if (link_type > LT_SQUARE_CAP) {
            assert(link_type == uint(LT_HEMICIRCLE_CAP));
            return true;
        } else {
            assert(link_type != LT_ROUND_CAP_PRE_REMAP);
            assert(link_type == LT_NO_CAP || link_type == LT_TRIANGULAR_CAP || link_type == LT_SQUARE_CAP);
            return false;
        }
    }
}

void StrokeTessellatorMETHOD setSteps(uint steps)
{
    // Clamp the number of steps to the GPU tessellator maximum.
    if (steps > max_steps) {
        printf("clamping %d to GPU maximum steps of %d\n", steps, max_steps);
        steps = max_steps;
    }

    // Update varyings that depend on step counts.
    float D0A_steps = 0;
    float DAB_steps = 0;
    float DB1_steps = 0;

    float D0A = angleDelta_stash[0];
    float DAB = angleDelta_stash[1];
    float DB1 = angleDelta_stash[2];

    // Give everybody at least one step.
    if (D0A > 0) {
        D0A_steps += 1;
    }
    if (DAB > 0) {
        DAB_steps += 1;
    }
    if (DB1 > 0) {
        DB1_steps += 1;
    }
    float assigned = D0A_steps + DAB_steps + DB1_steps;
    float left = steps - assigned;

    CONST float D0AB1 = D0A + DAB + DB1;
    if (D0AB1 <= 0) {
        if (steps == 31) {
            // XXX 31 because of setSteps(31) from hodograph.cpp
            assert(delta_steps[1] == 1 || delta_steps[1] == 0);
            assert(delta_steps[2] == 1 || delta_steps[2] == 0);
            assert(delta_steps[3] == 1);
        } else {
            assert(steps == 1);
            assert(delta_steps[1] == 0);
            assert(delta_steps[2] == 0);
            assert(delta_steps[3] == 0);
        }
        FOR_THREAD(1) delta_steps[TID] = 1;
        FOR_THREAD(2) delta_steps[TID] = 1;
        FOR_THREAD(3) delta_steps[TID] = 1;
        return;
    }
    float segment_delta = left / D0AB1;

    D0A_steps += floor(segment_delta * D0A);
    DAB_steps += floor(segment_delta * DAB);
    DB1_steps += floor(segment_delta * DB1);

    float total = D0A_steps + DAB_steps + DB1_steps;
    assert(total <= steps);

    float remaining = steps - total;
    if (D0A > DAB && D0A > DB1) {
        D0A_steps += remaining;
    } else {
        if (DAB > DB1) {
            DAB_steps += remaining;
        } else {
            DB1_steps += remaining;
        }
    }
    float new_total = D0A_steps + DAB_steps + DB1_steps;
    assert(new_total == steps);

    FOR_THREAD(0) delta_steps[TID] = 0;
    FOR_THREAD(1) delta_steps[TID] = D0A_steps;
    FOR_THREAD(2) delta_steps[TID] = D0A_steps + DAB_steps;
    FOR_THREAD(3) delta_steps[TID] = D0A_steps + DAB_steps + DB1_steps;

    FOR_THREAD(0) dtheta_dsteps[TID] = D0A / D0A_steps;
    FOR_THREAD(1) dtheta_dsteps[TID] = DAB / DAB_steps;
    FOR_THREAD(2) dtheta_dsteps[TID] = DB1 / DB1_steps;
    FOR_THREAD(3) dtheta_dsteps[TID] = bogus_unreferenced_value;

    FOR_THREAD(3) {
        row_columns_orientationBitMask_steps[TID] = int(new_total);
        delta[TID] = D0AB1 / new_total;
    }
}

#endif // __CommonStrokeTessellatorTangentChangeMap_hpp__
