diff options
author | quou <quou@disroot.org> | 2025-01-03 23:15:16 +1100 |
---|---|---|
committer | quou <quou@disroot.org> | 2025-01-03 23:15:16 +1100 |
commit | cf4c007acc6bce0aa702a39b4675ecb879b911ed (patch) | |
tree | c30818ca49c18137c833e86ce589afeb6c51276a | |
parent | b4d02ca1b735e3aee642509b14dfdddcc04a0c04 (diff) |
HDR texture support
-rw-r--r-- | convtexture.c | 260 | ||||
-rw-r--r-- | video.cpp | 4 |
2 files changed, 233 insertions, 31 deletions
diff --git a/convtexture.c b/convtexture.c index b3be7dc..e5b603b 100644 --- a/convtexture.c +++ b/convtexture.c @@ -1,5 +1,6 @@ #include <stdio.h> #include <stdlib.h> +#include <math.h> #include "plat.h" #include "str.h" @@ -263,11 +264,15 @@ void compress_bc5(Colour* pixels, int w, int h, FILE* f) { } } -void convert(Image* image, Texture_Format target, FILE* f) { +void write_header(FILE* f, int w, int h, Texture_Format fmt) { fwrite("TXTR", 1, 4, f); - fwrite(&image->w, 1, 4, f); - fwrite(&image->h, 1, 4, f); - fwrite(&target, 1, 4, f); + fwrite(&w, 1, 4, f); + fwrite(&h, 1, 4, f); + fwrite(&fmt, 1, 4, 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); @@ -294,34 +299,13 @@ Texture_Format texture_format_from_string(const char* s) { return (Texture_Format)0; } -int main(int argc, const char** argv) { - FILE* outfile, * infile; - char bmp_magic[2]; +int proc_bitmap(FILE* infile, FILE* outfile, Texture_Format target) { unsigned bmp_offset; int bmp_w, bmp_h, s, x, y; unsigned short bmp_bits; Colour* buffer; Image img; Colour pixel; - Texture_Format target; - - if (argc < 4) { - print_err("Usage: %s infile outfile format.\n", argv[0]); - return 1; - } - - infile = fopen(argv[1], "rb"); - if (!infile) { - print_err("Failed to open %s.\n", argv[1]); - return 2; - } - target = texture_format_from_string(argv[3]); - - fread(bmp_magic, 2, 1, infile); - if (bmp_magic[0] != 'B' || bmp_magic[1] != 'M') { - print_err("Not a valid bitmap file.\n"); - return 3; - } fseek(infile, 10, SEEK_SET); fread(&bmp_offset, 4, 1, infile); @@ -360,11 +344,6 @@ int main(int argc, const char** argv) { buffer[x + (bmp_h - y - 1) * bmp_w] = pixel; } } - outfile = fopen(argv[2], "wb"); - if (!outfile) { - print_err("Failed to open %s.\n", argv[2]); - return 6; - } img.pixels = buffer; img.w = bmp_w; img.h = bmp_h; @@ -373,3 +352,222 @@ int main(int argc, const char** argv) { return 0; } +typedef struct { + float r, g, b; +} Hdr_Pixel; + +Hdr_Pixel hdr_pixel(uint8_t* bytes) { + Hdr_Pixel p; + float f = ldexp(1.0f, (int)bytes[3] - (128 + 8)); + p.r = ((float)bytes[0] + 0.5f) * f; + p.g = ((float)bytes[1] + 0.5f) * f; + p.b = ((float)bytes[2] + 0.5f) * f; + return p; +} + +/* from open xr */ +uint16_t f2h(uint32_t i) { + int s = (i >> 16) & 0x00008000; + int e = ((i >> 23) & 0x000000ff) - (127 - 15); + int m = i & 0x007fffff; + if (e <= 0) + { + if (e < -10) + return s; + m = m | 0x00800000; + int t = 14 - e; + int a = (1 << (t - 1)) - 1; + int b = (m >> t) & 1; + m = (m + a + b) >> t; + return s | m; + } + else if (e == 0xff - (127 - 15)) + { + if (m == 0) + return s | 0x7c00; + else + { + m >>= 13; + return s | 0x7c00 | m | (m == 0); + } + } + else + { + m = m + 0x00000fff + ((m >> 13) & 1); + if (m & 0x00800000) + { + m = 0; + e += 1; + } + if (e > 30) + return s | 0x7c00; + return s | (e << 10) | (m >> 13); + } +} + +void write_halves(FILE* f, int c, float* pixels) { + int i; + for (i = 0; i < c; i++) { + uint16_t h = f2h(*(uint32_t*)&pixels[i]); + fwrite(&h, 2, 1, f); + } +} + +int proc_hdr(FILE* infile, FILE* outfile, int half) { + char buf[256]; + char* tok; + int w, h, i; + Hdr_Pixel* pixels; + uint8_t* row; + int valid = 0; + fseek(infile, 0, SEEK_SET); + while (fgets(buf, sizeof buf, infile)) { + if (string_equal(buf, "FORMAT=32-bit_rle_rgbe\n")) + valid = 1; + if (buf[0] == '\n') break; + } + if (!valid) { + print_err("Format unsupported.\n"); + return 10; + } + tok = fgets(buf, sizeof buf, infile); + if (tok[0] != '-' || tok[1] != 'Y') { + print_err("Format unsupported.\n"); + return 11; + } + for (tok = tok + 2; *tok == ' '; tok++); + h = (int)strtol(tok, &tok, 10); + for (; *tok == ' '; tok++); + if (tok[0] != '+' || tok[1] != 'X') { + print_err("Format unsupported.\n"); + return 11; + } + for (tok = tok + 2; *tok == ' '; tok++); + w = (int)strtol(tok, &tok, 10); + if (w < 8 || w > 0x7ffff) { + /* todo */ + print_err("Format unsupported.\n"); + return 12; + } + pixels = malloc(w * h * sizeof *pixels); + row = malloc(w * 4); + for (i = 0; i < h; i++) { + int a, b, c, d, j; + a = fgetc(infile); + b = fgetc(infile); + c = fgetc(infile); + d = fgetc(infile); + if (d == EOF) { + print_err("Unexpected end of image file.\n"); + return 13; + } + if (b != 2 || (c & 0x80)) { + int j, shift = 0; + row[0] = a; + row[1] = b; + row[2] = c; + row[3] = d; + for (j = 1; j < w; j++) { + uint8_t* p = &row[j * 4]; + p[0] = fgetc(infile); + p[1] = fgetc(infile); + p[2] = fgetc(infile); + p[3] = fgetc(infile); + if ( + p[0] == 1 && + p[1] == 1 && + p[2] == 1 + ) { + int k; + for (k = p[3] << shift; k > 0; k--) { + p[0] = p[-4]; + p[1] = p[-3]; + p[2] = p[-2]; + p[3] = p[-1]; + p += 4; + j++; + } + shift += 8; + } else + shift = 0; + } + goto convert; + } + if (((c << 8) | d) != w) { + print("%d, %d\n", i, ((c << 8) | d)); + print_err("Corrupt run.\n"); + return 14; + } + for (j = 0; j < 4; j++) { + int k; + for (k = 0; k < w;) { + int d1 = fgetc(infile), d2; + if (d1 == EOF) { + print_err("Unexpected end of image file.\n"); + return 14; + } + if (d1 > 128) { + d1 &= 127; + d2 = fgetc(infile); + for (; d1--; k++) + row[k * 4 + j] = (uint8_t)d2; + } else + for (; d1--; k++) + row[k * 4 + j] = (uint8_t)fgetc(infile); + } + } + convert: + for (j = 0; j < w; j++) { + pixels[j + i * w] = hdr_pixel(&row[j * 4]); + } + } + if (half) { + write_header(outfile, w, h, texture_format_rgb16f); + write_halves(outfile, w * h * 3, (float*)pixels); + } else { + write_header(outfile, w, h, texture_format_rgb32f); + fwrite(pixels, sizeof *pixels, w * h, outfile); + } + fclose(outfile); + return 0; +} + +int main(int argc, const char** argv) { + FILE* outfile, * infile; + char magic[11]; + Texture_Format target; + + if (argc < 4) { + print_err("Usage: %s infile outfile format.\n", argv[0]); + return 1; + } + + infile = fopen(argv[1], "rb"); + if (!infile) { + print_err("Failed to open %s.\n", argv[1]); + return 2; + } + target = texture_format_from_string(argv[3]); + + outfile = fopen(argv[2], "wb"); + if (!outfile) { + print_err("Failed to open %s.\n", argv[2]); + return 6; + } + + fread(magic, 1, 10, infile); magic[10] = 0; + if (magic[0] == 'B' && magic[1] == 'M') { + return proc_bitmap(infile, outfile, target); + } + if (string_equal(magic, "#?RADIANCE")) { + int half = target == texture_format_rgb16f; + if (!half && target != texture_format_rgb32f) { + print_err("Unsupported target format.\n"); + return 40; + } + return proc_hdr(infile, outfile, half); + } + print_err("Invalid image file.\n"); + return 80; +} + @@ -3689,6 +3689,10 @@ size_t Texture_Loader::calc_size( return (w / 4) * (h / 4) * 16; case texture_format_r8i: return w * h; + case texture_format_rgb16f: + return w * h * 6; + case texture_format_rgb32f: + return w * h * 12; default: print_err("Can't load this texture format.\n"); pbreak(45498); |