#pragma once
#include <stdint.h>
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include "colour.h"
#include "physics.h"

/* Recommended for compatibility bullshit. */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
#  define RMASK 0xff000000
#  define GMASK 0x00ff0000
#  define BMASK 0x0000ff00
#  define AMASK 0x000000ff
#else
#  define RMASK 0x000000ff
#  define GMASK 0x0000ff00
#  define BMASK 0x00ff0000
#  define AMASK 0xff000000
#endif
#define RGBAMASK RMASK,GMASK,BMASK,AMASK

/* Info about opengl screen. */
#define OPENGL_FULLSCREEN   (1<<0)    /**< Fullscreen. */
#define OPENGL_DOUBLEBUF    (1<<1)    /**< Doublebuffer. */
#define OPENGL_AA_POINT     (1<<2)    /**< Antialiasing points. */
#define OPENGL_AA_LINE      (1<<3)    /**< Antialiasing lines. */
#define OPENGL_AA_POLYGON   (1<<4)    /**< Antialiasing polygons. */
#define OPENGL_FRAG_SHADER  (1<<5)    /**< Fragment shaders. */
#define OPENGL_VERT_SHADER  (1<<6)    /**< Vertex shaders. */
#define gl_has(f)           (gl_screen.flags & (f)) /**< Check for the flag. */

/**
 * @struct glInfo
 *
 * @brief Store data about the current opengl environment.
 */
typedef struct glInfo_ {
  int w;            /**< Window width. */
  int h;            /**< Window height. */
  int depth;        /**< Depth in bpp. */
  int r;            /**< Amount of red bits. */
  int g;            /**< Amount of green bits. */
  int b;            /**< Amount of blue bits. */
  int a;            /**< Amount of alpha bits. */
  int flags;        /**< Store different properties. */
  int tex_max;      /**< Max texture size. */
  int multitex_max; /**< Max multitexture levels. */
} glInfo;
extern glInfo gl_screen; /* Local structure set with gl_init etc. */

#define SCREEN_W      gl_screen.w   /**< Screen width. */
#define SCREEN_H      gl_screen.h   /**< Screen height. */

#define COLOUR(x)     glColor4d((x).r, (x).g, (x).b, (x).a) /**< Change colour. */
#define ACOLOUR(x,a)  glColor4d((x).r, (x).g, (x).b, a) /**< Change colour and override alpha. */

/**
 * @struct glTexture
 *
 * @brief Abstraction for rendering spritesheets.
 *
 * The basic unit all the graphic rendering works with.
 */
typedef struct glTexture_ {
  char* name;         /**< Name of graphic. */

  /* Dimensions */
  double w;           /**< Real width of the image. */
  double h;           /**< Real height of the image. */
  double rw;          /**< Padded POT width of the image. */
  double rh;          /**< Padded POT height of the image. */

  /* Sprites */
  double sx;          /**< Number of sprites on the x axis. */
  double sy;          /**< Number of sprites on the y axis. */
  double sw;          /**< Width of the sprite. */
  double sh;          /**< Height of the sprite. */

  /* Data */
  GLuint texture;     /**< The opengl texture itself. */
  uint8_t* trans;     /**< Maps the transparency. */

  /* Properties */
  uint8_t flags;      /**< Flags used for texture properties. */
} glTexture;

/* glTexture loading/freeing. */
SDL_Surface* gl_prepareSurface(SDL_Surface* surface); /* Only preps it. */
glTexture* gl_loadImage(SDL_Surface* surface); /* Frees the surface. */
glTexture* gl_newImage(const char* path);
glTexture* gl_newSprite(const char* path, const int sx, const int sy);
void gl_freeTexture(glTexture* texture);

/* Rendering. */
/* Blits a sprite, relative pos. */
void gl_blitSprite(const glTexture* sprite, const double bx, const double by,
				   const int sx, const int sy, const glColour* c);

/* Blit a sprite, absolute position. */
void gl_blitStaticSprite(const glTexture* sprite,
	const double bx, const double by,
	const int sx, const int sy, const glColour* c);

/* Blit a texture scaled, absolure pos. */
void gl_blitScale(const glTexture* texture,
	const double bx, const double by,
	const double bw, const double bh, const glColour* c);

/* Blit the entire image, absolute pos. */
void gl_blitStatic(const glTexture* texture, const double bx, const double by,
				   const glColour* c);

/* Bind the camera to a vector. */
void gl_bindCamera(const Vec2* pos);

/* Circle drawing. */
void gl_drawCircle(const double x, const double y, const double r);
void gl_drawCircleInRect(const double x, const double y, const double r,
						 const double rc, const double ry, const double rw,
						 const double rh);

/* Initialize/cleanup. */
int gl_init(void);
void gl_exit(void);

/* Misc. */
void gl_defViewport(void);
int gl_pot(int n);
int gl_isTrans(const glTexture* t, const int x, const int y);
void gl_getSpriteFromDir(int* x, int* y, const glTexture* t, const double dir);
void gl_screenshot(const char* filename);
int SDL_savePNG(SDL_Surface* surface, const char* file);
/*#if DEBUG == 1 */
void gl_checkErr(void);
/*#else */
/*#define gl_checkErr() */
/*#endif */

