/*
 *  Copyright (c) 2007 Adrian Page <adrian@pagenet.plus.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */
#ifndef KIS_OPENGL_PROGRAM_H_
#define KIS_OPENGL_PROGRAM_H_

#include <GL/glew.h>

#include "krita_export.h"

class QPointF;
class KisOpenGLShader;

/**
 * An encapsulation of an OpenGL Shading Language program object.
 *
 * Create a KisOpenGLProgram then create one or more KisOpenGLVertexShader
 * and KisOpenGLFragmentShader objects, attach them to the program with attachShader()
 * and link() the program. Check if the link was successful (isValid() returns true),
 * and if not, check the info log (getInfoLog()) for error messages.
 *
 * When the program is ready to be used, activate() it
 * and set any uniform variables with setUniformVariable(). Call deactivate()
 * when the program has finished being used.
 */
class KRITAUI_EXPORT KisOpenGLProgram
{
public:
    /**
     * Create a program object.
     */
    KisOpenGLProgram();

    /**
     * Destructor
     */
    virtual ~KisOpenGLProgram();

    /**
     * Returns the handle of the program object.
     */
    GLhandleARB handle() const;

    /**
     * Attach a shader object to the program.
     * @param shader The shader to attach
     */
    void attachShader(KisOpenGLShader& shader);

    /**
     * Detach a shader object from the program.
     * @param shader The shader to detach
     */
    void detachShader(KisOpenGLShader& shader);

    /**
     * Link the program. If isValid() returns false after linking,
     * getInfoLog() can be used to view error messages generated
     * by the OpenGL driver.
     */
    void link();

    /**
     * Activate the program, making it the active program object in the render
     * context.
     */
    virtual void activate();

    /**
     * Deactivate the program so that it is no longer the active program object
     * in the render context.
     */
    static void deactivate();

    /**
     * Returns true if this program is the active program object in the render
     * context.
     */
    bool active() const;

    /**
     * Returns true if the program successfully linked and is ready to be used.
     */
    bool isValid() const;

    /**
     * Returns the information log generated by the OpenGL driver while
     * linking the program. If the link failed, check this for error messages
     * indicating the reason for the failure.
     */
    QString getInfoLog() const;

    /**
     * Set a vec4 uniform variable value. The program must be activated before
     * variables can be set.
     * @param variableName The name of the variable
     * @param v0 The value to set the first component to
     * @param v1 The value to set the second component to
     * @param v2 The value to set the third component to
     * @param v3 The value to set the fourth component to
     */
    void setUniformVariable(const GLchar *variableName, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) const;

    /**
     * Set a vec2 uniform variable value. The program must be activated before
     * variables can be set.
     * @param variableName The name of the variable
     * @param v0 The value to set the first component to
     * @param v1 The value to set the second component to
     */
    void setUniformVariable(const GLchar *variableName, GLfloat v0, GLfloat v1) const;

    /**
     * Set a vec2 uniform variable value. The program must be activated before
     * variables can be set.
     * @param variableName The name of the variable
     * @param value The value to set the variable to
     */
    void setUniformVariable(const GLchar *variableName, const QPointF &value) const;

    /**
     * Set an integer scalar uniform variable value. The program must be activated before
     * variables can be set.
     * @param variableName The name of the variable
     * @param i The value to set the variable to
     */
    void setUniformVariable(const GLchar *variableName, GLint i) const;

    /**
     * Set a float scalar uniform variable value. The program must be activated before
     * variables can be set.
     * @param variableName The name of the variable
     * @param value The value to set the variable to
     */
    void setUniformVariable(const GLchar *variableName, GLfloat value) const;

    /**
     * Return the location of a uniform variable.
     * @param variableName The name of the variable
     */
    GLint uniformVariableLocation(const GLchar *variableName) const;

protected:
    /**
     * The handle of the program object.
     */
    GLhandleARB m_program;

    /**
     * True if the program has been successfully linked.
     */
    bool m_isValid;
};

#endif // KIS_OPENGL_PROGRAM_H_

