diff options
author | quou <quou@disroot.org> | 2024-07-21 20:22:36 +1000 |
---|---|---|
committer | quou <quou@disroot.org> | 2024-07-21 20:22:36 +1000 |
commit | e50e53b3ea82926ab01858e5728e489bd38d6878 (patch) | |
tree | 312c584a23ad3458314c1229c6be49cbaa75be00 /convtexture.c | |
parent | 2d0d48846e66bbb0b5c6966d842cea01f4ca468d (diff) |
texture compression
Diffstat (limited to 'convtexture.c')
-rw-r--r-- | convtexture.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/convtexture.c b/convtexture.c new file mode 100644 index 0000000..a07c331 --- /dev/null +++ b/convtexture.c @@ -0,0 +1,169 @@ +#include "render.h" +#include <stdio.h> +#include <stdlib.h> + +typedef struct { + float r, g, b; +} vec3; + +typedef struct { + vec3 start, end; + unsigned char indices[4 * 4]; +} Block; + +void get_block(Block* block, Colour* pixels, int stride) { + int x, y, i; + vec3 cols[4 * 4]; + vec3 s, e; + float cd; + for (y = 0; y < 4; y++) { + for (x = 0; x < 4; x++) { + Colour pixel = pixels[x + y * stride]; + vec3 vec; + vec.r = (float)pixel.r / 255.0f; + vec.g = (float)pixel.g / 255.0f; + vec.b = (float)pixel.b / 255.0f; + cols[x + y * 4] = vec; + } + } + cd = -1.0f; + for (i = 0; i < 4 * 4; i++) { + int j; + vec3* a = &cols[i]; + for (j = i + 1; j < 4 * 4; j++) { + vec3* b = &cols[j]; + float d = + (b->r - a->r) * (b->r - a->r) + + (b->g - a->g) * (b->g - a->g) + + (b->b - a->b) * (b->b - a->b); + if (d > cd) { + cd = d; + s = *a; + e = *b; + } + } + } + for (i = 0; i < 4 * 4; i++) { + vec3* col = &cols[i]; + float d; + d = + (e.r - col->r) * (e.r - col->r) + + (e.g - col->g) * (e.g - col->g) + + (e.b - col->b) * (e.b - col->b); + if (cd < 0.0001f) + block->indices[i] = 0; + else { + d = d / cd; + block->indices[i] = (int)((1.0f - d) * 3.1f); + } + } + block->start = s; + block->end = e; +} + +void compress_block(const Block* block, FILE* f) { + int i; + unsigned start = + ((unsigned)(block->start.r * 31.9999f) << 11) | + ((unsigned)(block->start.g * 63.9999f) << 5) | + ((unsigned)(block->start.b * 31.9999f)); + unsigned end = + ((unsigned)(block->end.r * 31.9999f) << 11) | + ((unsigned)(block->end.g * 63.9999f) << 5) | + ((unsigned)(block->end.b * 31.9999f)); + unsigned palette = (start << 16) | end; + unsigned indices = 0; + fwrite(&palette, 1, 4, f); + for (i = 0; i < 4 * 4; i++) { + indices |= block->indices[i] << (i * 2); + } + fwrite(&indices, 1, 4, f); +} + +void compress_bc1(Colour* pixels, int w, int h, FILE* f) { + int x, y, cw, ch; + Block block; + fwrite(&w, 1, 4, f); + fwrite(&h, 1, 4, f); + cw = w / 4; + ch = h / 4; + for (y = 0; y < ch; y++) { + for (x = 0; x < cw; x++) { + get_block(&block, &pixels[x * 4 + y * 4 * w], w); + compress_block(&block, f); + } + } +} + +int main(int argc, const char** argv) { + FILE* outfile, * infile; + char bmp_magic[2]; + unsigned bmp_offset; + int bmp_w, bmp_h, s, x, y; + unsigned short bmp_bits; + Colour* buffer; + Colour pixel; + + if (argc < 3) { + fprintf(stderr, "Usage: %s infile outfile.\n", argv[0]); + return 1; + } + + infile = fopen(argv[1], "rb"); + if (!infile) { + fprintf(stderr, "Failed to open %s.\n", argv[1]); + return 2; + } + + fread(bmp_magic, 2, 1, infile); + if (bmp_magic[0] != 'B' || bmp_magic[1] != 'M') { + fprintf(stderr, "Not a valid bitmap file.\n"); + return 3; + } + + fseek(infile, 10, SEEK_SET); + fread(&bmp_offset, 4, 1, infile); + fseek(infile, 18, SEEK_SET); + fread(&bmp_w, 4, 1, infile); + fread(&bmp_h, 4, 1, infile); + fseek(infile, 28, SEEK_SET); + fread(&bmp_bits, 2, 1, infile); + + if (bmp_bits != 32) { + fprintf(stderr, "Bitmap must have 32 bit pixels. Instead has %d bit pixels.\n", bmp_bits); + return 4; + } + + if (bmp_w % 4 != 0 || bmp_h % 4 != 0) { + fprintf(stderr, "Bitmap must have a size divisible by four.\n"); + return 5; + } + + fseek(infile, bmp_offset, SEEK_SET); + s = bmp_w * bmp_h; + buffer = malloc(s * 4); + /* Flip & read. */ + for (y = 0; y < bmp_h; y++) { + for (x = 0; x < bmp_w; x++) { + unsigned char t; + fread(&pixel, 1, 4, infile); + t = pixel.r; + pixel.r = pixel.b; + pixel.b = t; + if (pixel.a == 0) { + pixel.r = 0; + pixel.g = 0; + pixel.b = 0; + } + buffer[x + (bmp_h - y - 1) * bmp_w] = pixel; + } + } + outfile = fopen(argv[2], "wb"); + if (!outfile) { + fprintf(stderr, "Failed to open %s.\n", argv[2]); + return 6; + } + compress_bc1(buffer, bmp_w, bmp_h, outfile); + fclose(outfile); + return 0; +} |