
// GLPathStrokeState.hpp - interface for OpenGL resources for a baked polar stroked path

#ifndef __GLPathStrokeState_hpp__
#define __GLPathStrokeState_hpp__

#include <GL/glew.h>

#include "../BakeIndexedStrokedPath.hpp"
#include "countof.h"

class GLPathStrokeState {
    GLuint vbo;  // OpenGL vertex buffer object, stores patch indexes + path coordinates
    GLenum component_type;  // GL_FLOAT or GL_SHORT

    void configVertexArrayObject(size_t component_size, size_t aligned_link_bytes);
    void configVertexBufferObject(size_t buffer_bytes, 
                                  size_t link_bytes, const void *index_data,
                                  size_t aligned_link_bytes,
                                  size_t coord_bytes, const void *coord_data);

protected:
    GLuint vao;  // OpenGL vertex array object
    GLenum index_type;  // GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT
    GLsizei draw_index_count;
    GLsizei components_per_element;  // 1 or 2
    GLsizei control_point_count;  // XXX this should belong only to GLPathStrokeStateExt

    bool valid : 1;  // true if VBO is validated for use (or determined empty), false otherwise
    bool empty : 1;  // true if VBO contains nothing to render

public:
    GLPathStrokeState();
    ~GLPathStrokeState();

    void init();
    void load(BakeIndexedStrokedPath &baker);
    void draw() const;
    void invalidate();
    void markEmpty();

    bool hasConics() const {
        return (components_per_element == 1);
    }
    inline bool isValid() const {
        if (vbo) {
            assert(vao);
            assert(draw_index_count > 0);
            assert(control_point_count > 0);
        } else {
            assert(vao == 0);
            assert(draw_index_count == 0);
            assert(control_point_count == 0);
        }
        return valid;
    }
    inline bool isInvalid() const { return !isValid(); }
    inline bool isEmpty() const { return empty; }
    inline bool isNotEmpty() const { return !isEmpty(); }
    inline unsigned int linkCount() const {
        assert(draw_index_count % 6 == 0);
        return draw_index_count/6;
    }
};

// Extended version of GLPathStrokeState
class GLPathStrokeStateExt : public GLPathStrokeState {
public:
    void drawPatch(int i) const;  // draw patches 
    int numPatches() const;
    void drawControlPoints() const;
};

#endif // __GLPathStrokeState_hpp__
