/*  Copyright 2005 Guillaume Duhamel
    Copyright 2005-2006 Theo Berkau

    This file is part of Yabause.

    Yabause is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Yabause is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Yabause; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/
#ifndef  _YGL_H_
#define  _YGL_H_
#ifdef __cplusplus
extern "C" {
#endif

#if defined(HAVE_LIBGL) || defined(__ANDROID__) || defined(IOS)

#if defined(__LIBRETRO__)
    #if defined(__APPLE__)
        #include <OpenGL/gl3.h>
        #define GL_TEXTURE_FETCH_BARRIER_BIT      0x00000008
        #define GL_TEXTURE_UPDATE_BARRIER_BIT     0x00000100
        #define GL_FRAMEBUFFER_BARRIER_BIT        0x00000400
    #endif
    #include <glsym/glsym.h>
    #include <glsm/glsm.h>
#elif defined(__ANDROID__)
    #include <GLES3/gl3.h>
    #include <GLES3/gl3ext.h>
    #include <EGL/egl.h>


#define GL_GEOMETRY_SHADER                0x8DD9

#define GL_ARB_tessellation_shader

#ifdef GL_ARB_tessellation_shader
#define GL_PATCHES                        0x000E
#define GL_PATCH_VERTICES                 0x8E72
#define GL_PATCH_DEFAULT_INNER_LEVEL      0x8E73
#define GL_PATCH_DEFAULT_OUTER_LEVEL      0x8E74
#define GL_TESS_CONTROL_OUTPUT_VERTICES   0x8E75
#define GL_TESS_GEN_MODE                  0x8E76
#define GL_TESS_GEN_SPACING               0x8E77
#define GL_TESS_GEN_VERTEX_ORDER          0x8E78
#define GL_TESS_GEN_POINT_MODE            0x8E79
/* reuse GL_TRIANGLES */
/* reuse GL_QUADS */
#define GL_ISOLINES                       0x8E7A
/* reuse GL_EQUAL */
#define GL_FRACTIONAL_ODD                 0x8E7B
#define GL_FRACTIONAL_EVEN                0x8E7C
/* reuse GL_CCW */
/* reuse GL_CW */
#define GL_MAX_PATCH_VERTICES             0x8E7D
#define GL_MAX_TESS_GEN_LEVEL             0x8E7E
#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
#define GL_MAX_TESS_PATCH_COMPONENTS      0x8E84
#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
#define GL_TESS_EVALUATION_SHADER         0x8E87
#define GL_TESS_CONTROL_SHADER            0x8E88
#endif

typedef void(*PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);
extern PFNGLPATCHPARAMETERIPROC glPatchParameteri;

#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
#define GL_ELEMENT_ARRAY_BARRIER_BIT      0x00000002
#define GL_UNIFORM_BARRIER_BIT            0x00000004
#define GL_TEXTURE_FETCH_BARRIER_BIT      0x00000008
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
#define GL_COMMAND_BARRIER_BIT            0x00000040
#define GL_PIXEL_BUFFER_BARRIER_BIT       0x00000080
#define GL_TEXTURE_UPDATE_BARRIER_BIT     0x00000100
#define GL_BUFFER_UPDATE_BARRIER_BIT      0x00000200
#define GL_FRAMEBUFFER_BARRIER_BIT        0x00000400
#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
#define GL_ATOMIC_COUNTER_BARRIER_BIT     0x00001000
#define GL_ALL_BARRIER_BITS               0xFFFFFFFF

typedef void (* PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
extern PFNGLMEMORYBARRIERPROC glMemoryBarrier;

#elif defined(_WIN32)

#include <windows.h>
  #if defined(_USEGLEW_)
    #include <GL/glew.h>
    #include <GL/gl.h>
    #include "glext.h"
#else
    #include <GL/gl.h>
    #include "glext.h"
    extern PFNGLACTIVETEXTUREPROC glActiveTexture;
#endif

#elif defined(IOS)
#include <OpenGLES/ES3/gl.h>
#include <OpenGLES/ES3/glext.h>

#define GL_GEOMETRY_SHADER                0x8DD9

#ifndef GL_ARB_tessellation_shader
#define GL_PATCHES                        0x000E
#define GL_PATCH_VERTICES                 0x8E72
#define GL_PATCH_DEFAULT_INNER_LEVEL      0x8E73
#define GL_PATCH_DEFAULT_OUTER_LEVEL      0x8E74
#define GL_TESS_CONTROL_OUTPUT_VERTICES   0x8E75
#define GL_TESS_GEN_MODE                  0x8E76
#define GL_TESS_GEN_SPACING               0x8E77
#define GL_TESS_GEN_VERTEX_ORDER          0x8E78
#define GL_TESS_GEN_POINT_MODE            0x8E79
/* reuse GL_TRIANGLES */
/* reuse GL_QUADS */
#define GL_ISOLINES                       0x8E7A
/* reuse GL_EQUAL */
#define GL_FRACTIONAL_ODD                 0x8E7B
#define GL_FRACTIONAL_EVEN                0x8E7C
/* reuse GL_CCW */
/* reuse GL_CW */
#define GL_MAX_PATCH_VERTICES             0x8E7D
#define GL_MAX_TESS_GEN_LEVEL             0x8E7E
#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
#define GL_MAX_TESS_PATCH_COMPONENTS      0x8E84
#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER 0x84F0
#define GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER 0x84F1
#define GL_TESS_EVALUATION_SHADER         0x8E87
#define GL_TESS_CONTROL_SHADER            0x8E88
#endif

typedef void(*PFNGLPATCHPARAMETERIPROC) (GLenum pname, GLint value);
extern PFNGLPATCHPARAMETERIPROC glPatchParameteri;

#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
#define GL_ELEMENT_ARRAY_BARRIER_BIT      0x00000002
#define GL_UNIFORM_BARRIER_BIT            0x00000004
#define GL_TEXTURE_FETCH_BARRIER_BIT      0x00000008
#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
#define GL_COMMAND_BARRIER_BIT            0x00000040
#define GL_PIXEL_BUFFER_BARRIER_BIT       0x00000080
#define GL_TEXTURE_UPDATE_BARRIER_BIT     0x00000100
#define GL_BUFFER_UPDATE_BARRIER_BIT      0x00000200
#define GL_FRAMEBUFFER_BARRIER_BIT        0x00000400
#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
#define GL_ATOMIC_COUNTER_BARRIER_BIT     0x00001000
#define GL_ALL_BARRIER_BITS               0xFFFFFFFF

typedef void (* PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
extern PFNGLMEMORYBARRIERPROC glMemoryBarrier;

#elif  defined(__APPLE__)
    #include <OpenGL/gl.h>
    #include <OpenGL/gl3.h>

#else // Linux?
#if defined(_USEGLEW_)
    #define GL_GLEXT_PROTOTYPES 1
    #define GLX_GLXEXT_PROTOTYPES 1
    #include <GL/glew.h>
#endif
    #if defined(_OGL3_)
        #include <GL/gl.h>
    #endif
    #if defined(_OGLES3_)
        #include <GLES3/gl3.h>
    #endif
    #if defined(_OGLES31_)
        #include <GLES3/gl31.h>
    #endif
#endif

#include <stdarg.h>
#include <string.h>

#ifndef YGL_H
#define YGL_H

#include "core.h"
#include "threads.h"
#include "vidshared.h"
#include "vdp1.h"

// #define DEBUG_BLIT

#ifdef DEBUG_BLIT
#define NB_RENDER_LAYER 5
#else
#define NB_RENDER_LAYER 1
#endif

typedef GLuint (*GetFBFunc)(int);

typedef struct {
	float vertices[8];
	int w;
	int h;
	int flip;
	int priority;
	int dst;
  s32 cor;
  s32 cog;
  s32 cob;
  int linescreen;
  int idScreen;
} YglSprite;

typedef struct {
	float x;
	float y;
} YglCache;

typedef struct {
	unsigned int * textdata;
	unsigned int w;
} YglTexture;

#define HASHSIZE  (0xFFFF)
typedef struct _YglCacheHash {
	u64 addr;
	float x;
	float y;
	struct _YglCacheHash * next;
} YglCacheHash;

typedef struct {
	unsigned int currentX;
	unsigned int currentY;
	unsigned int yMax;
	unsigned int * texture;
	unsigned int width;
	unsigned int height;
        YabMutex *mtx;
	YglCacheHash *HashTable[HASHSIZE+1];
	YglCacheHash CashLink[HASHSIZE * 2+1];
	u32 CashLink_index;
	GLuint textureID;
	GLuint pixelBufferID;
} YglTextureManager;

extern YglTextureManager * YglTM_vdp2;

YglTextureManager * YglTMInit(unsigned int, unsigned int);
void YglTMDeInit(YglTextureManager ** tm );
void YglTMReset( YglTextureManager * tm );
void YglTMReserve(YglTextureManager * tm, unsigned int w, unsigned int h);
void YglTMAllocate(YglTextureManager * tm, YglTexture *, unsigned int, unsigned int, unsigned int *, unsigned int *);
void YglTmPush(YglTextureManager * tm);
void YglTmPull(YglTextureManager * tm, u32 flg);

void YglCacheInit(YglTextureManager * tm);
void YglCacheDeInit(YglTextureManager * tm);
int YglIsCached(YglTextureManager * tm, u64, YglCache *);
void YglCacheAdd(YglTextureManager * tm, u64, YglCache *);
void YglCacheReset(YglTextureManager * tm);
void setupMaxSize();

void YglCheckFBSwitch(int sync);

#define BLIT_TEXTURE_NB_PROG (16*2*4*14*5*4)

enum
{
   PG_VDP2_NORMAL=1,
   PG_VDP2_MOSAIC=2,
   PG_VDP2_NORMAL_CRAM=3,
   PG_VDP2_MOSAIC_CRAM=4,



   PG_VDP2_DRAWFRAMEBUFF_NONE=8,
   PG_VDP2_DRAWFRAMEBUFF_LESS_NONE=(PG_VDP2_DRAWFRAMEBUFF_NONE+1),
   PG_VDP2_DRAWFRAMEBUFF_EUQAL_NONE=(PG_VDP2_DRAWFRAMEBUFF_NONE+2),
   PG_VDP2_DRAWFRAMEBUFF_MORE_NONE=(PG_VDP2_DRAWFRAMEBUFF_NONE+3),
   PG_VDP2_DRAWFRAMEBUFF_MSB_NONE=(PG_VDP2_DRAWFRAMEBUFF_NONE+4),

   PG_MAX = (PG_VDP2_DRAWFRAMEBUFF_NONE+BLIT_TEXTURE_NB_PROG)
};



typedef struct {
    GLint  sprite;
    GLint  fbo;
    GLint  texsize;
    GLuint mtxModelView;
    GLuint sysclip;
    GLuint expand;
    GLuint tex0;
    GLint vaid;
    GLint vertexp;
    GLint texcoordp;
} YglVdp1CommonParam;

// std140
typedef struct  {
 int u_pri[8*4];
 int u_alpha[8*4];
 float u_coloroffset[4];
 int u_cctll;
 int u_color_ram_offset;
} UniformFrameBuffer;

/*
int isSpecialColorCal;   // (fixVdp2Regs->CCCTL >> 6) & 0x01);
int SpecialColorCalMode; // (fixVdp2Regs->SPCTL >> 12) & 0x3;
*/

#define FRAME_BUFFER_UNIFORM_ID (5)

typedef struct {
   int prgid;
   GLuint prg;
   GLuint vertexBuffer;
   float * quads;
   float * textcoords;
   float * vertexAttribute;
   int currentQuad;
   int maxQuad;
   int vaid;
   short ux1,uy1,ux2,uy2;
   GLuint vertexp;
   GLuint texcoordp;
   GLuint mtxModelView;
   GLuint color_offset;
   GLuint tex0;
   GLuint tex1;
   int var1, var2, var3, var4, var5;
   int (*setupUniform)(void *, YglTextureManager *tm, Vdp2* regs, int id);
   int (*cleanupUniform)(void *, YglTextureManager *tm);
   YglVdp1CommonParam * ids;
   GLfloat* matrix;
   int mosaic[2];
   int id;
   int colornumber;
   float emu_height;
   float vheight;
   float emu_width;
   float vwidth;
   GLuint interuput_texture;
   u16 systemClipX2;
   u16 systemClipY2;
} YglProgram;

typedef struct {
   int prgcount;
   int prgcurrent;
   int uclipcurrent;
   short ux1,uy1,ux2,uy2;
   YglProgram * prg;
} YglLevel;

typedef struct
{
    GLfloat   m[4][4];
} YglMatrix;

typedef enum
{
  AA_NONE = 0,
  AA_BILINEAR_FILTER,
  AA_BICUBIC_FILTER,
  AA_ADAPTATIVE_FILTER,
  AA_ADAPTATIVE_DEBUG_FILTER,
  AA_BOB_FILTER,
  AA_SCANLINE
} AAMODE;

typedef enum
{
  UP_NONE = 0,
  UP_HQ4X,
  UP_4XBRZ,
  UP_6XBRZ,
} UPMODE;

typedef enum
{
    ORIGINAL_MESH = 0,
    IMPROVED_MESH
} MESHMODE;

typedef enum
{
    ORIGINAL_BANDING = 0,
    IMPROVED_BANDING
} BANDINGMODE;

typedef enum
{
    RES_ORIGINAL = 0x1, //For compatibility - Saturn output
    RES_SD = 0x2, //For compatibility - Saturn output
    RES_1X = 0x4,
    RES_2X = 0x8,
    RES_4X = 0x20,
    RES_NATIVE = 0x40
} RESOLUTION_MODE;

typedef enum
{
	ORIGINAL_RATIO = 0,
	STRETCH_RATIO = 1,
  INTEGER_RATIO_FULL = 2,
  INTEGER_RATIO = 3
} RATIOMODE;


typedef enum {
    VDP_SETTING_FILTERMODE = 0,
    VDP_SETTING_RESOLUTION_MODE,
    VDP_SETTING_UPSCALMODE,
    VDP_SETTING_ASPECT_RATIO,
    VDP_SETTING_MESH_MODE,
    VDP_SETTING_BANDING_MODE,
    VDP_SETTING_COMPUTE_SHADER,
    VDP_SETTING_WIREFRAME
} enSettings;


typedef enum {
	NBG0 = 0,
	NBG1,
	NBG2,
	NBG3,
	RBG0,
	RBG1,
	SPRITE,
	enBGMAX
} enBG;

typedef enum {
  S0CCRT = 0, //Alpha
  S1CCRT,
  S2CCRT,
  S3CCRT,
  S4CCRT,
  S5CCRT,
  S6CCRT,
  S7CCRT,
  S0PRI, //Prio
  S1PRI,
  S2PRI,
  S3PRI,
  S4PRI,
  S5PRI,
  S6PRI,
  S7PRI,
  SPCC, //CC condition
  VDP1COR, //Color offset
  VDP1COG,
  VDP1COB,
  VDP1CORS, //Color offset sign
  VDP1COGS,
  VDP1COBS,
  CRAOFB, //COLOR RAM OFFSET
	NB_VDP2_REG = 32
} enVdp2;


typedef enum {
	NONE = 1,
	AS_IS = 2,
	SRC_ALPHA = 3,
	DST_ALPHA = 4
} SpriteMode;

typedef enum {
	NORMAL_INTERLACE = 0,
	DOUBLE_INTERLACE = 1,
	SINGLE_INTERLACE = 2
} InterlaceMode;

typedef struct {
   //GLuint texture;
   //GLuint pixelBufferID;
   int st;
   int originx;
   int originy;
   unsigned int width;
   unsigned int height;

   // VDP1 Framebuffer
   int rwidth;
   int rheight;
   int vdp1width;
   int vdp1height;
   float widthRatio;
   float heightRatio;
   int drawframe;
   int readframe;
   int shallVdp1Erase[2];
   GLuint rboid_depth;
   GLuint vdp1fbo;
   GLuint vdp1FrameBuff[4];
   GLuint vdp1AccessFB[2];
   GLuint vdp1AccessTex[2];
   GLuint vdp1_pbo[2];
   GLuint vdp1IsNotEmpty[2];
   GLuint FBDirty[2];
   u32* vdp1fb_write_buf[2];
   u32* vdp1fb_read_buf[2];
   GLuint original_fbo;
   GLuint original_fbotex[NB_RENDER_LAYER];

   GLuint back_fbo;
   GLuint back_fbotex;

   GLuint screen_fbo;
   GLuint screen_fbotex[SPRITE];

   GLuint rbg_compute_fbo;
   GLuint rbg_compute_fbotex[2];

   GLuint window_fbo;
   GLuint window_fbotex[enBGMAX];

   GLuint window_cc_fbo;
   GLuint window_cc_fbotex;

   GLuint tmpfbo;
   GLuint tmpfbotex;

   GLuint upfbo;
   GLuint upfbotex;

   // Message Layer
   int msgwidth;
   int msgheight;
   GLuint msgtexture;
   u32 * messagebuf;

   u32* win[2];
   u32 window_tex[2];

   int Win0[enBGMAX+1];
   int Win0_mode[enBGMAX+1];
   int Win1[enBGMAX+1];
   int Win1_mode[enBGMAX+1];
   int WinS[enBGMAX+1];
   int WinS_mode[enBGMAX+1];
   int Win_op[enBGMAX+1];

   YglMatrix rbgModelView;

   YglProgram windowpg;

   YglLevel * vdp2levels;

   // Thread
   YabMutex * mutex;

   u32 linecolorscreen_tex;
   u32 linecolorscreen_pbo;
   u32* linecolorscreen_buf;

   u32 linecolorcoef_tex[2];
   u32 linecolorcoef_pbo[2];
   u32* linecolorcoef_buf[2];

   u32 coloroffset_tex;
   u32 coloroffset_pbo;
   u32* coloroffset_buf;

   u32 vdp2reg_tex;
   u32 vdp2reg_pbo;
   u8* vdp2reg_buf;
   u8 * vdp2buf;

   u32 back_tex;
   u32 back_pbo;
   u32 * backcolor_buf;

   AAMODE aamode;
   UPMODE upmode;
   MESHMODE meshmode;
   BANDINGMODE bandingmode;
   int wireframe_mode;
   RATIOMODE stretch;
   RESOLUTION_MODE resolution_mode;
   GLsync sync;
   GLuint default_fbo;
   int vpd1_running;
   int needVdp1Render;
   GLint m_viewport[4];
   int min_fb_x;
   int max_fb_x;
   int min_fb_y;
   int max_fb_y;

   int needWinUpdate;

   GLuint cram_tex;
   u32 * cram_tex_buf;
   GLuint cram_map_tex;
   u32 colorRamIndex;
   int colorRamIndexFull[512];
   u8 ColorRamNeedSync;
   YabMutex * crammutex;

   int msb_shadow_count_[2];
   GLuint vao;
   GLuint win0v_buf;
   GLuint win1v_buf;
   GLuint vertexPosition_buf;
   GLuint textureCoordFlip_buf;
   GLuint textureCoord_buf;
   GLuint vb_buf;
   GLuint tb_buf;

   GLuint quads_buf;
   GLuint textcoords_buf;
   GLuint vertexAttribute_buf;

   int vdp1_stencil_mode;

   int useLineColorOffset[2];

   float vdp1ratio;

   float vdp1wdensity;
   float vdp1hdensity;

   float vdp2wdensity;
   float vdp2hdensity;

   InterlaceMode interlace;
   float last_back_color[4];
} Ygl;

extern Ygl * _Ygl;

// Rotate Screen
typedef struct {
  vdp2draw_struct info;
  YglTexture texture;
  Vdp2 *regs;
  u8 order;
} Vdp2Ctrl;

typedef struct {
  Vdp2Ctrl ctrl;
  int useb;
  int rbg_type;
  int pagesize;
  int patternshift;
  u32 LineColorRamAdress;
  YglCache c;
  int vres;
  int hres;
  int async;
  volatile int vdp2_sync_flg;
  vdp2rotationparameter_struct  paraA;
  vdp2rotationparameter_struct  paraB;
  int alpha[270];
} RBGDrawInfo;


int YglInit(int, int, unsigned int);
void YglDeInit(void);
float * YglQuad(vdp2draw_struct *, YglTexture *, YglCache * c, YglTextureManager *tm);
int YglQuadRbg0(RBGDrawInfo * rbg, YglTexture * output, YglCache * c, int rbg_type, YglTextureManager *tm, Vdp2 *varVdp2Regs);
void YglQuadOffset(vdp2draw_struct * input, YglTexture * output, YglCache * c, int cx, int cy, float sx, float sy, YglTextureManager *tm);
void YglCachedQuadOffset(vdp2draw_struct * input, YglCache * cache, int cx, int cy, float sx, float sy, YglTextureManager *tm);
void YglCachedQuad(vdp2draw_struct *, YglCache *, YglTextureManager *tm);
void YglReset(YglLevel level);
void YglShowTexture(void);
void YglChangeResolution(int, int);
void YglCacheQuadGrowShading(YglSprite * input, float * colors, YglCache * cache, YglTextureManager *tm);
int YglQuadGrowShading(YglSprite * input, YglTexture * output, float * colors,YglCache * c, YglTextureManager *tm);
void YglSetBackColor(float r, float g, float b);
void YglStartWindow( vdp2draw_struct * info, int win0, int logwin0, int win1, int logwin1, int mode );
void YglEndWindow( vdp2draw_struct * info );

int YglVDP1AllocateTexture(vdp1cmd_struct * input, YglTexture * output, YglTextureManager *tm);

int YglInitShader(int id, const GLchar * vertex[], int vcount, const GLchar * frag[], int fcount);

int YglTriangleGrowShading(YglSprite * input, YglTexture * output, float * colors, YglCache * c, YglTextureManager *tm);
void YglCacheTriangleGrowShading(YglSprite * input, float * colors, YglCache * cache, YglTextureManager *tm);

u32 * YglGetPerlineBuf(void);
void YglSetPerlineBuf(u32 * pbuf);

extern int YglBlitSimple(int texture, int blend);
extern int YglBlitTexture(int* prioscreens, int* modescreens, int* isRGB, int * isBlur, int* isPerline, int* isShadow, int* lncl, GetFBFunc vdp1fb, int win_s, int win_s_mode, int Win0, int Win0_mode, int Win1, int Win1_mode, int Win_op, int* use_lncl_off, Vdp2 *varVdp2Regs);
extern SpriteMode getSpriteRenderMode(Vdp2* varVdp2Regs);

extern u8 * YglGetVDP2RegPointer();

int Ygl_uniformVDP2DrawFramebuffer(float * offsetcol, int nb_screen, Vdp2* varVdp2Regs);

void showMatrix(YglMatrix *mat, const char* name);
void YglOrtho(YglMatrix *result, float left, float right, float bottom, float top, float nearZ, float farZ);
void YglLoadIdentity(YglMatrix *result);
void YglMatrixMultiply(YglMatrix *result, YglMatrix *srcA, YglMatrix *srcB);

int YglInitVertexBuffer( int initsize );
void YglDeleteVertexBuffer();
int YglUnMapVertexBuffer();
int YglMapVertexBuffer();
int YglUserDirectVertexBuffer();
int YglUserVertexBuffer();
int YglGetVertexBuffer( int size, void ** vpos, void **tcpos, void **vapos );
int YglExpandVertexBuffer( int addsize, void ** vpos, void **tcpos, void **vapos );
intptr_t YglGetOffset( void* address );
int YglBlitVDP1(u32 srcTexture, float w, float h, int flip);
int YglBlitFramebuffer(u32 srcTexture, float w, float h, float dispw, float disph);
int YglUpscaleFramebuffer(u32 srcTexture, u32 targetFbo, float w, float h, float texw, float texh);

u32 * YglGetLineColorScreenPointer();
void YglSetLineColorScreen(u32 * pbuf, int size);

void syncVDP2ColorLine(int line);

//To be removed
void vdp1_write_gl();
u32* vdp1_read_gl(int);
void vdp1_write();
u32* vdp1_read(int);
//End of remove

u32 * YglGetLineColorOffsetPointer(int id, int start, int size);
void YglSetLineColorOffset(u32 * pbuf, int start, int size, int id);

u32* YglGetBackColorPointer();
void YglSetBackTextureColor(int size);

void YglGetWindowPointer(int id);
void YglSetWindow(int id);

int Ygl_uniformWindow(void * p, YglTextureManager *tm, Vdp2 *varVdp2Regs, int id);
int YglProgramInit();
int YglProgramChange( YglLevel * level, int prgid );
int Ygl_cleanupNormal(void * p, YglTextureManager *tm);

int YglSetupWindow(YglProgram * prg);
void Vdp2GenerateWindowInfo(Vdp2 *varVdp2Regs);

void clearVDP1Framebuffer(int frame);

int VIDCSEraseWriteVdp1(int id);
void VIDCSFrameChangeVdp1();

extern void RBGGenerator_init(int width, int height);
extern void RBGGenerator_resize(int width, int height);
extern void RBGGenerator_update(RBGDrawInfo * rbg, Vdp2 *varVdp2Regs );
extern GLuint RBGGenerator_getTexture( int id );
extern GLuint RBGGenerator_getLnclTexture( int id );
extern void RBGGenerator_onFinish();

// Keep a way to switch to gles shaders for embedded devices
#if defined(_OGLES3_) || defined(_OGLES31_)
#define SHADER_VERSION "#version 310 es \n"
#define SHADER_VERSION_TESS "#version 310 es \n#extension GL_ANDROID_extension_pack_es31a : enable \n"
#define SHADER_VERSION_COMPUTE "#version 310 es \n"

#else
#define SHADER_VERSION "#version 330 core \n"
#define SHADER_VERSION_TESS "#version 420 core \n"
#define SHADER_VERSION_COMPUTE "#version 430 core \n"
#endif

#if !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_USEGLEW_) && !defined(_OGLES3_) && !defined(_OGLES31_) && !defined(__LIBRETRO__)

extern GLuint (STDCALL *glCreateProgram)(void);
extern GLuint (STDCALL *glCreateShader)(GLenum);
extern void (STDCALL *glShaderSource)(GLuint,GLsizei,const GLchar **,const GLint *);
extern void (STDCALL *glCompileShader)(GLuint);
extern void (STDCALL *glAttachShader)(GLuint,GLuint);
extern void (STDCALL *glLinkProgram)(GLuint);
extern void (STDCALL *glUseProgram)(GLuint);
extern GLint (STDCALL *glGetUniformLocation)(GLuint,const GLchar *);
extern void (STDCALL *glUniform1i)(GLint,GLint);
extern void (STDCALL *glGetShaderInfoLog)(GLuint,GLsizei,GLsizei *,GLchar *);
extern void (STDCALL *glVertexAttribPointer)(GLuint index,GLint size, GLenum type, GLboolean normalized, GLsizei stride,const void *pointer);
extern void (STDCALL *glBindAttribLocation)( GLuint program, GLuint index, const GLchar * name);
extern void (STDCALL *glGetProgramiv)( GLuint    program, GLenum pname, GLint * params);
extern void (STDCALL *glGetShaderiv)(GLuint shader,GLenum pname,GLint *    params);
extern GLint (STDCALL *glGetAttribLocation)(GLuint program,const GLchar *    name);

extern void (STDCALL *glEnableVertexAttribArray)(GLuint index);
extern void (STDCALL *glDisableVertexAttribArray)(GLuint index);


//GL_ARB_framebuffer_object
extern PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
extern PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
extern PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
extern PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
extern PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;
extern PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;

extern PFNGLUNIFORM4FPROC glUniform4f;
extern PFNGLUNIFORM1FPROC glUniform1f;
extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;



#endif // !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_USEGLEW_)

/*
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|S|C|A|A|A|P|P|P|s| | | | | | | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
S show flag
C index or direct color
A alpha index
P priority
s Shadow Flag

*/

#ifdef DEBUG_PROG
#define GLUSEPROG(A) printf("use prog %s (%d) @ %d\n", #A, A, __LINE__);glUseProgram(A)
#else
#define GLUSEPROG(A) glUseProgram(A)
#endif

extern int VDP1_MASK;

INLINE u32 VDP1COLOR(u16 TAG, u16 CMDCOLR) {
  return (TAG << 16) | (CMDCOLR & VDP1_MASK);
}

INLINE u32 VDP1COLORFB(u16 CMDCOLR) {
  return (0xFF<<16)|(CMDCOLR & VDP1_MASK);
}


INLINE u32 VDP2COLOR(int id, u32 alpha, u32 priority, u32 cc_on, u32 cramindex) {
  return (((alpha & 0xF8) | priority) << 24 | ((cc_on & 0x1)<<16) | (cramindex& 0xFEFFFF));
  //In 32 bit rgb mode, the Blue LSB is always considered as 0.
  //This small artifact allows to implement Special color calculation without the need of an extra texture.
}

#define RGB555_TO_RGB24(temp)  ((temp & 0x1F) << 3 | (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9)

#if defined WORDS_BIGENDIAN
#define SAT2YAB1(alpha,temp)      (alpha | (temp & 0x7C00) << 1 | (temp & 0x3E0) << 14 | (temp & 0x1F) << 27)
#else
#define SAT2YAB1(alpha,temp)      (alpha << 24 | (temp & 0x1F) << 3 | (temp & 0x3E0) << 6 | (temp & 0x7C00) << 9)
#endif

#if defined WORDS_BIGENDIAN
#define SAT2YAB2(alpha,dot1,dot2)       ((dot2 & 0xFF << 24) | ((dot2 & 0xFF00) << 8) | ((dot1 & 0xFF) << 8) | alpha)
#else
//Here FE is not accurate to get an extra bit for MSB shadow information...
#define SAT2YAB2(alpha,dot1,dot2)       (alpha << 24 | ((dot1 & 0xFE) << 16) | (dot2 & 0xFF00) | (dot2 & 0xFF))
#endif

#endif // YGL_H

#endif // defined(HAVE_LIBGL) || defined(__ANDROID__)

#ifdef __cplusplus
}
#endif

#endif // _YGL_H_
