Skip to content

Instantly share code, notes, and snippets.

@nothings
Last active May 2, 2017 13:18
Show Gist options
  • Select an option

  • Save nothings/bf70e9aa2b2af38555d5475fdc721ad1 to your computer and use it in GitHub Desktop.

Select an option

Save nothings/bf70e9aa2b2af38555d5475fdc721ad1 to your computer and use it in GitHub Desktop.
#define FOURCC(s) (((uint32)s[0]<<0) | ((uint32)s[1]<<8) | ((uint32)s[2]<<16) | ((uint32)s[3]<<24))
// this is not the public function, see following two functions after this one
static GLuint load_dds_bc_only_raw(GLuint tex, int slice, int total_slices, char *filename)
{
int target = slice < 0 ? GL_TEXTURE_2D : GL_TEXTURE_2D_ARRAY, i, mips;
GLenum fmt_for_bc[8] = { 0, 0x83F0, 0x83F2, 0x83F3, 0x8DBB, 0x8DBD, 0x8E8E, 0x8E8F };
int bytes_per_4x4block[8] = { 0, 8,16,16,8,16,16,16 };
uint32 width,height,flags,size,fourcc,depth,fflags,caps,caps2,dim=0;
int len, bc=0, fmt=1, intfmt;
uint32 *data = (uint32 *) stb_file(filename, &len);
char *pixels;
if (data == 0 || len < 128) goto fail; // file too small or non-existant
if (data[0] != 0x20534444) goto fail; // dwMagic
if (data[1] != 124 ) goto fail; // dwSize
flags = data[2];
width = data[3];
height = data[4];
if (width > 65536 || height > 65536) goto fail; // probably corrupted
if ((width>>2) * (height>>2) > (1u<<24)) goto fail; // total pixels > 2^28, probably corrupted
size = data[5]; // dwPitchOrLinearSize
depth = data[6];
if (flags & 0x20000) // DDSD_MIPMAPCOUNT
mips = (int) data[7];
else
mips = 1;
// data[8]..data[18] dwReserved
if (data[19] != 32) goto fail; // dwSize
fflags = data[20]; // dwFlags
if (fflags & 0x40) goto fail; // uncompressed
if (!(fflags & 0x4)) goto fail; // no FOURCC
fourcc = data[21];
// data[21] dwRGBBitCount
// data[22..25] R/G/B/A mask
caps = data[26];
caps2 = data[27];
pixels = (char*) &data[32];
if (fourcc == FOURCC("DXT1")) bc=1;
if (fourcc == FOURCC("DXT5")) bc=3;
if (fourcc == FOURCC("ATI2")) bc=5;
if (fourcc == FOURCC("BC5S")) bc=5, fmt=3; // SNORM
if (fourcc == FOURCC("DX10")) {
uint32 dxgifmt;
if (len < 148) goto fail;
dxgifmt = data[32];
if (dxgifmt >= 70 && dxgifmt <= 84) {
bc = 1 + (dxgifmt-70)/3;
fmt = (dxgifmt-70)%3; // TYPELESS, UNORM, UNORM_SRGB
} else if (dxgifmt >= 94 && dxgifmt <= 99) {
bc = 6 + (dxgifmt-94)/3;
fmt = (dxgifmt-70)%3; // bc6 is actually different meaning for fmt=1,2
} else
goto fail; // unhandled format, we only do BC1..BC7
dim = data[33];
pixels = (char*) &data[37];
}
if (bc == 0) goto fail;
// @TODO mipmaps, arrays, cubemaps -- maybe use ktx for those!
if (size != ((width+3)/4)*((height+3)/4)*bytes_per_4x4block[bc]) goto fail; // size isn't correct
if (pixels - (char*)data + size > (unsigned) len) goto fail; // size goes past EOF
intfmt = fmt_for_bc[bc];
if (bc == 4 && fmt == 3) intfmt = 0x8DBC; // GL_COMPRESSED_SIGNED_RED_RGTC1
if (bc == 5 && fmt == 3) intfmt = 0x8DBE; // GL_COMPRESSED_SIGNED_RG_RGTC2
if (tex == 0) {
assert(slice >= 0);
glGenTextures(1, &tex);
glBindTexture(target, tex);
for (i=0; i < mips; ++i)
glTexImage3D(target, i, intfmt, width>>i,height>>i,total_slices,0,GL_RGB,GL_UNSIGNED_BYTE,0);
if (mips)
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
else
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
glBindTexture(target, tex);
for (i=0; i < mips; ++i) {
if (pixels - (char*)data + size > (unsigned) len) goto fail; // size goes past EOF
if (target == GL_TEXTURE_2D)
glCompressedTexImage2D(target, i, intfmt, width, height, 0, size, pixels);
else
glCompressedTexSubImage3D(target, i, 0,0,slice,width,height,1,intfmt,size,pixels);
pixels += size;
width = width>>1;
height = height>>1;
size = ((width+3)/4)*((height+3)/4)*bytes_per_4x4block[bc];
}
glBindTexture(target, 0);
free(data);
return tex;
fail:
free(data);
return tex;
}
// caller has to set GL_LINEAR_MIPMAP_LINEAR if there are mipmaps
static GLuint load_dds_bc_only(char *filename)
{
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return load_dds_bc_only_raw(tex,-1,0, filename);
}
static GLuint load_dds_bc_only_array(char *filename, GLuint tex, int total_slices, int slice)
{
return load_dds_bc_only_raw(tex, slice, total_slices, filename);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment