parser_material.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. let parser_material_con: node_shader_context_t;
  2. let parser_material_kong: node_shader_t;
  3. let parser_material_matcon: material_context_t;
  4. let parser_material_parsed: string[];
  5. let parser_material_parents: ui_node_t[];
  6. let parser_material_canvases: ui_node_canvas_t[];
  7. let parser_material_nodes: ui_node_t[];
  8. let parser_material_links: ui_node_link_t[];
  9. let parser_material_cotangent_frame_written: bool;
  10. let parser_material_tex_coord: string = "tex_coord";
  11. let parser_material_eps: f32 = 0.000001;
  12. let parser_material_node_values: map_t<string, any> = map_create();
  13. let parser_material_node_vectors: map_t<string, any> = map_create();
  14. let parser_material_custom_nodes: map_t<string, any> = map_create(); // JSValue -> (n: ui_node_t, s: string)=>string
  15. let parser_material_parse_surface: bool = true;
  16. let parser_material_parse_opacity: bool = true;
  17. let parser_material_parse_height: bool = false;
  18. let parser_material_parse_height_as_channel: bool = false;
  19. let parser_material_parse_emission: bool = false;
  20. let parser_material_parse_subsurface: bool = false;
  21. let parser_material_parsing_basecolor: bool = false;
  22. let parser_material_triplanar: bool = false; // Sample using tex_coord/1/2 & tex_coord_blend
  23. let parser_material_sample_keep_aspect: bool = false; // Adjust uvs to preserve texture aspect ratio
  24. let parser_material_sample_uv_scale: string = "1.0";
  25. let parser_material_transform_color_space: bool = true;
  26. let parser_material_blur_passthrough: bool = false;
  27. let parser_material_warp_passthrough: bool = false;
  28. let parser_material_bake_passthrough: bool = false;
  29. let parser_material_start_group: ui_node_canvas_t = null;
  30. let parser_material_start_parents: ui_node_t[] = null;
  31. let parser_material_start_node: ui_node_t = null;
  32. let parser_material_arm_export_tangents: bool = true;
  33. let parser_material_out_normaltan: string; // Raw tangent space normal parsed from normal map
  34. let parser_material_script_links: map_t<string, string> = null;
  35. let parser_material_parsed_map: map_t<string, string> = map_create();
  36. let parser_material_texture_map: map_t<string, string> = map_create();
  37. let parser_material_is_frag: bool = true;
  38. function parser_material_get_node(id: i32): ui_node_t {
  39. for (let i: i32 = 0; i < parser_material_nodes.length; ++i) {
  40. let n: ui_node_t = parser_material_nodes[i];
  41. if (n.id == id) {
  42. return n;
  43. }
  44. }
  45. return null;
  46. }
  47. function parser_material_get_input_link(inp: ui_node_socket_t): ui_node_link_t {
  48. for (let i: i32 = 0; i < parser_material_links.length; ++i) {
  49. let l: ui_node_link_t = parser_material_links[i];
  50. if (l.to_id == inp.node_id) {
  51. let node: ui_node_t = parser_material_get_node(inp.node_id);
  52. if (node.inputs.length <= l.to_socket) {
  53. return null;
  54. }
  55. if (node.inputs[l.to_socket] == inp) {
  56. return l;
  57. }
  58. }
  59. }
  60. return null;
  61. }
  62. function parser_material_init() {
  63. parser_material_parsed = [];
  64. parser_material_parents = [];
  65. parser_material_cotangent_frame_written = false;
  66. parser_material_out_normaltan = "float3(0.5, 0.5, 1.0)";
  67. parser_material_script_links = null;
  68. parser_material_parsing_basecolor = false;
  69. }
  70. function parser_material_parse(canvas: ui_node_canvas_t, _con: node_shader_context_t, _kong: node_shader_t, _matcon: material_context_t): shader_out_t {
  71. parser_material_init();
  72. parser_material_canvases = [ canvas ];
  73. parser_material_nodes = canvas.nodes;
  74. parser_material_links = canvas.links;
  75. parser_material_con = _con;
  76. parser_material_kong = _kong;
  77. parser_material_matcon = _matcon;
  78. if (parser_material_start_group != null) {
  79. parser_material_push_group(parser_material_start_group);
  80. parser_material_parents = parser_material_start_parents;
  81. }
  82. if (parser_material_start_node != null) {
  83. let link: ui_node_link_t = {id : 99999, from_id : parser_material_start_node.id, from_socket : 0, to_id : -1, to_socket : -1};
  84. parser_material_write_result(link);
  85. let sout: shader_out_t = {
  86. out_basecol : "float3(0.0, 0.0, 0.0)",
  87. out_roughness : "0.0",
  88. out_metallic : "0.0",
  89. out_occlusion : "1.0",
  90. out_opacity : "1.0",
  91. out_height : "0.0",
  92. out_emission : "0.0",
  93. out_subsurface : "0.0"
  94. };
  95. return sout;
  96. }
  97. let output_node: ui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL");
  98. if (output_node != null) {
  99. return parser_material_parse_output(output_node);
  100. }
  101. output_node = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR");
  102. if (output_node != null) {
  103. return parser_material_parse_output_pbr(output_node);
  104. }
  105. return null;
  106. }
  107. function parser_material_finalize(con: node_shader_context_t) {
  108. let kong: node_shader_t = con.kong;
  109. if (kong.frag_dotnv) {
  110. kong.frag_vvec = true;
  111. kong.frag_n = true;
  112. }
  113. if (kong.frag_vvec) {
  114. kong.frag_wposition = true;
  115. }
  116. if (kong.frag_bposition) {
  117. if (parser_material_triplanar) {
  118. node_shader_write_attrib_frag(kong, "var bposition: float3 = float3(\
  119. tex_coord1.x * tex_coord_blend.y + tex_coord2.x * tex_coord_blend.z,\
  120. tex_coord.x * tex_coord_blend.x + tex_coord2.y * tex_coord_blend.z,\
  121. tex_coord.y * tex_coord_blend.x + tex_coord1.y * tex_coord_blend.y);");
  122. }
  123. else if (kong.frag_ndcpos) {
  124. node_shader_add_out(kong, "_bposition: float3");
  125. node_shader_write_vert(kong, "output._bposition = (output.ndc.xyz / output.ndc.w);");
  126. node_shader_write_attrib_frag(kong, "var bposition: float3 = input._bposition;");
  127. }
  128. else {
  129. node_shader_add_out(kong, "_bposition: float3");
  130. node_shader_add_constant(kong, "dim: float3", "_dim");
  131. node_shader_add_constant(kong, "hdim: float3", "_half_dim");
  132. node_shader_write_attrib_vert(kong, "output._bposition = (input.pos.xyz + constants.hdim) / constants.dim;");
  133. node_shader_write_attrib_frag(kong, "var bposition: float3 = input._bposition;");
  134. }
  135. }
  136. if (kong.frag_wposition) {
  137. node_shader_add_constant(kong, "W: float4x4", "_world_matrix");
  138. node_shader_add_out(kong, "wposition: float3");
  139. node_shader_write_attrib_vert(kong, "output.wposition = (constants.W * float4(input.pos.xyz, 1.0)).xyz;");
  140. }
  141. if (kong.frag_vposition) {
  142. node_shader_add_constant(kong, "WV: float4x4", "_world_view_matrix");
  143. node_shader_add_out(kong, "vposition: float3");
  144. node_shader_write_attrib_vert(kong, "output.vposition = (constants.WV * float4(input.pos.xyz, 1.0)).xyz;");
  145. }
  146. if (kong.frag_mposition) {
  147. node_shader_add_out(kong, "mposition: float3");
  148. if (kong.frag_ndcpos) {
  149. node_shader_write_vert(kong, "output.mposition = (output.ndc.xyz / output.ndc.w);");
  150. }
  151. else {
  152. node_shader_write_attrib_vert(kong, "output.mposition = input.pos.xyz;");
  153. }
  154. }
  155. if (kong.frag_wtangent) {
  156. node_shader_add_out(kong, "wtangent: float3");
  157. node_shader_write_attrib_vert(kong, "output.wtangent = float3(0.0, 0.0, 0.0);");
  158. }
  159. if (kong.frag_vvec_cam) {
  160. node_shader_add_constant(kong, "WV: float4x4", "_world_view_matrix");
  161. node_shader_add_out(kong, "eye_dir_cam: float3");
  162. node_shader_write_attrib_vert(kong, "output.eye_dir_cam = (constants.WV * float4(input.pos.xyz, 1.0)).xyz;");
  163. node_shader_write_attrib_vert(kong, "output.eye_dir_cam.z *= -1.0;");
  164. node_shader_write_attrib_frag(kong, "var vvec_cam: float3 = normalize(input.eye_dir_cam);");
  165. }
  166. if (kong.frag_vvec) {
  167. node_shader_add_constant(kong, "eye: float3", "_camera_pos");
  168. node_shader_add_out(kong, "eye_dir: float3");
  169. node_shader_write_attrib_vert(kong, "output.eye_dir = constants.eye - output.wposition;");
  170. node_shader_write_attrib_frag(kong, "var vvec: float3 = normalize(input.eye_dir);");
  171. }
  172. if (kong.frag_n) {
  173. node_shader_add_constant(kong, "N: float3x3", "_normal_matrix");
  174. node_shader_add_out(kong, "wnormal: float3");
  175. node_shader_write_attrib_vert(kong, "output.wnormal = constants.N * float3(input.nor.xy, input.pos.w);");
  176. node_shader_write_attrib_frag(kong, "var n: float3 = normalize(input.wnormal);");
  177. }
  178. else if (kong.vert_n) {
  179. node_shader_add_constant(kong, "N: float3x3", "_normal_matrix");
  180. node_shader_write_attrib_vert(kong, "var wnormal: float3 = normalize(constants.N * float3(input.nor.xy, input.pos.w));");
  181. }
  182. if (kong.frag_nattr) {
  183. node_shader_add_out(kong, "nattr: float3");
  184. node_shader_write_attrib_vert(kong, "output.nattr = float3(input.nor.xy, input.pos.w);");
  185. }
  186. if (kong.frag_dotnv) {
  187. node_shader_write_attrib_frag(kong, "var dotnv: float = max(dot(n, vvec), 0.0);");
  188. }
  189. if (kong.frag_wvpposition) {
  190. node_shader_add_out(kong, "wvpposition: float4");
  191. node_shader_write_end_vert(kong, "output.wvpposition = output.pos;");
  192. }
  193. if (node_shader_context_is_elem(con, "col")) {
  194. node_shader_add_out(kong, "vcolor: float3");
  195. node_shader_write_attrib_vert(kong, "output.vcolor = input.col.rgb;");
  196. }
  197. }
  198. function parser_material_parse_output(node: ui_node_t): shader_out_t {
  199. if (parser_material_parse_surface || parser_material_parse_opacity) {
  200. return parser_material_parse_shader_input(node.inputs[0]);
  201. }
  202. return null;
  203. }
  204. function parser_material_parse_output_pbr(node: ui_node_t): shader_out_t {
  205. if (parser_material_parse_surface || parser_material_parse_opacity) {
  206. return parser_material_parse_shader(node, null);
  207. }
  208. return null;
  209. }
  210. function parser_material_get_group(name: string): ui_node_canvas_t {
  211. for (let i: i32 = 0; i < project_material_groups.length; ++i) {
  212. let g: node_group_t = project_material_groups[i];
  213. if (g.canvas.name == name) {
  214. return g.canvas;
  215. }
  216. }
  217. return null;
  218. }
  219. function parser_material_push_group(g: ui_node_canvas_t) {
  220. array_push(parser_material_canvases, g);
  221. parser_material_nodes = g.nodes;
  222. parser_material_links = g.links;
  223. }
  224. function parser_material_pop_group() {
  225. array_pop(parser_material_canvases);
  226. let g: ui_node_canvas_t = parser_material_canvases[parser_material_canvases.length - 1];
  227. parser_material_nodes = g.nodes;
  228. parser_material_links = g.links;
  229. }
  230. function parser_material_parse_group(node: ui_node_t, socket: ui_node_socket_t): string {
  231. array_push(parser_material_parents, node); // Entering group
  232. parser_material_push_group(parser_material_get_group(node.name));
  233. let output_node: ui_node_t = parser_material_node_by_type(parser_material_nodes, "GROUP_OUTPUT");
  234. if (output_node == null) {
  235. return null;
  236. }
  237. let index: i32 = parser_material_socket_index(node, socket);
  238. let inp: ui_node_socket_t = output_node.inputs[index];
  239. let out_group: string = parser_material_parse_input(inp);
  240. array_pop(parser_material_parents);
  241. parser_material_pop_group();
  242. return out_group;
  243. }
  244. function parser_material_parse_group_input(node: ui_node_t, socket: ui_node_socket_t): string {
  245. let parent: ui_node_t = array_pop(parser_material_parents); // Leaving group
  246. parser_material_pop_group();
  247. let index: i32 = parser_material_socket_index(node, socket);
  248. let inp: ui_node_socket_t = parent.inputs[index];
  249. let res: string = parser_material_parse_input(inp);
  250. array_push(parser_material_parents, parent); // Return to group
  251. parser_material_push_group(parser_material_get_group(parent.name));
  252. return res;
  253. }
  254. function parser_material_parse_input(inp: ui_node_socket_t): string {
  255. if (inp.type == "RGB") {
  256. return parser_material_parse_vector_input(inp);
  257. }
  258. else if (inp.type == "RGBA") {
  259. return parser_material_parse_vector_input(inp);
  260. }
  261. else if (inp.type == "VECTOR") {
  262. return parser_material_parse_vector_input(inp);
  263. }
  264. else if (inp.type == "VALUE") {
  265. return parser_material_parse_value_input(inp);
  266. }
  267. return null;
  268. }
  269. function parser_material_parse_shader_input(inp: ui_node_socket_t): shader_out_t {
  270. let l: ui_node_link_t = parser_material_get_input_link(inp);
  271. let from_node: ui_node_t = l != null ? parser_material_get_node(l.from_id) : null;
  272. if (from_node != null) {
  273. return parser_material_parse_shader(from_node, from_node.outputs[l.from_socket]);
  274. }
  275. else {
  276. let sout: shader_out_t = {
  277. out_basecol : "float3(0.8, 0.8, 0.8)",
  278. out_roughness : "0.0",
  279. out_metallic : "0.0",
  280. out_occlusion : "1.0",
  281. out_opacity : "1.0",
  282. out_height : "0.0",
  283. out_emission : "0.0",
  284. out_subsurface : "0.0"
  285. };
  286. return sout;
  287. }
  288. }
  289. function parser_material_parse_shader(node: ui_node_t, socket: ui_node_socket_t): shader_out_t {
  290. let sout: shader_out_t = {
  291. out_basecol : "float3(0.8, 0.8, 0.8)",
  292. out_roughness : "0.0",
  293. out_metallic : "0.0",
  294. out_occlusion : "1.0",
  295. out_opacity : "1.0",
  296. out_height : "0.0",
  297. out_emission : "0.0",
  298. out_subsurface : "0.0"
  299. };
  300. if (node.type == "OUTPUT_MATERIAL_PBR") {
  301. if (parser_material_parse_surface) {
  302. // Normal - parsed first to retrieve uv coords
  303. parse_normal_map_color_input(node.inputs[5]);
  304. // Base color
  305. parser_material_parsing_basecolor = true;
  306. sout.out_basecol = parser_material_parse_vector_input(node.inputs[0]);
  307. parser_material_parsing_basecolor = false;
  308. // Occlusion
  309. sout.out_occlusion = parser_material_parse_value_input(node.inputs[2]);
  310. // Roughness
  311. sout.out_roughness = parser_material_parse_value_input(node.inputs[3]);
  312. // Metallic
  313. sout.out_metallic = parser_material_parse_value_input(node.inputs[4]);
  314. // Emission
  315. if (parser_material_parse_emission) {
  316. sout.out_emission = parser_material_parse_value_input(node.inputs[6]);
  317. }
  318. // Subsurface
  319. if (parser_material_parse_subsurface) {
  320. sout.out_subsurface = parser_material_parse_value_input(node.inputs[8]);
  321. }
  322. }
  323. if (parser_material_parse_opacity) {
  324. sout.out_opacity = parser_material_parse_value_input(node.inputs[1]);
  325. }
  326. // Displacement / Height
  327. if (parser_material_parse_height) {
  328. if (!parser_material_parse_height_as_channel) {
  329. parser_material_is_frag = false;
  330. }
  331. sout.out_height = parser_material_parse_value_input(node.inputs[7]);
  332. if (!parser_material_parse_height_as_channel) {
  333. parser_material_is_frag = true;
  334. }
  335. }
  336. }
  337. return sout;
  338. }
  339. function parser_material_write(raw: node_shader_t, s: string) {
  340. if (parser_material_is_frag) {
  341. node_shader_write_frag(raw, s);
  342. }
  343. else {
  344. node_shader_write_vert(raw, s);
  345. }
  346. }
  347. function parser_material_parse_vector_input(inp: ui_node_socket_t): string {
  348. let l: ui_node_link_t = parser_material_get_input_link(inp);
  349. let from_node: ui_node_t = l != null ? parser_material_get_node(l.from_id) : null;
  350. if (from_node != null) {
  351. let res_var: string = parser_material_write_result(l);
  352. let st: string = from_node.outputs[l.from_socket].type;
  353. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  354. return res_var;
  355. }
  356. else { // VALUE
  357. return parser_material_to_vec3(res_var);
  358. }
  359. }
  360. else {
  361. return parser_material_vec3(inp.default_value);
  362. }
  363. }
  364. function parser_material_parse_vector(node: ui_node_t, socket: ui_node_socket_t): string {
  365. let node_vector: (node: ui_node_t, socket: ui_node_socket_t) => string = map_get(parser_material_node_vectors, node.type);
  366. if (node_vector != null) {
  367. return node_vector(node, socket);
  368. }
  369. else if (node.type == "GROUP_INPUT") {
  370. return parser_material_parse_group_input(node, socket);
  371. }
  372. else if (map_get(parser_material_custom_nodes, node.type) != null) {
  373. let cb: any = map_get(parser_material_custom_nodes, node.type); // JSValue -> (n: ui_node_t, s: string)=>string
  374. return js_call_ptr_str(cb, node, socket.name);
  375. }
  376. return "float3(0.0, 0.0, 0.0)";
  377. }
  378. function parse_normal_map_color_input(inp: ui_node_socket_t) {
  379. parser_material_kong.frag_write_normal++;
  380. parser_material_out_normaltan = parser_material_parse_vector_input(inp);
  381. let _parser_material_is_frag: bool = parser_material_is_frag;
  382. parser_material_is_frag = true;
  383. if (!parser_material_arm_export_tangents) {
  384. parser_material_write(parser_material_kong, "var texn: float3 = (" + parser_material_out_normaltan + ") * 2.0 - 1.0;");
  385. parser_material_write(parser_material_kong, "texn.y = -texn.y;");
  386. if (!parser_material_cotangent_frame_written) {
  387. parser_material_cotangent_frame_written = true;
  388. node_shader_add_function(parser_material_kong, str_cotangent_frame);
  389. }
  390. parser_material_kong.frag_n = true;
  391. parser_material_write(parser_material_kong, "var TBN: float3x3 = cotangent_frame(n, vvec, tex_coord);");
  392. parser_material_write(parser_material_kong, "n = TBN * normalize(texn);");
  393. }
  394. parser_material_is_frag = _parser_material_is_frag;
  395. parser_material_kong.frag_write_normal--;
  396. }
  397. function parser_material_parse_value_input(inp: ui_node_socket_t, vector_as_grayscale: bool = false): string {
  398. let l: ui_node_link_t = parser_material_get_input_link(inp);
  399. let from_node: ui_node_t = l != null ? parser_material_get_node(l.from_id) : null;
  400. if (from_node != null) {
  401. let res_var: string = parser_material_write_result(l);
  402. let st: string = from_node.outputs[l.from_socket].type;
  403. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  404. if (vector_as_grayscale) {
  405. return "dot(" + res_var + ".rbg, float3(0.299, 0.587, 0.114))";
  406. }
  407. else {
  408. return res_var + ".x";
  409. }
  410. }
  411. else { // VALUE
  412. return res_var;
  413. }
  414. }
  415. else {
  416. return parser_material_vec1(inp.default_value[0]);
  417. }
  418. }
  419. function parser_material_parse_value(node: ui_node_t, socket: ui_node_socket_t): string {
  420. let node_value: (node: ui_node_t, socket: ui_node_socket_t) => string = map_get(parser_material_node_values, node.type);
  421. if (node_value != null) {
  422. return node_value(node, socket);
  423. }
  424. else if (node.type == "GROUP_INPUT") {
  425. return parser_material_parse_group_input(node, socket);
  426. }
  427. else if (map_get(parser_material_custom_nodes, node.type) != null) {
  428. let cb: any = map_get(parser_material_custom_nodes, node.type);
  429. return js_call_ptr_str(cb, node, socket.name);
  430. }
  431. return "0.0";
  432. }
  433. function parser_material_get_coord(node: ui_node_t): string {
  434. if (parser_material_get_input_link(node.inputs[0]) != null) {
  435. return parser_material_parse_vector_input(node.inputs[0]);
  436. }
  437. else {
  438. parser_material_kong.frag_bposition = true;
  439. return "bposition";
  440. }
  441. }
  442. function parser_material_res_var_name(node: ui_node_t, socket: ui_node_socket_t): string {
  443. return parser_material_node_name(node) + "_" + parser_material_safesrc(socket.name) + "_res";
  444. }
  445. function parser_material_write_result(l: ui_node_link_t): string {
  446. let from_node: ui_node_t = parser_material_get_node(l.from_id);
  447. let from_socket: ui_node_socket_t = from_node.outputs[l.from_socket];
  448. let res_var: string = parser_material_res_var_name(from_node, from_socket);
  449. let st: string = from_socket.type;
  450. if (array_index_of(parser_material_parsed, res_var) < 0) {
  451. array_push(parser_material_parsed, res_var);
  452. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  453. let res: string = parser_material_parse_vector(from_node, from_socket);
  454. if (res == null) {
  455. return null;
  456. }
  457. map_set(parser_material_parsed_map, res_var, res);
  458. parser_material_write(parser_material_kong, "var " + res_var + ": float3 = " + res + ";");
  459. }
  460. else if (st == "VALUE") {
  461. let res: string = parser_material_parse_value(from_node, from_socket);
  462. if (res == null) {
  463. return null;
  464. }
  465. map_set(parser_material_parsed_map, res_var, res);
  466. parser_material_write(parser_material_kong, "var " + res_var + ": float = " + res + ";");
  467. }
  468. }
  469. return res_var;
  470. }
  471. function parser_material_store_var_name(node: ui_node_t): string {
  472. return parser_material_node_name(node) + "_store";
  473. }
  474. function parser_material_vec1(v: f32): string {
  475. return f32_to_string_with_zeros(v);
  476. // return "float(" + v + ")";
  477. // return v + "";
  478. }
  479. function parser_material_vec3(v: f32_array_t): string {
  480. // let v0: f32 = v[0];
  481. // let v1: f32 = v[1];
  482. // let v2: f32 = v[2];
  483. let v0: string = f32_to_string_with_zeros(v[0]);
  484. let v1: string = f32_to_string_with_zeros(v[1]);
  485. let v2: string = f32_to_string_with_zeros(v[2]);
  486. return "float3(" + v0 + ", " + v1 + ", " + v2 + ")";
  487. }
  488. function parser_material_to_vec3(s: string): string {
  489. // return "float3(" + s + ")";
  490. return "float3(" + s + ", " + s + ", " + s + ")";
  491. }
  492. function parser_material_node_by_type(nodes: ui_node_t[], ntype: string): ui_node_t {
  493. for (let i: i32 = 0; i < nodes.length; ++i) {
  494. let n: ui_node_t = nodes[i];
  495. if (n.type == ntype) {
  496. return n;
  497. }
  498. }
  499. return null;
  500. }
  501. function parser_material_socket_index(node: ui_node_t, socket: ui_node_socket_t): i32 {
  502. for (let i: i32 = 0; i < node.outputs.length; ++i) {
  503. if (node.outputs[i] == socket) {
  504. return i;
  505. }
  506. }
  507. return -1;
  508. }
  509. function parser_material_node_name(node: ui_node_t, _parents: ui_node_t[] = null): string {
  510. if (_parents == null) {
  511. _parents = parser_material_parents;
  512. }
  513. let s: string = node.name;
  514. for (let i: i32 = 0; i < _parents.length; ++i) {
  515. let p: ui_node_t = _parents[i];
  516. s = p.name + p.id + "_" + s;
  517. }
  518. s = parser_material_safesrc(s);
  519. let nid: i32 = node.id;
  520. s = s + nid;
  521. return s;
  522. }
  523. function parser_material_safesrc(s: string): string {
  524. for (let i: i32 = 0; i < s.length; ++i) {
  525. let code: i32 = char_code_at(s, i);
  526. let letter: bool = (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
  527. let digit: bool = code >= 48 && code <= 57;
  528. if (!letter && !digit) {
  529. s = string_replace_all(s, char_at(s, i), "_");
  530. }
  531. if (i == 0 && digit) {
  532. s = "_" + s;
  533. }
  534. }
  535. return s;
  536. }
  537. function parser_material_enum_data(s: string): string {
  538. for (let i: i32 = 0; i < project_assets.length; ++i) {
  539. let a: asset_t = project_assets[i];
  540. if (a.name == s) {
  541. return a.file;
  542. }
  543. }
  544. return "";
  545. }
  546. function parser_material_make_bind_tex(tex_name: string, file: string): bind_tex_t {
  547. let tex: bind_tex_t = {name : tex_name, file : file};
  548. return tex;
  549. }
  550. function u8_array_string_at(a: u8_array_t, i: i32): string {
  551. let s: string = u8_array_to_string(a);
  552. let ss: string[] = string_split(s, "\n");
  553. return ss[i];
  554. }
  555. type shader_out_t = {
  556. out_basecol?: string;
  557. out_roughness?: string;
  558. out_metallic?: string;
  559. out_occlusion?: string;
  560. out_opacity?: string;
  561. out_height?: string;
  562. out_emission?: string;
  563. out_subsurface?: string;
  564. };