
// StrokerShaderConfig.hpp - stroker shader configuration

#ifndef __StrokerShaderConfig_hpp__
#define __StrokerShaderConfig_hpp__

#include <stddef.h>  // for size_t

#include "StrokeTessellatorSettings.hpp"

class StrokeConfigTypes {
public:
    enum CurveType {
        INTEGRAL,
        RATIONAL
    };

    enum TransformType {
        PROJECTIVE,          // General projective 2D transform
        NON_SIMILAR_AFFINE,  // Affine 2D transform with non-uniform scaling or shearing
        SIMILIAR_AFFINE      // Uniform-scaling, shear-free affine 2D transform
    };

    enum StrokingSpace {
        OBJECT_SPACE,  // Path space
        WINDOW_SPACE,  // Effectively non-scaling-stroke
        EYE_SPACE,     // XXX unsupported but could be
    };

    enum ShadingMode {
        CONSTANT_COLOR,
        LINEAR_GRADIENT,
        CENTER_RADIAL_GRADIENT,
        FOCAL_RADIAL_GRADIENT,
        IMAGE_GRADIENT,
        ARC_LENGTH_TEXTURE_2D,
        ARC_LENGTH_TEXTURE_2D_EARLY_FRAGMENT_TEST,
        NUM_SHADING_MODES // Count, must be last!
    };

    enum CompositeMode {
        COMPOSITE_OFF,
        COMPOSITE_BLEND,  // can double blend!
        COMPOSITE_BLEND_ONCE,
        COMPOSITE_BLEND_ONCE_LAST,  // not yet working properly
        NUM_COMPOSITE_MODES // Count, must be last!
    };

    // Combine CurveType with TransformType to compute the needed transform correction
    enum TransformCorrection {
        NO_CORRECTION,
        SIMILARITY_TRANSFORM_OF_INTEGRAL_CURVE,
        AFFINE_TRANSFORM_OF_INTEGRAL_CURVE,
        PROJECTIVE_TRANSFORM_OF_INTEGRAL_CURVE,
        SIMILARITY_TRANSFORM_OF_RATIONAL_CURVE,
        PROJECTIVE_TRANSFORM_OF_RATIONAL_CURVE,
        AFFINE_TRANSFORM_OF_RATIONAL_CURVE
    };

    static bool shadingModeNeedsArcLength(ShadingMode shading_mode);
    static bool shadingModeNeedsMemoryBarrier(ShadingMode shading_mode);
    static const char* strokingSpaceString(StrokingSpace storking_space);
    static const char* shadingModeString(ShadingMode shading_mode);
    static bool usesArcLengthExtension(ShadingMode shading_mode);
};

extern int computeDrawInsideOfRoundJoins(StrokeSettingTypes::InsideRoundJoinEnum inside_round_join_mode, StrokeConfigTypes::ShadingMode shading_mode);

class StrokerConfig : public StrokeConfigTypes, public StrokeSettingTypes {
protected:
    StrokingSpace stroking_space;
    ShadingMode shading_mode;
    InsideRoundJoinEnum inside_round_join_mode;
#if SUPPORT_POLAR_VISUALIZE
    // Modes for visualize state controlled by settings
    Parameterization parameterization;
#endif

public:
    StrokerConfig(const StrokeTessellatorSettings& settings);
    StrokerConfig(const StrokeTessellatorSettings& settings, StrokingSpace s, ShadingMode sm);
    // operator == so unordered_map template works.
    bool operator == (const StrokerConfig& rhs) const;
    void setShadingMode(ShadingMode value);
    bool hasGradientCoeffs() const;
    bool isConstantColor() const;
    void setStrokingSpace(StrokingSpace value);

    StrokingSpace getStrokingSpace() const {
        return stroking_space;
    }
    ShadingMode getShadingMode() const {
        return shading_mode;
    }
    const char* getShadingModeString() const;

    InsideRoundJoinEnum InsideRoundJoinMode() const {
        return inside_round_join_mode;
    }
    int DrawInsideOfRoundJoins() const {
        return computeDrawInsideOfRoundJoins(inside_round_join_mode, shading_mode);
    }

#if SUPPORT_POLAR_VISUALIZE
    Parameterization getParameterization() const {
        return parameterization;
    }
    bool isPolarStroking() const {
        return parameterization == POLAR;
    }
    bool isUniformStroking() const {
        return parameterization == UNIFORM;
    }
#endif
};

class StrokerShaderMiniConfig : public StrokerConfig {
public:
    CurveType curve_type;
    TransformType transform;

    // XXX do we need all these ctors??
    StrokerShaderMiniConfig(const StrokeTessellatorSettings& settings);
    StrokerShaderMiniConfig(const StrokerConfig& config, CurveType ct, TransformType t);
    StrokerShaderMiniConfig(const StrokeTessellatorSettings& settings, CurveType ct, TransformType t);
    StrokerShaderMiniConfig(const StrokeTessellatorSettings& settings, StrokingSpace s, ShadingMode sm);
    StrokerShaderMiniConfig(const StrokeTessellatorSettings& settings, CurveType ct, TransformType t, StrokingSpace s, ShadingMode sm);
    // operator == so unordered_map template works.
    bool operator == (const StrokerShaderMiniConfig& rhs) const;
    size_t hash() const;
};

enum DrawingMode {
    STROKE,
    STROKE_TESSELLATION,
    RAW_GRID
};

#if SUPPORT_POLAR_VISUALIZE
// Amends StrokerShaderMiniConfig to include SUPPORT_POLAR_VISUALIZE features.
class StrokerShaderProConfig : public StrokerShaderMiniConfig {
    // Modes for visualize state controller per-draw
    DrawingMode drawing_mode;

public:
    StrokerShaderProConfig(const StrokeTessellatorSettings& settings);
    StrokerShaderProConfig(const StrokerConfig& config, CurveType ct, TransformType t, DrawingMode dm = STROKE);
    StrokerShaderProConfig(const StrokeTessellatorSettings& settings, CurveType ct, TransformType t, DrawingMode dm = STROKE);
    StrokerShaderProConfig(const StrokeTessellatorSettings& settings, StrokingSpace s, ShadingMode sm);
    StrokerShaderProConfig(const StrokeTessellatorSettings& settings, CurveType ct, TransformType t, StrokingSpace s, ShadingMode sm, DrawingMode dm);
    // operator == so unordered_map template works.
    bool operator == (const StrokerShaderProConfig& rhs) const;
    size_t hash() const;

    DrawingMode getDrawingMode() const {
        return drawing_mode;
    }
};
#endif

#if SUPPORT_POLAR_VISUALIZE
typedef StrokerShaderProConfig StrokerShaderConfig;
#else
typedef StrokerShaderMiniConfig StrokerShaderConfig;
#endif

#endif // __StrokerShaderConfig_hpp__
