summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorquou <quou@disroot.org>2025-01-03 23:15:16 +1100
committerquou <quou@disroot.org>2025-01-03 23:15:16 +1100
commitcf4c007acc6bce0aa702a39b4675ecb879b911ed (patch)
treec30818ca49c18137c833e86ce589afeb6c51276a
parentb4d02ca1b735e3aee642509b14dfdddcc04a0c04 (diff)
HDR texture support
-rw-r--r--convtexture.c260
-rw-r--r--video.cpp4
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;
+}
+
diff --git a/video.cpp b/video.cpp
index 4e38bc5..ef724bf 100644
--- a/video.cpp
+++ b/video.cpp
@@ -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);