Created
August 20, 2016 15:44
-
-
Save justinmeiners/bfdf8c5f4d0dafc52e7cbdf5cb1ba33f to your computer and use it in GitHub Desktop.
This file contains 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
#include <stdint.h> | |
#include <stdio.h> | |
#include <memory.h> | |
#define STB_IMAGE_WRITE_IMPLEMENTATION | |
#include "stb_image_write.h" | |
#define DDS_MAGIC 542327876 | |
#define FOUR_CC_DXT1 0x31545844 | |
#define FOUR_CC_DXT3 0x33545844 | |
typedef struct | |
{ | |
uint32_t size; | |
uint32_t flags; | |
uint32_t fourCC; | |
uint32_t RGBBitCount; | |
uint32_t RBitMask; | |
uint32_t GBitMask; | |
uint32_t BBitMask; | |
uint32_t ABitMask; | |
} DdsPixelFormat; | |
typedef struct | |
{ | |
uint32_t magic; | |
uint32_t size; | |
uint32_t flags; | |
uint32_t height; | |
uint32_t width; | |
uint32_t linearSize; | |
uint32_t depth; | |
uint32_t mipCount; | |
uint32_t reserved1[11]; | |
DdsPixelFormat pixelFormat; | |
uint32_t caps; | |
uint32_t caps2; | |
uint32_t caps3; | |
uint32_t caps4; | |
uint32_t reserved2; | |
} DdsHeader; | |
typedef union | |
{ | |
uint8_t c[3]; | |
} Rgb; | |
typedef struct | |
{ | |
uint16_t c[2]; | |
uint32_t table; | |
} DdsBlock; | |
typedef struct | |
{ | |
Rgb c[16]; | |
} ColorBlock; | |
ColorBlock dxt1_decompress_block(const uint64_t block) | |
{ | |
uint16_t c0 = block & 0xFFFF; | |
uint16_t c1 = (block >> 16) & 0xFFFF; | |
uint32_t table = (block >> 32); | |
Rgb pallete[4]; | |
pallete[0].c[0] = ((c0 >> 11) & 0x1F) * 255 / 0x1F; | |
pallete[0].c[1] = ((c0 >> 5) & 0x3F) * 255 / 0x3F; | |
pallete[0].c[2] = (c0 & 0x1F) * 255 / 0x1F; | |
pallete[1].c[0] = ((c1 >> 11) & 0x1F) * 255 / 0x1F; | |
pallete[1].c[1] = ((c1 >> 5) & 0x3F) * 255 / 0x3F; | |
pallete[1].c[2] = (c1 & 0x1F) * 255 / 0x1F; | |
int i; | |
for (i = 0; i < 3; ++i) | |
{ | |
pallete[2].c[i] = pallete[0].c[i] * 2 / 3 + pallete[1].c[i] / 3; | |
pallete[3].c[i] = pallete[0].c[i] / 3 + pallete[1].c[i] * 2 / 3; | |
} | |
ColorBlock output; | |
for (i = 0; i < 16; ++i) | |
{ | |
output.c[i] = pallete[(table >> i * 2) & 0x3]; | |
} | |
return output; | |
} | |
int ReadDds(FILE* file) | |
{ | |
DdsHeader header; | |
fread(&header, 1, sizeof(DdsHeader), file); | |
printf("mips: %i\n", header.mipCount); | |
printf("%i, %i\n", header.width, header.height); | |
short blockSize = 0; | |
if (header.pixelFormat.fourCC == FOUR_CC_DXT1) | |
{ | |
printf("dxt1\n"); | |
blockSize = 8; | |
assert(blockSize == sizeof(DdsBlock)); | |
} | |
short width = header.width; | |
short height = header.height; | |
size_t offset = 0; | |
int i, j; | |
for (i = 0; i < 3; ++i) | |
{ | |
size_t mipLength = ((width + 3) / 4) * ((height + 3) / 4) * blockSize; | |
unsigned char* outputBuffer = malloc(width * height * 3); | |
unsigned char* mipBuffer = malloc(mipLength); | |
fread(mipBuffer, mipLength, 1, file); | |
size_t blockIndex = 0; | |
while (blockIndex * blockSize < mipLength) | |
{ | |
uint64_t* block = (uint64_t*)(mipBuffer + blockIndex * blockSize); | |
ColorBlock output = dxt1_decompress_block(*block); | |
int y; | |
for (y = 0; y < 4; ++y) | |
{ | |
size_t writePos = (y + (blockIndex * 16) / width) * width * 3; | |
writePos += ((blockIndex * 4) % width) * 3; | |
memcpy(outputBuffer + writePos, output.c + y * 4, 3 * 4); | |
} | |
++blockIndex; | |
} | |
free(mipBuffer); | |
char filename[32]; | |
sprintf(filename, "%i.bmp", i); | |
stbi_write_bmp(filename, width, height, 3, outputBuffer); | |
free(outputBuffer); | |
offset += mipLength; | |
width = width >> 1; | |
height = height >> 1; | |
} | |
} | |
int main(int argc, char* argv[]) | |
{ | |
printf("opening: %s\n", argv[1]); | |
FILE* ddsFile = fopen(argv[1], "rb"); | |
if (ReadDds(ddsFile)) | |
{ | |
printf("success\n"); | |
} | |
else | |
{ | |
printf("failure\n"); | |
} | |
fclose(ddsFile); | |
printf("closing\n"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment