From 0bc95e2084b970819d15306f7e3ab8b81a108dcd Mon Sep 17 00:00:00 2001 From: quou Date: Sun, 2 Mar 2025 19:23:29 +1100 Subject: generate mips for textures --- convtexture.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 105 insertions(+), 23 deletions(-) (limited to 'convtexture.c') diff --git a/convtexture.c b/convtexture.c index e5ec996..5ad4735 100644 --- a/convtexture.c +++ b/convtexture.c @@ -35,6 +35,73 @@ const char* format_names[] = { #undef x }; +void gen_mip(Image* src, Image* dst, int w, int h) { + const float weight = 1.0f / 4.0f; + int i, x, y, sw = src->w; + dst->pixels = malloc(w * h * sizeof *dst->pixels); + dst->w = w; + dst->h = h; + assert(w == src->w / 2); + assert(h == src->h / 2); + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int sx = x << 1; + int sy = y << 1; + int ind[] = { + sx + (sy) * sw, + sx + 1 + (sy) * sw, + sx + (sy + 1) * sw, + sx + 1 + (sy + 1) * sw + }; + float avg[4] = { 0 }; + Colour* d = &dst->pixels[x + y * w]; + for (i = 0; i < 4; i++) { + int j; + for (j = 0; j < 4; j++) + avg[j] += + (float)((uint8_t*)&src->pixels[ind[i]])[j] * + weight; + } + d->r = (uint8_t)avg[0]; + d->g = (uint8_t)avg[1]; + d->b = (uint8_t)avg[2]; + d->a = (uint8_t)avg[3]; + } + } +} + +int auto_count(int w, int h) { + int i; + for (i = 0; w > 1 || h > 1; i++, w >>= 1, h >>= 1); + return i; +} + +int po2(int x) { + return x && (!(x & (x - 1))); +} + +Image* gen_mips(Image* src, int count, int* gen_count) { + int i, w, h; + Image* imgs; + if (!count) + count = auto_count(src->w, src->h); + imgs = malloc(count * sizeof *imgs); + imgs[0] = *src; + w = src->w >> 1; + h = src->h >> 1; + if (count && (!po2(src->w) || !po2(src->h))) { + print_war("Image size not a power of 2 (no mips for you >:(\n"); + count = 1; + } + for (i = 1; i < count; i++) { + gen_mip(&imgs[i - 1], &imgs[i], w, h); + w >>= 1; + h >>= 1; + } + *gen_count = i; + return imgs; +} + unsigned encode_endpoint(const vec3* v) { return ((unsigned)(v->r * 31.9999f) << 11) | @@ -264,28 +331,33 @@ void compress_bc5(Colour* pixels, int w, int h, FILE* f) { } } -void write_header(FILE* f, int w, int h, Texture_Format fmt) { +void write_header(FILE* f, int w, int h, int mips, Texture_Format fmt) { fwrite("TXTR", 1, 4, f); fwrite(&w, 1, 4, f); fwrite(&h, 1, 4, f); - fwrite(&fmt, 1, 4, f); + fwrite(&fmt, 1, 2, f); + fwrite(&mips, 1, 2, f); } -void convert(Image* image, Texture_Format target, FILE* f) { - write_header(f, image->w, image->h, target); - switch (target) { - case texture_format_bc1: - compress_bc1(image->pixels, image->w, image->h, f); - break; - case texture_format_bc4: - compress_bc4(image->pixels, image->w, image->h, f); - break; - case texture_format_bc5: - compress_bc5(image->pixels, image->w, image->h, f); - break; - default: - print_err("Unsupported target format.\n"); - pbreak(40); +void convert(Image* images, int count, Texture_Format target, FILE* f) { + int i; + write_header(f, images->w, images->h, count, target); + for (i = 0; i < count; i++) { + Image* image = &images[i]; + switch (target) { + case texture_format_bc1: + compress_bc1(image->pixels, image->w, image->h, f); + break; + case texture_format_bc4: + compress_bc4(image->pixels, image->w, image->h, f); + break; + case texture_format_bc5: + compress_bc5(image->pixels, image->w, image->h, f); + break; + default: + print_err("Unsupported target format.\n"); + pbreak(40); + } } } @@ -299,12 +371,17 @@ Texture_Format texture_format_from_string(const char* s) { return (Texture_Format)0; } -int proc_bitmap(FILE* infile, FILE* outfile, Texture_Format target) { +int proc_bitmap( + FILE* infile, + FILE* outfile, + Texture_Format target, + int mc +) { unsigned bmp_offset; int bmp_w, bmp_h, s, x, y; unsigned short bmp_bits; Colour* buffer; - Image img; + Image img, * imgs; Colour pixel; fseek(infile, 10, SEEK_SET); @@ -347,7 +424,8 @@ int proc_bitmap(FILE* infile, FILE* outfile, Texture_Format target) { img.pixels = buffer; img.w = bmp_w; img.h = bmp_h; - convert(&img, target, outfile); + imgs = gen_mips(&img, mc, &mc); + convert(imgs, mc, target, outfile); fclose(outfile); return 0; } @@ -519,12 +597,13 @@ int proc_hdr(FILE* infile, FILE* outfile, int half) { } } if (half) { - write_header(outfile, w, h, texture_format_rgba16f); + write_header(outfile, w, h, 1, texture_format_rgba16f); write_halves(outfile, w * h * 4, (float*)pixels); } else { - write_header(outfile, w, h, texture_format_rgba32f); + write_header(outfile, w, h, 1, texture_format_rgba32f); fwrite(pixels, sizeof *pixels, w * h, outfile); } + /* todo mipgen for hdr */ fclose(outfile); return 0; } @@ -532,6 +611,7 @@ int proc_hdr(FILE* infile, FILE* outfile, int half) { int main(int argc, const char** argv) { FILE* outfile, * infile; char magic[11]; + int mips = 0; Texture_Format target; if (argc < 4) { @@ -545,6 +625,8 @@ int main(int argc, const char** argv) { return 2; } target = texture_format_from_string(argv[3]); + if (argc > 4) + mips = (int)strtol(argv[4], 0, 10); outfile = fopen(argv[2], "wb"); if (!outfile) { @@ -554,7 +636,7 @@ int main(int argc, const char** argv) { fread(magic, 1, 10, infile); magic[10] = 0; if (magic[0] == 'B' && magic[1] == 'M') { - return proc_bitmap(infile, outfile, target); + return proc_bitmap(infile, outfile, target, mips); } if (string_equal(magic, "#?RADIANCE")) { int half = target == texture_format_rgba16f; -- cgit v1.2.3-54-g00ecf