summaryrefslogtreecommitdiff
path: root/convtexture.c
diff options
context:
space:
mode:
Diffstat (limited to 'convtexture.c')
-rw-r--r--convtexture.c169
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;
+}