#include <imgpp/glhelper.hpp>

namespace {
using namespace imgpp::gl;
enum InternalFormat: uint16_t {
  INTERNAL_RGB_UNORM= 0x1907,     
  INTERNAL_BGR_UNORM = 0x80E0,    
  INTERNAL_RGBA_UNORM = 0x1908,   
  INTERNAL_BGRA_UNORM = 0x80E1,   
  INTERNAL_BGRA8_UNORM = 0x93A1,    

  INTERNAL_R8_UNORM = 0x8229,     
  INTERNAL_RG8_UNORM = 0x822B,    
  INTERNAL_RGB8_UNORM = 0x8051,   
  INTERNAL_RGBA8_UNORM = 0x8058,    

  INTERNAL_R16_UNORM = 0x822A,    
  INTERNAL_RG16_UNORM = 0x822C,   
  INTERNAL_RGB16_UNORM = 0x8054,    
  INTERNAL_RGBA16_UNORM = 0x805B,   

  INTERNAL_RGB10A2_UNORM = 0x8059,  
  INTERNAL_RGB10A2_SNORM_EXT = 0xFFFC,

  INTERNAL_R8_SNORM = 0x8F94,     
  INTERNAL_RG8_SNORM = 0x8F95,    
  INTERNAL_RGB8_SNORM = 0x8F96,   
  INTERNAL_RGBA8_SNORM = 0x8F97,    

  INTERNAL_R16_SNORM = 0x8F98,    
  INTERNAL_RG16_SNORM= 0x8F99,    
  INTERNAL_RGB16_SNORM= 0x8F9A,   
  INTERNAL_RGBA16_SNORM = 0x8F9B,   

  INTERNAL_R8U = 0x8232,        
  INTERNAL_RG8U = 0x8238,       
  INTERNAL_RGB8U = 0x8D7D,      
  INTERNAL_RGBA8U = 0x8D7C,     

  INTERNAL_R16U = 0x8234,       
  INTERNAL_RG16U = 0x823A,      
  INTERNAL_RGB16U = 0x8D77,     
  INTERNAL_RGBA16U = 0x8D76,      

  INTERNAL_R32U = 0x8236,       
  INTERNAL_RG32U = 0x823C,      
  INTERNAL_RGB32U = 0x8D71,     
  INTERNAL_RGBA32U = 0x8D70,      

  INTERNAL_RGB10A2U = 0x906F,     
  INTERNAL_RGB10A2I_EXT = 0xFFFB,

  INTERNAL_R8I = 0x8231,        
  INTERNAL_RG8I = 0x8237,       
  INTERNAL_RGB8I = 0x8D8F,      
  INTERNAL_RGBA8I = 0x8D8E,     

  INTERNAL_R16I = 0x8233,       
  INTERNAL_RG16I = 0x8239,      
  INTERNAL_RGB16I = 0x8D89,     
  INTERNAL_RGBA16I = 0x8D88,      

  INTERNAL_R32I = 0x8235,       
  INTERNAL_RG32I = 0x823B,      
  INTERNAL_RGB32I = 0x8D83,     
  INTERNAL_RGBA32I = 0x8D82,      

  INTERNAL_R16F = 0x822D,       
  INTERNAL_RG16F = 0x822F,      
  INTERNAL_RGB16F = 0x881B,     
  INTERNAL_RGBA16F = 0x881A,      

  INTERNAL_R32F = 0x822E,       
  INTERNAL_RG32F = 0x8230,      
  INTERNAL_RGB32F = 0x8815,     
  INTERNAL_RGBA32F = 0x8814,      

  INTERNAL_R64F_EXT = 0xFFFA,     
  INTERNAL_RG64F_EXT = 0xFFF9,    
  INTERNAL_RGB64F_EXT = 0xFFF8,   
  INTERNAL_RGBA64F_EXT = 0xFFF7,    

  INTERNAL_SR8 = 0x8FBD,        
  INTERNAL_SRG8 = 0x8FBE,       
  INTERNAL_SRGB8 = 0x8C41,      
  INTERNAL_SRGB8_ALPHA8 = 0x8C43,   

  INTERNAL_RGB9E5 = 0x8C3D,     
  INTERNAL_RG11B10F = 0x8C3A,     
  INTERNAL_RG3B2 = 0x2A10,      
  INTERNAL_R5G6B5 = 0x8D62,     
  INTERNAL_RGB5A1 = 0x8057,     
  INTERNAL_RGBA4 = 0x8056,      

  INTERNAL_RG4_EXT = 0xFFFE,

  INTERNAL_LA4 = 0x8043,        
  INTERNAL_L8 = 0x8040,       
  INTERNAL_A8 = 0x803C,       
  INTERNAL_LA8 = 0x8045,        
  INTERNAL_L16 = 0x8042,        
  INTERNAL_A16 = 0x803E,        
  INTERNAL_LA16 = 0x8048,       

  INTERNAL_D16 = 0x81A5,        
  INTERNAL_D24 = 0x81A6,        
  INTERNAL_D16S8_EXT = 0xFFF6,
  INTERNAL_D24S8 = 0x88F0,      
  INTERNAL_D32 = 0x81A7,        
  INTERNAL_D32F = 0x8CAC,       
  INTERNAL_D32FS8X24 = 0x8CAD,    
  INTERNAL_S8_EXT = 0x8D48,     

  INTERNAL_RGB_DXT1 = 0x83F0,           
  INTERNAL_RGBA_DXT1 = 0x83F1,          
  INTERNAL_RGBA_DXT3 = 0x83F2,          
  INTERNAL_RGBA_DXT5 = 0x83F3,          
  INTERNAL_R_ATI1N_UNORM = 0x8DBB,        
  INTERNAL_R_ATI1N_SNORM = 0x8DBC,        
  INTERNAL_RG_ATI2N_UNORM = 0x8DBD,       
  INTERNAL_RG_ATI2N_SNORM = 0x8DBE,       
  INTERNAL_RGB_BP_UNSIGNED_FLOAT = 0x8E8F,    
  INTERNAL_RGB_BP_SIGNED_FLOAT = 0x8E8E,      
  INTERNAL_RGB_BP_UNORM = 0x8E8C,         
  INTERNAL_RGB_PVRTC_4BPPV1 = 0x8C00,       
  INTERNAL_RGB_PVRTC_2BPPV1 = 0x8C01,       
  INTERNAL_RGBA_PVRTC_4BPPV1 = 0x8C02,      
  INTERNAL_RGBA_PVRTC_2BPPV1 = 0x8C03,      
  INTERNAL_RGBA_PVRTC_4BPPV2 = 0x9137,      
  INTERNAL_RGBA_PVRTC_2BPPV2 = 0x9138,      
  INTERNAL_ATC_RGB = 0x8C92,            
  INTERNAL_ATC_RGBA_EXPLICIT_ALPHA = 0x8C93,    
  INTERNAL_ATC_RGBA_INTERPOLATED_ALPHA = 0x87EE,  

  INTERNAL_RGB_ETC = 0x8D64,            
  INTERNAL_RGB_ETC2 = 0x9274,           
  INTERNAL_RGBA_PUNCHTHROUGH_ETC2 = 0x9276,   
  INTERNAL_RGBA_ETC2 = 0x9278,          
  INTERNAL_R11_EAC = 0x9270,            
  INTERNAL_SIGNED_R11_EAC = 0x9271,       
  INTERNAL_RG11_EAC = 0x9272,           
  INTERNAL_SIGNED_RG11_EAC = 0x9273,        

  INTERNAL_RGBA_ASTC_4x4 = 0x93B0,        
  INTERNAL_RGBA_ASTC_5x4 = 0x93B1,        
  INTERNAL_RGBA_ASTC_5x5 = 0x93B2,        
  INTERNAL_RGBA_ASTC_6x5 = 0x93B3,        
  INTERNAL_RGBA_ASTC_6x6 = 0x93B4,        
  INTERNAL_RGBA_ASTC_8x5 = 0x93B5,        
  INTERNAL_RGBA_ASTC_8x6 = 0x93B6,        
  INTERNAL_RGBA_ASTC_8x8 = 0x93B7,        
  INTERNAL_RGBA_ASTC_10x5 = 0x93B8,       
  INTERNAL_RGBA_ASTC_10x6 = 0x93B9,       
  INTERNAL_RGBA_ASTC_10x8 = 0x93BA,       
  INTERNAL_RGBA_ASTC_10x10 = 0x93BB,        
  INTERNAL_RGBA_ASTC_12x10 = 0x93BC,        
  INTERNAL_RGBA_ASTC_12x12 = 0x93BD,        

  INTERNAL_SRGB_DXT1 = 0x8C4C,          
  INTERNAL_SRGB_ALPHA_DXT1 = 0x8C4D,        
  INTERNAL_SRGB_ALPHA_DXT3 = 0x8C4E,        
  INTERNAL_SRGB_ALPHA_DXT5 = 0x8C4F,        
  INTERNAL_SRGB_BP_UNORM = 0x8E8D,        
  INTERNAL_SRGB_PVRTC_2BPPV1 = 0x8A54,      
  INTERNAL_SRGB_PVRTC_4BPPV1 = 0x8A55,      
  INTERNAL_SRGB_ALPHA_PVRTC_2BPPV1 = 0x8A56,    
  INTERNAL_SRGB_ALPHA_PVRTC_4BPPV1 = 0x8A57,    
  INTERNAL_SRGB_ALPHA_PVRTC_2BPPV2 = 0x93F0,    
  INTERNAL_SRGB_ALPHA_PVRTC_4BPPV2 = 0x93F1,    
  INTERNAL_SRGB8_ETC2 = 0x9275,           
  INTERNAL_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277, 
  INTERNAL_SRGB8_ALPHA8_ETC2_EAC = 0x9279,      
  INTERNAL_SRGB8_ALPHA8_ASTC_4x4 = 0x93D0,    
  INTERNAL_SRGB8_ALPHA8_ASTC_5x4 = 0x93D1,    
  INTERNAL_SRGB8_ALPHA8_ASTC_5x5 = 0x93D2,    
  INTERNAL_SRGB8_ALPHA8_ASTC_6x5 = 0x93D3,    
  INTERNAL_SRGB8_ALPHA8_ASTC_6x6 = 0x93D4,    
  INTERNAL_SRGB8_ALPHA8_ASTC_8x5 = 0x93D5,    
  INTERNAL_SRGB8_ALPHA8_ASTC_8x6 = 0x93D6,    
  INTERNAL_SRGB8_ALPHA8_ASTC_8x8 = 0x93D7,    
  INTERNAL_SRGB8_ALPHA8_ASTC_10x5 = 0x93D8,   
  INTERNAL_SRGB8_ALPHA8_ASTC_10x6 = 0x93D9,   
  INTERNAL_SRGB8_ALPHA8_ASTC_10x8 = 0x93DA,   
  INTERNAL_SRGB8_ALPHA8_ASTC_10x10 = 0x93DB,    
  INTERNAL_SRGB8_ALPHA8_ASTC_12x10 = 0x93DC,    
  INTERNAL_SRGB8_ALPHA8_ASTC_12x12 = 0x93DD,    

  INTERNAL_ALPHA8 = 0x803C,
  INTERNAL_ALPHA16 = 0x803E,
  INTERNAL_LUMINANCE8 = 0x8040,
  INTERNAL_LUMINANCE16 = 0x8042,
  INTERNAL_LUMINANCE8_ALPHA8 = 0x8045,
  INTERNAL_LUMINANCE16_ALPHA16 = 0x8048,
};

enum ExternalFormat: uint16_t {
  EXTERNAL_NONE = 0,          
  EXTERNAL_RED = 0x1903,        
  EXTERNAL_RG = 0x8227,       
  EXTERNAL_RGB= 0x1907,       
  EXTERNAL_BGR = 0x80E0,        
  EXTERNAL_RGBA = 0x1908,       
  EXTERNAL_BGRA = 0x80E1,       
  EXTERNAL_RED_INTEGER = 0x8D94,    
  EXTERNAL_RG_INTEGER = 0x8228,   
  EXTERNAL_RGB_INTEGER = 0x8D98,    
  EXTERNAL_BGR_INTEGER = 0x8D9A,    
  EXTERNAL_RGBA_INTEGER = 0x8D99,   
  EXTERNAL_BGRA_INTEGER = 0x8D9B,   
  EXTERNAL_DEPTH = 0x1902,      
  EXTERNAL_DEPTH_STENCIL = 0x84F9,  
  EXTERNAL_STENCIL = 0x1901,      

  EXTERNAL_LUMINANCE = 0x1909,        
  EXTERNAL_ALPHA = 0x1906,          
  EXTERNAL_LUMINANCE_ALPHA = 0x190A,      

  EXTERNAL_SRGB_EXT = 0x8C40,         
  EXTERNAL_SRGB_ALPHA_EXT = 0x8C42      
};

enum BaseInternalFormat: uint16_t {
  BASE_INTERNAL_NONE = 0,          
  BASE_INTERNAL_RED = 0x1903,        
  BASE_INTERNAL_RG = 0x8227,       
  BASE_INTERNAL_RGB= 0x1907,       
  BASE_INTERNAL_RGBA = 0x1908,       

  BASE_INTERNAL_DEPTH = 0x1902,      
  BASE_INTERNAL_DEPTH_STENCIL = 0x84F9,  
  BASE_INTERNAL_STENCIL = 0x1901,      
};

enum Type: uint16_t {
  TYPE_NONE = 0,            
  TYPE_I8 = 0x1400,         
  TYPE_U8 = 0x1401,         
  TYPE_I16 = 0x1402,          
  TYPE_U16 = 0x1403,          
  TYPE_I32 = 0x1404,          
  TYPE_U32 = 0x1405,          
  TYPE_I64 = 0x140E,          
  TYPE_U64 = 0x140F,          
  TYPE_F16 = 0x140B,          
  TYPE_F16_OES = 0x8D61,        
  TYPE_F32 = 0x1406,          
  TYPE_F64 = 0x140A,          
  TYPE_UINT32_RGB9_E5_REV = 0x8C3E, 
  TYPE_UINT32_RG11B10F_REV = 0x8C3B,  
  TYPE_UINT8_RG3B2 = 0x8032,      
  TYPE_UINT8_RG3B2_REV = 0x8362,    
  TYPE_UINT16_RGB5A1 = 0x8034,    
  TYPE_UINT16_RGB5A1_REV = 0x8366,  
  TYPE_UINT16_R5G6B5 = 0x8363,    
  TYPE_UINT16_R5G6B5_REV = 0x8364,  
  TYPE_UINT16_RGBA4 = 0x8033,     
  TYPE_UINT16_RGBA4_REV = 0x8365,   
  TYPE_UINT32_RGBA8 = 0x8035,     
  TYPE_UINT32_RGBA8_REV = 0x8367,   
  TYPE_UINT32_RGB10A2 = 0x8036,   
  TYPE_UINT32_RGB10A2_REV = 0x8368, 

  TYPE_UINT8_RG4_REV_GTC = 0xFFFD,
  TYPE_UINT16_A1RGB5_GTC = 0xFFFC
};

struct GLDesc {
  InternalFormat internal;
  ExternalFormat external;
  BaseInternalFormat base_internal;
  Type type;
};

static const GLDesc DESCS[] = {
  {INTERNAL_RG4_EXT, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_UINT8_RG4_REV_GTC},                   
  {INTERNAL_RGBA4, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_UINT16_RGBA4_REV},                    
  {INTERNAL_R5G6B5, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_UINT16_R5G6B5_REV},                   
  {INTERNAL_RGB5A1, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_UINT16_RGB5A1_REV},                  

  {INTERNAL_R8_UNORM, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_U8},          
  {INTERNAL_R8_SNORM, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_I8},          
  {INTERNAL_R8U, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_U8},       
  {INTERNAL_R8I, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_I8},       
  {INTERNAL_SR8, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_U8},           

  {INTERNAL_RG8_UNORM, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_U8},          
  {INTERNAL_RG8_SNORM, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_I8},          
  {INTERNAL_RG8U, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_U8},       
  {INTERNAL_RG8I, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_I8},       
  {INTERNAL_SRG8, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_U8},           

  {INTERNAL_RGB8_UNORM, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_U8},        
  {INTERNAL_RGB8_SNORM, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_I8},        
  {INTERNAL_RGB8U, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_U8},       
  {INTERNAL_RGB8I, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_I8},       
  {INTERNAL_SRGB8, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_U8},          

  {INTERNAL_RGBA8_UNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_U8},        
  {INTERNAL_RGBA8_SNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_I8},        
  {INTERNAL_RGBA8U, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_U8},     
  {INTERNAL_RGBA8I, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_I8},     
  {INTERNAL_SRGB8_ALPHA8, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_U8},      

  {INTERNAL_RGB10A2_UNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV},      
  {INTERNAL_RGB10A2_SNORM_EXT, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV},    
  {INTERNAL_RGB10A2U, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV},     
  {INTERNAL_RGB10A2I_EXT, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV},   

  {INTERNAL_R16_UNORM, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_U16},          
  {INTERNAL_R16_SNORM, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_I16},          
  {INTERNAL_R16U, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_U16},         
  {INTERNAL_R16I, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_I16},         
  {INTERNAL_R16F, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_F16},              

  {INTERNAL_RG16_UNORM, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_U16},          
  {INTERNAL_RG16_SNORM, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_I16},          
  {INTERNAL_RG16U, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_U16},         
  {INTERNAL_RG16I, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_I16},         
  {INTERNAL_RG16F, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_F16},              

  {INTERNAL_RGB16_UNORM, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_U16},          
  {INTERNAL_RGB16_SNORM, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_I16},          
  {INTERNAL_RGB16U, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_U16},       
  {INTERNAL_RGB16I, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_I16},       
  {INTERNAL_RGB16F, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_F16},            

  {INTERNAL_RGBA16_UNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_U16},        
  {INTERNAL_RGBA16_SNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_I16},        
  {INTERNAL_RGBA16U, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_U16},       
  {INTERNAL_RGBA16I, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_I16},       
  {INTERNAL_RGBA16F, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_F16},            

  {INTERNAL_R32U, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_U32},         
  {INTERNAL_R32I, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_I32},         
  {INTERNAL_R32F, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_F32},             

  {INTERNAL_RG32U, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_U32},         
  {INTERNAL_RG32I, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_I32},         
  {INTERNAL_RG32F, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_F32},             

  {INTERNAL_RGB32U, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_U32},       
  {INTERNAL_RGB32I, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_I32},       
  {INTERNAL_RGB32F, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_F32},           

  {INTERNAL_RGBA32U, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_U32},       
  {INTERNAL_RGBA32I, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_I32},       
  {INTERNAL_RGBA32F, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_F32},           

  {INTERNAL_R64F_EXT, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_U64},           
  {INTERNAL_R64F_EXT, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_I64},           
  {INTERNAL_R64F_EXT, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_F64},           

  {INTERNAL_RG64F_EXT, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_U64},           
  {INTERNAL_RG64F_EXT, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_I64},           
  {INTERNAL_RG64F_EXT, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_F64},           

  {INTERNAL_RGB64F_EXT, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_U64},         
  {INTERNAL_RGB64F_EXT, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_I64},         
  {INTERNAL_RGB64F_EXT, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_F64},         

  {INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_U64},         
  {INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_I64},         
  {INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_F64},         

  {INTERNAL_RGB_DXT1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},         
  {INTERNAL_SRGB_DXT1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},          
  {INTERNAL_RGBA_DXT1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB_ALPHA_DXT1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_RGBA_DXT3, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB_ALPHA_DXT3, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_RGBA_DXT5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB_ALPHA_DXT5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_R_ATI1N_UNORM, EXTERNAL_NONE, BASE_INTERNAL_RED, TYPE_NONE},        
  {INTERNAL_R_ATI1N_SNORM, EXTERNAL_NONE, BASE_INTERNAL_RED, TYPE_NONE},        
  {INTERNAL_RG_ATI2N_UNORM, EXTERNAL_NONE, BASE_INTERNAL_RG, TYPE_NONE},       
  {INTERNAL_RG_ATI2N_SNORM, EXTERNAL_NONE, BASE_INTERNAL_RG, TYPE_NONE},       
  {INTERNAL_RGB_BP_UNSIGNED_FLOAT, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},    
  {INTERNAL_RGB_BP_SIGNED_FLOAT, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},    
  {INTERNAL_RGB_BP_UNORM, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},       
  {INTERNAL_SRGB_BP_UNORM, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},        

  {INTERNAL_RGB_ETC, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},              
  {INTERNAL_SRGB8_ETC2, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},           
  {INTERNAL_RGBA_PUNCHTHROUGH_ETC2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},     
  {INTERNAL_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE}, 
  {INTERNAL_RGBA_ETC2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ETC2_EAC, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_R11_EAC, EXTERNAL_NONE, BASE_INTERNAL_RED, TYPE_NONE},            
  {INTERNAL_SIGNED_R11_EAC, EXTERNAL_NONE, BASE_INTERNAL_RED, TYPE_NONE},         
  {INTERNAL_RG11_EAC, EXTERNAL_NONE, BASE_INTERNAL_RG, TYPE_NONE},           
  {INTERNAL_SIGNED_RG11_EAC, EXTERNAL_NONE, BASE_INTERNAL_RG, TYPE_NONE},        

  {INTERNAL_RGBA_ASTC_4x4, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ASTC_4x4, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        
  {INTERNAL_RGBA_ASTC_5x4, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ASTC_5x4, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        
  {INTERNAL_RGBA_ASTC_5x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ASTC_5x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        
  {INTERNAL_RGBA_ASTC_6x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ASTC_6x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        
  {INTERNAL_RGBA_ASTC_6x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ASTC_6x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        
  {INTERNAL_RGBA_ASTC_8x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ASTC_8x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        
  {INTERNAL_RGBA_ASTC_8x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ASTC_8x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        
  {INTERNAL_RGBA_ASTC_8x8, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            
  {INTERNAL_SRGB8_ALPHA8_ASTC_8x8, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        
  {INTERNAL_RGBA_ASTC_10x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},           
  {INTERNAL_SRGB8_ALPHA8_ASTC_10x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},       
  {INTERNAL_RGBA_ASTC_10x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},           
  {INTERNAL_SRGB8_ALPHA8_ASTC_10x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},       
  {INTERNAL_RGBA_ASTC_10x8, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},           
  {INTERNAL_SRGB8_ALPHA8_ASTC_10x8, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},       
  {INTERNAL_RGBA_ASTC_10x10, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB8_ALPHA8_ASTC_10x10, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_RGBA_ASTC_12x10, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB8_ALPHA8_ASTC_12x10, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_RGBA_ASTC_12x12, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB8_ALPHA8_ASTC_12x12, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      

  {INTERNAL_RGB_PVRTC_4BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},         
  {INTERNAL_SRGB_PVRTC_2BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},          
  {INTERNAL_RGB_PVRTC_2BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},         
  {INTERNAL_SRGB_PVRTC_4BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},          
  {INTERNAL_RGBA_PVRTC_4BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB_ALPHA_PVRTC_2BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_RGBA_PVRTC_2BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB_ALPHA_PVRTC_4BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_RGBA_PVRTC_4BPPV2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB_ALPHA_PVRTC_4BPPV2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_RGBA_PVRTC_2BPPV2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          
  {INTERNAL_SRGB_ALPHA_PVRTC_2BPPV2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      

  {INTERNAL_RGB_ETC, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},              
  {INTERNAL_ATC_RGB, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},              
  {INTERNAL_ATC_RGBA_EXPLICIT_ALPHA, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      
  {INTERNAL_ATC_RGBA_INTERPOLATED_ALPHA, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE}    
};

inline InternalFormat TranslateFromES20(InternalFormat internal) {
  if (internal == INTERNAL_RGB_ETC2) {
    return INTERNAL_RGB_ETC;
  }
  return internal;
}

inline InternalFormat TranslateToES20(InternalFormat internal) {
  if (internal == INTERNAL_RGB_ETC) {
    return INTERNAL_RGB_ETC2;
  }
  return internal;
}

inline ExternalFormat TranslateFromES20(InternalFormat internal, ExternalFormat external) {
  if (internal == INTERNAL_SRGB8 && external == EXTERNAL_SRGB_EXT) {
    return EXTERNAL_RGB;
  }
  if (internal == INTERNAL_SRGB8_ALPHA8 && external == EXTERNAL_SRGB_ALPHA_EXT) {
    return EXTERNAL_RGBA;
  }
  return external;
}

inline ExternalFormat TranslateToES20(InternalFormat internal, ExternalFormat external) {
  if (internal == INTERNAL_SRGB8 && external == EXTERNAL_RGB) {
    return EXTERNAL_SRGB_EXT;
  }
  if (internal ==INTERNAL_SRGB8_ALPHA8 && external == EXTERNAL_RGBA) {
    return EXTERNAL_SRGB_ALPHA_EXT;
  }
  return external;
}

inline Type TranslateFromES20(Type type) {
  if (type == TYPE_F16_OES) {
    return TYPE_F16;
  }
  return type;
}

inline Type TranslateToES20(Type type) {
  if (type == TYPE_F16) {
    return TYPE_F16_OES;
  }
  return type;
}
}

namespace imgpp { namespace gl {
TextureFormat TranslateFromGL(uint16_t internal, uint16_t external,
  uint16_t base_internal, uint16_t type) {

  InternalFormat translated_internal = TranslateFromES20(
    static_cast<InternalFormat>(internal));
  ExternalFormat translated_external = TranslateFromES20(
    translated_internal, static_cast<ExternalFormat>(external));
  BaseInternalFormat translated_base_internal =
    static_cast<BaseInternalFormat>(base_internal);
  Type translated_type = TranslateFromES20(static_cast<Type>(type));
  for (uint16_t format_id = 0; format_id < 142; ++format_id) {
    const GLDesc &desc = DESCS[format_id];
    if (desc.internal == translated_internal &&
      desc.external == translated_external &&
      desc.base_internal == translated_base_internal &&
      desc.type == translated_type) {
      return static_cast<TextureFormat>(format_id + (uint16_t)FORMAT_FIRST);
    }
  }
  return FORMAT_UNDEFINED;
}

GLFormatDesc TranslateToGL(TextureFormat format, Profile profile) {
  const GLDesc &gl_desc = DESCS[(int)(format - FORMAT_FIRST)];
  GLFormatDesc desc {
    (uint16_t)gl_desc.internal,
    (uint16_t)gl_desc.external,
    (uint16_t)gl_desc.base_internal,
    (uint16_t)gl_desc.type
  };
  if (profile == ES20) {
    desc.internal_format = (uint16_t)TranslateToES20(gl_desc.internal);
    desc.external_format = (uint16_t)TranslateToES20(gl_desc.internal, gl_desc.external);
    desc.type = (uint16_t)TranslateToES20(gl_desc.type);
  }
  return desc;
}

GLFormatDesc TranslateToGL(TextureFormat format) {
  return TranslateToGL(format, GL33);
}

uint32_t GetTypeSize(uint16_t type) {
  Type t = static_cast<Type>(type);
  switch(t) {
    case TYPE_I8:
    case TYPE_U8:
    case TYPE_UINT8_RG3B2:
    case TYPE_UINT8_RG3B2_REV:
    case TYPE_UINT8_RG4_REV_GTC:
      return 1;

    case TYPE_I16:
    case TYPE_U16:
    case TYPE_UINT16_RGB5A1:
    case TYPE_UINT16_RGB5A1_REV:
    case TYPE_UINT16_R5G6B5:
    case TYPE_UINT16_R5G6B5_REV:
    case TYPE_UINT16_RGBA4:
    case TYPE_UINT16_RGBA4_REV:
    case TYPE_UINT16_A1RGB5_GTC:
    case TYPE_F16:
    case TYPE_F16_OES:
      return 2;

    case TYPE_I32:
    case TYPE_U32:
    case TYPE_UINT32_RGB9_E5_REV:
    case TYPE_UINT32_RG11B10F_REV:
    case TYPE_UINT32_RGBA8:
    case TYPE_UINT32_RGBA8_REV:
    case TYPE_UINT32_RGB10A2:
    case TYPE_UINT32_RGB10A2_REV:
    case TYPE_F32:
      return 4;

    case TYPE_F64:
      return 8;
    default:
      return 0x0501; 
  }
}
}}
#include <imgpp/glhelper.hpp>

namespace {
using namespace imgpp::gl;
enum InternalFormat: uint16_t {
  INTERNAL_RGB_UNORM= 0x1907,     //GL_RGB
  INTERNAL_BGR_UNORM = 0x80E0,    //GL_BGR
  INTERNAL_RGBA_UNORM = 0x1908,   //GL_RGBA
  INTERNAL_BGRA_UNORM = 0x80E1,   //GL_BGRA
  INTERNAL_BGRA8_UNORM = 0x93A1,    //GL_BGRA8_EXT

  // unorm formats
  INTERNAL_R8_UNORM = 0x8229,     //GL_R8
  INTERNAL_RG8_UNORM = 0x822B,    //GL_RG8
  INTERNAL_RGB8_UNORM = 0x8051,   //GL_RGB8
  INTERNAL_RGBA8_UNORM = 0x8058,    //GL_RGBA8

  INTERNAL_R16_UNORM = 0x822A,    //GL_R16
  INTERNAL_RG16_UNORM = 0x822C,   //GL_RG16
  INTERNAL_RGB16_UNORM = 0x8054,    //GL_RGB16
  INTERNAL_RGBA16_UNORM = 0x805B,   //GL_RGBA16

  INTERNAL_RGB10A2_UNORM = 0x8059,  //GL_RGB10_A2
  INTERNAL_RGB10A2_SNORM_EXT = 0xFFFC,

  // snorm formats
  INTERNAL_R8_SNORM = 0x8F94,     //GL_R8_SNORM
  INTERNAL_RG8_SNORM = 0x8F95,    //GL_RG8_SNORM
  INTERNAL_RGB8_SNORM = 0x8F96,   //GL_RGB8_SNORM
  INTERNAL_RGBA8_SNORM = 0x8F97,    //GL_RGBA8_SNORM

  INTERNAL_R16_SNORM = 0x8F98,    //GL_R16_SNORM
  INTERNAL_RG16_SNORM= 0x8F99,    //GL_RG16_SNORM
  INTERNAL_RGB16_SNORM= 0x8F9A,   //GL_RGB16_SNORM
  INTERNAL_RGBA16_SNORM = 0x8F9B,   //GL_RGBA16_SNORM

  // unsigned integer formats
  INTERNAL_R8U = 0x8232,        //GL_R8UI
  INTERNAL_RG8U = 0x8238,       //GL_RG8UI
  INTERNAL_RGB8U = 0x8D7D,      //GL_RGB8UI
  INTERNAL_RGBA8U = 0x8D7C,     //GL_RGBA8UI

  INTERNAL_R16U = 0x8234,       //GL_R16UI
  INTERNAL_RG16U = 0x823A,      //GL_RG16UI
  INTERNAL_RGB16U = 0x8D77,     //GL_RGB16UI
  INTERNAL_RGBA16U = 0x8D76,      //GL_RGBA16UI

  INTERNAL_R32U = 0x8236,       //GL_R32UI
  INTERNAL_RG32U = 0x823C,      //GL_RG32UI
  INTERNAL_RGB32U = 0x8D71,     //GL_RGB32UI
  INTERNAL_RGBA32U = 0x8D70,      //GL_RGBA32UI

  INTERNAL_RGB10A2U = 0x906F,     //GL_RGB10_A2UI
  INTERNAL_RGB10A2I_EXT = 0xFFFB,

  // signed integer formats
  INTERNAL_R8I = 0x8231,        //GL_R8I
  INTERNAL_RG8I = 0x8237,       //GL_RG8I
  INTERNAL_RGB8I = 0x8D8F,      //GL_RGB8I
  INTERNAL_RGBA8I = 0x8D8E,     //GL_RGBA8I

  INTERNAL_R16I = 0x8233,       //GL_R16I
  INTERNAL_RG16I = 0x8239,      //GL_RG16I
  INTERNAL_RGB16I = 0x8D89,     //GL_RGB16I
  INTERNAL_RGBA16I = 0x8D88,      //GL_RGBA16I

  INTERNAL_R32I = 0x8235,       //GL_R32I
  INTERNAL_RG32I = 0x823B,      //GL_RG32I
  INTERNAL_RGB32I = 0x8D83,     //GL_RGB32I
  INTERNAL_RGBA32I = 0x8D82,      //GL_RGBA32I

  // Floating formats
  INTERNAL_R16F = 0x822D,       //GL_R16F
  INTERNAL_RG16F = 0x822F,      //GL_RG16F
  INTERNAL_RGB16F = 0x881B,     //GL_RGB16F
  INTERNAL_RGBA16F = 0x881A,      //GL_RGBA16F

  INTERNAL_R32F = 0x822E,       //GL_R32F
  INTERNAL_RG32F = 0x8230,      //GL_RG32F
  INTERNAL_RGB32F = 0x8815,     //GL_RGB32F
  INTERNAL_RGBA32F = 0x8814,      //GL_RGBA32F

  INTERNAL_R64F_EXT = 0xFFFA,     //GL_R64F
  INTERNAL_RG64F_EXT = 0xFFF9,    //GL_RG64F
  INTERNAL_RGB64F_EXT = 0xFFF8,   //GL_RGB64F
  INTERNAL_RGBA64F_EXT = 0xFFF7,    //GL_RGBA64F

  // sRGB formats
  INTERNAL_SR8 = 0x8FBD,        //GL_SR8_EXT
  INTERNAL_SRG8 = 0x8FBE,       //GL_SRG8_EXT
  INTERNAL_SRGB8 = 0x8C41,      //GL_SRGB8
  INTERNAL_SRGB8_ALPHA8 = 0x8C43,   //GL_SRGB8_ALPHA8

  // Packed formats
  INTERNAL_RGB9E5 = 0x8C3D,     //GL_RGB9_E5
  INTERNAL_RG11B10F = 0x8C3A,     //GL_R11F_G11F_B10F
  INTERNAL_RG3B2 = 0x2A10,      //GL_R3_G3_B2
  INTERNAL_R5G6B5 = 0x8D62,     //GL_RGB565
  INTERNAL_RGB5A1 = 0x8057,     //GL_RGB5_A1
  INTERNAL_RGBA4 = 0x8056,      //GL_RGBA4

  INTERNAL_RG4_EXT = 0xFFFE,

  // Luminance Alpha formats
  INTERNAL_LA4 = 0x8043,        //GL_LUMINANCE4_ALPHA4
  INTERNAL_L8 = 0x8040,       //GL_LUMINANCE8
  INTERNAL_A8 = 0x803C,       //GL_ALPHA8
  INTERNAL_LA8 = 0x8045,        //GL_LUMINANCE8_ALPHA8
  INTERNAL_L16 = 0x8042,        //GL_LUMINANCE16
  INTERNAL_A16 = 0x803E,        //GL_ALPHA16
  INTERNAL_LA16 = 0x8048,       //GL_LUMINANCE16_ALPHA16

  // Depth formats
  INTERNAL_D16 = 0x81A5,        //GL_DEPTH_COMPONENT16
  INTERNAL_D24 = 0x81A6,        //GL_DEPTH_COMPONENT24
  INTERNAL_D16S8_EXT = 0xFFF6,
  INTERNAL_D24S8 = 0x88F0,      //GL_DEPTH24_STENCIL8
  INTERNAL_D32 = 0x81A7,        //GL_DEPTH_COMPONENT32
  INTERNAL_D32F = 0x8CAC,       //GL_DEPTH_COMPONENT32F
  INTERNAL_D32FS8X24 = 0x8CAD,    //GL_DEPTH32F_STENCIL8
  INTERNAL_S8_EXT = 0x8D48,     //GL_STENCIL_INDEX8

  // Compressed formats
  INTERNAL_RGB_DXT1 = 0x83F0,           //GL_COMPRESSED_RGB_S3TC_DXT1_EXT
  INTERNAL_RGBA_DXT1 = 0x83F1,          //GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
  INTERNAL_RGBA_DXT3 = 0x83F2,          //GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
  INTERNAL_RGBA_DXT5 = 0x83F3,          //GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
  INTERNAL_R_ATI1N_UNORM = 0x8DBB,        //GL_COMPRESSED_RED_RGTC1
  INTERNAL_R_ATI1N_SNORM = 0x8DBC,        //GL_COMPRESSED_SIGNED_RED_RGTC1
  INTERNAL_RG_ATI2N_UNORM = 0x8DBD,       //GL_COMPRESSED_RG_RGTC2
  INTERNAL_RG_ATI2N_SNORM = 0x8DBE,       //GL_COMPRESSED_SIGNED_RG_RGTC2
  INTERNAL_RGB_BP_UNSIGNED_FLOAT = 0x8E8F,    //GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT
  INTERNAL_RGB_BP_SIGNED_FLOAT = 0x8E8E,      //GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT
  INTERNAL_RGB_BP_UNORM = 0x8E8C,         //GL_COMPRESSED_RGBA_BPTC_UNORM
  INTERNAL_RGB_PVRTC_4BPPV1 = 0x8C00,       //GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG
  INTERNAL_RGB_PVRTC_2BPPV1 = 0x8C01,       //GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG
  INTERNAL_RGBA_PVRTC_4BPPV1 = 0x8C02,      //GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
  INTERNAL_RGBA_PVRTC_2BPPV1 = 0x8C03,      //GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
  INTERNAL_RGBA_PVRTC_4BPPV2 = 0x9137,      //GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG
  INTERNAL_RGBA_PVRTC_2BPPV2 = 0x9138,      //GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG
  INTERNAL_ATC_RGB = 0x8C92,            //GL_ATC_RGB_AMD
  INTERNAL_ATC_RGBA_EXPLICIT_ALPHA = 0x8C93,    //GL_ATC_RGBA_EXPLICIT_ALPHA_AMD
  INTERNAL_ATC_RGBA_INTERPOLATED_ALPHA = 0x87EE,  //GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD

  INTERNAL_RGB_ETC = 0x8D64,            //GL_COMPRESSED_RGB8_ETC1
  INTERNAL_RGB_ETC2 = 0x9274,           //GL_COMPRESSED_RGB8_ETC2
  INTERNAL_RGBA_PUNCHTHROUGH_ETC2 = 0x9276,   //GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
  INTERNAL_RGBA_ETC2 = 0x9278,          //GL_COMPRESSED_RGBA8_ETC2_EAC
  INTERNAL_R11_EAC = 0x9270,            //GL_COMPRESSED_R11_EAC
  INTERNAL_SIGNED_R11_EAC = 0x9271,       //GL_COMPRESSED_SIGNED_R11_EAC
  INTERNAL_RG11_EAC = 0x9272,           //GL_COMPRESSED_RG11_EAC
  INTERNAL_SIGNED_RG11_EAC = 0x9273,        //GL_COMPRESSED_SIGNED_RG11_EAC

  INTERNAL_RGBA_ASTC_4x4 = 0x93B0,        //GL_COMPRESSED_RGBA_ASTC_4x4_KHR
  INTERNAL_RGBA_ASTC_5x4 = 0x93B1,        //GL_COMPRESSED_RGBA_ASTC_5x4_KHR
  INTERNAL_RGBA_ASTC_5x5 = 0x93B2,        //GL_COMPRESSED_RGBA_ASTC_5x5_KHR
  INTERNAL_RGBA_ASTC_6x5 = 0x93B3,        //GL_COMPRESSED_RGBA_ASTC_6x5_KHR
  INTERNAL_RGBA_ASTC_6x6 = 0x93B4,        //GL_COMPRESSED_RGBA_ASTC_6x6_KHR
  INTERNAL_RGBA_ASTC_8x5 = 0x93B5,        //GL_COMPRESSED_RGBA_ASTC_8x5_KHR
  INTERNAL_RGBA_ASTC_8x6 = 0x93B6,        //GL_COMPRESSED_RGBA_ASTC_8x6_KHR
  INTERNAL_RGBA_ASTC_8x8 = 0x93B7,        //GL_COMPRESSED_RGBA_ASTC_8x8_KHR
  INTERNAL_RGBA_ASTC_10x5 = 0x93B8,       //GL_COMPRESSED_RGBA_ASTC_10x5_KHR
  INTERNAL_RGBA_ASTC_10x6 = 0x93B9,       //GL_COMPRESSED_RGBA_ASTC_10x6_KHR
  INTERNAL_RGBA_ASTC_10x8 = 0x93BA,       //GL_COMPRESSED_RGBA_ASTC_10x8_KHR
  INTERNAL_RGBA_ASTC_10x10 = 0x93BB,        //GL_COMPRESSED_RGBA_ASTC_10x10_KHR
  INTERNAL_RGBA_ASTC_12x10 = 0x93BC,        //GL_COMPRESSED_RGBA_ASTC_12x10_KHR
  INTERNAL_RGBA_ASTC_12x12 = 0x93BD,        //GL_COMPRESSED_RGBA_ASTC_12x12_KHR

  // sRGB formats
  INTERNAL_SRGB_DXT1 = 0x8C4C,          //GL_COMPRESSED_SRGB_S3TC_DXT1_EXT
  INTERNAL_SRGB_ALPHA_DXT1 = 0x8C4D,        //GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT
  INTERNAL_SRGB_ALPHA_DXT3 = 0x8C4E,        //GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT
  INTERNAL_SRGB_ALPHA_DXT5 = 0x8C4F,        //GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT
  INTERNAL_SRGB_BP_UNORM = 0x8E8D,        //GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM
  INTERNAL_SRGB_PVRTC_2BPPV1 = 0x8A54,      //GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT
  INTERNAL_SRGB_PVRTC_4BPPV1 = 0x8A55,      //GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT
  INTERNAL_SRGB_ALPHA_PVRTC_2BPPV1 = 0x8A56,    //GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT
  INTERNAL_SRGB_ALPHA_PVRTC_4BPPV1 = 0x8A57,    //GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT
  INTERNAL_SRGB_ALPHA_PVRTC_2BPPV2 = 0x93F0,    //COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG
  INTERNAL_SRGB_ALPHA_PVRTC_4BPPV2 = 0x93F1,    //GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG
  INTERNAL_SRGB8_ETC2 = 0x9275,           //GL_COMPRESSED_SRGB8_ETC2
  INTERNAL_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277, //GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
  INTERNAL_SRGB8_ALPHA8_ETC2_EAC = 0x9279,      //GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
  INTERNAL_SRGB8_ALPHA8_ASTC_4x4 = 0x93D0,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_5x4 = 0x93D1,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_5x5 = 0x93D2,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_6x5 = 0x93D3,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_6x6 = 0x93D4,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_8x5 = 0x93D5,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_8x6 = 0x93D6,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_8x8 = 0x93D7,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_10x5 = 0x93D8,   //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_10x6 = 0x93D9,   //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_10x8 = 0x93DA,   //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_10x10 = 0x93DB,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_12x10 = 0x93DC,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR
  INTERNAL_SRGB8_ALPHA8_ASTC_12x12 = 0x93DD,    //GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR

  INTERNAL_ALPHA8 = 0x803C,
  INTERNAL_ALPHA16 = 0x803E,
  INTERNAL_LUMINANCE8 = 0x8040,
  INTERNAL_LUMINANCE16 = 0x8042,
  INTERNAL_LUMINANCE8_ALPHA8 = 0x8045,
  INTERNAL_LUMINANCE16_ALPHA16 = 0x8048,
};

enum ExternalFormat: uint16_t {
  EXTERNAL_NONE = 0,          //GL_NONE
  EXTERNAL_RED = 0x1903,        //GL_RED
  EXTERNAL_RG = 0x8227,       //GL_RG
  EXTERNAL_RGB= 0x1907,       //GL_RGB
  EXTERNAL_BGR = 0x80E0,        //GL_BGR
  EXTERNAL_RGBA = 0x1908,       //GL_RGBA
  EXTERNAL_BGRA = 0x80E1,       //GL_BGRA
  EXTERNAL_RED_INTEGER = 0x8D94,    //GL_RED_INTEGER
  EXTERNAL_RG_INTEGER = 0x8228,   //GL_RG_INTEGER
  EXTERNAL_RGB_INTEGER = 0x8D98,    //GL_RGB_INTEGER
  EXTERNAL_BGR_INTEGER = 0x8D9A,    //GL_BGR_INTEGER
  EXTERNAL_RGBA_INTEGER = 0x8D99,   //GL_RGBA_INTEGER
  EXTERNAL_BGRA_INTEGER = 0x8D9B,   //GL_BGRA_INTEGER
  EXTERNAL_DEPTH = 0x1902,      //GL_DEPTH_COMPONENT
  EXTERNAL_DEPTH_STENCIL = 0x84F9,  //GL_DEPTH_STENCIL
  EXTERNAL_STENCIL = 0x1901,      //GL_STENCIL_INDEX

  EXTERNAL_LUMINANCE = 0x1909,        //GL_LUMINANCE
  EXTERNAL_ALPHA = 0x1906,          //GL_ALPHA
  EXTERNAL_LUMINANCE_ALPHA = 0x190A,      //GL_LUMINANCE_ALPHA

  EXTERNAL_SRGB_EXT = 0x8C40,         //SRGB_EXT
  EXTERNAL_SRGB_ALPHA_EXT = 0x8C42      //SRGB_ALPHA_EXT
};

enum BaseInternalFormat: uint16_t {
  BASE_INTERNAL_NONE = 0,          //GL_NONE
  BASE_INTERNAL_RED = 0x1903,        //GL_RED
  BASE_INTERNAL_RG = 0x8227,       //GL_RG
  BASE_INTERNAL_RGB= 0x1907,       //GL_RGB
  BASE_INTERNAL_RGBA = 0x1908,       //GL_RGBA

  BASE_INTERNAL_DEPTH = 0x1902,      // GL_DEPTH_COMPONENT
  BASE_INTERNAL_DEPTH_STENCIL = 0x84F9,  // GL_DEPTH_STENCIL
  BASE_INTERNAL_STENCIL = 0x1901,      // GL_STENCIL_INDEX
};

enum Type: uint16_t {
  TYPE_NONE = 0,            //GL_NONE
  TYPE_I8 = 0x1400,         //GL_BYTE
  TYPE_U8 = 0x1401,         //GL_UNSIGNED_BYTE
  TYPE_I16 = 0x1402,          //GL_SHORT
  TYPE_U16 = 0x1403,          //GL_UNSIGNED_SHORT
  TYPE_I32 = 0x1404,          //GL_INT
  TYPE_U32 = 0x1405,          //GL_UNSIGNED_INT
  TYPE_I64 = 0x140E,          //GL_INT64_ARB
  TYPE_U64 = 0x140F,          //GL_UNSIGNED_INT64_ARB
  TYPE_F16 = 0x140B,          //GL_HALF_FLOAT
  TYPE_F16_OES = 0x8D61,        //GL_HALF_FLOAT_OES
  TYPE_F32 = 0x1406,          //GL_FLOAT
  TYPE_F64 = 0x140A,          //GL_DOUBLE
  TYPE_UINT32_RGB9_E5_REV = 0x8C3E, //GL_UNSIGNED_INT_5_9_9_9_REV
  TYPE_UINT32_RG11B10F_REV = 0x8C3B,  //GL_UNSIGNED_INT_10F_11F_11F_REV
  TYPE_UINT8_RG3B2 = 0x8032,      //GL_UNSIGNED_BYTE_3_3_2
  TYPE_UINT8_RG3B2_REV = 0x8362,    //GL_UNSIGNED_BYTE_2_3_3_REV
  TYPE_UINT16_RGB5A1 = 0x8034,    //GL_UNSIGNED_SHORT_5_5_5_1
  TYPE_UINT16_RGB5A1_REV = 0x8366,  //GL_UNSIGNED_SHORT_1_5_5_5_REV
  TYPE_UINT16_R5G6B5 = 0x8363,    //GL_UNSIGNED_SHORT_5_6_5
  TYPE_UINT16_R5G6B5_REV = 0x8364,  //GL_UNSIGNED_SHORT_5_6_5_REV
  TYPE_UINT16_RGBA4 = 0x8033,     //GL_UNSIGNED_SHORT_4_4_4_4
  TYPE_UINT16_RGBA4_REV = 0x8365,   //GL_UNSIGNED_SHORT_4_4_4_4_REV
  TYPE_UINT32_RGBA8 = 0x8035,     //GL_UNSIGNED_SHORT_8_8_8_8
  TYPE_UINT32_RGBA8_REV = 0x8367,   //GL_UNSIGNED_SHORT_8_8_8_8_REV
  TYPE_UINT32_RGB10A2 = 0x8036,   //GL_UNSIGNED_INT_10_10_10_2
  TYPE_UINT32_RGB10A2_REV = 0x8368, //GL_UNSIGNED_INT_2_10_10_10_REV

  TYPE_UINT8_RG4_REV_GTC = 0xFFFD,
  TYPE_UINT16_A1RGB5_GTC = 0xFFFC
};

struct GLDesc {
  InternalFormat internal;
  ExternalFormat external;
  BaseInternalFormat base_internal;
  Type type;
};

static const GLDesc DESCS[] = {
  {INTERNAL_RG4_EXT, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_UINT8_RG4_REV_GTC},                   //FORMAT_R4G4_UNORM,
  {INTERNAL_RGBA4, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_UINT16_RGBA4_REV},                    //FORMAT_RGBA4_UNORM,
  {INTERNAL_R5G6B5, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_UINT16_R5G6B5_REV},                   //FORMAT_R5G6B5_UNORM,
  {INTERNAL_RGB5A1, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_UINT16_RGB5A1_REV},                  //FORMAT_RGB5A1_UNORM,

  {INTERNAL_R8_UNORM, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_U8},          //FORMAT_R8_UNORM,
  {INTERNAL_R8_SNORM, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_I8},          //FORMAT_R8_SNORM,
  {INTERNAL_R8U, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_U8},       //FORMAT_R8_UINT,
  {INTERNAL_R8I, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_I8},       //FORMAT_R8_SINT,
  {INTERNAL_SR8, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_U8},           //FORMAT_R8_SRGB,

  {INTERNAL_RG8_UNORM, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_U8},          //FORMAT_RG8_UNORM,
  {INTERNAL_RG8_SNORM, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_I8},          //FORMAT_RG8_SNORM,
  {INTERNAL_RG8U, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_U8},       //FORMAT_RG8_UINT,
  {INTERNAL_RG8I, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_I8},       //FORMAT_RG8_SINT,
  {INTERNAL_SRG8, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_U8},           //FORMAT_RG8_SRGB,

  {INTERNAL_RGB8_UNORM, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_U8},        //FORMAT_RGB8_UNORM,
  {INTERNAL_RGB8_SNORM, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_I8},        //FORMAT_RGB8_SNORM,
  {INTERNAL_RGB8U, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_U8},       //FORMAT_RGB8_UINT,
  {INTERNAL_RGB8I, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_I8},       //FORMAT_RGB8_SINT,
  {INTERNAL_SRGB8, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_U8},          //FORMAT_RGB8_SRGB,

  {INTERNAL_RGBA8_UNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_U8},        //FORMAT_RGBA8_UNORM_PACK8,
  {INTERNAL_RGBA8_SNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_I8},        //FORMAT_RGBA8_SNORM_PACK8,
  {INTERNAL_RGBA8U, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_U8},     //FORMAT_RGBA8_UINT_PACK8,
  {INTERNAL_RGBA8I, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_I8},     //FORMAT_RGBA8_SINT_PACK8,
  {INTERNAL_SRGB8_ALPHA8, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_U8},      //FORMAT_RGBA8_SRGB_PACK8,

  {INTERNAL_RGB10A2_UNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV},      //FORMAT_RGB10A2_UNORM_PACK32,
  {INTERNAL_RGB10A2_SNORM_EXT, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV},    //FORMAT_RGB10A2_SNORM_PACK32,
  {INTERNAL_RGB10A2U, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV},     //FORMAT_RGB10A2_UINT_PACK32,
  {INTERNAL_RGB10A2I_EXT, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV},   //FORMAT_RGB10A2_SINT_PACK32,

  {INTERNAL_R16_UNORM, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_U16},          //FORMAT_R16_UNORM_PACK16,
  {INTERNAL_R16_SNORM, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_I16},          //FORMAT_R16_SNORM_PACK16,
  {INTERNAL_R16U, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_U16},         //FORMAT_R16_UINT_PACK16,
  {INTERNAL_R16I, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_I16},         //FORMAT_R16_SINT_PACK16,
  {INTERNAL_R16F, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_F16},              //FORMAT_R16_SFLOAT_PACK16,

  {INTERNAL_RG16_UNORM, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_U16},          //FORMAT_RG16_UNORM_PACK16,
  {INTERNAL_RG16_SNORM, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_I16},          //FORMAT_RG16_SNORM_PACK16,
  {INTERNAL_RG16U, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_U16},         //FORMAT_RG16_UINT_PACK16,
  {INTERNAL_RG16I, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_I16},         //FORMAT_RG16_SINT_PACK16,
  {INTERNAL_RG16F, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_F16},              //FORMAT_RG16_SFLOAT_PACK16,

  {INTERNAL_RGB16_UNORM, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_U16},          //FORMAT_RGB16_UNORM_PACK16,
  {INTERNAL_RGB16_SNORM, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_I16},          //FORMAT_RGB16_SNORM_PACK16,
  {INTERNAL_RGB16U, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_U16},       //FORMAT_RGB16_UINT_PACK16,
  {INTERNAL_RGB16I, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_I16},       //FORMAT_RGB16_SINT_PACK16,
  {INTERNAL_RGB16F, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_F16},            //FORMAT_RGB16_SFLOAT_PACK16,

  {INTERNAL_RGBA16_UNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_U16},        //FORMAT_RGBA16_UNORM_PACK16,
  {INTERNAL_RGBA16_SNORM, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_I16},        //FORMAT_RGBA16_SNORM_PACK16,
  {INTERNAL_RGBA16U, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_U16},       //FORMAT_RGBA16_UINT_PACK16,
  {INTERNAL_RGBA16I, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_I16},       //FORMAT_RGBA16_SINT_PACK16,
  {INTERNAL_RGBA16F, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_F16},            //FORMAT_RGBA16_SFLOAT_PACK16,

  {INTERNAL_R32U, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_U32},         //FORMAT_R32_UINT_PACK32,
  {INTERNAL_R32I, EXTERNAL_RED_INTEGER, BASE_INTERNAL_RED, TYPE_I32},         //FORMAT_R32_SINT_PACK32,
  {INTERNAL_R32F, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_F32},             //FORMAT_R32_SFLOAT_PACK32,

  {INTERNAL_RG32U, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_U32},         //FORMAT_RG32_UINT_PACK32,
  {INTERNAL_RG32I, EXTERNAL_RG_INTEGER, BASE_INTERNAL_RG, TYPE_I32},         //FORMAT_RG32_SINT_PACK32,
  {INTERNAL_RG32F, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_F32},             //FORMAT_RG32_SFLOAT_PACK32,

  {INTERNAL_RGB32U, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_U32},       //FORMAT_RGB32_UINT_PACK32,
  {INTERNAL_RGB32I, EXTERNAL_RGB_INTEGER, BASE_INTERNAL_RGB, TYPE_I32},       //FORMAT_RGB32_SINT_PACK32,
  {INTERNAL_RGB32F, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_F32},           //FORMAT_RGB32_SFLOAT_PACK32,

  {INTERNAL_RGBA32U, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_U32},       //FORMAT_RGBA32_UINT_PACK32,
  {INTERNAL_RGBA32I, EXTERNAL_RGBA_INTEGER, BASE_INTERNAL_RGBA, TYPE_I32},       //FORMAT_RGBA32_SINT_PACK32,
  {INTERNAL_RGBA32F, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_F32},           //FORMAT_RGBA32_SFLOAT_PACK32,

  {INTERNAL_R64F_EXT, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_U64},           //FORMAT_R64_UINT_PACK64,
  {INTERNAL_R64F_EXT, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_I64},           //FORMAT_R64_SINT_PACK64,
  {INTERNAL_R64F_EXT, EXTERNAL_RED, BASE_INTERNAL_RED, TYPE_F64},           //FORMAT_R64_SFLOAT_PACK64,

  {INTERNAL_RG64F_EXT, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_U64},           //FORMAT_RG64_UINT_PACK64,
  {INTERNAL_RG64F_EXT, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_I64},           //FORMAT_RG64_SINT_PACK64,
  {INTERNAL_RG64F_EXT, EXTERNAL_RG, BASE_INTERNAL_RG, TYPE_F64},           //FORMAT_RG64_SFLOAT_PACK64,

  {INTERNAL_RGB64F_EXT, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_U64},         //FORMAT_RGB64_UINT_PACK64,
  {INTERNAL_RGB64F_EXT, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_I64},         //FORMAT_RGB64_SINT_PACK64,
  {INTERNAL_RGB64F_EXT, EXTERNAL_RGB, BASE_INTERNAL_RGB, TYPE_F64},         //FORMAT_RGB64_SFLOAT_PACK64,

  {INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_U64},         //FORMAT_RGBA64_UINT_PACK64,
  {INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_I64},         //FORMAT_RGBA64_SINT_PACK64,
  {INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, BASE_INTERNAL_RGBA, TYPE_F64},         //FORMAT_RGBA64_SFLOAT_PACK64,

  {INTERNAL_RGB_DXT1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},         //FORMAT_RGB_DXT1_UNORM_BLOCK8,
  {INTERNAL_SRGB_DXT1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},          //FORMAT_RGB_DXT1_SRGB_BLOCK8,
  {INTERNAL_RGBA_DXT1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_DXT1_UNORM_BLOCK8,
  {INTERNAL_SRGB_ALPHA_DXT1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_DXT1_SRGB_BLOCK8,
  {INTERNAL_RGBA_DXT3, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_DXT3_UNORM_BLOCK16,
  {INTERNAL_SRGB_ALPHA_DXT3, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_DXT3_SRGB_BLOCK16,
  {INTERNAL_RGBA_DXT5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_DXT5_UNORM_BLOCK16,
  {INTERNAL_SRGB_ALPHA_DXT5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_DXT5_SRGB_BLOCK16,
  {INTERNAL_R_ATI1N_UNORM, EXTERNAL_NONE, BASE_INTERNAL_RED, TYPE_NONE},        //FORMAT_R_ATI1N_UNORM_BLOCK8,
  {INTERNAL_R_ATI1N_SNORM, EXTERNAL_NONE, BASE_INTERNAL_RED, TYPE_NONE},        //FORMAT_R_ATI1N_SNORM_BLOCK8,
  {INTERNAL_RG_ATI2N_UNORM, EXTERNAL_NONE, BASE_INTERNAL_RG, TYPE_NONE},       //FORMAT_RG_ATI2N_UNORM_BLOCK16,
  {INTERNAL_RG_ATI2N_SNORM, EXTERNAL_NONE, BASE_INTERNAL_RG, TYPE_NONE},       //FORMAT_RG_ATI2N_SNORM_BLOCK16,
  {INTERNAL_RGB_BP_UNSIGNED_FLOAT, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},    //FORMAT_RGB_BP_UFLOAT_BLOCK16,
  {INTERNAL_RGB_BP_SIGNED_FLOAT, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},    //FORMAT_RGB_BP_SFLOAT_BLOCK16,
  {INTERNAL_RGB_BP_UNORM, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},       //FORMAT_RGB_BP_UNORM,
  {INTERNAL_SRGB_BP_UNORM, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},        //FORMAT_RGB_BP_SRGB,

  {INTERNAL_RGB_ETC, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},              //FORMAT_RGB_ETC2_UNORM_BLOCK8,
  {INTERNAL_SRGB8_ETC2, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},           //FORMAT_RGB_ETC2_SRGB_BLOCK8,
  {INTERNAL_RGBA_PUNCHTHROUGH_ETC2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},     //FORMAT_RGBA_ETC2_PUNCHTHROUGH_UNORM,
  {INTERNAL_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE}, //FORMAT_RGBA_ETC2_PUNCHTHROUGH_SRGB,
  {INTERNAL_RGBA_ETC2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ETC2_UNORM_BLOCK16,
  {INTERNAL_SRGB8_ALPHA8_ETC2_EAC, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_ETC2_SRGB_BLOCK16,
  {INTERNAL_R11_EAC, EXTERNAL_NONE, BASE_INTERNAL_RED, TYPE_NONE},            //FORMAT_R11_EAC_UNORM,
  {INTERNAL_SIGNED_R11_EAC, EXTERNAL_NONE, BASE_INTERNAL_RED, TYPE_NONE},         //FORMAT_R11_EAC_SNORM,
  {INTERNAL_RG11_EAC, EXTERNAL_NONE, BASE_INTERNAL_RG, TYPE_NONE},           //FORMAT_RG11_EAC_UNORM,
  {INTERNAL_SIGNED_RG11_EAC, EXTERNAL_NONE, BASE_INTERNAL_RG, TYPE_NONE},        //FORMAT_RG11_EAC_SNORM,

  {INTERNAL_RGBA_ASTC_4x4, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ASTC4X4_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_4x4, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        //FORMAT_RGBA_ASTC4X4_SRGB,
  {INTERNAL_RGBA_ASTC_5x4, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ASTC5X4_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_5x4, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        //FORMAT_RGBA_ASTC5X4_SRGB,
  {INTERNAL_RGBA_ASTC_5x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ASTC5X5_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_5x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        //FORMAT_RGBA_ASTC5X5_SRGB,
  {INTERNAL_RGBA_ASTC_6x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ASTC6X5_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_6x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        //FORMAT_RGBA_ASTC6X5_SRGB,
  {INTERNAL_RGBA_ASTC_6x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ASTC6X6_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_6x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        //FORMAT_RGBA_ASTC6X6_SRGB,
  {INTERNAL_RGBA_ASTC_8x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ASTC8X5_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_8x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        //FORMAT_RGBA_ASTC8X5_SRGB,
  {INTERNAL_RGBA_ASTC_8x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ASTC8X6_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_8x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        //FORMAT_RGBA_ASTC8X6_SRGB,
  {INTERNAL_RGBA_ASTC_8x8, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},            //FORMAT_RGBA_ASTC8X8_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_8x8, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},        //FORMAT_RGBA_ASTC8X8_SRGB,
  {INTERNAL_RGBA_ASTC_10x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},           //FORMAT_RGBA_ASTC10X5_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_10x5, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},       //FORMAT_RGBA_ASTC10X5_SRGB,
  {INTERNAL_RGBA_ASTC_10x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},           //FORMAT_RGBA_ASTC10X6_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_10x6, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},       //FORMAT_RGBA_ASTC10X6_SRGB,
  {INTERNAL_RGBA_ASTC_10x8, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},           //FORMAT_RGBA_ASTC10X8_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_10x8, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},       //FORMAT_RGBA_ASTC10X8_SRGB,
  {INTERNAL_RGBA_ASTC_10x10, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_ASTC10X10_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_10x10, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_ASTC10X10_SRGB,
  {INTERNAL_RGBA_ASTC_12x10, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_ASTC12X10_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_12x10, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_ASTC12X10_SRGB,
  {INTERNAL_RGBA_ASTC_12x12, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_ASTC12X12_UNORM,
  {INTERNAL_SRGB8_ALPHA8_ASTC_12x12, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_ASTC12X12_SRGB,

  {INTERNAL_RGB_PVRTC_4BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},         //FORMAT_RGB_PVRTC1_8X8_UNORM_BLOCK32,
  {INTERNAL_SRGB_PVRTC_2BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},          //FORMAT_RGB_PVRTC1_8X8_SRGB_BLOCK32,
  {INTERNAL_RGB_PVRTC_2BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},         //FORMAT_RGB_PVRTC1_16X8_UNORM_BLOCK32,
  {INTERNAL_SRGB_PVRTC_4BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},          //FORMAT_RGB_PVRTC1_16X8_SRGB_BLOCK32,
  {INTERNAL_RGBA_PVRTC_4BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_PVRTC1_8X8_UNORM_BLOCK32,
  {INTERNAL_SRGB_ALPHA_PVRTC_2BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_PVRTC1_8X8_SRGB_BLOCK32,
  {INTERNAL_RGBA_PVRTC_2BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_PVRTC1_16X8_UNORM_BLOCK32,
  {INTERNAL_SRGB_ALPHA_PVRTC_4BPPV1, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_PVRTC1_16X8_SRGB_BLOCK32,
  {INTERNAL_RGBA_PVRTC_4BPPV2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_PVRTC2_4X4_UNORM_BLOCK8,
  {INTERNAL_SRGB_ALPHA_PVRTC_4BPPV2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_PVRTC2_4X4_SRGB_BLOCK8,
  {INTERNAL_RGBA_PVRTC_2BPPV2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},          //FORMAT_RGBA_PVRTC2_8X4_UNORM_BLOCK8,
  {INTERNAL_SRGB_ALPHA_PVRTC_2BPPV2, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_PVRTC2_8X4_SRGB_BLOCK8,

  {INTERNAL_RGB_ETC, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},              //FORMAT_RGB_ETC_UNORM_BLOCK8,
  {INTERNAL_ATC_RGB, EXTERNAL_NONE, BASE_INTERNAL_RGB, TYPE_NONE},              //FORMAT_RGB_ATC_UNORM_BLOCK8,
  {INTERNAL_ATC_RGBA_EXPLICIT_ALPHA, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE},      //FORMAT_RGBA_ATCA_UNORM_BLOCK16,
  {INTERNAL_ATC_RGBA_INTERPOLATED_ALPHA, EXTERNAL_NONE, BASE_INTERNAL_RGBA, TYPE_NONE}    //FORMAT_RGBA_ATCI_UNORM_BLOCK16
};

inline InternalFormat TranslateFromES20(InternalFormat internal) {
  if (internal == INTERNAL_RGB_ETC2) {
    return INTERNAL_RGB_ETC;
  }
  return internal;
}

inline InternalFormat TranslateToES20(InternalFormat internal) {
  if (internal == INTERNAL_RGB_ETC) {
    return INTERNAL_RGB_ETC2;
  }
  return internal;
}

inline ExternalFormat TranslateFromES20(InternalFormat internal, ExternalFormat external) {
  if (internal == INTERNAL_SRGB8 && external == EXTERNAL_SRGB_EXT) {
    return EXTERNAL_RGB;
  }
  if (internal == INTERNAL_SRGB8_ALPHA8 && external == EXTERNAL_SRGB_ALPHA_EXT) {
    return EXTERNAL_RGBA;
  }
  return external;
}

inline ExternalFormat TranslateToES20(InternalFormat internal, ExternalFormat external) {
  if (internal == INTERNAL_SRGB8 && external == EXTERNAL_RGB) {
    return EXTERNAL_SRGB_EXT;
  }
  if (internal ==INTERNAL_SRGB8_ALPHA8 && external == EXTERNAL_RGBA) {
    return EXTERNAL_SRGB_ALPHA_EXT;
  }
  return external;
}

inline Type TranslateFromES20(Type type) {
  if (type == TYPE_F16_OES) {
    return TYPE_F16;
  }
  return type;
}

inline Type TranslateToES20(Type type) {
  if (type == TYPE_F16) {
    return TYPE_F16_OES;
  }
  return type;
}
}

namespace imgpp { namespace gl {
TextureFormat TranslateFromGL(uint16_t internal, uint16_t external,
  uint16_t base_internal, uint16_t type) {
  // translate
  InternalFormat translated_internal = TranslateFromES20(
    static_cast<InternalFormat>(internal));
  ExternalFormat translated_external = TranslateFromES20(
    translated_internal, static_cast<ExternalFormat>(external));
  BaseInternalFormat translated_base_internal =
    static_cast<BaseInternalFormat>(base_internal);
  Type translated_type = TranslateFromES20(static_cast<Type>(type));
  for (uint16_t format_id = 0; format_id < 142; ++format_id) {
    const GLDesc &desc = DESCS[format_id];
    if (desc.internal == translated_internal &&
      desc.external == translated_external &&
      desc.base_internal == translated_base_internal &&
      desc.type == translated_type) {
      return static_cast<TextureFormat>(format_id + (uint16_t)FORMAT_FIRST);
    }
  }
  return FORMAT_UNDEFINED;
}

GLFormatDesc TranslateToGL(TextureFormat format, Profile profile) {
  const GLDesc &gl_desc = DESCS[(int)(format - FORMAT_FIRST)];
  GLFormatDesc desc {
    (uint16_t)gl_desc.internal,
    (uint16_t)gl_desc.external,
    (uint16_t)gl_desc.base_internal,
    (uint16_t)gl_desc.type
  };
  if (profile == ES20) {
    desc.internal_format = (uint16_t)TranslateToES20(gl_desc.internal);
    desc.external_format = (uint16_t)TranslateToES20(gl_desc.internal, gl_desc.external);
    desc.type = (uint16_t)TranslateToES20(gl_desc.type);
  }
  return desc;
}

GLFormatDesc TranslateToGL(TextureFormat format) {
  return TranslateToGL(format, GL33);
}

uint32_t GetTypeSize(uint16_t type) {
  Type t = static_cast<Type>(type);
  switch(t) {
    case TYPE_I8:
    case TYPE_U8:
    case TYPE_UINT8_RG3B2:
    case TYPE_UINT8_RG3B2_REV:
    case TYPE_UINT8_RG4_REV_GTC:
      return 1;

    case TYPE_I16:
    case TYPE_U16:
    case TYPE_UINT16_RGB5A1:
    case TYPE_UINT16_RGB5A1_REV:
    case TYPE_UINT16_R5G6B5:
    case TYPE_UINT16_R5G6B5_REV:
    case TYPE_UINT16_RGBA4:
    case TYPE_UINT16_RGBA4_REV:
    case TYPE_UINT16_A1RGB5_GTC:
    case TYPE_F16:
    case TYPE_F16_OES:
      return 2;

    case TYPE_I32:
    case TYPE_U32:
    case TYPE_UINT32_RGB9_E5_REV:
    case TYPE_UINT32_RG11B10F_REV:
    case TYPE_UINT32_RGBA8:
    case TYPE_UINT32_RGBA8_REV:
    case TYPE_UINT32_RGB10A2:
    case TYPE_UINT32_RGB10A2_REV:
    case TYPE_F32:
      return 4;

    case TYPE_F64:
      return 8;
    default:
      return 0x0501; // GL_INVALID_VALUE
  }
}
}}
