imagelib: add rudimentary KTX2 support
It only does a very basic header validation, and passes the entire file as PF_KTX2_RAW format. This is to simplify KTX2 reading in ref_vk and trying out different formats. KTX2 has support for >200 format, and passing all of them through PF_ types is a non-starter. The plan is to figure out which formats we want to support, and add their support to imagelib/ktx2 incrementally, leaving the rest as PF_KTX2_RAW, so ref_vk still can use them.
This commit is contained in:
parent
726fcee3f7
commit
90119ae84a
|
@ -9,7 +9,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 ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2 || type == PF_BC6H_SIGNED || type == PF_BC6H_UNSIGNED || type == PF_BC7)
|
||||
#define ImageDXT( type ) (type == PF_DXT1 || type == PF_DXT3 || type == PF_DXT5 || type == PF_ATI2 || type == PF_BC6H_SIGNED || type == PF_BC6H_UNSIGNED || type == PF_BC7 || type == PF_KTX2_RAW)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -28,6 +28,7 @@ typedef enum
|
|||
PF_BC6H_SIGNED, // bptc BC6H signed FP16 format
|
||||
PF_BC6H_UNSIGNED, // bptc BC6H unsigned FP16 format
|
||||
PF_BC7, // bptc BC7 format
|
||||
PF_KTX2_RAW, // Raw KTX2 data, used for yet unsupported KTX2 subformats
|
||||
PF_TOTALCOUNT, // must be last
|
||||
} pixformat_t;
|
||||
|
||||
|
|
|
@ -156,6 +156,7 @@ qboolean Image_LoadDDS( const char *name, const byte *buffer, fs_offset_t filesi
|
|||
qboolean Image_LoadFNT( const char *name, const byte *buffer, fs_offset_t filesize );
|
||||
qboolean Image_LoadLMP( const char *name, const byte *buffer, fs_offset_t filesize );
|
||||
qboolean Image_LoadPAL( const char *name, const byte *buffer, fs_offset_t filesize );
|
||||
qboolean Image_LoadKTX2( const char *name, const byte *buffer, fs_offset_t filesize );
|
||||
|
||||
//
|
||||
// formats save
|
||||
|
|
|
@ -255,7 +255,7 @@ uint Image_DXTCalcSize( const char *name, dds_t *hdr, size_t filesize )
|
|||
|
||||
if( filesize != buffsize ) // main check
|
||||
{
|
||||
Con_DPrintf( S_WARN "Image_LoadDDS: (%s) probably corrupted (%i should be %lu)\n", name, buffsize, filesize );
|
||||
Con_DPrintf( S_WARN "Image_LoadDDS: (%s) probably corrupted (%zu should be %lu)\n", name, buffsize, filesize );
|
||||
if( buffsize > filesize )
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
img_dds.c - dds format load
|
||||
Copyright (C) 2015 Uncle Mike
|
||||
|
||||
This program 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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.
|
||||
*/
|
||||
|
||||
#include "imagelib.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "ktx2.h"
|
||||
|
||||
qboolean Image_LoadKTX2( const char *name, const byte *buffer, fs_offset_t filesize ) {
|
||||
if( filesize < KTX_MINIMAL_HEADER_SIZE )
|
||||
return false;
|
||||
|
||||
if ( memcmp(buffer, KTX_IDENTIFIER, KTX_IDENTIFIER_SIZE) != 0) {
|
||||
Con_DPrintf( S_ERROR "%s: (%s) has invalid identifier\n", __FUNCTION__, name );
|
||||
return false;
|
||||
}
|
||||
|
||||
ktx_header_t header;
|
||||
memcpy(&header, buffer + KTX_IDENTIFIER_SIZE, sizeof header);
|
||||
|
||||
/* ktx_index_t index; */
|
||||
/* memcpy(&header, buffer + KTX_IDENTIFIER_SIZE + sizeof header, sizeof index); */
|
||||
|
||||
image.width = header.pixelWidth;
|
||||
image.height = header.pixelHeight;
|
||||
image.depth = Q_max(1, header.pixelDepth);
|
||||
|
||||
// Just pass file contents as rgba data directly
|
||||
|
||||
// TODO support various formats individually, for other renders to be able to consume them too
|
||||
// This is a catch-all for ref_vk, which can do this format directly and natively
|
||||
image.type = PF_KTX2_RAW;
|
||||
|
||||
image.size = filesize;
|
||||
//image.encode = TODO custom encode type?
|
||||
|
||||
// FIXME format-dependent
|
||||
image.flags = IMAGE_HAS_COLOR; // | IMAGE_HAS_ALPHA
|
||||
|
||||
image.rgba = Mem_Malloc( host.imagepool, image.size);
|
||||
memcpy(image.rgba, buffer, image.size);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -105,6 +105,7 @@ static const loadpixformat_t load_game[] =
|
|||
{ "%s%s.%s", "lmp", Image_LoadLMP, IL_HINT_NO }, // hl menu images (cached.wad etc)
|
||||
{ "%s%s.%s", "fnt", Image_LoadFNT, IL_HINT_HL }, // hl console font (fonts.wad etc)
|
||||
{ "%s%s.%s", "pal", Image_LoadPAL, IL_HINT_NO }, // install studio\sprite palette
|
||||
{ "%s%s.%s", "ktx2", Image_LoadKTX2, IL_HINT_NO }, // dds for world and studio models
|
||||
{ NULL, NULL, NULL, IL_HINT_NO }
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define KTX_IDENTIFIER_SIZE 12
|
||||
#define KTX_IDENTIFIER "\xABKTX 20\xBB\r\n\x1A\n"
|
||||
|
||||
/*
|
||||
static const char k_ktx2_identifier[KTX_IDENTIFIER_SIZE] = {
|
||||
'\xAB', 'K', 'T', 'X', ' ', '2', '0', '\xBB', '\r', '\n', '\x1A', '\n'
|
||||
};
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32_t vkFormat;
|
||||
uint32_t typeSize;
|
||||
uint32_t pixelWidth;
|
||||
uint32_t pixelHeight;
|
||||
uint32_t pixelDepth;
|
||||
uint32_t layerCount;
|
||||
uint32_t faceCount;
|
||||
uint32_t levelCount;
|
||||
uint32_t supercompressionScheme;
|
||||
} ktx_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t dfdByteOffset;
|
||||
uint32_t dfdByteLength;
|
||||
uint32_t kvdByteOffset;
|
||||
uint32_t kvdByteLength;
|
||||
uint64_t sgdByteOffset;
|
||||
uint64_t sgdByteLength;
|
||||
} ktx_index_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t byteOffset;
|
||||
uint64_t byteLength;
|
||||
uint64_t uncompressedByteLength;
|
||||
} ktx_level_t;
|
||||
|
||||
#define KTX_MINIMAL_HEADER_SIZE (KTX_IDENTIFIER_SIZE + sizeof(ktx_header_t) + sizeof(ktx_index_t) + sizeof(ktx_level_t))
|
|
@ -15,6 +15,7 @@
|
|||
#include "crclib.h"
|
||||
#include "com_strings.h"
|
||||
#include "eiface.h"
|
||||
#include "ktx2.h"
|
||||
|
||||
#define PCG_IMPLEMENT
|
||||
#include "pcg.h"
|
||||
|
@ -638,7 +639,13 @@ static VkSampler pickSamplerForFlags( texFlags_t flags ) {
|
|||
return tglob.default_sampler_fixme;
|
||||
}
|
||||
|
||||
static qboolean loadKtx2Raw( vk_texture_t *tex, const rgbdata_t* pic );
|
||||
|
||||
static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap, colorspace_hint_e colorspace_hint) {
|
||||
|
||||
if (num_layers == 1 && layers[0]->type == PF_KTX2_RAW)
|
||||
return loadKtx2Raw(tex, layers[0]);
|
||||
|
||||
const VkFormat format = VK_GetFormat(layers[0]->type, colorspace_hint);
|
||||
int mipCount = 0;
|
||||
|
||||
|
@ -896,68 +903,18 @@ const byte* VK_TextureData( unsigned int texnum )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
#define KTX_IDENTIFIER_SIZE 12
|
||||
static const char k_ktx2_identifier[KTX_IDENTIFIER_SIZE] = {
|
||||
'\xAB', 'K', 'T', 'X', ' ', '2', '0', '\xBB', '\r', '\n', '\x1A', '\n'
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t vkFormat;
|
||||
uint32_t typeSize;
|
||||
uint32_t pixelWidth;
|
||||
uint32_t pixelHeight;
|
||||
uint32_t pixelDepth;
|
||||
uint32_t layerCount;
|
||||
uint32_t faceCount;
|
||||
uint32_t levelCount;
|
||||
uint32_t supercompressionScheme;
|
||||
} ktx_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t dfdByteOffset;
|
||||
uint32_t dfdByteLength;
|
||||
uint32_t kvdByteOffset;
|
||||
uint32_t kvdByteLength;
|
||||
uint64_t sgdByteOffset;
|
||||
uint64_t sgdByteLength;
|
||||
} ktx_index_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t byteOffset;
|
||||
uint64_t byteLength;
|
||||
uint64_t uncompressedByteLength;
|
||||
} ktx_level_t;
|
||||
|
||||
static int loadKtx2( const char *name ) {
|
||||
fs_offset_t size = 0;
|
||||
byte *data = gEngine.fsapi->LoadFile( name, &size, false );
|
||||
|
||||
DEBUG("Loading KTX2 file \"%s\", exists=%d", name, data != 0);
|
||||
|
||||
if ( !data )
|
||||
return 0;
|
||||
static qboolean loadKtx2Raw( vk_texture_t *tex, const rgbdata_t* pic ) {
|
||||
const byte *const data = pic->buffer;
|
||||
const int size = pic->size;
|
||||
|
||||
const ktx_header_t* header;
|
||||
const ktx_index_t* index;
|
||||
const ktx_level_t* levels;
|
||||
vk_texture_t* tex = NULL;
|
||||
|
||||
if (size < (sizeof k_ktx2_identifier + sizeof(ktx_header_t) + sizeof(ktx_index_t) + sizeof(ktx_level_t))) {
|
||||
ERR("KTX2 file \"%s\" seems truncated", name);
|
||||
goto fail;
|
||||
}
|
||||
header = (const ktx_header_t*)(data + KTX_IDENTIFIER_SIZE);
|
||||
index = (const ktx_index_t*)(data + KTX_IDENTIFIER_SIZE + sizeof(ktx_header_t));
|
||||
levels = (const ktx_level_t*)(data + KTX_IDENTIFIER_SIZE + sizeof(ktx_header_t) + sizeof(ktx_index_t));
|
||||
|
||||
if (memcmp(data, k_ktx2_identifier, sizeof k_ktx2_identifier) != 0) {
|
||||
ERR("KTX2 file \"%s\" identifier is invalid", name);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
header = (const ktx_header_t*)(data + sizeof k_ktx2_identifier);
|
||||
index = (const ktx_index_t*)(data + sizeof k_ktx2_identifier + sizeof(ktx_header_t));
|
||||
levels = (const ktx_level_t*)(data + sizeof k_ktx2_identifier + sizeof(ktx_header_t) + sizeof(ktx_index_t));
|
||||
|
||||
DEBUG("KTX2 file \"%s\"", name);
|
||||
DEBUG(" header:");
|
||||
#define X(field) DEBUG(" " # field "=%d", header->field);
|
||||
DEBUG(" vkFormat = %s(%d)", R_VkFormatName(header->vkFormat), header->vkFormat);
|
||||
|
@ -988,13 +945,6 @@ static int loadKtx2( const char *name ) {
|
|||
DEBUG(" uncompressedByteLength=%llu", (unsigned long long)level->uncompressedByteLength);
|
||||
}
|
||||
|
||||
{
|
||||
const uint32_t flags = 0;
|
||||
tex = Common_AllocTexture( name, flags );
|
||||
if (!tex)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// FIXME check that format is supported
|
||||
// FIXME layers == 0
|
||||
// FIXME has_alpha
|
||||
|
@ -1147,18 +1097,20 @@ static int loadKtx2( const char *name ) {
|
|||
tex->width = header->pixelWidth;
|
||||
tex->height = header->pixelHeight;
|
||||
|
||||
goto finalize;
|
||||
|
||||
fail:
|
||||
if (tex)
|
||||
memset( tex, 0, sizeof( vk_texture_t ));
|
||||
|
||||
finalize:
|
||||
Mem_Free( data );
|
||||
return (tex - vk_textures);
|
||||
return true;
|
||||
}
|
||||
|
||||
static int loadTextureUsingEngine( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint ) {
|
||||
static int loadTextureInternal( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint ) {
|
||||
if( !Common_CheckTexName( name ))
|
||||
return 0;
|
||||
|
||||
// see if already loaded
|
||||
{
|
||||
const vk_texture_t *const tex = Common_TextureForName( name );
|
||||
if( tex )
|
||||
return (tex - vk_textures);
|
||||
}
|
||||
|
||||
uint picFlags = 0;
|
||||
|
||||
if( FBitSet( flags, TF_NOFLIP_TGA ))
|
||||
|
@ -1195,25 +1147,6 @@ static int loadTextureUsingEngine( const char *name, const byte *buf, size_t siz
|
|||
return tex - vk_textures;
|
||||
}
|
||||
|
||||
static int loadTextureInternal( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint ) {
|
||||
if( !Common_CheckTexName( name ))
|
||||
return 0;
|
||||
|
||||
// see if already loaded
|
||||
vk_texture_t *tex = Common_TextureForName( name );
|
||||
if( tex )
|
||||
return (tex - vk_textures);
|
||||
|
||||
{
|
||||
const char *ext = Q_strrchr(name, '.');
|
||||
if (Q_strcmp(ext, ".ktx2") == 0) {
|
||||
return loadKtx2(name);
|
||||
}
|
||||
}
|
||||
|
||||
return loadTextureUsingEngine(name, buf, size, flags, colorspace_hint);
|
||||
}
|
||||
|
||||
int VK_LoadTextureExternal( const char *name, const byte *buf, size_t size, int flags ) {
|
||||
return loadTextureInternal(name, buf, size, flags, kColorspaceGamma);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue