
// StrokerShaderConfig.cpp - stroker shader configuration

#include "StrokerShaderConfig.hpp"

StrokerConfig::StrokerConfig(const StrokeTessellatorSettings& settings)
    : stroking_space(OBJECT_SPACE)
    , shading_mode(CONSTANT_COLOR)
    , inside_round_join_mode(AUTOMATIC_INSIDE_ROUND_JOIN)
#if SUPPORT_POLAR_VISUALIZE
    , parameterization(settings.getParameterization())
#endif
{}

StrokerConfig::StrokerConfig(const StrokeTessellatorSettings& settings, StrokingSpace s, ShadingMode sm)
    : stroking_space(s)
    , shading_mode(sm)
    , inside_round_join_mode(settings.InsideRoundJoinMode())
#if SUPPORT_POLAR_VISUALIZE
    , parameterization(settings.getParameterization())
#endif
{
#if SUPPORT_POLAR_VISUALIZE
    // Uniform mode is incompatible with various polar stroking-specific modes.
    if (parameterization == UNIFORM) {
        shading_mode = CONSTANT_COLOR;
    }
#endif
}

// operator == so unordered_map template works.
bool StrokerConfig::operator == (const StrokerConfig& rhs) const
{
    if (this == &rhs) {
        return true;
    }
    if (stroking_space != rhs.stroking_space) {
        return false;
    }
    if (shading_mode != rhs.shading_mode) {
        return false;
    }
    if (inside_round_join_mode != rhs.inside_round_join_mode) {
        return false;
    }
#if SUPPORT_POLAR_VISUALIZE
    if (parameterization != rhs.parameterization) {
        return false;
    }
#endif
    return true;
}

void StrokerConfig::setShadingMode(ShadingMode value)
{
    shading_mode = value;
}

const char* StrokerConfig::getShadingModeString() const
{
    return shadingModeString(shading_mode);
}

bool StrokerConfig::hasGradientCoeffs() const
{
    switch (shading_mode) {
    case LINEAR_GRADIENT:
    case CENTER_RADIAL_GRADIENT:
    case FOCAL_RADIAL_GRADIENT:
    case IMAGE_GRADIENT:
        return true;
    case CONSTANT_COLOR:
    case ARC_LENGTH_TEXTURE_2D:
    case ARC_LENGTH_TEXTURE_2D_EARLY_FRAGMENT_TEST:
    default:
        return false;
    }
}

bool StrokerConfig::isConstantColor() const
{
    if (shading_mode == CONSTANT_COLOR) {
        return true;
    } else {
        return false;
    }
}

void StrokerConfig::setStrokingSpace(StrokingSpace value)
{
    stroking_space = value;
}

StrokerShaderMiniConfig::StrokerShaderMiniConfig(const StrokeTessellatorSettings& settings)
    : StrokerConfig(settings)
    , curve_type(INTEGRAL)
    , transform(SIMILIAR_AFFINE)
{}

StrokerShaderMiniConfig::StrokerShaderMiniConfig(const StrokerConfig& config, CurveType ct, TransformType t)
    : StrokerConfig(config)
    , curve_type(ct)
    , transform(t)
{}

StrokerShaderMiniConfig::StrokerShaderMiniConfig(const StrokeTessellatorSettings& settings, CurveType ct, TransformType t)
    : StrokerConfig(settings)
    , curve_type(ct)
    , transform(t)
{}

StrokerShaderMiniConfig::StrokerShaderMiniConfig(const StrokeTessellatorSettings& settings, StrokingSpace s, ShadingMode sm)
    : StrokerConfig(settings, s, sm)
    , curve_type(INTEGRAL)
    , transform(SIMILIAR_AFFINE)
{}

StrokerShaderMiniConfig::StrokerShaderMiniConfig(const StrokeTessellatorSettings& settings, CurveType ct, TransformType t, StrokingSpace s, ShadingMode sm)
    : StrokerConfig(settings, s, sm)
    , curve_type(ct)
    , transform(t)
{}

// operator == so unordered_map template works.
bool StrokerShaderMiniConfig::operator == (const StrokerShaderMiniConfig& rhs) const
{
    if (this == &rhs) {
        return true;
    }
    if (StrokerConfig::operator == (rhs)) {
        if (curve_type != rhs.curve_type) {
            return false;
        }
        if (transform != rhs.transform) {
            return false;
        }
        return true;
    } else {
        return false;
    }
}

size_t StrokerShaderMiniConfig::hash() const
{
    size_t hash_value = 
        (size_t(stroking_space)         << 0) ^
        (size_t(shading_mode)           << 1) ^
        // don't hash transform_correction
        (size_t(curve_type)             << 4) ^
        (size_t(transform)              << 5) ^
        (size_t(inside_round_join_mode) << 7) ^
#if SUPPORT_POLAR_VISUALIZE
        (size_t(parameterization)       << 10) ^
#endif
        0;
    return hash_value;
}

int computeDrawInsideOfRoundJoins(StrokeSettingTypes::InsideRoundJoinEnum inside_round_join_mode,
                                  StrokeConfigTypes::ShadingMode shading_mode)
{
    switch (inside_round_join_mode) {
    case StrokeSettingTypes::NO_INSIDE_ROUND_JOIN:
        return 0;
    case StrokeSettingTypes::FORCE_INSIDE_ROUND_JOIN:
        return 1;
    default:
        assert(!"bad inside join mode");
        // Fallthrough...
    case StrokeSettingTypes::AUTOMATIC_INSIDE_ROUND_JOIN:
        switch (shading_mode) {
        case StrokeConfigTypes::ARC_LENGTH_TEXTURE_2D:
        case StrokeConfigTypes::ARC_LENGTH_TEXTURE_2D_EARLY_FRAGMENT_TEST:
            return 1;
        default:
            return 0;
        }
    }
}

#if SUPPORT_POLAR_VISUALIZE
// Amends StrokerShaderMiniConfig to include SUPPORT_POLAR_VISUALIZE features.

StrokerShaderProConfig::StrokerShaderProConfig(const StrokeTessellatorSettings& settings)
    : StrokerShaderMiniConfig(settings)
    , drawing_mode(STROKE)
{}

StrokerShaderProConfig::StrokerShaderProConfig(const StrokerConfig& config, CurveType ct, TransformType t, DrawingMode dm)
    : StrokerShaderMiniConfig(config, ct, t)
    , drawing_mode(dm)
{}

StrokerShaderProConfig::StrokerShaderProConfig(const StrokeTessellatorSettings& settings, CurveType ct, TransformType t, DrawingMode dm)
    : StrokerShaderMiniConfig(settings,ct,t)
    , drawing_mode(dm)
{}

StrokerShaderProConfig::StrokerShaderProConfig(const StrokeTessellatorSettings& settings, StrokingSpace s, ShadingMode sm)
    : StrokerShaderMiniConfig(settings, s, sm)
    , drawing_mode(STROKE)
{}

StrokerShaderProConfig::StrokerShaderProConfig(const StrokeTessellatorSettings& settings, CurveType ct, TransformType t, StrokingSpace s, ShadingMode sm, DrawingMode dm)
    : StrokerShaderMiniConfig(settings, ct, t, s, sm)
    , drawing_mode(dm)
{}

// operator == so unordered_map template works.
bool StrokerShaderProConfig::operator == (const StrokerShaderProConfig& rhs) const
{
    if (this == &rhs) {
        return true;
    }
    if (StrokerShaderMiniConfig::operator == (rhs)) {
        if (drawing_mode != rhs.drawing_mode) {
            return false;
        }
        return true;
    } else {
        return false;
    }
}

size_t StrokerShaderProConfig::hash() const
{
    size_t hash_value = StrokerShaderMiniConfig::hash();
    hash_value ^= 
        (size_t(drawing_mode) << 14);
    return hash_value;
}

#endif // SUPPORT_POLAR_VISUALIZE
