Skip to content

Instantly share code, notes, and snippets.

@rotoglup
Created February 25, 2016 09:04
Show Gist options
  • Save rotoglup/9a6340752a2629496d4b to your computer and use it in GitHub Desktop.
Save rotoglup/9a6340752a2629496d4b to your computer and use it in GitHub Desktop.
/*
* rtgu_ktx.h - Version -1 WIP untested
* No endianness swap support
int ktx_load(ktx_image* i, ktx__context* k);
*/
// TODO(nico) public typedefs
typedef unsigned char ktx_uc;
#ifdef _MSC_VER
typedef unsigned short ktx__uint16;
typedef signed short ktx__int16;
typedef unsigned int ktx__uint32;
typedef signed int ktx__int32;
typedef unsigned __int64 ktx_uint64;
#else
#include <stdint.h>
typedef uint16_t ktx__uint16;
typedef int16_t ktx__int16;
typedef uint32_t ktx__uint32;
typedef int32_t ktx__int32;
#endif
typedef struct {
ktx_uc identifier[12];
ktx__uint32 endianness;
ktx__uint32 glType;
ktx__uint32 glTypeSize;
ktx__uint32 glFormat;
ktx__uint32 glInternalFormat;
ktx__uint32 glBaseInternalFormat;
ktx__uint32 pixelWidth;
ktx__uint32 pixelHeight;
ktx__uint32 pixelDepth;
ktx__uint32 numberOfArrayElements;
ktx__uint32 numberOfFaces;
ktx__uint32 numberOfMipmapLevels;
ktx__uint32 bytesOfKeyValueData;
} ktx__header;
#define KTX__MAX_NUM_FACES 6
#define KTX__MAX_NUM_MIPMAPS 16
typedef struct {
int w, h, d; // width, height, depth
int dimensions; // 1, 2 or 3
int is_compressed; // bool
int requests_generate_mipmaps; // bool
int is_array; // bool
int num_mipmaps;
int num_array_elements;
int num_faces;
int gl_target; // GL_TEXTURE_1D ... GL_TEXTURE_CUBE_MAP
int gl_internal_format;
int gl_format;
int gl_type;
ktx_uint64 images_offsets[KTX__MAX_NUM_FACES * KTX__MAX_NUM_MIPMAPS];
} ktx_image;
// should produce compiler error if sizes are wrong
typedef unsigned char ktx__validate_uint32[sizeof(ktx__uint32)== 4 ? 1 : -1];
typedef unsigned char ktx__validate_header[sizeof(ktx__header)==64 ? 1 : -1];
//
typedef struct {
ktx_uc *buffer, *buffer_end;
} ktx__context;
//
#define KTXDEF // TODO
#define KTX__IDENTIFIER_REF { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A } // TODO
#define KTX__ENDIAN_REF 0x04030201
#define KTX__ENDIAN_REF_REV 0x01020304
#define KTX__GL_TEXTURE_1D 0x0 // TODO
#define KTX__GL_TEXTURE_2D 0x0
#define KTX__GL_TEXTURE_3D 0x0
#define KTX__GL_TEXTURE_CUBE_MAP 0x0
#define KTX__MAX(x, y) (((y)<(x)) ? (x) : (y))
//
static int ktx__getn(ktx__context *k, ktx_uc *buffer, int n)
{
if (k->buffer+n <= k->buffer_end) {
memcpy(buffer, k->buffer, n);
k->buffer += n;
return 1;
} else
return 0;
}
static ktx__uint32 ktx__get32(ktx__context *k)
{
ktx__uint32 res;
if (!ktx__getn(k, (ktx_uc*)&res, sizeof(res))) return 0;
return res;
}
//
// this is not threadsafe
static const char *ktx__g_failure_reason;
KTXDEF const char *ktx_failure_reason(void)
{
return ktx__g_failure_reason;
}
static int ktx__err(const char *str)
{
ktx__g_failure_reason = str;
return 0;
}
#ifdef STBI_NO_FAILURE_STRINGS
#define ktx__err(x,y) 0
#elif defined(STBI_FAILURE_USERMSG)
#define ktx__err(x,y) ktx__err(y)
#else
#define ktx__err(x,y) ktx__err(x)
#endif
//
static int ktx__check_ktx_header(ktx__header *h, ktx_image *i) {
ktx__uint32 max_dim;
if (h->endianness == KTX__ENDIAN_REF_REV) return ktx__err("header", "Wrong endianness for this plaftorm");
if (h->endianness != KTX__ENDIAN_REF) return ktx__err("header", "Invalid signature");
i->is_compressed = (h->glType == 0 || h->glFormat == 0);
if (i->is_compressed && (h->glType == h->glFormat)) return ktx__err("header", "Invalid glType or glFormat");
if (h->pixelWidth == 0) return ktx__err("header", "Image without width");
if (h->pixelDepth > 0 && h->pixelHeight == 0) return ktx__err("header", "Image without height");
i->dimensions = 1;
i->gl_target = KTX__GL_TEXTURE_1D;
if (h->pixelHeight > 0) {
i->dimensions = 2;
i->gl_target = KTX__GL_TEXTURE_2D;
}
if (h->pixelDepth > 0) {
i->dimensions = 3;
i->gl_target = KTX__GL_TEXTURE_3D;
}
if (h->numberOfFaces == 6) {
if (i->dimensions != 2) return ktx__err("header", "Invalid cubemap faces");
i->gl_target = KTX__GL_TEXTURE_CUBE_MAP;
}
else {
if (h->numberOfFaces != 1) return ktx__err("header", "Invalid number of faces");
}
i->requests_generate_mipmaps = (h->numberOfMipmapLevels == 0);
h->numberOfMipmapLevels = KTX__MAX(1, h->numberOfMipmapLevels);
if (h->numberOfMipmapLevels > KTX__MAX_NUM_MIPMAPS) return ktx__err("header", "Unsupported number of mipmaps");
i->is_array = (h->numberOfArrayElements != 0);
h->numberOfArrayElements = KTX__MAX(1, h->numberOfArrayElements);
max_dim = KTX__MAX( KTX__MAX(h->pixelWidth, h->pixelHeight), h->pixelDepth );
if (max_dim < (1u << (h->numberOfMipmapLevels-1)) ) return ktx__err("header", "Too many mipmaps");
i->w = h->pixelWidth;
i->h = h->pixelHeight;
i->d = h->pixelDepth;
return 1;
}
static int ktx__load_ktx_key_value_data(ktx__context *k, ktx__header *h) {
return 0; // TODO(nico)
}
int ktx_load(ktx_image* i, ktx__context* k) {
ktx__header header;
int level, array_elem, face;
int res = 0;
if (!ktx__getn(k, (ktx_uc*)&header, sizeof(header))) return ktx__err("outofdata", "Corrupt KTX header");
if (!ktx__check_ktx_header(&header, i)) return 0;
if (!ktx__load_ktx_key_value_data(k, &header)) return 0;
for (level = 0; level < header.numberOfMipmapLevels; ++level)
{
ktx__int32 w = KTX__MAX(1, header.pixelWidth >> level);
ktx__int32 h = KTX__MAX(1, header.pixelHeight >> level);
ktx__int32 d = KTX__MAX(1, header.pixelDepth >> level);
ktx__uint32 face_lod_size = ktx__get32(k);
ktx__uint32 face_lod_size_padded = (face_lod_size + 3u) & (ktx__uint32)(~3);
if (face_lod_size == 0) return ktx__err("outofdata", "Invalid imageSize");
// TODO(nico) allocate memory ?
for (face = 0; face < header.numberOfFaces; ++face)
{
//if (!stbi__getn(k, some_buffer, face_lod_size_padded)) goto errorEnd; // TODO(nico) some error info
}
}
res = 1;
errorEnd:
return res;
}
#include "rtgu_ktx.h"
#define GLenum int // TODO(nico)
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0 // TODO
#define GL_TEXTURE_CUBE_MAP 0 // TODO
#define GL_UNPACK_ALIGNMENT 0 // TODO
int main()
{
ktx_image c;
ktx__context k;
int face, level;
if (ktx_load(&c, &k)) {
void **image_data = c.images_data;
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
for (level=0; level<c.num_mipmaps; ++level) {
int w = c.w, h = c.h, d = c.d;
int dim = c.dimensions;
if (c.is_array) {
// adjust dimensions to upload the whole array in one batch
if (dim == 1) h = c.num_array_elements;
if (dim == 2) d = c.num_array_elements;
else return 0; // TODO(nico) err("Arrays of 3D textures unsupported")
if (c.gl_target == GL_TEXTURE_CUBE_MAP) return 0; // TODO(nico) err("Arrays of cubemap textures unsupported")
++dim;
}
for (face=0; face<c.num_faces; ++face) {
GLenum gl_target =
(c.gl_target == GL_TEXTURE_CUBE_MAP)
? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face
: c.gl_target
;
if (c.is_compressed) {
// TODO(nico)
}
else {
if (dim == 1) {
glTexImage1D(
gl_target,
level,
c.gl_internal_format,
w,
0,
c.gl_format, c.gl_type, image_data
);
}
else if (dim == 2) {
glTexImage2D(
gl_target,
level,
c.gl_internal_format,
w, h,
0,
c.gl_format, c.gl_type, image_data
);
}
else if (dim == 3) {
// TODO(nico)
}
}
++image_data;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment