/* -*- mode: C; c-basic-offset: 2 -*- */
/*   EXTRAITS DE LA LICENCE
	Copyright CEA, contributeurs : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)
  
	Adresse mèl :
	BILLARD, non joignable par mèl ;
	CALISTE, damien P caliste AT cea P fr.

	Ce logiciel est un programme informatique servant à visualiser des
	structures atomiques dans un rendu pseudo-3D. 

	Ce logiciel est régi par la licence CeCILL soumise au droit français et
	respectant les principes de diffusion des logiciels libres. Vous pouvez
	utiliser, modifier et/ou redistribuer ce programme sous les conditions
	de la licence CeCILL telle que diffusée par le CEA, le CNRS et l'INRIA 
	sur le site "http://www.cecill.info".

	Le fait que vous puissiez accéder à cet en-tête signifie que vous avez 
	pris connaissance de la licence CeCILL, et que vous en avez accepté les
	termes (cf. le fichier Documentation/licence.fr.txt fourni avec ce logiciel).
*/

/*   LICENCE SUM UP
	Copyright CEA, contributors : Luc BILLARD et Damien
	CALISTE, laboratoire L_Sim, (2001-2005)

	E-mail address:
	BILLARD, not reachable any more ;
	CALISTE, damien P caliste AT cea P fr.

	This software is a computer program whose purpose is to visualize atomic
	configurations in 3D.

	This software is governed by the CeCILL  license under French law and
	abiding by the rules of distribution of free software.  You can  use, 
	modify and/ or redistribute the software under the terms of the CeCILL
	license as circulated by CEA, CNRS and INRIA at the following URL
	"http://www.cecill.info". 

	The fact that you are presently reading this means that you have had
	knowledge of the CeCILL license and that you accept its terms. You can
	find a copy of this licence shipped with this software at Documentation/licence.en.txt.
*/
#ifndef VISU_GL_EXT_H
#define VISU_GL_EXT_H

#include <glib.h>
#include <glib-object.h>

#include "visu_tools.h"
#include "opengl.h"
#include "openGLFunctions/renderingMode.h"
#include "openGLFunctions/view.h"
#include "coreTools/toolWriter.h"
#include "coreTools/toolGl.h"
#include "coreTools/toolColor.h"

G_BEGIN_DECLS

/***************/
/* Public part */
/***************/

/**
 * VISU_GL_EXT_PRIORITY_BACKGROUND
 *
 * An extension with this priority is drawn first.
 */
#define VISU_GL_EXT_PRIORITY_BACKGROUND 0
/**
 * VISU_GL_EXT_PRIORITY_NODES
 *
 * An extension with this priority is drawn alsmost first with the nodes.
 */
#define VISU_GL_EXT_PRIORITY_NODES 2
/**
 * VISU_GL_EXT_PRIORITY_NODE_DECORATIONS
 *
 * An extension with this priority is drawn just after the nodes.
 */
#define VISU_GL_EXT_PRIORITY_NODE_DECORATIONS 5
/**
 * VISU_GL_EXT_PRIORITY_HIGH
 *
 * An extension with this priority is drawn after the higher priorities.
 */
#define VISU_GL_EXT_PRIORITY_HIGH 20
/**
 * VISU_GL_EXT_PRIORITY_NORMAL
 *
 * An extension with this priority is drawn after the higher priorities.
 */
#define VISU_GL_EXT_PRIORITY_NORMAL 50
/**
 * VISU_GL_EXT_PRIORITY_LOW
 *
 * An extension with this priority is drawn among last extensions.
 */
#define VISU_GL_EXT_PRIORITY_LOW 80
/**
 * VISU_GL_EXT_PRIORITY_LAST
 *
 * An extension with this priority is drawn last.
 */
#define VISU_GL_EXT_PRIORITY_LAST 100

#define VISU_TYPE_GL_EXT	     (visu_gl_ext_get_type ())
#define VISU_GL_EXT(obj)	        (G_TYPE_CHECK_INSTANCE_CAST(obj, VISU_TYPE_GL_EXT, VisuGlExt))
#define VISU_GL_EXT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST(klass, VISU_TYPE_GL_EXT, VisuGlExtClass))
#define VISU_IS_GL_EXT(obj)    (G_TYPE_CHECK_INSTANCE_TYPE(obj, VISU_TYPE_GL_EXT))
#define VISU_IS_GL_EXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, VISU_TYPE_GL_EXT))
#define VISU_GL_EXT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS(obj, VISU_TYPE_GL_EXT, VisuGlExtClass))

/**
 * VisuGlExtDirtyStates
 * @VISU_GL_READY: no need to call any redraw for this extension.
 * @VISU_GL_REBUILD_REQUIRED: a call to the rebuild class method should
 * be done before next OpenGL rendering.
 * @VISU_GL_DRAW_REQUIRED: a call to the draw class method should be
 * done before next OpenGL rendering.
 * @VISU_GL_RENDER_REQUIRED: a call to the render class method should
 * be done before the next OpenGL rendering.
 *
 * The possible dirty state of a #VisuGlExt object.
 */
typedef enum
  {
   VISU_GL_READY,
   VISU_GL_REBUILD_REQUIRED,
   VISU_GL_DRAW_REQUIRED,
   VISU_GL_RENDER_REQUIRED
  } VisuGlExtDirtyStates;

/**
 * VisuGlExtPackingModels:
 * @VISU_GL_XYZ: data array contains 3 floats , featuring x, y and z for each vertice.
 * @VISU_GL_RGBA_XYZ: 7 floats for each vertices, containg colour and position data.
 * @VISU_GL_XYZ_NRM: 6 floats for each vertices, with position and normal data.
 *
 * Packing scheme for each vertice in the data array transfered to GPU.
 * 
 * Since: 3.9
 */
typedef enum
  {
    VISU_GL_XYZ,
    VISU_GL_RGBA_XYZ,
    VISU_GL_XYZ_NRM
  } VisuGlExtPackingModels;

/**
 * VisuGlExtPrimitives:
 * @VISU_GL_POINTS: draw points at vertices.
 * @VISU_GL_LINE_LOOP: draw lines closing loops in group.
 * @VISU_GL_LINE_STRIP: draw lines using vertice groups to link them.
 * @VISU_GL_LINES: draw lines taking vertices two by two.
 * @VISU_GL_TRIANGLE_FAN: draw triangles reusing previous side.
 * @VISU_GL_TRIANGLE_STRIP: draw triangles, taking vertices two by two.
 * @VISU_GL_TRIANGLES: draw triangles taking vertices three by three.
 * @VISU_GL_N_PRIMITIVES: number of known primitives.
 * 
 * Drawing primitives.
 *
 * Since: 3.9
 */
typedef enum
  {
    VISU_GL_POINTS,
    VISU_GL_LINE_LOOP,
    VISU_GL_LINE_STRIP,
    VISU_GL_LINES,
    VISU_GL_TRIANGLE_FAN,
    VISU_GL_TRIANGLE_STRIP,
    VISU_GL_TRIANGLES,
    VISU_GL_N_PRIMITIVES
  } VisuGlExtPrimitives;

/**
 * VisuGlExtAlignments:
 * @VISU_GL_LEFT: left aligment.
 * @VISU_GL_CENTER: center aligment.
 * @VISU_GL_RIGHT: right aligment.
 *
 * Positioning flag for texture alignments.
 */
typedef enum
  {
   VISU_GL_LEFT,
   VISU_GL_CENTER,
   VISU_GL_RIGHT
  } VisuGlExtAlignments;

/**
 * VisuGlExtPrivate:
 * 
 * Private data for #VisuGlExt objects.
 */
typedef struct _VisuGlExtPrivate VisuGlExtPrivate;

/**
 * VisuGlExt:
 * 
 * Common name to refer to a #_VisuGlExt.
 */
typedef struct _VisuGlExt VisuGlExt;
struct _VisuGlExt
{
  VisuObject parent;

  VisuGlExtPrivate *priv;
};

/**
 * VisuGlExtClass:
 * @parent: private.
 * @setGlView: a method to attach a #VisuGlView object to this extension.
 * @rebuild: a method called when some new OpenGL context appears and
 * some graphical resources should be allocated.
 * @release: a method called when the OpenGL resources allocated in the
 * @rebuild method should be finalised.
 * @draw: a method called when the extension is marked as dirty.
 * @render: a method called at each OpenGL rendering cycle.
 * @renderText: a method called at each OpenGL rendering cycle,
 * dedicated to text rendering.
 * @allExtensions: the list of all stored #VisuGlExt objects.
 * 
 * Common name to refer to a #_VisuGlExtClass.
 */
typedef struct _VisuGlExtClass VisuGlExtClass;
struct _VisuGlExtClass
{
  VisuObjectClass parent;

  gboolean (*setGlView)(VisuGlExt *ext, VisuGlView *view);
  void (*rebuild)(VisuGlExt *self);
  void (*release)(VisuGlExt *self);
  void (*draw)(VisuGlExt *self);
  void (*render)(const VisuGlExt *self);
  void (*renderText)(const VisuGlExt *self);

  GList *allExtensions;
};

/**
 * VisuGlExtLabel:
 * @lbl: store a text.
 * @xyz: store a position in scene coordinates or window coordinates.
 * @offset: store an offset in modelview coordinates.
 * @rgba: store a rendering colour for the text.
 * @align: store the alignment when using window coordinates.
 * @width: the width of the rendered label.
 * @height: the height of the rendered label.
 *
 * Convenient packing structure to store labels to be rendered on scene.
 * When used with visu_gl_ext_blitLabels(), the coordinates are used as
 * object coordinates. When used with visu_gl_ext_blitLabelsOnScreen()
 * the coordinates are window coordinates and alignment can be tuned with
 * the @align member.
 *
 * @width and @height are readable values after a call to visu_gl_ext_setLabels().
 *
 * Since: 3.9
 */
typedef struct _VisuGlExtLabel VisuGlExtLabel;
struct _VisuGlExtLabel
{
  gchar lbl[64];
  gfloat xyz[3], offset[3];
  gfloat rgba[4];
  VisuGlExtAlignments align[2];

  guint width, height;
};

/**
 * VisuGlExtAttrib:
 * @lbl: store a text.
 * @nEle: number of elements.
 * @kind: kind of elements.
 * @stride: stride to read in the array.
 * @offset: offset for each stride.
 *
 * Describes where to find attrib @lbl in the data buffer.
 *
 * Since: 3.9
 */
typedef struct _VisuGlExtAttrib VisuGlExtAttrib;
struct _VisuGlExtAttrib
{
  const gchar *lbl;
  guint nEle;
  guint kind;
  guint stride;
  const void* offset;
};
/**
 * VISU_GL_EXT_NULL_ATTRIB:
 *
 * Define a null #VisuGlExtAttrib to terminate arrays.
 *
 * Since: 3.9
 */
#define VISU_GL_EXT_NULL_ATTRIB {NULL, 0, 0, 0, NULL}

/**
 * VisuGlExtGlobals:
 * @mvp: the current projection - view matrix.
 * @MV: the current view matrix.
 * @camPosition: the current camera position.
 * @fogColor: the fog colour.
 * @fogStartEnd: start, end position of the fog.
 * @resolution: output width, height in pixels.
 *
 * Contains the current uniform values for GPU shaders.
 *
 * Since: 3.9
 */
typedef struct _VisuGlExtGlobals VisuGlExtGlobals;
struct _VisuGlExtGlobals
{
  ToolGlMatrix mvp;
  ToolGlMatrix MV;
  gfloat camPosition[3];
  gfloat fogColor[4];
  gfloat fogStartEnd[2];
  gfloat resolution[2];
};

/**
 * VisuGlExtShaderIds:
 * @VISU_GL_SHADER_ORTHO: an orthogonal projection for simple on window drawing
 * @VISU_GL_SHADER_FLAT: a scene shader with global colour
 * @VISU_GL_SHADER_SIMPLE: a scene shader with per vertex colour
 * @VISU_GL_SHADER_LINE: a scene shader for lines
 * @VISU_GL_SHADER_COLORED_LINE: a scene shader for lines with colour per vertex
 * @VISU_GL_SHADER_MATERIAL: a scene shader with light effect for surface
 *
 * Built-in shaders.
 *
 * Since: 3.9
 */
typedef enum
  {
   VISU_GL_SHADER_ORTHO,
   VISU_GL_SHADER_FLAT,
   VISU_GL_SHADER_SIMPLE,
   VISU_GL_SHADER_LINE,
   VISU_GL_SHADER_COLORED_LINE,
   VISU_GL_SHADER_MATERIAL
  } VisuGlExtShaderIds;

/**
 * visu_gl_ext_get_type:
 *
 * This method returns the type of #VisuGlExt, use
 * VISU_TYPE_GL_EXT instead.
 *
 * Since: 3.7
 *
 * Returns: the type of #VisuGlExt.
 */
GType visu_gl_ext_get_type(void);

gboolean visu_gl_ext_setDirty(VisuGlExt *ext, VisuGlExtDirtyStates status);

guint visu_gl_ext_getPriority(VisuGlExt *extension);

gboolean visu_gl_ext_getActive(VisuGlExt* extension);
gboolean visu_gl_ext_setActive(VisuGlExt* extension, gboolean value);

VisuGl* visu_gl_ext_getGlContext(VisuGlExt* extension);
gboolean visu_gl_ext_setGlContext(VisuGlExt* extension, VisuGl *gl);

gboolean visu_gl_ext_setPreferedRenderingMode(VisuGlExt* extension,
						  VisuGlRenderingMode value);
VisuGlRenderingMode visu_gl_ext_getPreferedRenderingMode(VisuGlExt* extension);

gboolean visu_gl_ext_setTranslation(VisuGlExt *extension, const gfloat trans[3]);
void visu_gl_ext_getTranslation(const VisuGlExt *extension, gfloat trans[3]);

gboolean visu_gl_ext_setShader(VisuGlExt *ext, guint id,
                               const char *vertexSource, const char *fragmentSource,
                               const char **uniforms, GError **error);
gboolean visu_gl_ext_setShaderById(VisuGlExt *ext, guint id, VisuGlExtShaderIds shader, GError **error);
void visu_gl_ext_setViewport(const VisuGlExt *ext, guint x, guint y, guint width, guint height);
void visu_gl_ext_setUniformRGBA(const VisuGlExt *ext, const gfloat rgba[4]);
void visu_gl_ext_setUniformMaterial(const VisuGlExt *ext, const gfloat material[TOOL_MATERIAL_N_VALUES]);
void visu_gl_ext_setUniformStipple(const VisuGlExt *ext, const guint16 stipple);
void visu_gl_ext_setUniformMV(const VisuGlExt *ext, guint iProg,
                              const ToolGlMatrix *MV);
void visu_gl_ext_setUniformMVP(const VisuGlExt *ext, guint iProg,
                               const ToolGlMatrix *MVP);
void visu_gl_ext_setUniformXYZ(const VisuGlExt *ext, guint id, const gfloat xyz[3]);
void visu_gl_ext_setUniformCamera(const VisuGlExt *ext, guint iProg,
                                  const gfloat xyz[3]);
void visu_gl_ext_setUniformTexRGBA(const VisuGlExt *ext, const gfloat rgba[4]);
void visu_gl_ext_setUniformTexResolution(const VisuGlExt *ext, guint w, guint h);
void visu_gl_ext_setUniformTexMVP(const VisuGlExt *ext, const ToolGlMatrix *MVP);
guint visu_gl_ext_getBufferDimension(const VisuGlExt *ext);

guint visu_gl_ext_getGlBuffer(const VisuGlExt *ext, guint id);
const gchar* visu_gl_ext_getName(const VisuGlExt *extension);

void visu_gl_ext_clearBuffers(VisuGlExt *self);
guint visu_gl_ext_addBuffers(VisuGlExt *self, guint number);
void visu_gl_ext_bookBuffers(VisuGlExt *self, guint number);
void visu_gl_ext_setBufferWithAttrib(VisuGlExt *self, guint id, const GArray *data,
                                     guint iProg, const VisuGlExtAttrib *attribs);
void visu_gl_ext_setBuffer(VisuGlExt *self, guint id, const GArray *data);
void visu_gl_ext_takeBufferWithAttribs(VisuGlExt *self, guint id, GArray *data,
                                       guint iProg, const VisuGlExtAttrib *attribs);
void visu_gl_ext_takeBuffer(VisuGlExt *self, guint id, GArray *data);
void visu_gl_ext_transferBuffer(const VisuGlExt *self, guint id,
                                const GArray *buffer, guint offset);
GArray* visu_gl_ext_startBuffer(VisuGlExt *self, guint iProg, guint id,
                                VisuGlExtPackingModels layout,
                                VisuGlExtPrimitives primitive);
void visu_gl_ext_layoutBuffer(VisuGlExt *self, guint id, const GArray *data);
void visu_gl_ext_layoutBufferWithColor(VisuGlExt *self, guint id, const GArray *data,
                                       const gfloat rgba[4], const gfloat material[5]);

guint visu_gl_ext_addTextures(VisuGlExt *self, guint number);
void visu_gl_ext_bookTextures(VisuGlExt *self, guint number);
void visu_gl_ext_setLabels(VisuGlExt *self, GArray *labels,
                           ToolWriterFontSize size, gboolean stroke);
void visu_gl_ext_clearLabels(VisuGlExt *self);
void visu_gl_ext_setTexture2D(const VisuGlExt *extension, guint texId,
                              const unsigned char *pixels, guint width, guint height);
void visu_gl_ext_setImage(const VisuGlExt *extension, guint texId,
                          const unsigned char *pixels, guint width, guint height, gboolean hasAlpha);
void visu_gl_ext_adjustTextureDimensions(const VisuGlExt *ext, guint texId,
                                         gfloat width, gfloat height);
void visu_gl_ext_blitLabels(const VisuGlExt *extension);
void visu_gl_ext_blitLabelsOnScreen(const VisuGlExt *extension);
void visu_gl_ext_blitTextureAt(const VisuGlExt *extension, guint texId,
                               const gfloat at[3], const gfloat offset[3]);
void visu_gl_ext_blitTextureOnScreen(const VisuGlExt *extension, guint texId, const gfloat at[2],
                                     VisuGlExtAlignments hAlign, VisuGlExtAlignments vAlign);

void visu_gl_ext_draw(VisuGlExt *ext);
void visu_gl_ext_call(const VisuGlExt *extension, const VisuGlExtGlobals *globals);
void visu_gl_ext_callText(const VisuGlExt *ext, const VisuGlExtGlobals *globals);
void visu_gl_ext_startRenderShader(const VisuGlExt *ext, guint shaderId, guint bufId);
void visu_gl_ext_stopRenderShader(const VisuGlExt *ext, guint shaderId, guint bufId);
void visu_gl_ext_renderBuffers(const VisuGlExt *ext);
void visu_gl_ext_renderBuffer(const VisuGlExt *ext, guint id);
void visu_gl_ext_renderBufferWithPrimitive(const VisuGlExt *ext, guint id,
                                           VisuGlExtPrimitives primitive,
                                           const gfloat *rgba);

void visu_gl_ext_cullFace(const VisuGlExt *ext, gboolean status);

void visu_gl_ext_rebuild(VisuGlExt *self);
void visu_gl_ext_release(VisuGlExt *self);
gboolean visu_gl_ext_setGlView(VisuGlExt *ext, VisuGlView *view);

G_END_DECLS

#endif
