Skip to content

Instantly share code, notes, and snippets.

@justinmeiners
Created August 20, 2016 15:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinmeiners/bfdf8c5f4d0dafc52e7cbdf5cb1ba33f to your computer and use it in GitHub Desktop.
Save justinmeiners/bfdf8c5f4d0dafc52e7cbdf5cb1ba33f to your computer and use it in GitHub Desktop.
#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