
/* path_stats.hpp - path statisitics */

#pragma once
#ifndef __path_stats_hpp__
#define __path_stats_hpp__

#include <stdlib.h>

//#include "sg/renderer.hpp"

// Grumble, Microsoft's <windef.h> (and probably other headers) define these as macros
#undef min
#undef max

// For collecting stats on vertex buffer contents
struct PathVertexArrayBufferStats {
    size_t num_vertex_buffers;
    size_t num_draw_arrays;
    size_t num_vertices;
    size_t num_components;
    size_t num_bytes;
    size_t num_independent_triangles;
    size_t num_independent_quads;
    size_t num_anchor_fan_triangles;
    size_t num_arc_fan_triangles;
    size_t num_quadratic_fan_triangles;
    size_t num_all_two_edge_quadratic_hulls;
    size_t num_stoke_with_quadratic_fans;

    PathVertexArrayBufferStats()
        : num_vertex_buffers(0)
        , num_draw_arrays(0)
        , num_vertices(0)
        , num_components(0)
        , num_bytes(0)
        , num_independent_triangles(0)
        , num_independent_quads(0)
        , num_anchor_fan_triangles(0)
        , num_arc_fan_triangles(0)
        , num_quadratic_fan_triangles(0)
        , num_all_two_edge_quadratic_hulls(0)
        , num_stoke_with_quadratic_fans(0)
    { }
    void add(const PathVertexArrayBufferStats &add_me) {
        num_vertex_buffers += add_me.num_vertex_buffers;
        num_draw_arrays += add_me.num_draw_arrays;
        num_vertices += add_me.num_vertices;
        num_components += add_me.num_components;
        num_bytes += add_me.num_bytes;
        num_independent_triangles += add_me.num_independent_triangles;
        num_independent_quads += add_me.num_independent_quads;
        num_anchor_fan_triangles += add_me.num_anchor_fan_triangles;
        num_arc_fan_triangles += add_me.num_arc_fan_triangles;
        num_quadratic_fan_triangles += add_me.num_quadratic_fan_triangles;
        num_all_two_edge_quadratic_hulls += add_me.num_all_two_edge_quadratic_hulls;
        num_stoke_with_quadratic_fans += add_me.num_stoke_with_quadratic_fans;
    }
    void max(const PathVertexArrayBufferStats &max_me) {
        if (max_me.num_draw_arrays > num_draw_arrays) {
            num_draw_arrays = max_me.num_draw_arrays;
        }
        if (max_me.num_vertices > num_vertices) {
            num_vertices = max_me.num_vertices;
        }
        if (max_me.num_components > num_components) {
            num_components = max_me.num_components;
        }
        if (max_me.num_bytes > num_bytes) {
            num_bytes = max_me.num_bytes;
        }
        if (max_me.num_independent_triangles > num_independent_triangles) {
            num_independent_triangles = max_me.num_independent_triangles;
        }
        if (max_me.num_independent_quads > num_independent_quads) {
            num_independent_quads = max_me.num_independent_quads;
        }
        if (max_me.num_anchor_fan_triangles > num_anchor_fan_triangles) {
            num_anchor_fan_triangles = max_me.num_anchor_fan_triangles;
        }
        if (max_me.num_arc_fan_triangles > num_arc_fan_triangles) {
            num_arc_fan_triangles = max_me.num_arc_fan_triangles;
        }
        if (max_me.num_quadratic_fan_triangles > num_quadratic_fan_triangles) {
            num_quadratic_fan_triangles = max_me.num_quadratic_fan_triangles;
        }
    }
    size_t triangleEquivalentPrimitives() {
        size_t prims = num_anchor_fan_triangles
                     + num_arc_fan_triangles
                     + num_quadratic_fan_triangles
                     + num_independent_triangles
                     + 2*num_independent_quads;
        return prims;
    }
};

struct BasicPathStates {
    // Conventional paths
    size_t num_paths;
    size_t num_cmds;
    size_t num_coords;
    // Text stats
    size_t num_text_spans;
    size_t num_glyphs;
    size_t num_glyph_cmds;
    size_t num_glyph_coords;

    BasicPathStates()
        : num_paths(0)
        , num_cmds(0)
        , num_coords(0)
        , num_text_spans(0)
        , num_glyphs(0)
        , num_glyph_cmds(0)
        , num_glyph_coords(0)
    { }

    void add(const BasicPathStates &add_me) {
        num_paths += add_me.num_paths;
        num_cmds += add_me.num_cmds;
        num_coords += add_me.num_coords;
        num_text_spans += add_me.num_text_spans;
        num_glyphs += add_me.num_glyphs;
        num_glyph_cmds += add_me.num_glyph_cmds;
        num_glyph_coords += add_me.num_glyph_coords;
    }
    void max(const BasicPathStates &max_me) {
        if (max_me.num_paths > num_paths) {
            num_paths = max_me.num_paths;
        }
        if (max_me.num_cmds > num_cmds) {
            num_cmds = max_me.num_cmds;
        }
        if (max_me.num_coords > num_coords) {
            num_coords = max_me.num_coords;
        }
        if (max_me.num_text_spans > num_text_spans) {
            num_text_spans = max_me.num_text_spans;
        }
        if (max_me.num_glyphs > num_glyphs) {
            num_glyphs = max_me.num_glyphs;
        }
        if (max_me.num_glyph_cmds > num_glyph_cmds) {
            num_glyph_cmds = max_me.num_glyph_cmds;
        }
        if (max_me.num_glyph_coords > num_glyph_coords) {
            num_glyph_coords = max_me.num_glyph_coords;
        }
    }
};

struct PathStats : BasicPathStates {
    BasicPathStates f;
    BasicPathStates s;

    PathVertexArrayBufferStats fill;
    PathVertexArrayBufferStats stroke;

    PathStats()
    { }

    void add(const PathStats &add_me) {
        BasicPathStates::add(add_me);
        f.add(add_me.f);
        s.add(add_me.s);
        fill.add(add_me.fill);
        stroke.add(add_me.stroke);
    }
    void max(const PathStats &max_me) {
        BasicPathStates::max(max_me);
        f.max(max_me.f);
        s.max(max_me.s);
        fill.max(max_me.fill);
        stroke.max(max_me.stroke);
    }
};

#endif // __path_stats_hpp__
