/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the libgltf project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef LIBGLTF_H
#define LIBGLTF_H

#include <stddef.h>
#include "types.h"
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <string>
#include <vector>

namespace libgltf
{

/**
 * Initialize the glTF renderer object - using the content of the *.json file.
 *
 * The method parses the *.json file and returns a glTFHandle which means an
 * access to the glTF renderer object. Additionally it pushes path and type
 * information of all necessary files into o_glTFFiles vector so the caller code
 * can find all files of the glTF format (images/shaders/buffers) without parsing
 * the *.json file.
 *
 * @since libglTF 0.0
 *
 * @param[in]   jsonfile:       system path of the *.json file
 * @param[out]  o_glTFFiles:    relative path (glTFFile::filename) and file type
 *                              (glTFFile::type) of all files which is part of the glTF model
 *                              (excluding the *.json file). It's size indicate the counts of files.
 *
 * @return      reference to the glTF renderer object,  if parsing went well.
 *              null pointer,                           if any error occured during parsing the *.json file.
 *
**/
glTFHandle* gltf_renderer_init(const std::string& jsonfile, std::vector<glTFFile>& o_glTFFiles);

/**
 * Apply the content of the files included in inputFiles vector on the renderer object.
 *
 * It converts the file buffers into internally used format for the rendering and parses
 * all date from the *.json file to set up the scene. So all of the getter methods which are
 * used for getting the state of the scene can be called after this method is returned successfully.
 * After that call the vector of input files is not needed any more.
 *
 * @since libglTF 0.0
 *
 * @pre handle must point to an existing object
 * @pre inputFiles must be filled with the necessary information (see bellow)
 * @pre need to be called in a valid OpenGL context
 *
 * @param[in,out]   handle          access to the renderer object
 * @param[in]       inputFiles      contains all informations of the files part of the glTF model
 *                                  excluding the *.json file. Struct members should filled following
 *                                  the next rules:
 *                                  *filename: relative file path to the *.json file (set by gltf_renderer_init())
 *                                  *type: type of the file (GLTF_BINARY, GLTF_IMAGE or GLTF_GLSL)
 *                                  *buffer:
 *                                      * type == GLTF_IMAGE: an RGBA_8888 buffer (all color values(0-255) take 8 bit
 *                                        (e.g. one place in the char buffer)). Pixels are stored in row-major order
 *                                        and pixel lines are stored from bottom to top (e.g. flipped -
 *                                        following OpenGL convention).
 *                                      * type == GLTF_BINARY or type == GLTF_GLSL: file content read byte by byte.
 *                                  *size:
 *                                      * type == GLTF_IMAGE: not used, can be anything
 *                                      * type == GLTF_BINARY or type == GLTF_GLSL: size of the file in bytes.
 *                                  *imagewidth and imageheight:
 *                                      * type == GLTF_IMAGE: width and height of the image stored in the file.
 *                                      * type == GLTF_BINARY or type == GLTF_GLSL: not used, can be anything.
 *
 * @return      LIBGLTF_SUCCESS(0),     if no error occured.
 *              error code,             in case of any error, see types.h for error codes.
**/
int gltf_renderer_set_content(glTFHandle* handle, const std::vector<glTFFile>& inputFiles);

/** Display FPS in the current window */
void gltf_render_FPS_enable(glTFHandle* handle);

/** Prepare to draw 3D model */
int gltf_prepare_renderer(glTFHandle* handle);

/** Drawing the 3D model to the current OpenGL context. */
void gltf_renderer(glTFHandle* handle);

/** Complete to draw 3D model */
void gltf_complete_renderer(glTFHandle* handle);

/** Release the data of 3D model */
void gltf_renderer_release(glTFHandle* handle);

/**
 * This method fills the three given vector parameters with the eye, view
 * and up vectors which vectors define the position and orientation of the camera.
 * Meaning of these three vectors:
 *      eye:     position of the camera
 *      view:    a position where the camera look at
 *      up:      a normal vector defining the up direction
 *
 * @since libglTF 0.0
 *
 * @pre gltf_renderer_set_content() must be called before this method is used
 * @pre handle must point to an existing object
 * @pre eye, view and up vectors must point to existing objects
 *
 * @param[in,out]      handle      access to the renderer object
 * @param[out]         eye         object to fill with eye vector
 * @param[out]         view        object to fill with view vector
 * @param[out]         up          object to fill with up vector
**/
void gltf_get_camera_pos(glTFHandle* handle, glm::vec3* eye,
                         glm::vec3* view, glm::vec3* up);

/**
 * Get center position of the model.
 *
 * Center position means the center of a minimal globe around the model.
 *
 * @since libglTF 0.0
 *
 * @pre gltf_renderer_set_content() must be called before this method is used
 * @pre handle must point to an existing object
 *
 * @param[in,out]      handle      access to the renderer object
 *
 * @return             pointer of the vector storing the position.
**/
glm::vec3* gltf_get_model_center_pos(glTFHandle* handle);

/**
 * Get size of the model.
 *
 * Model size means the diameter of a minimal globe around the model.
 *
 * @since libglTF 0.0
 *
 * @pre gltf_renderer_set_content() must be called before this method is used
 * @pre handle must point to an existing object
 *
 * @param[in,out]      handle      access to the renderer object
 *
 * @return             size of the model.
**/
double gltf_get_model_size(glTFHandle* handle);

/** Update camera position, in the time frame of 'time' */
void gltf_renderer_move_camera(glTFHandle* handle, double x, double y,
                               double z, double time);

/** Update model rotation */
void gltf_renderer_rotate_model(glTFHandle* handle, double horizontal,
                                    double vertical, double planar);

/** Update camera rotation */
void gltf_renderer_rotate_camera(glTFHandle* handle, double horizontal,
                                 double vertical, double planar);

/**
 * Enable rotation transformations.
 *
 * When rotation is enabled camera and object rotation will affect the view
 * Rotation is enabled by default, so this method mainly used to reenable
 * rotations after it was disabled.
 *
 * @since libglTF 0.0
 *
 * @pre handle must point to an existing object
 *
 * @param[in,out]      handle      access to the renderer object
**/
void gltf_enable_rotation(glTFHandle* handle);

/**
 * Disable rotation transformations.
 *
 * When rotation is disabled camera and object rotation won't have any effect on the
 * view, which means camera can't be rotated while gltf_enable_rotation() is not called again.
 *
 * @since libglTF 0.0
 *
 * @pre handle must point to an existing object
 *
 * @param[in,out]      handle      access to the renderer object
**/
void gltf_disable_rotation(glTFHandle* handle);

/** Enable transparency */
void gltf_enable_transparency(glTFHandle* handle);

/** Disable transparency */
void gltf_disable_transparency(glTFHandle* handle);

/** Get a bitmap of the screen in the given point in time. */
int gltf_renderer_get_bitmap(glTFHandle** handle, int size,
                              char* buffer, GLenum format, double time = 0);

/** Start orbit mode  */
void gltf_orbit_mode_start(glTFHandle* handle);

/** Stop orbit mode . */
void gltf_orbit_mode_stop(glTFHandle* handle);

/** Start playing the glTF animation (from the beginning). */
void gltf_animation_start(glTFHandle* handle);

/** Stop playing the glTF animation. */
void gltf_animation_stop(glTFHandle* handle);

/** Return the state of the glTF animation. */
bool gltf_animation_is_playing(glTFHandle* handle);

/** Set the animation to loop. */
void gltf_animation_set_looping(glTFHandle* handle, bool loop);

/** Is the animation looping? */
bool gltf_animation_get_looping(glTFHandle* handle);

/** Return amount of seconds this glTF animation takes. */
double gltf_animation_get_duration(glTFHandle* handle);

/** Fast forward / rewind to the given point in time. */
void gltf_animation_set_time(glTFHandle* handle, double time);

/** Query where exactly the animation is, in seconds. */
double gltf_animation_get_time(glTFHandle* handle);

/** Play glTF animation from that point where it was stopped before or from the beginning. */
void gltf_animation_resume(glTFHandle* handle);

} // namespace libgltf

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
