/*
** This file is part of the ViTE project.
**
** This software is governed by the CeCILL-A 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-A license as circulated by CEA, CNRS and INRIA at the following
** URL: "http://www.cecill.info".
** 
** As a counterpart to the access to the source code and rights to copy,
** modify and redistribute granted by the license, users are provided
** only with a limited warranty and the software's author, the holder of
** the economic rights, and the successive licensors have only limited
** liability.
** 
** In this respect, the user's attention is drawn to the risks associated
** with loading, using, modifying and/or developing or reproducing the
** software by the user in light of its specific status of free software,
** that may mean that it is complicated to manipulate, and that also
** therefore means that it is reserved for developers and experienced
** professionals having in-depth computer knowledge. Users are therefore
** encouraged to load and test the software's suitability as regards
** their requirements in conditions enabling the security of their
** systems and/or data to be ensured and, more generally, to use and
** operate it in the same conditions as regards security.
** 
** The fact that you are presently reading this means that you have had
** knowledge of the CeCILL-A license and that you accept its terms.
**
**
** ViTE developpers are (for version 0.* to 1.0):
**
**        - COULOMB Kevin
**        - FAVERGE Mathieu
**        - JAZEIX Johnny
**        - LAGRASSE Olivier
**        - MARCOUEILLE Jule
**        - NOISETTE Pascal
**        - REDONDY Arthur
**        - VUCHENER Clément 
**
*/
/*!
 *\file vbo.cpp
 */
 #include <GL/glew.h>
#include <stdlib.h>
#include <iostream>
#include "vbo.hpp"


#define ERROR(m) printf("%s", m);

using namespace std;

const int Vbo::VBO_OK              = 0;
const int Vbo::VBO_OUT_OF_MEMORY   = 1;
const int Vbo::VBO_UNDEFINED_ERROR = 2;

/***********************************
 *
 *
 *
 * Constructor and destructor.
 *
 *
 *
 **********************************/

Vbo::Vbo(){
}


Vbo::Vbo(int nb_object, Type object_type){

    /* init class attributes */

    _nb_coordinates_per_vertex = 2;/* 2 dimensions (x and y) */
    _cur = 0;
    _id = 0;

    _nb_object = nb_object;

    switch (object_type){
    case TRIANGLES:
        _nb_verteces_per_object = 3;
        _object_type = GL_TRIANGLES;
        break;
    case QUADS:
        _nb_verteces_per_object = 4;
        _object_type = GL_QUADS;
        break;
    case LINES:
        _nb_verteces_per_object = 2;
        _object_type = GL_LINES;
    }
    
    /* There is _nb_object*(number_of_vertices_per_object) elements. */
    _size =  _nb_coordinates_per_vertex*_nb_verteces_per_object*_nb_object;

    _client_state = GL_VERTEX_ARRAY;


    /* init OpenGL */

    glGenBuffers(1, &_id);/* create the buffer an put its value to _id */

    glBindBuffer(GL_ARRAY_BUFFER, _id);/* select our vbo */
    
    glBufferData(GL_ARRAY_BUFFER, _size*sizeof(Data_type), NULL, GL_STREAM_DRAW);/* allocate memory space inside graphic card */
       
    glBindBuffer(GL_ARRAY_BUFFER, 0);/* deselect our vbo */

}


Vbo::~Vbo(){
    glDeleteBuffers(1, &_id);/* release the buffer and free its memory inside the graphic card */
    _id = 0;
}




/***********************************
 *
 *
 *
 * Buffer filling.
 *
 *
 *
 **********************************/

int Vbo::add(const unsigned int data_size,  const Data_type* const data){

    glBindBuffer(GL_ARRAY_BUFFER, _id);/* select our vbo */

    /* Take care:
     *
     * For performance, please use glMapBuffer() if data amount is more than 32Kbits,
     * else use glBufferSubData().
     *
     */

    if ( (_cur+data_size) <= _size){
        
        glBufferSubData(GL_ARRAY_BUFFER, _cur*sizeof(Data_type), data_size*sizeof(Data_type), data);
        _cur += data_size;
   
    }else{
        glBindBuffer(GL_ARRAY_BUFFER, 0);/* deselect our vbo */
        return Vbo::VBO_OUT_OF_MEMORY;
    }
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);/* deselect our vbo */


    return Vbo::VBO_OK;
}


int Vbo::get_remaining_size() const{
    return (_size-_cur)/(_nb_verteces_per_object*_nb_coordinates_per_vertex);
}




 /***********************************
  *
  *
  *
  * Buffer display.
  *
  *
  *
  **********************************/

void Vbo::display() const{

    glBindBuffer(GL_ARRAY_BUFFER, _id);/* select our vbo */


    /* glVertexPointer(A, B, C, D)
     *
     * A: coordinate number to identify a vertex (2 in 2 dimension space, 3 in 3 dimension space).
     * B: the coordinate type (GL_INT, GL_FLOAT, GL_DOUBLE, etc.)
     * C: stride -> the case offset between two vertex group (and not coordinate !) . Use to interleaves to kind of objects (for example, verteces and colors).
     * D: the vertex buffer address in the VRAM. Use 0 with the VBO_BUFFER_OFFSET macro to convert a number into an address.
     */
    glVertexPointer(_nb_coordinates_per_vertex, GL_DOUBLE, 0, VBO_BUFFER_OFFSET(0));/* give to OpenGL the VBO address */

    glEnableClientState(_client_state);
    

    /* glDrawArrays(A, B, C)
     *
     * A: an OpenGL primitive (GL_LINES, GL_TRIANGLES, etc.)
     * B: the first vertex index of the vertex buffer which will be printed.
     * C: the whole number of verteces which will be drawn.
     *
     * Please take care that a vertex is represented by _nb_coordinates_per_vertex cases of the _cur array.
     */
    glDrawArrays(_object_type, 0, _cur/_nb_coordinates_per_vertex);/* RENDERING */
        
    glDisableClientState(_client_state);
    
    glBindBuffer(GL_ARRAY_BUFFER, 0);/* deselect our vbo */
}




 /***********************************
  *
  *
  *
  * Debug tools.
  *
  *
  *
  **********************************/

void Vbo::display_info(){
}
