332 lines
8.4 KiB
C
332 lines
8.4 KiB
C
|
|
#include "global.h"
|
|
|
|
// Based on miniexr.cpp - public domain - 2013 Aras Pranckevicius / Unity Technologies
|
|
// https://github.com/aras-p/miniexr
|
|
// https://www.openexr.com/documentation/openexrfilelayout.pdf
|
|
|
|
void export_exr_write_string(u8_array_t *out, char *str) {
|
|
for (i32 i = 0; i < string_length(str); ++i) {
|
|
u8_array_push(out, char_code_at(str, i));
|
|
}
|
|
}
|
|
|
|
void export_exr_write_line16(i32 byte_pos) {
|
|
for (i32 x = 0; x < _export_exr_width; ++x) {
|
|
u8_array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos));
|
|
u8_array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos + 1));
|
|
byte_pos += _export_exr_stride;
|
|
}
|
|
}
|
|
|
|
void export_exr_write_line32(i32 byte_pos) {
|
|
for (i32 x = 0; x < _export_exr_width; ++x) {
|
|
u8_array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos));
|
|
u8_array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos + 1));
|
|
u8_array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos + 2));
|
|
u8_array_push(_export_exr_out, buffer_get_u8(_export_exr_src_view, byte_pos + 3));
|
|
byte_pos += _export_exr_stride;
|
|
}
|
|
}
|
|
|
|
void export_exr_write_bgr(i32 off, i32 pos, i32 byte_size) {
|
|
_export_exr_write_line(pos + byte_size * 2);
|
|
_export_exr_write_line(pos + byte_size);
|
|
_export_exr_write_line(pos);
|
|
}
|
|
|
|
void export_exr_write_single(i32 off, i32 pos, i32 byte_size) {
|
|
_export_exr_write_line(pos + off * byte_size);
|
|
_export_exr_write_line(pos + off * byte_size);
|
|
_export_exr_write_line(pos + off * byte_size);
|
|
}
|
|
|
|
buffer_t *export_exr_run(i32 width, i32 height, buffer_t *src, i32 bits, i32 type, i32 off) {
|
|
u8_array_t *out = u8_array_create_from_raw((u8[]){}, 0);
|
|
u8_array_push(out, 0x76); // magic
|
|
u8_array_push(out, 0x2f);
|
|
u8_array_push(out, 0x31);
|
|
u8_array_push(out, 0x01);
|
|
u8_array_push(out, 2); // version, scanline
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
export_exr_write_string(out, "channels");
|
|
u8_array_push(out, 0);
|
|
export_exr_write_string(out, "chlist");
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 55);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
i32 attrib = bits == 16 ? 1 : 2; // half, float
|
|
|
|
u8_array_push(out, char_code_at("B", 0)); // B
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, attrib);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 1);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 1);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, char_code_at("G", 0)); // G
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, attrib);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 1);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 1);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, char_code_at("R", 0)); // R
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, attrib);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 1);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 1);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
|
|
export_exr_write_string(out, "compression");
|
|
u8_array_push(out, 0);
|
|
export_exr_write_string(out, "compression");
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 1);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0); // no compression
|
|
|
|
export_exr_write_string(out, "dataWindow");
|
|
u8_array_push(out, 0);
|
|
export_exr_write_string(out, "box2i");
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 16);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
i32 ww = width - 1;
|
|
i32 hh = height - 1;
|
|
|
|
u8_array_push(out, ww & 0xff);
|
|
u8_array_push(out, (ww >> 8) & 0xff);
|
|
u8_array_push(out, (ww >> 16) & 0xff);
|
|
u8_array_push(out, (ww >> 24) & 0xff);
|
|
|
|
u8_array_push(out, hh & 0xff);
|
|
u8_array_push(out, (hh >> 8) & 0xff);
|
|
u8_array_push(out, (hh >> 16) & 0xff);
|
|
u8_array_push(out, (hh >> 24) & 0xff);
|
|
|
|
export_exr_write_string(out, "displayWindow");
|
|
u8_array_push(out, 0);
|
|
export_exr_write_string(out, "box2i");
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 16);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, ww & 0xff);
|
|
u8_array_push(out, (ww >> 8) & 0xff);
|
|
u8_array_push(out, (ww >> 16) & 0xff);
|
|
u8_array_push(out, (ww >> 24) & 0xff);
|
|
|
|
u8_array_push(out, hh & 0xff);
|
|
u8_array_push(out, (hh >> 8) & 0xff);
|
|
u8_array_push(out, (hh >> 16) & 0xff);
|
|
u8_array_push(out, (hh >> 24) & 0xff);
|
|
|
|
export_exr_write_string(out, "lineOrder");
|
|
u8_array_push(out, 0);
|
|
export_exr_write_string(out, "lineOrder");
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 1);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0); // increasing Y
|
|
|
|
export_exr_write_string(out, "pixelAspectRatio");
|
|
u8_array_push(out, 0);
|
|
export_exr_write_string(out, "float");
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 4);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0); // 1.0f
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0x80);
|
|
u8_array_push(out, 0x3f);
|
|
|
|
export_exr_write_string(out, "screenWindowCenter");
|
|
u8_array_push(out, 0);
|
|
|
|
export_exr_write_string(out, "v2f");
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 8);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
export_exr_write_string(out, "screenWindowWidth");
|
|
u8_array_push(out, 0);
|
|
|
|
export_exr_write_string(out, "float");
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 4);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
|
|
u8_array_push(out, 0); // 1.0f
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0x80);
|
|
u8_array_push(out, 0x3f);
|
|
|
|
u8_array_push(out, 0); // end of header
|
|
|
|
i32 channels = 4;
|
|
i32 byte_size = bits == 16 ? 2 : 4;
|
|
i32 k_header_size = out->length;
|
|
i32 k_scanline_table_size = 8 * height;
|
|
i32 pixel_row_size = width * 3 * byte_size;
|
|
i32 full_row_size = pixel_row_size + 8;
|
|
|
|
// line offset table
|
|
i32 ofs = k_header_size + k_scanline_table_size;
|
|
for (i32 y = 0; y < height; ++y) {
|
|
u8_array_push(out, ofs & 0xff);
|
|
u8_array_push(out, (ofs >> 8) & 0xff);
|
|
u8_array_push(out, (ofs >> 16) & 0xff);
|
|
u8_array_push(out, (ofs >> 24) & 0xff);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
u8_array_push(out, 0);
|
|
ofs += full_row_size;
|
|
}
|
|
|
|
// scanline data
|
|
i32 stride = channels * byte_size;
|
|
i32 pos = 0;
|
|
|
|
_export_exr_width = width;
|
|
_export_exr_stride = stride;
|
|
gc_unroot(_export_exr_out);
|
|
_export_exr_out = out;
|
|
gc_root(_export_exr_out);
|
|
gc_unroot(_export_exr_src_view);
|
|
_export_exr_src_view = src;
|
|
gc_root(_export_exr_src_view);
|
|
gc_unroot(_export_exr_write_line);
|
|
_export_exr_write_line = bits == 16 ? export_exr_write_line16 : export_exr_write_line32;
|
|
gc_root(_export_exr_write_line);
|
|
void (*write_data)(i32, i32, i32) = type == 1 ? export_exr_write_bgr : export_exr_write_single;
|
|
|
|
for (i32 y = 0; y < height; ++y) {
|
|
// coordinate
|
|
u8_array_push(out, y & 0xff);
|
|
u8_array_push(out, (y >> 8) & 0xff);
|
|
u8_array_push(out, (y >> 16) & 0xff);
|
|
u8_array_push(out, (y >> 24) & 0xff);
|
|
// data size
|
|
u8_array_push(out, pixel_row_size & 0xff);
|
|
u8_array_push(out, (pixel_row_size >> 8) & 0xff);
|
|
u8_array_push(out, (pixel_row_size >> 16) & 0xff);
|
|
u8_array_push(out, (pixel_row_size >> 24) & 0xff);
|
|
// data
|
|
write_data(off, pos, byte_size);
|
|
pos += width * stride;
|
|
}
|
|
|
|
return out;
|
|
}
|