
// StrokeTessellatorSettings.hpp - interface to global stroke tessellator settings

#ifndef __StrokeTessellatorSettings_hpp__
#define __StrokeTessellatorSettings_hpp__

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <assert.h>
#include <stdio.h>
#include <vector>

class StrokeSettingTypes {
public:
#if SUPPORT_POLAR_VISUALIZE
    enum Parameterization {
        UNIFORM,
        POLAR
    };
#endif

    enum InsideRoundJoinEnum {
        NO_INSIDE_ROUND_JOIN,
        FORCE_INSIDE_ROUND_JOIN,
        AUTOMATIC_INSIDE_ROUND_JOIN,
        INSIDE_ROUND_JOIN_MODES  // must be last
    };
};

// Set of global settings for the stroke tessellator
class StrokeTessellatorSettings : StrokeSettingTypes {
    bool trivial_culling;
    bool min_window_stroke_radius_clamp;
    float min_window_stroke_radius;
    float max_turning_angle_delta;
    InsideRoundJoinEnum inside_round_join_mode;
#if SUPPORT_POLAR_VISUALIZE
    Parameterization parameterization;
    unsigned int uniform_segments;
    int extra_steps;  // Number of extra steps to be added between intervals of like signed curvature.
    bool show_joins; // when true, draw join triangles as opaque white
#endif

public:
    StrokeTessellatorSettings();
    StrokeTessellatorSettings(float angle_in_radians);

    bool TrivialCulling() const {
        return trivial_culling;
    }
    void toggleTrivialCulling() {
        trivial_culling = !trivial_culling;
    }
    void disableTrivialCulling() {
        trivial_culling = false;
    }
    void enableTrivialCulling() {
        trivial_culling = true;
    }
    void setTrivialCulling(bool state) {
        trivial_culling = state;
    }

    float MaxTurningAngleDelta() const {
        return max_turning_angle_delta;
    }
    void scaleMaxTurningAngleDelta(float scale) {
        max_turning_angle_delta *= scale;
    }
    void biasMaxTurningAngleDelta(float bias) {
        float new_value = max_turning_angle_delta + bias;
        if (0.000001f <= new_value && new_value < 3.14159) {
            max_turning_angle_delta = new_value;
        }
    }
    void setMaxTurningAngleDelta(float radians) {
        max_turning_angle_delta = radians;
    }

    bool MinWindowStrokeRadiusClamp() const {
        return min_window_stroke_radius_clamp;
    }
    void toggleMinWindowStrokeRadiusClamp() {
        min_window_stroke_radius_clamp = !min_window_stroke_radius_clamp;
    }
    void disableMinWindowStrokeRadiusClamp() {
        min_window_stroke_radius_clamp = false;
    }

    float MinWindowStrokeRadius() const {
        return min_window_stroke_radius;
    }
    bool EffectiveMinWindowStrokeRadius() const {
        // Same as MinWindowStrokeRadius but returns zero if clamp is false.
        return min_window_stroke_radius_clamp ? min_window_stroke_radius_clamp : 0;
    }
    void scaleMinWindowStrokeRadius(float scale) {
        min_window_stroke_radius *= scale;
    }

#if SUPPORT_POLAR_VISUALIZE
    Parameterization getParameterization() const {
        return parameterization;
    }
    bool isPolarStroking() const {
        return parameterization == POLAR;
    }
    bool isUniformStroking() const {
        return parameterization == UNIFORM;
    }
    void setParameterization(Parameterization new_value) {
        assert(new_value == UNIFORM || new_value == POLAR);
        parameterization = new_value;
    }
    void toggleParameterization() {
        if (parameterization == UNIFORM) {
            parameterization = POLAR;
        } else {
            parameterization = UNIFORM;
        }
    }
    unsigned int UniformSegments() const {
        return uniform_segments;
    }
    void setUniformSegments(unsigned int new_value) {
        uniform_segments = new_value;
    }

    int ExtraSteps() const {
        return extra_steps;
    }
    void setExtraSteps(int v) {
        extra_steps = v;
    }

    bool ShowJoins() const {
        return show_joins;
    }
    void setShowJoins(bool new_value) {
        show_joins = new_value;
    }
    void toggleShowJoins() {
        show_joins = !show_joins;
    }
#else
    bool isPolarStroking() const {
        return true;
    }
#endif

    InsideRoundJoinEnum InsideRoundJoinMode() const {
        return inside_round_join_mode;
    }
    const char* InsideRoundJoinModeString() const;
    void setInsideRoundJoinMode(InsideRoundJoinEnum mode);
    void cycleInsideRoundJoinMode();
};

#endif // __StrokeTessellatorSettings_hpp__
