Compare commits

...

4 Commits

Author SHA1 Message Date
Alibek Omarov
70a3ff531c ref_gl: fix texturelist output 2021-11-24 01:41:25 +03:00
Alibek Omarov
501ff944b9 ref_gl: add VERY basic 16-bit texture support(no mips, no rescale, no filters), as an example to ref_vk dev 2021-11-23 04:12:30 +03:00
Alibek Omarov
f16641b606 engine: imagelib: add 16-bit PNG load support 2021-11-23 04:03:07 +03:00
Alibek Omarov
f045103abb engine: imagelib: add common definitions for 16-bit images 2021-11-23 03:58:47 +03:00
4 changed files with 131 additions and 23 deletions

View File

@@ -10,6 +10,7 @@ NOTE: number at end of pixelformat name it's a total bitscount e.g. PF_RGB_24 ==
*/ */
#define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24 || type == PF_LUMINANCE) #define ImageRAW( type ) (type == PF_RGBA_32 || type == PF_BGRA_32 || type == PF_RGB_24 || type == PF_BGR_24 || type == PF_LUMINANCE)
#define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2) #define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2)
#define Image16( type ) (type == PF_RGBA_64 || type == PF_RGB_48)
typedef enum typedef enum
{ {
@@ -25,6 +26,8 @@ typedef enum
PF_DXT3, // s3tc DXT3 format PF_DXT3, // s3tc DXT3 format
PF_DXT5, // s3tc DXT5 format PF_DXT5, // s3tc DXT5 format
PF_ATI2, // latc ATI2N format PF_ATI2, // latc ATI2N format
PF_RGBA_64, // 16-bit RGBA
PF_RGB_48, // 16-bit RGB
PF_TOTALCOUNT, // must be last PF_TOTALCOUNT, // must be last
} pixformat_t; } pixformat_t;

View File

@@ -71,7 +71,7 @@ static const cubepack_t load_cubemap[] =
}; };
// soul of ImageLib - table of image format constants // soul of ImageLib - table of image format constants
const bpc_desc_t PFDesc[] = const bpc_desc_t PFDesc[PF_TOTALCOUNT] =
{ {
{ PF_UNKNOWN, "raw", 0x1908, 0 }, { PF_UNKNOWN, "raw", 0x1908, 0 },
{ PF_INDEXED_24, "pal 24", 0x1908, 1 }, { PF_INDEXED_24, "pal 24", 0x1908, 1 },
@@ -85,6 +85,8 @@ const bpc_desc_t PFDesc[] =
{ PF_DXT3, "DXT 3", 0x83F2, 4 }, { PF_DXT3, "DXT 3", 0x83F2, 4 },
{ PF_DXT5, "DXT 5", 0x83F3, 4 }, { PF_DXT5, "DXT 5", 0x83F3, 4 },
{ PF_ATI2, "ATI 2", 0x8837, 4 }, { PF_ATI2, "ATI 2", 0x8837, 4 },
{ PF_RGBA_64, "RGBA 64", 0x1908, 8 },
{ PF_RGB_48, "RGB 48", 0x1908, 6 },
}; };
void Image_Reset( void ) void Image_Reset( void )

View File

@@ -40,9 +40,9 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
{ {
int ret; int ret;
short p, a, b, c, pa, pb, pc; short p, a, b, c, pa, pb, pc;
byte *buf_p, *pixbuf, *raw, *prior, *idat_buf = NULL, *uncompressed_buffer = NULL, *rowend; byte *buf_p, *pixbuf, *raw, *prior, *idat_buf = NULL, *uncompressed_buffer = NULL;
uint chunk_len, crc32, crc32_check, oldsize = 0, newsize = 0, rowsize; uint chunk_len, crc32, crc32_check, oldsize = 0, newsize = 0, rowsize;
uint uncompressed_size, pixel_size, i, y, filter_type, chunk_sign; uint uncompressed_size, pixel_size, i, y, filter_type, chunk_sign, channel_size;
qboolean has_iend_chunk = false; qboolean has_iend_chunk = false;
z_stream stream = {0}; z_stream stream = {0};
png_t png_hdr; png_t png_hdr;
@@ -89,9 +89,9 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
return false; return false;
} }
if( png_hdr.ihdr_chunk.bitdepth != 8 ) if( png_hdr.ihdr_chunk.bitdepth != 8 && png_hdr.ihdr_chunk.bitdepth != 16 )
{ {
Con_DPrintf( S_WARN "Image_LoadPNG: Only 8-bit images is supported (%s)\n", name ); Con_DPrintf( S_WARN "Image_LoadPNG: Only 8-bit or 16-bit images is supported (%s)\n", name );
return false; return false;
} }
@@ -228,10 +228,19 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
break; break;
} }
image.type = PF_RGBA_32; // always exctracted to 32-bit buffer if( png_hdr.ihdr_chunk.bitdepth == 8 )
{
image.type = PF_RGBA_32; // always exctracted to 32-bit buffer
channel_size = 1;
}
else // if( png_hdr.ihdr_chunk.bitdepth == 16 )
{
image.type = PF_RGBA_64;
channel_size = 2;
}
image.width = png_hdr.ihdr_chunk.width; image.width = png_hdr.ihdr_chunk.width;
image.height = png_hdr.ihdr_chunk.height; image.height = png_hdr.ihdr_chunk.height;
image.size = image.height * image.width * 4; image.size = image.height * image.width * channel_size * 4;
image.flags |= IMAGE_HAS_COLOR; image.flags |= IMAGE_HAS_COLOR;
if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGBA ) if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGBA )
@@ -241,7 +250,7 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
rowsize = pixel_size * image.width; rowsize = pixel_size * image.width;
uncompressed_size = image.height * ( rowsize + 1 ); // +1 for filter uncompressed_size = image.height * ( rowsize * channel_size + 1 ); // +1 for filter
uncompressed_buffer = Mem_Malloc( host.imagepool, uncompressed_size ); uncompressed_buffer = Mem_Malloc( host.imagepool, uncompressed_size );
stream.next_in = idat_buf; stream.next_in = idat_buf;
@@ -279,6 +288,9 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGB ) if( png_hdr.ihdr_chunk.colortype == PNG_CT_RGB )
prior = pixbuf = raw; prior = pixbuf = raw;
rowsize *= channel_size;
pixel_size *= channel_size;
filter_type = *raw++; filter_type = *raw++;
// decode adaptive filter // decode adaptive filter
@@ -384,19 +396,38 @@ qboolean Image_LoadPNG( const char *name, const byte *buffer, fs_offset_t filesi
pixbuf = image.rgba; pixbuf = image.rgba;
raw = uncompressed_buffer; raw = uncompressed_buffer;
for( y = 0; y < image.height; y++ ) for( y = 0; y < image.height * image.width; y++, raw += pixel_size )
{ {
rowend = raw + rowsize; *pixbuf++ = raw[0];
for( ; raw < rowend; raw += pixel_size ) *pixbuf++ = raw[1];
*pixbuf++ = raw[2];
if( channel_size == 1 )
{ {
*pixbuf++ = raw[0]; *pixbuf++ = 0xFF;
*pixbuf++ = raw[1]; }
*pixbuf++ = raw[2]; else
{
*pixbuf++ = raw[3];
*pixbuf++ = raw[4];
*pixbuf++ = raw[5];
*pixbuf++ = 0xFF;
*pixbuf++ = 0xFF; *pixbuf++ = 0xFF;
} }
} }
} }
#if XASH_LITTLE_ENDIAN
if( channel_size == 2 )
{
pixbuf = image.rgba;
for( y = 0; y < image.height * image.width * 4; y++, pixbuf += 2 )
{
uint16_t val = *(uint16_t*)pixbuf;
*(uint16_t*)pixbuf = ntohs( val );
}
}
#endif /* XASH_LITTLE_ENDIAN */
Mem_Free( uncompressed_buffer ); Mem_Free( uncompressed_buffer );
return true; return true;

View File

@@ -362,6 +362,12 @@ static size_t GL_CalcImageSize( pixformat_t format, int width, int height, int d
case PF_RGBA_32: case PF_RGBA_32:
size = width * height * depth * 4; size = width * height * depth * 4;
break; break;
case PF_RGB_48:
size = width * height * depth * 6;
break;
case PF_RGBA_64:
size = width * height * depth * 8;
break;
case PF_DXT1: case PF_DXT1:
size = (((width + 3) >> 2) * ((height + 3) >> 2) * 8) * depth; size = (((width + 3) >> 2) * ((height + 3) >> 2) * 8) * depth;
break; break;
@@ -452,9 +458,11 @@ static size_t GL_CalcTextureSize( GLenum format, int width, int height, int dept
case GL_LUMINANCE_ALPHA32F_ARB: case GL_LUMINANCE_ALPHA32F_ARB:
size = width * height * depth * 8; size = width * height * depth * 8;
break; break;
case GL_RGB16:
case GL_RGB16F_ARB: case GL_RGB16F_ARB:
size = width * height * depth * 6; size = width * height * depth * 6;
break; break;
case GL_RGBA16:
case GL_RGBA16F_ARB: case GL_RGBA16F_ARB:
size = width * height * depth * 8; size = width * height * depth * 8;
break; break;
@@ -720,26 +728,56 @@ static void GL_SetTextureFormat( gl_texture_t *tex, pixformat_t format, int chan
switch( GL_CalcTextureSamples( channelMask )) switch( GL_CalcTextureSamples( channelMask ))
{ {
case 1: case 1:
{
if( FBitSet( tex->flags, TF_ALPHACONTRAST )) if( FBitSet( tex->flags, TF_ALPHACONTRAST ))
tex->format = GL_INTENSITY8; tex->format = Image16( format ) ? GL_INTENSITY16 : GL_INTENSITY8;
else tex->format = GL_LUMINANCE8; else tex->format = Image16( format ) ? GL_LUMINANCE16 : GL_LUMINANCE8;
break; break;
case 2: tex->format = GL_LUMINANCE8_ALPHA8; break; }
case 2:
{
tex->format = Image16( format ) ? GL_LUMINANCE16_ALPHA16 : GL_LUMINANCE8_ALPHA8;
break;
}
case 3: case 3:
switch( bits ) switch( bits )
{ {
case 16: tex->format = GL_RGB5; break; case 16:
case 32: tex->format = GL_RGB8; break; {
default: tex->format = GL_RGB; break; tex->format = Image16( format ) ? GL_RGB10 : GL_RGB5;
break;
}
case 32:
{
tex->format = Image16( format ) ? GL_RGB16 : GL_RGB8;
break;
}
default:
{
tex->format = GL_RGB;
break;
}
} }
break; break;
case 4: case 4:
default: default:
switch( bits ) switch( bits )
{ {
case 16: tex->format = GL_RGBA4; break; case 16:
case 32: tex->format = GL_RGBA8; break; {
default: tex->format = GL_RGBA; break; tex->format = Image16( format ) ? GL_RGBA8 : GL_RGBA4;
break;
}
case 32:
{
tex->format = Image16( format ) ? GL_RGBA16 : GL_RGBA8;
break;
}
default:
{
tex->format = GL_RGBA;
break;
}
} }
break; break;
} }
@@ -1016,6 +1054,8 @@ static void GL_TextureImageRAW( gl_texture_t *tex, GLint side, GLint level, GLin
dataType = GL_HALF_FLOAT_ARB; dataType = GL_HALF_FLOAT_ARB;
else if( FBitSet( tex->flags, TF_ARB_FLOAT )) else if( FBitSet( tex->flags, TF_ARB_FLOAT ))
dataType = GL_FLOAT; dataType = GL_FLOAT;
else if( Image16( type ))
dataType = GL_UNSIGNED_SHORT;
if( tex->target == GL_TEXTURE_1D ) if( tex->target == GL_TEXTURE_1D )
{ {
@@ -1185,6 +1225,20 @@ static qboolean GL_UploadTexture( gl_texture_t *tex, rgbdata_t *pic )
} }
} }
else if( Image16( pic->type ))
{
width = Q_max( 1, tex->width );
height = Q_max( 1, tex->height );
texsize = GL_CalcTextureSize( tex->format, width, height, tex->depth );
size = GL_CalcImageSize( pic->type, width, height, tex->depth );
GL_TextureImageRAW( tex, i, 0, width, height, tex->depth, pic->type, buf );
tex->size = texsize;
tex->numMips++;
buf += size; // move pointer
GL_CheckTexImageError( tex );
}
else // RGBA32 else // RGBA32
{ {
int mipCount = GL_CalcMipmapCount( tex, ( buf != NULL )); int mipCount = GL_CalcMipmapCount( tex, ( buf != NULL ));
@@ -2074,6 +2128,9 @@ void R_TextureList_f( void )
case GL_RGBA4: case GL_RGBA4:
gEngfuncs.Con_Printf( "RGBA4 " ); gEngfuncs.Con_Printf( "RGBA4 " );
break; break;
case GL_RGBA16:
gEngfuncs.Con_Printf( "RGBA16" );
break;
case GL_RGB: case GL_RGB:
gEngfuncs.Con_Printf( "RGB " ); gEngfuncs.Con_Printf( "RGB " );
break; break;
@@ -2083,6 +2140,12 @@ void R_TextureList_f( void )
case GL_RGB5: case GL_RGB5:
gEngfuncs.Con_Printf( "RGB5 " ); gEngfuncs.Con_Printf( "RGB5 " );
break; break;
case GL_RGB10:
gEngfuncs.Con_Printf( "RGB10 " );
break;
case GL_RGB16:
gEngfuncs.Con_Printf( "RGB16 " );
break;
case GL_LUMINANCE4_ALPHA4: case GL_LUMINANCE4_ALPHA4:
gEngfuncs.Con_Printf( "L4A4 " ); gEngfuncs.Con_Printf( "L4A4 " );
break; break;
@@ -2090,6 +2153,9 @@ void R_TextureList_f( void )
case GL_LUMINANCE8_ALPHA8: case GL_LUMINANCE8_ALPHA8:
gEngfuncs.Con_Printf( "L8A8 " ); gEngfuncs.Con_Printf( "L8A8 " );
break; break;
case GL_LUMINANCE16_ALPHA16:
gEngfuncs.Con_Printf( "L16A16" );
break;
case GL_LUMINANCE4: case GL_LUMINANCE4:
gEngfuncs.Con_Printf( "L4 " ); gEngfuncs.Con_Printf( "L4 " );
break; break;
@@ -2097,12 +2163,18 @@ void R_TextureList_f( void )
case GL_LUMINANCE8: case GL_LUMINANCE8:
gEngfuncs.Con_Printf( "L8 " ); gEngfuncs.Con_Printf( "L8 " );
break; break;
case GL_LUMINANCE16:
gEngfuncs.Con_Printf( "L16 " );
break;
case GL_ALPHA8: case GL_ALPHA8:
gEngfuncs.Con_Printf( "A8 " ); gEngfuncs.Con_Printf( "A8 " );
break; break;
case GL_INTENSITY8: case GL_INTENSITY8:
gEngfuncs.Con_Printf( "I8 " ); gEngfuncs.Con_Printf( "I8 " );
break; break;
case GL_INTENSITY16:
gEngfuncs.Con_Printf( "I16 " );
break;
case GL_DEPTH_COMPONENT: case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT24:
gEngfuncs.Con_Printf( "DPTH24" ); gEngfuncs.Con_Printf( "DPTH24" );