Last active
May 2, 2017 13:18
-
-
Save nothings/bf70e9aa2b2af38555d5475fdc721ad1 to your computer and use it in GitHub Desktop.
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
| #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