563 lines
20 KiB
C
563 lines
20 KiB
C
|
|
#include "global.h"
|
|
|
|
ui_node_t *parser_material_get_node(i32 id) {
|
|
for (i32 i = 0; i < parser_material_nodes->length; ++i) {
|
|
ui_node_t *n = parser_material_nodes->buffer[i];
|
|
if (n->id == id) {
|
|
return n;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
ui_node_link_t *parser_material_get_input_link(ui_node_socket_t *inp) {
|
|
for (i32 i = 0; i < parser_material_links->length; ++i) {
|
|
ui_node_link_t *l = parser_material_links->buffer[i];
|
|
if (l->to_id == inp->node_id) {
|
|
ui_node_t *node = parser_material_get_node(inp->node_id);
|
|
if (node->inputs->length <= l->to_socket) {
|
|
return NULL;
|
|
}
|
|
if (node->inputs->buffer[l->to_socket] == inp) {
|
|
return l;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool parser_material_owns_parents = false;
|
|
|
|
static void parser_material_free_scratch() {
|
|
array_delete(parser_material_parsed);
|
|
parser_material_parsed = NULL;
|
|
if (parser_material_owns_parents) {
|
|
array_delete(parser_material_parents);
|
|
}
|
|
parser_material_parents = NULL;
|
|
parser_material_owns_parents = false;
|
|
array_delete(parser_material_canvases);
|
|
parser_material_canvases = NULL;
|
|
}
|
|
|
|
void parser_material_init() {
|
|
parser_material_free_scratch();
|
|
|
|
parser_material_parsed = any_array_create_from_raw((void *[]){}, 0);
|
|
|
|
parser_material_parents = any_array_create_from_raw((void *[]){}, 0);
|
|
parser_material_owns_parents = true;
|
|
|
|
parser_material_out_normaltan = "float3(0.5, 0.5, 1.0)";
|
|
|
|
parser_material_script_links = NULL;
|
|
parser_material_parsing_basecolor = false;
|
|
}
|
|
|
|
bool parser_material_is_default_normal(char *s) {
|
|
// Enable height socket when normal map socket is not connected for now
|
|
return string_equals(s, "float3(0.500000, 0.500000, 1.000000)");
|
|
}
|
|
|
|
void parse_normal_map_color_input(ui_node_socket_t *inp) {
|
|
parser_material_kong->frag_write_normal++;
|
|
parser_material_out_normaltan = parser_material_parse_vector_input(inp);
|
|
bool _parser_material_is_frag = parser_material_is_frag;
|
|
parser_material_is_frag = true;
|
|
parser_material_is_frag = _parser_material_is_frag;
|
|
parser_material_kong->frag_write_normal--;
|
|
}
|
|
|
|
shader_out_t *parser_material_parse_shader(ui_node_t *node, ui_node_socket_t *socket) {
|
|
shader_out_t *sout = TMP_ALLOC_INIT(shader_out_t, {.out_basecol = "float3(0.8, 0.8, 0.8)",
|
|
.out_roughness = "0.0",
|
|
.out_metallic = "0.0",
|
|
.out_occlusion = "1.0",
|
|
.out_opacity = "1.0",
|
|
.out_height = "0.0",
|
|
.out_emission = "0.0",
|
|
.out_subsurface = "0.0"});
|
|
if (string_equals(node->type, "OUTPUT_MATERIAL_PBR")) {
|
|
|
|
// Normal - parsed first to retrieve uv coords
|
|
parse_normal_map_color_input(node->inputs->buffer[5]);
|
|
// Base color
|
|
parser_material_parsing_basecolor = true;
|
|
sout->out_basecol = parser_material_parse_vector_input(node->inputs->buffer[0]);
|
|
parser_material_parsing_basecolor = false;
|
|
// Occlusion
|
|
sout->out_occlusion = parser_material_parse_value_input(node->inputs->buffer[2], false);
|
|
// Roughness
|
|
sout->out_roughness = parser_material_parse_value_input(node->inputs->buffer[3], false);
|
|
// Metallic
|
|
sout->out_metallic = parser_material_parse_value_input(node->inputs->buffer[4], false);
|
|
// Emission
|
|
if (parser_material_parse_emission) {
|
|
sout->out_emission = parser_material_parse_value_input(node->inputs->buffer[6], false);
|
|
}
|
|
// Subsurface
|
|
if (parser_material_parse_subsurface) {
|
|
sout->out_subsurface = parser_material_parse_value_input(node->inputs->buffer[8], false);
|
|
}
|
|
// Opacity
|
|
sout->out_opacity = parser_material_parse_value_input(node->inputs->buffer[1], false);
|
|
// Height
|
|
if (parser_material_parse_height && parser_material_is_default_normal(parser_material_out_normaltan)) {
|
|
sout->out_height = parser_material_parse_value_input(node->inputs->buffer[7], false);
|
|
}
|
|
}
|
|
return sout;
|
|
}
|
|
|
|
shader_out_t *parser_material_parse_shader_input(ui_node_socket_t *inp) {
|
|
ui_node_link_t *l = parser_material_get_input_link(inp);
|
|
ui_node_t *from_node = l != NULL ? parser_material_get_node(l->from_id) : NULL;
|
|
if (from_node != NULL) {
|
|
return parser_material_parse_shader(from_node, from_node->outputs->buffer[l->from_socket]);
|
|
}
|
|
else {
|
|
shader_out_t *sout = TMP_ALLOC_INIT(shader_out_t, {.out_basecol = "float3(0.8, 0.8, 0.8)",
|
|
.out_roughness = "0.0",
|
|
.out_metallic = "0.0",
|
|
.out_occlusion = "1.0",
|
|
.out_opacity = "1.0",
|
|
.out_height = "0.0",
|
|
.out_emission = "0.0",
|
|
.out_subsurface = "0.0"});
|
|
return sout;
|
|
}
|
|
}
|
|
|
|
shader_out_t *parser_material_parse_output_pbr(ui_node_t *node) {
|
|
return parser_material_parse_shader(node, NULL);
|
|
}
|
|
|
|
shader_out_t *parser_material_parse(ui_node_canvas_t *canvas, node_shader_context_t *_con, node_shader_t *_kong) {
|
|
parser_material_init();
|
|
parser_material_canvases = any_array_create_from_raw(
|
|
(void *[]){
|
|
canvas,
|
|
},
|
|
1);
|
|
parser_material_nodes = canvas->nodes;
|
|
parser_material_links = canvas->links;
|
|
parser_material_con = _con;
|
|
parser_material_kong = _kong;
|
|
|
|
if (parser_material_start_group != NULL) {
|
|
parser_material_push_group(parser_material_start_group);
|
|
array_delete(parser_material_parents);
|
|
parser_material_parents = parser_material_start_parents;
|
|
parser_material_owns_parents = false;
|
|
}
|
|
|
|
if (parser_material_start_node != NULL) {
|
|
ui_node_link_t *link =
|
|
TMP_ALLOC_INIT(ui_node_link_t, {.id = 99999, .from_id = parser_material_start_node->id, .from_socket = 0, .to_id = -1, .to_socket = -1});
|
|
parser_material_write_result(link);
|
|
shader_out_t *sout = TMP_ALLOC_INIT(shader_out_t, {.out_basecol = "float3(0.0, 0.0, 0.0)",
|
|
.out_roughness = "0.0",
|
|
.out_metallic = "0.0",
|
|
.out_occlusion = "1.0",
|
|
.out_opacity = "1.0",
|
|
.out_height = "0.0",
|
|
.out_emission = "0.0",
|
|
.out_subsurface = "0.0"});
|
|
return sout;
|
|
}
|
|
|
|
ui_node_t *output_node = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR");
|
|
if (output_node != NULL) {
|
|
return parser_material_parse_output_pbr(output_node);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void parser_material_finalize(node_shader_context_t *con) {
|
|
node_shader_t *kong = con->kong;
|
|
|
|
if (kong->frag_dotnv) {
|
|
kong->frag_vvec = true;
|
|
kong->frag_n = true;
|
|
}
|
|
if (kong->frag_vvec) {
|
|
kong->frag_wposition = true;
|
|
}
|
|
|
|
if (kong->frag_bposition) {
|
|
if (parser_material_triplanar) {
|
|
node_shader_write_attrib_frag(kong, "var bposition: float3 = float3(\
|
|
tex_coord1.x * tex_coord_blend.y + tex_coord2.x * tex_coord_blend.z,\
|
|
tex_coord.x * tex_coord_blend.x + tex_coord2.y * tex_coord_blend.z,\
|
|
tex_coord.y * tex_coord_blend.x + tex_coord1.y * tex_coord_blend.y);");
|
|
}
|
|
else if (kong->frag_ndcpos) {
|
|
node_shader_add_out(kong, "_bposition: float3");
|
|
node_shader_write_vert(kong, "output._bposition = (output.ndc.xyz / output.ndc.w);");
|
|
node_shader_write_attrib_frag(kong, "var bposition: float3 = input._bposition;");
|
|
}
|
|
else {
|
|
node_shader_add_out(kong, "_bposition: float3");
|
|
node_shader_add_constant(kong, "dim: float3", "_dim");
|
|
node_shader_add_constant(kong, "hdim: float3", "_half_dim");
|
|
node_shader_write_attrib_vert(kong, "output._bposition = (input.pos.xyz + constants.hdim) / constants.dim;");
|
|
node_shader_write_attrib_frag(kong, "var bposition: float3 = input._bposition;");
|
|
}
|
|
}
|
|
if (kong->frag_wposition) {
|
|
node_shader_add_constant(kong, "W: float4x4", "_world_matrix");
|
|
node_shader_add_out(kong, "wposition: float3");
|
|
node_shader_write_attrib_vert(kong, "output.wposition = (constants.W * float4(input.pos.xyz, 1.0)).xyz;");
|
|
}
|
|
if (kong->frag_vposition) {
|
|
node_shader_add_constant(kong, "WV: float4x4", "_world_view_matrix");
|
|
node_shader_add_out(kong, "vposition: float3");
|
|
node_shader_write_attrib_vert(kong, "output.vposition = (constants.WV * float4(input.pos.xyz, 1.0)).xyz;");
|
|
}
|
|
if (kong->frag_mposition) {
|
|
node_shader_add_out(kong, "mposition: float3");
|
|
if (kong->frag_ndcpos) {
|
|
node_shader_write_vert(kong, "output.mposition = (output.ndc.xyz / output.ndc.w);");
|
|
}
|
|
else {
|
|
node_shader_write_attrib_vert(kong, "output.mposition = input.pos.xyz;");
|
|
}
|
|
}
|
|
if (kong->frag_wtangent) {
|
|
node_shader_add_out(kong, "wtangent: float3");
|
|
node_shader_write_attrib_vert(kong, "output.wtangent = float3(0.0, 0.0, 0.0);");
|
|
}
|
|
if (kong->frag_vvec_cam) {
|
|
node_shader_add_constant(kong, "WV: float4x4", "_world_view_matrix");
|
|
node_shader_add_out(kong, "eye_dir_cam: float3");
|
|
node_shader_write_attrib_vert(kong, "output.eye_dir_cam = (constants.WV * float4(input.pos.xyz, 1.0)).xyz;");
|
|
node_shader_write_attrib_vert(kong, "output.eye_dir_cam.z *= -1.0;");
|
|
node_shader_write_attrib_frag(kong, "var vvec_cam: float3 = normalize(input.eye_dir_cam);");
|
|
}
|
|
if (kong->frag_vvec) {
|
|
node_shader_add_constant(kong, "eye: float3", "_camera_pos");
|
|
node_shader_add_out(kong, "eye_dir: float3");
|
|
node_shader_write_attrib_vert(kong, "output.eye_dir = constants.eye - output.wposition;");
|
|
node_shader_write_attrib_frag(kong, "var vvec: float3 = normalize(input.eye_dir);");
|
|
}
|
|
if (kong->frag_n) {
|
|
node_shader_add_constant(kong, "N: float3x3", "_normal_matrix");
|
|
node_shader_add_out(kong, "wnormal: float3");
|
|
node_shader_write_attrib_vert(kong, "output.wnormal = constants.N * float3(input.nor.xy, input.pos.w);");
|
|
node_shader_write_attrib_frag(kong, "var n: float3 = normalize(input.wnormal);");
|
|
}
|
|
if (kong->vert_n) {
|
|
node_shader_add_constant(kong, "N: float3x3", "_normal_matrix");
|
|
node_shader_write_attrib_vert(kong, "var vert_wnormal: float3 = normalize(constants.N * float3(input.nor.xy, input.pos.w));");
|
|
}
|
|
if (kong->frag_nattr) {
|
|
node_shader_add_out(kong, "nattr: float3");
|
|
node_shader_write_attrib_vert(kong, "output.nattr = float3(input.nor.xy, input.pos.w);");
|
|
}
|
|
if (kong->frag_dotnv) {
|
|
node_shader_write_attrib_frag(kong, "var dotnv: float = max(dot(n, vvec), 0.0);");
|
|
}
|
|
if (kong->frag_wvpposition) {
|
|
node_shader_add_out(kong, "wvpposition: float4");
|
|
node_shader_write_end_vert(kong, "output.wvpposition = output.pos;");
|
|
}
|
|
if (node_shader_context_is_elem(con, "col")) {
|
|
node_shader_add_out(kong, "vcolor: float3");
|
|
node_shader_write_attrib_vert(kong, "output.vcolor = input.col.rgb;");
|
|
}
|
|
}
|
|
|
|
ui_node_canvas_t *parser_material_get_group(char *name) {
|
|
for (i32 i = 0; i < g_project->_->material_groups->length; ++i) {
|
|
node_group_t *g = g_project->_->material_groups->buffer[i];
|
|
if (string_equals(g->canvas->name, name)) {
|
|
return g->canvas;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void parser_material_push_group(ui_node_canvas_t *g) {
|
|
any_array_push(parser_material_canvases, g);
|
|
parser_material_nodes = g->nodes;
|
|
parser_material_links = g->links;
|
|
}
|
|
|
|
void parser_material_pop_group() {
|
|
array_pop(parser_material_canvases);
|
|
ui_node_canvas_t *g = parser_material_canvases->buffer[parser_material_canvases->length - 1];
|
|
parser_material_nodes = g->nodes;
|
|
parser_material_links = g->links;
|
|
}
|
|
|
|
char *parser_material_parse_input(ui_node_socket_t *inp) {
|
|
if (string_equals(inp->type, "RGB")) {
|
|
return parser_material_parse_vector_input(inp);
|
|
}
|
|
else if (string_equals(inp->type, "RGBA")) {
|
|
return parser_material_parse_vector_input(inp);
|
|
}
|
|
else if (string_equals(inp->type, "VECTOR")) {
|
|
return parser_material_parse_vector_input(inp);
|
|
}
|
|
else if (string_equals(inp->type, "VALUE")) {
|
|
return parser_material_parse_value_input(inp, false);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
i32 parser_material_socket_index(ui_node_t *node, ui_node_socket_t *socket) {
|
|
for (i32 i = 0; i < node->outputs->length; ++i) {
|
|
if (node->outputs->buffer[i] == socket) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
char *parser_material_parse_group(ui_node_t *node, ui_node_socket_t *socket) {
|
|
any_array_push(parser_material_parents, node); // Entering group
|
|
parser_material_push_group(parser_material_get_group(node->name));
|
|
ui_node_t *output_node = parser_material_node_by_type(parser_material_nodes, "GROUP_OUTPUT");
|
|
if (output_node == NULL) {
|
|
return NULL;
|
|
}
|
|
i32 index = parser_material_socket_index(node, socket);
|
|
ui_node_socket_t *inp = output_node->inputs->buffer[index];
|
|
char *out_group = parser_material_parse_input(inp);
|
|
array_pop(parser_material_parents);
|
|
parser_material_pop_group();
|
|
return out_group;
|
|
}
|
|
|
|
char *parser_material_parse_group_input(ui_node_t *node, ui_node_socket_t *socket) {
|
|
ui_node_t *parent = array_pop(parser_material_parents); // Leaving group
|
|
parser_material_pop_group();
|
|
i32 index = parser_material_socket_index(node, socket);
|
|
ui_node_socket_t *inp = parent->inputs->buffer[index];
|
|
char *res = parser_material_parse_input(inp);
|
|
any_array_push(parser_material_parents, parent); // Return to group
|
|
parser_material_push_group(parser_material_get_group(parent->name));
|
|
return res;
|
|
}
|
|
|
|
void parser_material_write(node_shader_t *raw, char *s) {
|
|
if (parser_material_is_frag) {
|
|
node_shader_write_frag(raw, s);
|
|
}
|
|
else {
|
|
node_shader_write_vert(raw, s);
|
|
}
|
|
}
|
|
|
|
char *parser_material_parse_vector_input(ui_node_socket_t *inp) {
|
|
ui_node_link_t *l = parser_material_get_input_link(inp);
|
|
ui_node_t *from_node = l != NULL ? parser_material_get_node(l->from_id) : NULL;
|
|
if (from_node != NULL) {
|
|
char *res_var = parser_material_write_result(l);
|
|
char *st = from_node->outputs->buffer[l->from_socket]->type;
|
|
if (string_equals(st, "RGB") || string_equals(st, "RGBA") || string_equals(st, "VECTOR")) {
|
|
return res_var;
|
|
}
|
|
else { // VALUE
|
|
return parser_material_to_vec3(res_var);
|
|
}
|
|
}
|
|
else {
|
|
return parser_material_vec3(inp->default_value);
|
|
}
|
|
}
|
|
|
|
char *parser_material_parse_vector(ui_node_t *node, ui_node_socket_t *socket) {
|
|
char *(*node_vector)(ui_node_t *, ui_node_socket_t *) = any_map_get(parser_material_node_vectors, node->type);
|
|
if (node_vector != NULL) {
|
|
return node_vector(node, socket);
|
|
}
|
|
else if (string_equals(node->type, "GROUP_INPUT")) {
|
|
return parser_material_parse_group_input(node, socket);
|
|
}
|
|
else if (any_map_get(parser_material_custom_nodes, node->type) != NULL) {
|
|
void *cb = any_map_get(parser_material_custom_nodes, node->type);
|
|
minic_val_t args[2] = {minic_val_ptr(node), minic_val_ptr(socket->name)};
|
|
return minic_call_fn(cb, args, 2).p;
|
|
}
|
|
return "float3(0.0, 0.0, 0.0)";
|
|
}
|
|
|
|
char *parser_material_parse_value_input(ui_node_socket_t *inp, bool vector_as_grayscale) {
|
|
ui_node_link_t *l = parser_material_get_input_link(inp);
|
|
ui_node_t *from_node = l != NULL ? parser_material_get_node(l->from_id) : NULL;
|
|
if (from_node != NULL) {
|
|
char *res_var = parser_material_write_result(l);
|
|
char *st = from_node->outputs->buffer[l->from_socket]->type;
|
|
if (string_equals(st, "RGB") || string_equals(st, "RGBA") || string_equals(st, "VECTOR")) {
|
|
if (vector_as_grayscale) {
|
|
return string_tmp("dot(%s.rbg, float3(0.299, 0.587, 0.114))", res_var);
|
|
}
|
|
else {
|
|
return string_tmp("%s.x", res_var);
|
|
}
|
|
}
|
|
else { // VALUE
|
|
return res_var;
|
|
}
|
|
}
|
|
else {
|
|
return parser_material_vec1(inp->default_value->buffer[0]);
|
|
}
|
|
}
|
|
|
|
char *parser_material_parse_value(ui_node_t *node, ui_node_socket_t *socket) {
|
|
char *(*node_value)(ui_node_t *, ui_node_socket_t *) = any_map_get(parser_material_node_values, node->type);
|
|
if (node_value != NULL) {
|
|
return node_value(node, socket);
|
|
}
|
|
else if (string_equals(node->type, "GROUP_INPUT")) {
|
|
return parser_material_parse_group_input(node, socket);
|
|
}
|
|
else if (any_map_get(parser_material_custom_nodes, node->type) != NULL) {
|
|
void *cb = any_map_get(parser_material_custom_nodes, node->type);
|
|
minic_val_t args[2] = {minic_val_ptr(node), minic_val_ptr(socket->name)};
|
|
return minic_call_fn(cb, args, 2).p;
|
|
}
|
|
return "0.0";
|
|
}
|
|
|
|
char *parser_material_get_coord(ui_node_t *node) {
|
|
if (parser_material_get_input_link(node->inputs->buffer[0]) != NULL) {
|
|
return parser_material_parse_vector_input(node->inputs->buffer[0]);
|
|
}
|
|
else {
|
|
parser_material_kong->frag_bposition = true;
|
|
return "bposition";
|
|
}
|
|
}
|
|
|
|
char *parser_material_safesrc(char *s) {
|
|
i32 len = string_length(s);
|
|
bool lead_digit = len > 0 && s[0] >= '0' && s[0] <= '9';
|
|
i32 pos = 0;
|
|
char *r = string_tmp_alloc(len + (lead_digit ? 1 : 0) + 1);
|
|
if (lead_digit) {
|
|
r[pos++] = '_';
|
|
}
|
|
for (i32 i = 0; i < len; ++i) {
|
|
char c = s[i];
|
|
bool letter = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
|
|
bool digit = c >= '0' && c <= '9';
|
|
r[pos++] = (letter || digit) ? c : '_';
|
|
}
|
|
r[pos] = '\0';
|
|
return r;
|
|
}
|
|
|
|
char *parser_material_res_var_name(ui_node_t *node, ui_node_socket_t *socket) {
|
|
return string_tmp("%s_%s_res", parser_material_node_name(node, NULL), parser_material_safesrc(socket->name));
|
|
}
|
|
|
|
char *parser_material_write_result(ui_node_link_t *l) {
|
|
ui_node_t *from_node = parser_material_get_node(l->from_id);
|
|
ui_node_socket_t *from_socket = from_node->outputs->buffer[l->from_socket];
|
|
char *res_var = parser_material_res_var_name(from_node, from_socket);
|
|
char *st = from_socket->type;
|
|
if (string_array_index_of(parser_material_parsed, res_var) < 0) {
|
|
any_array_push(parser_material_parsed, res_var);
|
|
if (string_equals(st, "RGB") || string_equals(st, "RGBA") || string_equals(st, "VECTOR")) {
|
|
char *res = parser_material_parse_vector(from_node, from_socket);
|
|
if (res == NULL) {
|
|
return NULL;
|
|
}
|
|
parser_material_write(parser_material_kong, string_tmp("var %s: float3 = %s;", res_var, res));
|
|
}
|
|
else if (string_equals(st, "VALUE")) {
|
|
char *res = parser_material_parse_value(from_node, from_socket);
|
|
if (res == NULL) {
|
|
return NULL;
|
|
}
|
|
parser_material_write(parser_material_kong, string_tmp("var %s: float = %s;", res_var, res));
|
|
}
|
|
}
|
|
return res_var;
|
|
}
|
|
|
|
char *parser_material_store_var_name(ui_node_t *node) {
|
|
return string_tmp("%s_store", parser_material_node_name(node, NULL));
|
|
}
|
|
|
|
char *parser_material_vec1(f32 v) {
|
|
return f32_to_string_with_zeros(v);
|
|
// return "float(" + v + ")";
|
|
// return v + "";
|
|
}
|
|
|
|
char *parser_material_vec3(f32_array_t *v) {
|
|
// let v0: f32 = v[0];
|
|
// let v1: f32 = v[1];
|
|
// let v2: f32 = v[2];
|
|
char *v0 = f32_to_string_with_zeros(v->buffer[0]);
|
|
char *v1 = f32_to_string_with_zeros(v->buffer[1]);
|
|
char *v2 = f32_to_string_with_zeros(v->buffer[2]);
|
|
return string_tmp("float3(%s, %s, %s)", v0, v1, v2);
|
|
}
|
|
|
|
char *parser_material_to_vec3(char *s) {
|
|
// return "float3(" + s + ")";
|
|
return string_tmp("float3(%s, %s, %s)", s, s, s);
|
|
}
|
|
|
|
ui_node_t *parser_material_node_by_type(ui_node_t_array_t *nodes, char *ntype) {
|
|
for (i32 i = 0; i < nodes->length; ++i) {
|
|
ui_node_t *n = nodes->buffer[i];
|
|
if (string_equals(n->type, ntype)) {
|
|
return n;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
char *parser_material_node_name(ui_node_t *node, ui_node_t_array_t *_parents) {
|
|
if (_parents == NULL) {
|
|
_parents = parser_material_parents;
|
|
}
|
|
char *s = node->name;
|
|
for (i32 i = 0; i < _parents->length; ++i) {
|
|
ui_node_t *p = _parents->buffer[i];
|
|
s = string_tmp("%s%s_%s", p->name, i32_to_string(p->id), s);
|
|
}
|
|
s = parser_material_safesrc(s);
|
|
i32 nid = node->id;
|
|
s = string_tmp("%s%s", s, i32_to_string(nid));
|
|
return s;
|
|
}
|
|
|
|
char *parser_material_enum_data(char *s) {
|
|
for (i32 i = 0; i < g_project->_->assets->length; ++i) {
|
|
asset_t *a = g_project->_->assets->buffer[i];
|
|
if (string_equals(a->name, s)) {
|
|
return a->file;
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
bind_tex_t *parser_material_make_bind_tex(char *tex_name, char *file) {
|
|
bind_tex_t *tex = ALLOC_INIT(bind_tex_t, {.name = string_copy(tex_name), .file = string_copy(file)});
|
|
return tex;
|
|
}
|
|
|
|
char *u8_array_string_at(u8_array_t *a, i32 i) {
|
|
char *s = u8_array_to_string(a);
|
|
string_array_t *ss = string_split(s, "\n");
|
|
char *r = ss->buffer[i];
|
|
for (i32 j = 0; j < (i32)ss->length; ++j) {
|
|
if (j != i) {
|
|
free(ss->buffer[j]);
|
|
}
|
|
}
|
|
array_free(ss);
|
|
free(ss);
|
|
free(s);
|
|
return r;
|
|
}
|