Ver Fonte

Add primitive io_exr

luboslenco há 5 dias atrás
pai
commit
c998d7c263

+ 6 - 2
base/sources/plugins/plugin_api.c

@@ -409,7 +409,11 @@ FN(gpu_create_texture_from_bytes) {
 	JS_ToInt64(ctx, &w, argv[1]);
 	int64_t h;
 	JS_ToInt64(ctx, &h, argv[2]);
-	uint64_t result = (uint64_t)gpu_create_texture_from_bytes(&b, w, h, 0);
+	int64_t format = 0;
+	if (argc > 3) {
+		JS_ToInt64(ctx, &format, argv[3]);
+	}
+	uint64_t result = (uint64_t)gpu_create_texture_from_bytes(&b, w, h, format);
 	return JS_NewBigUint64(ctx, result);
 }
 
@@ -596,7 +600,7 @@ void plugin_api_init() {
 	BIND(data_get_blob, 1);
 	BIND(data_delete_blob, 1);
 	BIND(iron_file_save_bytes, 3);
-	BIND(gpu_create_texture_from_bytes, 3);
+	BIND(gpu_create_texture_from_bytes, 4);
 
 	BIND(ui_handle_create, 0);
 	BIND(ui_handle_set_value, 2);

+ 12 - 0
paint/assets/plugins/import_exr.js

@@ -0,0 +1,12 @@
+
+function import_exr(path) {
+	let b = data_get_blob(path);
+	data_delete_blob(path);
+	return io_exr_parse(b);
+}
+
+let plugin = plugin_create();
+path_texture_importers_set("exr", import_exr);
+plugin_notify_on_delete(plugin, function() {
+	path_texture_importers_delete("exr");
+});

+ 175 - 0
paint/plugins/io_exr/io_exr.c

@@ -0,0 +1,175 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include "iron_array.h"
+#include "iron_gpu.h"
+void *gpu_create_texture_from_bytes(void *buffer, int width, int height, int format);
+void console_info(char *s);
+
+typedef struct {
+	char name[256];
+	int pixel_type;
+} channel_t;
+
+void *io_exr_parse(uint8_t *buf) {
+	if (buf[0] != 0x76 || buf[1] != 0x2f || buf[2] != 0x31 || buf[3] != 0x01) {
+		return NULL;
+	}
+	size_t pos = 0;
+	pos += 4;
+	pos += 4; // version
+
+	int width = 0;
+	int height = 0;
+	int bits = 16;
+	int pixel_type = 0;
+	channel_t channels[4];
+	int num_channels = 0;
+
+	while (1) {
+		char name[256];
+		int i = 0;
+		while (buf[pos] != 0) {
+			name[i++] = (char)buf[pos];
+			pos++;
+		}
+		name[i] = 0;
+		pos++; // null
+
+		if (strlen(name) == 0) {
+			break; // end of header
+		}
+
+		char attr_type[256];
+		i = 0;
+		while (buf[pos] != 0) {
+			attr_type[i++] = (char)buf[pos];
+			pos++;
+		}
+		attr_type[i] = 0;
+		pos++; // null
+
+		uint32_t attr_size = *(uint32_t *)(buf + pos);
+		pos += 4;
+
+		if (strcmp(name, "channels") == 0 && strcmp(attr_type, "chlist") == 0) {
+			size_t chpos = pos;
+			while (1) {
+				char chname[256];
+				i = 0;
+				while (buf[chpos] != 0) {
+					chname[i++] = (char)buf[chpos];
+					chpos++;
+				}
+				chname[i] = 0;
+				chpos++; // null
+				if (strlen(chname) == 0) {
+					break;
+				}
+
+				int32_t chpixel_type = *(int32_t *)(buf + chpos); chpos += 4;
+				chpos += 4; // pLinear
+				chpos += 4; // reserved
+				chpos += 4; // xSampling
+				chpos += 4; // ySampling
+				strcpy(channels[num_channels].name, chname);
+				channels[num_channels].pixel_type = chpixel_type;
+				num_channels++;
+			}
+		}
+		else if (strcmp(name, "dataWindow") == 0 || strcmp(name, "displayWindow") == 0) {
+			int32_t xMin = *(int32_t *)(buf + pos);
+			int32_t yMin = *(int32_t *)(buf + pos + 4);
+			int32_t xMax = *(int32_t *)(buf + pos + 8);
+			int32_t yMax = *(int32_t *)(buf + pos + 12);
+			if (strcmp(name, "dataWindow") == 0) {
+				width = xMax - xMin + 1;
+				height = yMax - yMin + 1;
+			}
+		}
+		else if (strcmp(name, "compression") == 0) {
+			uint8_t comp = buf[pos];
+			if (comp != 0) {
+				console_info("Error: Compressed exr files not yet implemented");
+				return NULL;
+			}
+		}
+		pos += attr_size;
+	}
+
+	pixel_type = channels[0].pixel_type;
+	bits = (pixel_type == 1) ? 16 : 32;
+
+	uint32_t *line_offset_table = (uint32_t *)malloc(height * sizeof(uint32_t));
+	for (int y = 0; y < height; y++) {
+		uint32_t lo = *(uint32_t *)(buf + pos);
+		line_offset_table[y] = lo;
+		pos += 8;
+	}
+
+	int is_bgr = (num_channels == 3 && strcmp(channels[0].name, "B") == 0 && strcmp(channels[1].name, "G") == 0 && strcmp(channels[2].name, "R") == 0);
+	int is_16bit = (bits == 16);
+	int channel_bytes = is_16bit ? 2 : 4;
+	size_t image_size = (size_t)width * height * 4 * channel_bytes;
+	uint8_t *pixels = (uint8_t *)malloc(image_size);
+
+	for (int y = 0; y < height; y++) {
+		uint32_t scan_line_pos = line_offset_table[y];
+		uint32_t off = scan_line_pos + 8;
+
+		for (int x = 0; x < width; x++) {
+			size_t outi = ((size_t)y * width + x) * 4 * channel_bytes;
+			float r = 0.0f;
+			float g = 0.0f;
+			float b = 0.0f;
+			float a = 1.0f;
+
+			if (is_bgr) {
+				if (is_16bit) {
+					uint16_t b_h = *(uint16_t *)(buf + off); off += 2;
+					uint16_t g_h = *(uint16_t *)(buf + off); off += 2;
+					uint16_t r_h = *(uint16_t *)(buf + off); off += 2;
+					*(uint16_t *)(pixels + outi + 0 * channel_bytes) = r_h;
+					*(uint16_t *)(pixels + outi + 1 * channel_bytes) = g_h;
+					*(uint16_t *)(pixels + outi + 2 * channel_bytes) = b_h;
+					*(uint16_t *)(pixels + outi + 3 * channel_bytes) = 0x3c00;
+				}
+				else {
+					float b = *(float *)(buf + off); off += 4;
+					float g = *(float *)(buf + off); off += 4;
+					float r = *(float *)(buf + off); off += 4;
+					*(float *)(pixels + outi + 0) = r;
+					*(float *)(pixels + outi + 4) = g;
+					*(float *)(pixels + outi + 8) = b;
+					*(float *)(pixels + outi + 12) = a;
+				}
+			}
+			else {
+				if (is_16bit) {
+					uint16_t v_h = *(uint16_t *)(buf + off); off += 2;
+					*(uint16_t *)(pixels + outi + 0 * channel_bytes) = v_h;
+					*(uint16_t *)(pixels + outi + 1 * channel_bytes) = v_h;
+					*(uint16_t *)(pixels + outi + 2 * channel_bytes) = v_h;
+					*(uint16_t *)(pixels + outi + 3 * channel_bytes) = 0x3c00;
+				}
+				else {
+					float v = *(float *)(buf + off); off += 4;
+					*(float *)(pixels + outi + 0) = v;
+					*(float *)(pixels + outi + 4) = v;
+					*(float *)(pixels + outi + 8) = v;
+					*(float *)(pixels + outi + 12) = a;
+				}
+			}
+		}
+	}
+
+	free(line_offset_table);
+
+	buffer_t *b = (buffer_t *)malloc(sizeof(buffer_t));
+	b->buffer = pixels;
+	b->length = b->capacity = (uint32_t)image_size;
+	int format = is_16bit ? GPU_TEXTURE_FORMAT_RGBA64 : GPU_TEXTURE_FORMAT_RGBA128;
+	return gpu_create_texture_from_bytes(b, width, height, format);
+}

+ 8 - 0
paint/plugins/plugins.c

@@ -26,6 +26,13 @@ FN(io_svg_parse) {
 	return JS_NewBigUint64(ctx, (uint64_t)io_svg_parse(ab));
 }
 
+void *io_exr_parse(char *buf);
+FN(io_exr_parse) {
+	size_t len;
+	void *ab = JS_GetArrayBuffer(ctx, &len, argv[0]);
+	return JS_NewBigUint64(ctx, (uint64_t)io_exr_parse(ab));
+}
+
 void *io_usd_parse(char *buf, size_t size);
 FN(io_usd_parse) {
 	size_t len;
@@ -258,6 +265,7 @@ void plugin_embed() {
 	BIND(proc_xatlas_unwrap, 1);
 	BIND(plugin_uv_unwrap_button, 0);
 	BIND(io_svg_parse, 1);
+	BIND(io_exr_parse, 1);
 	BIND(io_usd_parse, 1);
 	BIND(io_gltf_parse, 2);
 	BIND(io_fbx_parse, 1);

+ 1 - 0
paint/plugins/project.js

@@ -3,6 +3,7 @@ let project = new Project("plugins");
 project.add_cfiles("plugins.c");
 project.add_cfiles("proc_xatlas/**");
 project.add_cfiles("io_svg/**");
+project.add_cfiles("io_exr/**");
 project.add_cfiles("io_usd/**");
 project.add_define("TINYUSDZ_NO_STB_IMAGE_IMPLEMENTATION");
 project.add_cfiles("io_gltf/**");

+ 4 - 1
paint/sources/import_texture.ts

@@ -51,7 +51,10 @@ function import_texture_run(path: string, hdr_as_envmap: bool = true) {
 	array_push(project_asset_names, name);
 	map_set(project_asset_map, asset.id, image);
 	ui_base_hwnds[tab_area_t.STATUS].redraws = 2;
-	console_info(tr("Texture imported:") + " " + name);
+
+	if (image != null) {
+		console_info(tr("Texture imported:") + " " + name);
+	}
 
 	// Set as envmap
 	if (hdr_as_envmap && ends_with(to_lower_case(path), ".hdr")) {