Created
September 8, 2017 07:02
-
-
Save tilkinsc/d1a8a46853dea160dc86aa48618be6f9 to your computer and use it in GitHub Desktop.
Loading a DDS file DXT1 DXT3 DXT5 opengl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
GLuint texture_loadDDS(const char* path) { | |
FILE* f; | |
f = fopen(path, "rb"); | |
if(f == 0) | |
return 0; | |
// make sure this is a dds | |
char filecode[4]; | |
fread(&filecode, 1, 4, f); | |
if(strncmp(filecode, "DDS ", 4) != 0) { | |
fclose(f); | |
return 0; | |
} | |
unsigned char header[124]; | |
fread(&header, 1, 124, f); | |
// different depending on byte arrangement/endianess, this is the windows version | |
unsigned int width = (header[8]) | (header[9] << 8) | (header[10] << 16) | (header[11] << 24); | |
unsigned int height = (header[12]) | (header[13] << 8) | (header[14] << 16) | (header[15] << 24); | |
unsigned int linearSize = (header[16]) | (header[17] << 8) | (header[18] << 16) | (header[19] << 24); | |
unsigned int mipMapCount = (header[24]) | (header[25] << 8) | (header[26] << 16) | (header[27] << 24); | |
// a 4-byte array of chars | |
char* fourCC = (char*)&(header[80]); | |
// 'the sum of all the mipmap's byte-size' is never greater than 'two times the biggest mipmap byte-size' | |
unsigned int buffer_size = (mipMapCount > 1 ? linearSize + linearSize : linearSize); | |
unsigned char* buffer = malloc(buffer_size * sizeof(unsigned char)); | |
if(buffer == 0) { | |
// Handle OOM | |
return 0; | |
} | |
fread(buffer, 1, buffer_size, f); | |
fclose(f); | |
// decide byte format and block size from type | |
// probably should check if the EXT is available | |
unsigned int blockSize; | |
unsigned int format; | |
if(strncmp(fourCC, "DXT1", 4) == 0) { | |
format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; | |
blockSize = 8; | |
} else if(strncmp(fourCC, "DXT3", 4) == 0) { | |
format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; | |
blockSize = 16; | |
} else if(strncmp(fourCC, "DXT5", 4) == 0) { | |
format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; | |
blockSize = 16; | |
} else { | |
// unhandled type | |
free(buffer); | |
return 0; | |
} | |
// glGenTextures() CAN return 0 on error, see docs - probably won't happen unless you are bad | |
GLuint tid; | |
glGenTextures(1, &tid); | |
if(tid == 0) { | |
free(buffer); | |
return 0; | |
} | |
glBindTexture(GL_TEXTURE_2D, tid); | |
// dds gives you the wrong amount of mipMaps, MAX_LEVEL 0 = 1 mipmap, MAX_LEVEL 1 = 2 mipmaps | |
// thusly just minus one - simple off-by-one array fix | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipMapCount-1); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | |
unsigned int offset = 0; | |
for (unsigned int level=0; level<mipMapCount && (width || height); level++) { | |
// ignore mipmaps you will never see, save 4*4*4 + 2*2*4 + 1*1*4 data I guess | |
// if you don't at least ignore the 0*0 mipmaps, you will 0/2 | |
// dds can have mipmaps that aren't rectangular, thusly 256*128 and 128*64 and 1*0 can be levels | |
if(width <= 4 || height <= 4) { | |
// -1 because this iteration of level is the next, which we don't use | |
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level-1); | |
break; | |
} | |
// the 3's aren't magic numbers | |
unsigned int size = ((width+3)/4) * ((height+3)/4) * blockSize; | |
glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, buffer + offset); | |
// offset is current byte offset from mip to map, as data is stored linearly | |
offset += size; | |
// assuming pow2 mipmaps | |
width = width/2; | |
height = height/2; | |
} | |
glBindTexture(GL_TEXTURE_2D, 0); | |
free(buffer); | |
return tid; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment