2026-03-09 13:17:15 +01:00
|
|
|
|
|
|
|
|
#include "../global.h"
|
|
|
|
|
|
2026-04-05 16:09:00 +02:00
|
|
|
char *parser_material_tex_coord = "tex_coord";
|
|
|
|
|
|
2026-04-04 21:38:20 +02:00
|
|
|
bind_tex_t *parser_material_make_texture(ui_node_t *image_node, char *tex_name) {
|
|
|
|
|
i32 i = image_node->buttons->buffer[0]->default_value->buffer[0];
|
|
|
|
|
if (i > 9000) { // 9999 - Texture deleted, use pink now
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
char *filepath = parser_material_enum_data(base_combo_enum_texts(image_node->type)->buffer[i]);
|
|
|
|
|
if (string_equals(filepath, "") || string_index_of(filepath, ".") == -1) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return parser_material_make_bind_tex(tex_name, filepath);
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-07 21:12:59 +01:00
|
|
|
char *parser_material_texture_store(ui_node_t *node, bind_tex_t *tex, char *tex_name, i32 color_space) {
|
2026-03-06 12:56:38 +01:00
|
|
|
any_array_push(parser_material_matcon->bind_textures, tex);
|
|
|
|
|
node_shader_context_add_elem(parser_material_kong->context, "tex", "short2norm");
|
2026-03-10 11:49:57 +01:00
|
|
|
node_shader_add_texture(parser_material_kong, tex_name, NULL);
|
2026-03-07 21:12:59 +01:00
|
|
|
char *uv_name = "";
|
|
|
|
|
if (string_equals(node->type, "TEX_IMAGE") && parser_material_get_input_link(node->inputs->buffer[0]) != NULL) {
|
2026-03-06 12:56:38 +01:00
|
|
|
uv_name = string_copy(parser_material_parse_vector_input(node->inputs->buffer[0]));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
uv_name = string_copy(parser_material_tex_coord);
|
|
|
|
|
}
|
2026-03-07 21:12:59 +01:00
|
|
|
char *tex_store = parser_material_store_var_name(node);
|
2026-03-06 12:56:38 +01:00
|
|
|
if (parser_material_sample_keep_aspect) {
|
2026-03-10 11:49:57 +01:00
|
|
|
node_shader_add_constant(parser_material_kong, string("%s_size: float2", tex_name), string("_size(%s)", tex_name));
|
|
|
|
|
parser_material_write(parser_material_kong, string("var %s_size: float2 = constants.%s_size;", tex_store, tex_name));
|
|
|
|
|
parser_material_write(parser_material_kong, string("var %s_ax: float = %s_size.x / %s_size.y;", tex_store, tex_store, tex_store));
|
|
|
|
|
parser_material_write(parser_material_kong, string("var %s_ay: float = %s_size.y / %s_size.x;", tex_store, tex_store, tex_store));
|
2026-03-06 12:56:38 +01:00
|
|
|
parser_material_write(
|
|
|
|
|
parser_material_kong,
|
2026-03-10 11:49:57 +01:00
|
|
|
string("var %s_uv: float2 = ((%s.xy / float(%s) - float2(0.5, 0.5)) * float2(max(%s_ay, 1.0), max(%s_ax, 1.0))) + float2(0.5, 0.5);", tex_store,
|
|
|
|
|
uv_name, parser_material_sample_uv_scale, tex_store, tex_store));
|
|
|
|
|
parser_material_write(parser_material_kong, string("if (%s_uv.x < 0.0 || %s_uv.y < 0.0 || %s_uv.x > 1.0 || %s_uv.y > 1.0) { discard; }", tex_store,
|
|
|
|
|
tex_store, tex_store, tex_store));
|
|
|
|
|
parser_material_write(parser_material_kong, string("%s_uv = %s_uv * float(%s);", tex_store, tex_store, parser_material_sample_uv_scale));
|
|
|
|
|
uv_name = string("%s_uv", tex_store);
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
if (parser_material_triplanar) {
|
2026-04-16 15:03:05 +02:00
|
|
|
if (!string_equals(uv_name, parser_material_tex_coord)) {
|
|
|
|
|
parser_material_write(parser_material_kong, string("var %s1: float3 = %s;", uv_name, uv_name));
|
|
|
|
|
parser_material_write(parser_material_kong, string("var %s2: float3 = %s;", uv_name, uv_name));
|
|
|
|
|
}
|
2026-03-10 11:49:57 +01:00
|
|
|
parser_material_write(parser_material_kong, string("var %s: float4 = float4(0.0, 0.0, 0.0, 0.0);", tex_store));
|
|
|
|
|
parser_material_write(parser_material_kong, string("if (tex_coord_blend.x > 0.0) {%s += sample(%s, sampler_linear, %s.xy) * tex_coord_blend.x; }",
|
|
|
|
|
tex_store, tex_name, uv_name));
|
|
|
|
|
parser_material_write(parser_material_kong, string("if (tex_coord_blend.y > 0.0) {%s += sample(%s, sampler_linear, %s1.xy) * tex_coord_blend.y; }",
|
|
|
|
|
tex_store, tex_name, uv_name));
|
|
|
|
|
parser_material_write(parser_material_kong, string("if (tex_coord_blend.z > 0.0) {%s += sample(%s, sampler_linear, %s2.xy) * tex_coord_blend.z; }",
|
|
|
|
|
tex_store, tex_name, uv_name));
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (parser_material_is_frag) {
|
2026-03-10 11:49:57 +01:00
|
|
|
any_map_set(parser_material_texture_map, tex_store, string("sample(%s, sampler_linear, %s.xy)", tex_name, uv_name));
|
|
|
|
|
parser_material_write(parser_material_kong, string("var %s: float4 = sample(%s, sampler_linear, %s.xy);", tex_store, tex_name, uv_name));
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2026-03-10 11:49:57 +01:00
|
|
|
any_map_set(parser_material_texture_map, tex_store, string("sample_lod(%s, sampler_linear, %s.xy, 0.0)", tex_name, uv_name));
|
|
|
|
|
parser_material_write(parser_material_kong, string("var %s: float4 = sample_lod(%s, sampler_linear, %s.xy, 0.0);", tex_store, tex_name, uv_name));
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
if (!ends_with(tex->file, ".jpg")) { // Pre-mult alpha
|
2026-03-10 11:49:57 +01:00
|
|
|
parser_material_write(parser_material_kong, string("%s.rgb = %s.rgb * %s.a;", tex_store, tex_store, tex_store));
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (parser_material_transform_color_space) {
|
|
|
|
|
// Base color socket auto-converts from sRGB to linear
|
|
|
|
|
if (color_space == COLOR_SPACE_LINEAR && parser_material_parsing_basecolor) { // Linear to sRGB
|
2026-03-10 11:49:57 +01:00
|
|
|
parser_material_write(parser_material_kong, string("%s.rgb = pow3(%s.rgb, float3(2.2, 2.2, 2.2));", tex_store, tex_store));
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
else if (color_space == COLOR_SPACE_SRGB && !parser_material_parsing_basecolor) { // sRGB to linear
|
2026-03-10 11:49:57 +01:00
|
|
|
parser_material_write(parser_material_kong, string("%s.rgb = pow3(%s.rgb, float3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2));", tex_store, tex_store));
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
else if (color_space == COLOR_SPACE_DIRECTX_NORMAL_MAP) { // DirectX normal map to OpenGL normal map
|
2026-03-10 11:49:57 +01:00
|
|
|
parser_material_write(parser_material_kong, string("%s.y = 1.0 - %s.y;", tex_store, tex_store));
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return tex_store;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 21:12:59 +01:00
|
|
|
char *image_texture_node_vector(ui_node_t *node, ui_node_socket_t *socket) {
|
2026-03-06 12:56:38 +01:00
|
|
|
// Already fetched
|
2026-03-15 10:47:53 +01:00
|
|
|
if (string_array_index_of(parser_material_parsed, parser_material_res_var_name(node, node->outputs->buffer[1])) >= 0) { // TODO: node.outputs[0]
|
2026-03-07 21:12:59 +01:00
|
|
|
char *varname = parser_material_store_var_name(node);
|
2026-03-10 11:49:57 +01:00
|
|
|
return string("%s.rgb", varname);
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
2026-03-10 11:49:57 +01:00
|
|
|
char *tex_name = parser_material_node_name(node, NULL);
|
2026-03-06 12:56:38 +01:00
|
|
|
bind_tex_t *tex = parser_material_make_texture(node, tex_name);
|
2026-03-07 21:12:59 +01:00
|
|
|
if (tex != NULL) {
|
2026-03-10 11:49:57 +01:00
|
|
|
i32 color_space = node->buttons->buffer[1]->default_value->buffer[0];
|
2026-03-07 21:12:59 +01:00
|
|
|
char *texstore = parser_material_texture_store(node, tex, tex_name, color_space);
|
2026-03-10 11:49:57 +01:00
|
|
|
return string("%s.rgb", texstore);
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2026-03-07 21:12:59 +01:00
|
|
|
char *tex_store = parser_material_store_var_name(node); // Pink color for missing texture
|
2026-03-10 11:49:57 +01:00
|
|
|
parser_material_write(parser_material_kong, string("var %s: float4 = float4(1.0, 0.0, 1.0, 1.0);", tex_store));
|
|
|
|
|
return string("%s.rgb", tex_store);
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 21:12:59 +01:00
|
|
|
char *image_texture_node_value(ui_node_t *node, ui_node_socket_t *socket) {
|
2026-03-06 12:56:38 +01:00
|
|
|
// Already fetched
|
2026-03-15 10:47:53 +01:00
|
|
|
if (string_array_index_of(parser_material_parsed, parser_material_res_var_name(node, node->outputs->buffer[0])) >= 0) { // TODO: node.outputs[1]
|
2026-03-07 21:12:59 +01:00
|
|
|
char *varname = parser_material_store_var_name(node);
|
2026-03-10 11:49:57 +01:00
|
|
|
return string("%s.a", varname);
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
2026-03-10 11:49:57 +01:00
|
|
|
char *tex_name = parser_material_node_name(node, NULL);
|
2026-03-06 12:56:38 +01:00
|
|
|
bind_tex_t *tex = parser_material_make_texture(node, tex_name);
|
2026-03-07 21:12:59 +01:00
|
|
|
if (tex != NULL) {
|
2026-03-10 11:49:57 +01:00
|
|
|
i32 color_space = node->buttons->buffer[1]->default_value->buffer[0];
|
2026-03-07 21:12:59 +01:00
|
|
|
char *texstore = parser_material_texture_store(node, tex, tex_name, color_space);
|
2026-03-10 11:49:57 +01:00
|
|
|
return string("%s.a", texstore);
|
2026-03-06 12:56:38 +01:00
|
|
|
}
|
|
|
|
|
return "0.0";
|
|
|
|
|
}
|
2026-04-04 21:38:20 +02:00
|
|
|
|
|
|
|
|
void image_texture_node_init() {
|
|
|
|
|
|
2026-04-05 16:09:00 +02:00
|
|
|
char *image_texture_color_space_data = string("%s\n%s\n%s\n%s", _tr("Auto"), _tr("Linear"), _tr("sRGB"), _tr("DirectX Normal Map"));
|
|
|
|
|
ui_node_t *image_texture_node_def =
|
2026-04-04 21:38:20 +02:00
|
|
|
GC_ALLOC_INIT(ui_node_t, {.id = 0,
|
|
|
|
|
.name = _tr("Image Texture"),
|
|
|
|
|
.type = "TEX_IMAGE",
|
|
|
|
|
.x = 0,
|
|
|
|
|
.y = 0,
|
|
|
|
|
.color = 0xff4982a0,
|
|
|
|
|
.inputs = any_array_create_from_raw(
|
|
|
|
|
(void *[]){
|
|
|
|
|
GC_ALLOC_INIT(ui_node_socket_t, {.id = 0,
|
|
|
|
|
.node_id = 0,
|
|
|
|
|
.name = _tr("Vector"),
|
|
|
|
|
.type = "VECTOR",
|
|
|
|
|
.color = 0xff6363c7,
|
|
|
|
|
.default_value = f32_array_create_xyz(0.0, 0.0, 0.0),
|
|
|
|
|
.min = 0.0,
|
|
|
|
|
.max = 1.0,
|
|
|
|
|
.precision = 100,
|
|
|
|
|
.display = 0}),
|
|
|
|
|
},
|
|
|
|
|
1),
|
|
|
|
|
.outputs = any_array_create_from_raw(
|
|
|
|
|
(void *[]){
|
|
|
|
|
GC_ALLOC_INIT(ui_node_socket_t, {.id = 0,
|
|
|
|
|
.node_id = 0,
|
|
|
|
|
.name = _tr("Color"),
|
|
|
|
|
.type = "RGBA",
|
|
|
|
|
.color = 0xffc7c729,
|
|
|
|
|
.default_value = f32_array_create_xyzw(0.0, 0.0, 0.0, 1.0),
|
|
|
|
|
.min = 0.0,
|
|
|
|
|
.max = 1.0,
|
|
|
|
|
.precision = 100,
|
|
|
|
|
.display = 0}),
|
|
|
|
|
GC_ALLOC_INIT(ui_node_socket_t, {.id = 0,
|
|
|
|
|
.node_id = 0,
|
|
|
|
|
.name = _tr("Alpha"),
|
|
|
|
|
.type = "VALUE",
|
|
|
|
|
.color = 0xffa1a1a1,
|
|
|
|
|
.default_value = f32_array_create_x(1.0),
|
|
|
|
|
.min = 0.0,
|
|
|
|
|
.max = 1.0,
|
|
|
|
|
.precision = 100,
|
|
|
|
|
.display = 0}),
|
|
|
|
|
},
|
|
|
|
|
2),
|
|
|
|
|
.buttons = any_array_create_from_raw(
|
|
|
|
|
(void *[]){
|
|
|
|
|
GC_ALLOC_INIT(ui_node_button_t, {.name = _tr("File"),
|
|
|
|
|
.type = "ENUM",
|
|
|
|
|
.output = -1,
|
|
|
|
|
.default_value = f32_array_create_x(0),
|
|
|
|
|
.data = u8_array_create_from_string(""),
|
|
|
|
|
.min = 0.0,
|
|
|
|
|
.max = 1.0,
|
|
|
|
|
.precision = 100,
|
|
|
|
|
.height = 0}),
|
|
|
|
|
GC_ALLOC_INIT(ui_node_button_t, {.name = _tr("Color Space"),
|
|
|
|
|
.type = "ENUM",
|
|
|
|
|
.output = -1,
|
|
|
|
|
.default_value = f32_array_create_x(0),
|
|
|
|
|
.data = u8_array_create_from_string(image_texture_color_space_data),
|
|
|
|
|
.min = 0.0,
|
|
|
|
|
.max = 1.0,
|
|
|
|
|
.precision = 100,
|
|
|
|
|
.height = 0}),
|
|
|
|
|
},
|
|
|
|
|
2),
|
|
|
|
|
.width = 0,
|
|
|
|
|
.flags = 0});
|
|
|
|
|
|
|
|
|
|
any_array_push(nodes_material_texture, image_texture_node_def);
|
|
|
|
|
any_map_set(parser_material_node_vectors, "TEX_IMAGE", image_texture_node_vector);
|
|
|
|
|
any_map_set(parser_material_node_values, "TEX_IMAGE", image_texture_node_value);
|
|
|
|
|
}
|