/*
 * See Licensing and Copyright notice in naev.h
 */
#pragma once

/** @cond */
/* Include header generated by glad */
#include "glad.h"
#include <SDL3/SDL_video.h>
/** @endcond */

/* We put all the other openGL stuff here to only have to include one header. */
#include "mat4.h"
#include "opengl_render.h" // IWYU pragma: export
#include "opengl_shader.h" // IWYU pragma: export
#include "opengl_tex.h"    // IWYU pragma: export
#include "opengl_vbo.h"    // IWYU pragma: export

#define OPENGL_NUM_FBOS 4 /**< Number of FBOs to allocate and deal with. */
/** Currently used FBO IDs:
 * 0/1: front/back buffer for rendering
 * 2: temporary scratch buffer to use as necessary
 * 3: Used by toolkit */

/*
 * Contains info about the openGL screen
 */
#define OPENGL_DOUBLEBUF ( 1 << 1 ) /**< Doublebuffer. */
#define OPENGL_VSYNC ( 1 << 2 ) /**< Sync to monitor vertical refresh rate. */
#define OPENGL_SUBROUTINES                                                     \
   ( 1 << 3 ) /**< Ability to use shader subroutines.                          \
               */
#define gl_has( f ) ( gl_screen.flags & ( f ) ) /**< Check for the flag */
/**
 * @brief Stores data about the current openGL environment.
 */
typedef struct glInfo {
   unsigned char major; /**< OpenGL major version. */
   unsigned char minor; /**< OpenGL minor version. */
   int           glsl;  /**< GLSL version. */
   /* Viewport considers x/y offset. */
   int w; /**< Window viewport width. */
   int h; /**< Window viewport height. */
   /* Scaled window is the effective window resolution without considering
    * offsets. */
   int nw; /**< Scaled window width. */
   int nh; /**< Scaled window height. */
   /* Real window resolution is the real window resolution, unscaled and without
    * offsets. */
   int           rw;                   /**< Real window width. */
   int           rh;                   /**< Real window height. */
   double        scale;                /**< Scale factor. */
   double        wscale;               /**< Width scale factor. */
   double        hscale;               /**< Height scale factor. */
   double        dwscale;              /**< Drawable height scale factor. */
   double        dhscale;              /**< Drawable width scale factor. */
   double        mxscale;              /**< Mouse X scale factor. */
   double        myscale;              /**< Mouse y scale factor. */
   unsigned char depth;                /**< Depth in bpp */
   unsigned char r;                    /**< How many red bits we have. */
   unsigned char g;                    /**< How many green bits we have. */
   unsigned char b;                    /**< How many blue bits we have. */
   unsigned char a;                    /**< How many alpha bits we have. */
   unsigned int  flags;                /**< Stores different properties */
   int           tex_max;              /**< Maximum texture size */
   int           multitex_max;         /**< Maximum multitexture levels */
   unsigned char fsaa;                 /**< Full Scene Anti Aliasing level. */
   SDL_Window   *window;               /**< Window for SDL2. */
   SDL_GLContext context;              /**< Context for OpenGL. */
   GLuint        current_fbo;          /**< Current framebuffer. */
   GLuint        fbo[OPENGL_NUM_FBOS]; /**< Framebuffers. */
   GLuint        fbo_tex[OPENGL_NUM_FBOS]; /**< Texture for framebuffers. */
   GLuint
      fbo_depth_tex[OPENGL_NUM_FBOS]; /**< Depth texture for framebuffers. */
} glInfo;
extern glInfo gl_screen; /* local structure set with gl_init and co */

extern mat4 gl_view_matrix;

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

/*
 * initialization / cleanup
 */
int  gl_init( void );
void gl_exit( void );
void gl_resize( void );
void gl_resize_c( void );

/*
 * Viewport.
 */
void gl_windowToScreenPos( float *sx, float *sy, float wx, float wy );
void gl_screenToWindowPos( float *wx, float *wy, float sx, float sy );
void gl_defViewport( void );

/*
 * misc
 */
void   gl_toggleFullscreen( void );
void   gl_setFullscreen( int enable );
int    gl_supportsDebug( void );
void   gl_colourblind( void );
GLenum gl_stringToFilter( const char *s );
GLenum gl_stringToClamp( const char *s );
GLenum gl_stringToBlendFunc( const char *s );
GLenum gl_stringToBlendFactor( const char *s );
void   gl_screenshot( const char *filename );
#ifdef DEBUGGING
#define gl_debugGroupStart()                                                   \
   if ( gl_supportsDebug() ) {                                                 \
      glPushDebugGroup( GL_DEBUG_SOURCE_APPLICATION, 0, strlen( __func__ ),    \
                        __func__ );                                            \
   }
#define gl_debugGroupStartID( id )                                             \
   if ( gl_supportsDebug() ) {                                                 \
      glPushDebugGroup( GL_DEBUG_SOURCE_APPLICATION, id, strlen( __func__ ),   \
                        __func__ );                                            \
   }
#define gl_debugGroupStartName( name )                                         \
   if ( gl_supportsDebug() ) {                                                 \
      glPushDebugGroup( GL_DEBUG_SOURCE_APPLICATION, 0, strlen( name ),        \
                        name );                                                \
   }
#define gl_debugGroupEnd()                                                     \
   if ( gl_supportsDebug() ) {                                                 \
      glPopDebugGroup();                                                       \
   }
#define gl_checkErr() gl_checkHandleError( __func__, __LINE__ )
int gl_checkHandleError( const char *func, int line );
#else /* DEBUGGING */
#define gl_debugGroupStart()                                                   \
   do {                                                                        \
   } while ( 0 )
#define gl_debugGroupStartID( id )                                             \
   do {                                                                        \
   } while ( 0 )
#define gl_debugGroupStartName( name )                                         \
   do {                                                                        \
   } while ( 0 )
#define gl_debugGroupEnd()                                                     \
   do {                                                                        \
   } while ( 0 )
#define gl_checkErr() 0 /**< Hack to ignore errors when debugging. */
#endif                  /* DEBUGGING */
