parser_material.ts 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010
  1. //
  2. // This module builds upon Cycles nodes work licensed as
  3. // Copyright 2011-2013 Blender Foundation
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. //
  17. let parser_material_con: node_shader_context_t;
  18. let parser_material_vert: node_shader_t;
  19. let parser_material_frag: node_shader_t;
  20. let parser_material_curshader: node_shader_t;
  21. let parser_material_matcon: material_context_t;
  22. let parser_material_parsed: string[];
  23. let parser_material_parents: zui_node_t[];
  24. let parser_material_canvases: zui_node_canvas_t[];
  25. let parser_material_nodes: zui_node_t[];
  26. let parser_material_links: zui_node_link_t[];
  27. let parser_material_cotangent_frame_written: bool;
  28. let parser_material_tex_coord: string = "texCoord";
  29. let parser_material_eps: f32 = 0.000001;
  30. let parser_material_custom_nodes: map_t<any, any> = map_create();
  31. let parser_material_parse_surface: bool = true;
  32. let parser_material_parse_opacity: bool = true;
  33. let parser_material_parse_height: bool = false;
  34. let parser_material_parse_height_as_channel: bool = false;
  35. let parser_material_parse_emission: bool = false;
  36. let parser_material_parse_subsurface: bool = false;
  37. let parser_material_parsing_basecolor: bool = false;
  38. let parser_material_triplanar: bool = false; // Sample using texCoord/1/2 & texCoordBlend
  39. let parser_material_sample_keep_aspect: bool = false; // Adjust uvs to preserve texture aspect ratio
  40. let parser_material_sample_uv_scale: string = "1.0";
  41. let parser_material_transform_color_space: bool = true;
  42. let parser_material_blur_passthrough: bool = false;
  43. let parser_material_warp_passthrough: bool = false;
  44. let parser_material_bake_passthrough: bool = false;
  45. let parser_material_bake_passthrough_strength: string = "0.0";
  46. let parser_material_bake_passthrough_radius: string = "0.0";
  47. let parser_material_bake_passthrough_offset: string = "0.0";
  48. let parser_material_start_group: zui_node_canvas_t = null;
  49. let parser_material_start_parents: zui_node_t[] = null;
  50. let parser_material_start_node: zui_node_t = null;
  51. let parser_material_arm_export_tangents: bool = true;
  52. let parser_material_out_normaltan: string; // Raw tangent space normal parsed from normal map
  53. let parser_material_script_links: map_t<string, string> = null;
  54. let parser_material_parsed_map: map_t<string, string> = map_create();
  55. let parser_material_texture_map: map_t<string, string> = map_create();
  56. function parser_material_get_node(id: i32): zui_node_t {
  57. for (let i: i32 = 0; i < parser_material_nodes.length; ++i) {
  58. let n: zui_node_t = parser_material_nodes[i];
  59. if (n.id == id) {
  60. return n;
  61. }
  62. }
  63. return null;
  64. }
  65. function parser_material_get_link(id: i32): zui_node_link_t {
  66. for (let i: i32 = 0; i < parser_material_links.length; ++i) {
  67. let l: zui_node_link_t = parser_material_links[i];
  68. if (l.id == id) {
  69. return l;
  70. }
  71. }
  72. return null;
  73. }
  74. function parser_material_get_input_link(inp: zui_node_socket_t): zui_node_link_t {
  75. for (let i: i32 = 0; i < parser_material_links.length; ++i) {
  76. let l: zui_node_link_t = parser_material_links[i];
  77. if (l.to_id == inp.node_id) {
  78. let node: zui_node_t = parser_material_get_node(inp.node_id);
  79. if (node.inputs.length <= l.to_socket) {
  80. return null;
  81. }
  82. if (node.inputs[l.to_socket] == inp) {
  83. return l;
  84. }
  85. }
  86. }
  87. return null;
  88. }
  89. function parser_material_get_output_links(out: zui_node_socket_t): zui_node_link_t[] {
  90. let ls: zui_node_link_t[] = null;
  91. for (let i: i32 = 0; i < parser_material_links.length; ++i) {
  92. let l: zui_node_link_t = parser_material_links[i];
  93. if (l.from_id == out.node_id) {
  94. let node: zui_node_t = parser_material_get_node(out.node_id);
  95. if (node.outputs.length <= l.from_socket) {
  96. continue;
  97. }
  98. if (node.outputs[l.from_socket] == out) {
  99. if (ls == null) {
  100. ls = [];
  101. }
  102. array_push(ls, l);
  103. }
  104. }
  105. }
  106. return ls;
  107. }
  108. function parser_material_init() {
  109. parser_material_parsed = [];
  110. parser_material_parents = [];
  111. parser_material_cotangent_frame_written = false;
  112. parser_material_out_normaltan = "vec3(0.5, 0.5, 1.0)";
  113. parser_material_script_links = null;
  114. parser_material_parsing_basecolor = false;
  115. }
  116. function parser_material_parse(canvas: zui_node_canvas_t, _con: node_shader_context_t, _vert: node_shader_t, _frag: node_shader_t, _matcon: material_context_t): shader_out_t {
  117. parser_material_init();
  118. parser_material_canvases = [canvas];
  119. parser_material_nodes = canvas.nodes;
  120. parser_material_links = canvas.links;
  121. parser_material_con = _con;
  122. parser_material_vert = _vert;
  123. parser_material_frag = _frag;
  124. parser_material_curshader = parser_material_frag;
  125. parser_material_matcon = _matcon;
  126. if (parser_material_start_group != null) {
  127. parser_material_push_group(parser_material_start_group);
  128. parser_material_parents = parser_material_start_parents;
  129. }
  130. if (parser_material_start_node != null) {
  131. let link: zui_node_link_t = { id: 99999, from_id: parser_material_start_node.id, from_socket: 0, to_id: -1, to_socket: -1 };
  132. parser_material_write_result(link);
  133. return {
  134. out_basecol: "vec3(0.0, 0.0, 0.0)",
  135. out_roughness: "0.0",
  136. out_metallic: "0.0",
  137. out_occlusion: "1.0",
  138. out_opacity: "1.0",
  139. out_height: "0.0",
  140. out_emission: "0.0",
  141. out_subsurface: "0.0"
  142. }
  143. }
  144. let output_node: zui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL");
  145. if (output_node != null) {
  146. return parser_material_parse_output(output_node);
  147. }
  148. output_node = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR");
  149. if (output_node != null) {
  150. return parser_material_parse_output_pbr(output_node);
  151. }
  152. return null;
  153. }
  154. function parser_material_finalize(con: node_shader_context_t) {
  155. let vert: node_shader_t = con.vert;
  156. let frag: node_shader_t = con.frag;
  157. if (frag.dotnv) {
  158. frag.vvec = true;
  159. frag.n = true;
  160. }
  161. if (frag.vvec) {
  162. vert.wposition = true;
  163. }
  164. if (frag.bposition) {
  165. if (parser_material_triplanar) {
  166. node_shader_write_attrib(frag, "vec3 bposition = vec3(\
  167. texCoord1.x * texCoordBlend.y + texCoord2.x * texCoordBlend.z,\
  168. texCoord.x * texCoordBlend.x + texCoord2.y * texCoordBlend.z,\
  169. texCoord.y * texCoordBlend.x + texCoord1.y * texCoordBlend.y);");
  170. }
  171. else if (frag.ndcpos) {
  172. node_shader_add_out(vert, "vec3 bposition");
  173. node_shader_write(vert, "bposition = (ndc.xyz / ndc.w);");
  174. }
  175. else {
  176. node_shader_add_out(vert, "vec3 bposition");
  177. node_shader_add_uniform(vert, "vec3 dim", "_dim");
  178. node_shader_add_uniform(vert, "vec3 hdim", "_half_dim");
  179. node_shader_write_attrib(vert, "bposition = (pos.xyz + hdim) / dim;");
  180. }
  181. }
  182. if (frag.wposition) {
  183. node_shader_add_uniform(vert, "mat4 W", "_world_matrix");
  184. node_shader_add_out(vert, "vec3 wposition");
  185. node_shader_write_attrib(vert, "wposition = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;");
  186. }
  187. else if (vert.wposition) {
  188. node_shader_add_uniform(vert, "mat4 W", "_world_matrix");
  189. node_shader_write_attrib(vert, "vec3 wposition = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;");
  190. }
  191. if (frag.vposition) {
  192. node_shader_add_uniform(vert, "mat4 WV", "_world_view_matrix");
  193. node_shader_add_out(vert, "vec3 vposition");
  194. node_shader_write_attrib(vert, "vposition = vec4(mul(vec4(pos.xyz, 1.0), WV)).xyz;");
  195. }
  196. if (frag.mposition) {
  197. node_shader_add_out(vert, "vec3 mposition");
  198. if (frag.ndcpos) {
  199. node_shader_write(vert, "mposition = (ndc.xyz / ndc.w);");
  200. }
  201. else {
  202. node_shader_write_attrib(vert, "mposition = pos.xyz;");
  203. }
  204. }
  205. if (frag.wtangent) {
  206. // NodeShaderadd_elem(con, "tang", "short4norm");
  207. // add_uniform(vert, "mat3 N", "_normal_matrix");
  208. node_shader_add_out(vert, "vec3 wtangent");
  209. // write_attrib(vert, "wtangent = normalize(mul(tang.xyz, N));");
  210. node_shader_write_attrib(vert, "wtangent = vec3(0.0, 0.0, 0.0);");
  211. }
  212. if (frag.vvec_cam) {
  213. node_shader_add_uniform(vert, "mat4 WV", "_world_view_matrix");
  214. node_shader_add_out(vert, "vec3 eyeDirCam");
  215. node_shader_write_attrib(vert, "eyeDirCam = vec4(mul(vec4(pos.xyz, 1.0), WV)).xyz; eyeDirCam.z *= -1.0;");
  216. node_shader_write_attrib(frag, "vec3 vVecCam = normalize(eyeDirCam);");
  217. }
  218. if (frag.vvec) {
  219. node_shader_add_uniform(vert, "vec3 eye", "_camera_pos");
  220. node_shader_add_out(vert, "vec3 eyeDir");
  221. node_shader_write_attrib(vert, "eyeDir = eye - wposition;");
  222. node_shader_write_attrib(frag, "vec3 vVec = normalize(eyeDir);");
  223. }
  224. if (frag.n) {
  225. node_shader_add_uniform(vert, "mat3 N", "_normal_matrix");
  226. node_shader_add_out(vert, "vec3 wnormal");
  227. node_shader_write_attrib(vert, "wnormal = mul(vec3(nor.xy, pos.w), N);");
  228. node_shader_write_attrib(frag, "vec3 n = normalize(wnormal);");
  229. }
  230. else if (vert.n) {
  231. node_shader_add_uniform(vert, "mat3 N", "_normal_matrix");
  232. node_shader_write_attrib(vert, "vec3 wnormal = normalize(mul(vec3(nor.xy, pos.w), N));");
  233. }
  234. if (frag.nattr) {
  235. node_shader_add_out(vert, "vec3 nAttr");
  236. node_shader_write_attrib(vert, "nAttr = vec3(nor.xy, pos.w);");
  237. }
  238. if (frag.dotnv) {
  239. node_shader_write_attrib(frag, "float dotNV = max(dot(n, vVec), 0.0);");
  240. }
  241. if (frag.wvpposition) {
  242. node_shader_add_out(vert, "vec4 wvpposition");
  243. node_shader_write_end(vert, "wvpposition = gl_Position;");
  244. }
  245. if (node_shader_context_is_elem(con, "col")) {
  246. node_shader_add_out(vert, "vec3 vcolor");
  247. node_shader_write_attrib(vert, "vcolor = col.rgb;");
  248. }
  249. }
  250. function parser_material_parse_output(node: zui_node_t): shader_out_t {
  251. if (parser_material_parse_surface || parser_material_parse_opacity) {
  252. return parser_material_parse_shader_input(node.inputs[0]);
  253. }
  254. return null;
  255. // Parse volume, displacement..
  256. }
  257. function parser_material_parse_output_pbr(node: zui_node_t): shader_out_t {
  258. if (parser_material_parse_surface || parser_material_parse_opacity) {
  259. return parser_material_parse_shader(node, null);
  260. }
  261. return null;
  262. // Parse volume, displacement..
  263. }
  264. function parser_material_get_group(name: string): zui_node_canvas_t {
  265. for (let i: i32 = 0; i < project_material_groups.length; ++i) {
  266. let g: node_group_t = project_material_groups[i];
  267. if (g.canvas.name == name) {
  268. return g.canvas;
  269. }
  270. }
  271. return null;
  272. }
  273. function parser_material_push_group(g: zui_node_canvas_t) {
  274. array_push(parser_material_canvases, g);
  275. parser_material_nodes = g.nodes;
  276. parser_material_links = g.links;
  277. }
  278. function parser_material_pop_group() {
  279. parser_material_canvases.pop();
  280. let g: zui_node_canvas_t = parser_material_canvases[parser_material_canvases.length - 1];
  281. parser_material_nodes = g.nodes;
  282. parser_material_links = g.links;
  283. }
  284. function parser_material_parse_group(node: zui_node_t, socket: zui_node_socket_t): string {
  285. array_push(parser_material_parents, node); // Entering group
  286. parser_material_push_group(parser_material_get_group(node.name));
  287. let output_node: zui_node_t = parser_material_node_by_type(parser_material_nodes, "GROUP_OUTPUT");
  288. if (output_node == null) {
  289. return null;
  290. }
  291. let index: i32 = parser_material_socket_index(node, socket);
  292. let inp: zui_node_socket_t = output_node.inputs[index];
  293. let out_group: string = parser_material_parse_input(inp);
  294. parser_material_parents.pop();
  295. parser_material_pop_group();
  296. return out_group;
  297. }
  298. function parser_material_parse_group_input(node: zui_node_t, socket: zui_node_socket_t): string {
  299. let parent: zui_node_t = parser_material_parents.pop(); // Leaving group
  300. parser_material_pop_group();
  301. let index: i32 = parser_material_socket_index(node, socket);
  302. let inp: zui_node_socket_t = parent.inputs[index];
  303. let res: string = parser_material_parse_input(inp);
  304. array_push(parser_material_parents, parent); // Return to group
  305. parser_material_push_group(parser_material_get_group(parent.name));
  306. return res;
  307. }
  308. function parser_material_parse_input(inp: zui_node_socket_t): string {
  309. if (inp.type == "RGB") {
  310. return parser_material_parse_vector_input(inp);
  311. }
  312. else if (inp.type == "RGBA") {
  313. return parser_material_parse_vector_input(inp);
  314. }
  315. else if (inp.type == "VECTOR") {
  316. return parser_material_parse_vector_input(inp);
  317. }
  318. else if (inp.type == "VALUE") {
  319. return parser_material_parse_value_input(inp);
  320. }
  321. return null;
  322. }
  323. function parser_material_parse_shader_input(inp: zui_node_socket_t): shader_out_t {
  324. let l: zui_node_link_t = parser_material_get_input_link(inp);
  325. let from_node: zui_node_t = l != null ? parser_material_get_node(l.from_id) : null;
  326. if (from_node != null) {
  327. if (from_node.type == "REROUTE") {
  328. return parser_material_parse_shader_input(from_node.inputs[0]);
  329. }
  330. return parser_material_parse_shader(from_node, from_node.outputs[l.from_socket]);
  331. }
  332. else {
  333. return {
  334. out_basecol: "vec3(0.8, 0.8, 0.8)",
  335. out_roughness: "0.0",
  336. out_metallic: "0.0",
  337. out_occlusion: "1.0",
  338. out_opacity: "1.0",
  339. out_height: "0.0",
  340. out_emission: "0.0",
  341. out_subsurface: "0.0"
  342. };
  343. }
  344. }
  345. function parser_material_parse_shader(node: zui_node_t, socket: zui_node_socket_t): shader_out_t {
  346. let sout: shader_out_t = {
  347. out_basecol: "vec3(0.8, 0.8, 0.8)",
  348. out_roughness: "0.0",
  349. out_metallic: "0.0",
  350. out_occlusion: "1.0",
  351. out_opacity: "1.0",
  352. out_height: "0.0",
  353. out_emission: "0.0",
  354. out_subsurface: "0.0"
  355. }
  356. if (node.type == "OUTPUT_MATERIAL_PBR") {
  357. if (parser_material_parse_surface) {
  358. // Normal - parsed first to retrieve uv coords
  359. parse_normal_map_color_input(node.inputs[5]);
  360. // Base color
  361. parser_material_parsing_basecolor = true;
  362. sout.out_basecol = parser_material_parse_vector_input(node.inputs[0]);
  363. parser_material_parsing_basecolor = false;
  364. // Occlusion
  365. sout.out_occlusion = parser_material_parse_value_input(node.inputs[2]);
  366. // Roughness
  367. sout.out_roughness = parser_material_parse_value_input(node.inputs[3]);
  368. // Metallic
  369. sout.out_metallic = parser_material_parse_value_input(node.inputs[4]);
  370. // Emission
  371. if (parser_material_parse_emission) {
  372. sout.out_emission = parser_material_parse_value_input(node.inputs[6]);
  373. }
  374. // Subsurface
  375. if (parser_material_parse_subsurface) {
  376. sout.out_subsurface = parser_material_parse_value_input(node.inputs[8]);
  377. }
  378. }
  379. if (parser_material_parse_opacity) {
  380. sout.out_opacity = parser_material_parse_value_input(node.inputs[1]);
  381. }
  382. // Displacement / Height
  383. if (node.inputs.length > 7 && parser_material_parse_height) {
  384. if (!parser_material_parse_height_as_channel) {
  385. parser_material_curshader = parser_material_vert;
  386. }
  387. sout.out_height = parser_material_parse_value_input(node.inputs[7]);
  388. if (!parser_material_parse_height_as_channel) {
  389. parser_material_curshader = parser_material_frag;
  390. }
  391. }
  392. }
  393. return sout;
  394. }
  395. function parser_material_parse_vector_input(inp: zui_node_socket_t): string {
  396. let l: zui_node_link_t = parser_material_get_input_link(inp);
  397. let from_node: zui_node_t = l != null ? parser_material_get_node(l.from_id) : null;
  398. if (from_node != null) {
  399. if (from_node.type == "REROUTE") {
  400. return parser_material_parse_vector_input(from_node.inputs[0]);
  401. }
  402. let res_var: string = parser_material_write_result(l);
  403. let st: string = from_node.outputs[l.from_socket].type;
  404. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  405. return res_var;
  406. }
  407. else {// VALUE
  408. return parser_material_to_vec3(res_var);
  409. }
  410. }
  411. else {
  412. if (inp.type == "VALUE") { // Unlinked reroute
  413. return parser_material_vec3(f32_array_create_xyz(0.0, 0.0, 0.0));
  414. }
  415. else {
  416. return parser_material_vec3(inp.default_value);
  417. }
  418. }
  419. }
  420. function parser_material_parse_vector(node: zui_node_t, socket: zui_node_socket_t): string {
  421. if (node.type == "GROUP") {
  422. return parser_material_parse_group(node, socket);
  423. }
  424. else if (node.type == "GROUP_INPUT") {
  425. return parser_material_parse_group_input(node, socket);
  426. }
  427. else if (node.type == "ATTRIBUTE") {
  428. if (socket == node.outputs[0]) { // Color
  429. if (parser_material_curshader.context.allow_vcols) {
  430. node_shader_context_add_elem(parser_material_curshader.context, "col", "short4norm"); // Vcols only for now
  431. return "vcolor";
  432. }
  433. else {
  434. return("vec3(0.0, 0.0, 0.0)");
  435. }
  436. }
  437. else { // Vector
  438. node_shader_context_add_elem(parser_material_curshader.context, "tex", "short2norm"); // UVMaps only for now
  439. return "vec3(texCoord.x, texCoord.y, 0.0)";
  440. }
  441. }
  442. else if (node.type == "VERTEX_COLOR") {
  443. if (parser_material_curshader.context.allow_vcols) {
  444. node_shader_context_add_elem(parser_material_curshader.context, "col", "short4norm");
  445. return "vcolor";
  446. }
  447. else {
  448. return("vec3(0.0, 0.0, 0.0)");
  449. }
  450. }
  451. else if (node.type == "RGB") {
  452. return parser_material_vec3(socket.default_value);
  453. }
  454. else if (node.type == "TEX_BRICK") {
  455. node_shader_add_function(parser_material_curshader, str_tex_brick);
  456. let co: string = parser_material_get_coord(node);
  457. let col1: string = parser_material_parse_vector_input(node.inputs[1]);
  458. let col2: string = parser_material_parse_vector_input(node.inputs[2]);
  459. let col3: string = parser_material_parse_vector_input(node.inputs[3]);
  460. let scale: string = parser_material_parse_value_input(node.inputs[4]);
  461. let res: string = "tex_brick(" + co + " * " + scale + ", " + col1 + ", " + col2 + ", " + col3 + ")";
  462. return res;
  463. }
  464. else if (node.type == "TEX_CHECKER") {
  465. node_shader_add_function(parser_material_curshader, str_tex_checker);
  466. let co: string = parser_material_get_coord(node);
  467. let col1: string = parser_material_parse_vector_input(node.inputs[1]);
  468. let col2: string = parser_material_parse_vector_input(node.inputs[2]);
  469. let scale: string = parser_material_parse_value_input(node.inputs[3]);
  470. let res: string = "tex_checker(" + co + ", " + col1 + ", " + col2 + ", " + scale + ")";
  471. return res;
  472. }
  473. else if (node.type == "TEX_GRADIENT") {
  474. let co: string = parser_material_get_coord(node);
  475. let but: zui_node_button_t = node.buttons[0]; //gradient_type;
  476. let grad: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  477. grad = string_replace_all(grad, " ", "_");
  478. let f: string = parser_material_get_gradient(grad, co);
  479. let res: string = parser_material_to_vec3("clamp(" + f + ", 0.0, 1.0)");
  480. return res;
  481. }
  482. else if (node.type == "TEX_IMAGE") {
  483. // Already fetched
  484. if (array_index_of(parser_material_parsed, parser_material_res_var_name(node, node.outputs[1])) >= 0) { // TODO: node.outputs[0]
  485. let varname: string = parser_material_store_var_name(node);
  486. return varname + ".rgb";
  487. }
  488. let tex_name: string = parser_material_node_name(node);
  489. let tex: bind_tex_t = parser_material_make_texture(node, tex_name);
  490. if (tex != null) {
  491. let color_space: i32 = node.buttons[1].default_value[0];
  492. let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space);
  493. return texstore + ".rgb";
  494. }
  495. else {
  496. let tex_store: string = parser_material_store_var_name(node); // Pink color for missing texture
  497. node_shader_write(parser_material_curshader, "vec4 " + tex_store + " = vec4(1.0, 0.0, 1.0, 1.0);");
  498. return tex_store + ".rgb";
  499. }
  500. }
  501. else if (node.type == "TEX_MAGIC") {
  502. node_shader_add_function(parser_material_curshader, str_tex_magic);
  503. let co: string = parser_material_get_coord(node);
  504. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  505. let res: string = "tex_magic(" + co + " * " + scale + " * 4.0)";
  506. return res;
  507. }
  508. else if (node.type == "TEX_NOISE") {
  509. node_shader_add_function(parser_material_curshader, str_tex_noise);
  510. let co: string = parser_material_get_coord(node);
  511. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  512. let res: string = "vec3(tex_noise(" + co + " * " + scale + "), tex_noise(" + co + " * " + scale + " + 0.33), tex_noise(" + co + " * " + scale + " + 0.66))";
  513. return res;
  514. }
  515. else if (node.type == "TEX_VORONOI") {
  516. node_shader_add_function(parser_material_curshader, str_tex_voronoi);
  517. node_shader_add_uniform(parser_material_curshader, "sampler2D snoise256", "$noise256.k");
  518. let co: string = parser_material_get_coord(node);
  519. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  520. let but: zui_node_button_t = node.buttons[0]; //coloring;
  521. let coloring: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  522. coloring = string_replace_all(coloring, " ", "_");
  523. let res: string = "";
  524. if (coloring == "INTENSITY") {
  525. res = parser_material_to_vec3("tex_voronoi(" + co + " * " + scale + ", texturePass(snoise256)).a");
  526. }
  527. else { // Cells
  528. res = "tex_voronoi(" + co + " * " + scale + ", texturePass(snoise256)).rgb";
  529. }
  530. return res;
  531. }
  532. else if (node.type == "TEX_WAVE") {
  533. node_shader_add_function(parser_material_curshader, str_tex_wave);
  534. let co: string = parser_material_get_coord(node);
  535. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  536. let res: string = parser_material_to_vec3("tex_wave_f(" + co + " * " + scale + ")");
  537. return res;
  538. }
  539. else if (node.type == "BRIGHTCONTRAST") {
  540. let out_col: string = parser_material_parse_vector_input(node.inputs[0]);
  541. let bright: string = parser_material_parse_value_input(node.inputs[1]);
  542. let contr: string = parser_material_parse_value_input(node.inputs[2]);
  543. node_shader_add_function(parser_material_curshader, str_brightcontrast);
  544. return "brightcontrast(" + out_col + ", " + bright + ", " + contr + ")";
  545. }
  546. else if (node.type == "GAMMA") {
  547. let out_col: string = parser_material_parse_vector_input(node.inputs[0]);
  548. let gamma: string = parser_material_parse_value_input(node.inputs[1]);
  549. return "pow(" + out_col + ", " + parser_material_to_vec3(gamma) + ")";
  550. }
  551. else if (node.type == "DIRECT_WARP") {
  552. if (parser_material_warp_passthrough) {
  553. return parser_material_parse_vector_input(node.inputs[0]);
  554. }
  555. let angle: string = parser_material_parse_value_input(node.inputs[1], true);
  556. let mask: string = parser_material_parse_value_input(node.inputs[2], true);
  557. let tex_name: string = "texwarp_" + parser_material_node_name(node);
  558. node_shader_add_uniform(parser_material_curshader, "sampler2D " + tex_name, "_" + tex_name);
  559. let store: string = parser_material_store_var_name(node);
  560. node_shader_write(parser_material_curshader, "float " + store + "_rad = " + angle + " * (" + math_pi() + " / 180);");
  561. node_shader_write(parser_material_curshader, "float " + store + "_x = cos(" + store + "_rad);");
  562. node_shader_write(parser_material_curshader, "float " + store + "_y = sin(" + store + "_rad);");
  563. return "texture(" + tex_name + ", texCoord + vec2(" + store + "_x, " + store + "_y) * " + mask + ").rgb;";
  564. }
  565. else if (node.type == "BLUR") {
  566. if (parser_material_blur_passthrough) {
  567. return parser_material_parse_vector_input(node.inputs[0]);
  568. }
  569. let strength: string = parser_material_parse_value_input(node.inputs[1]);
  570. if (strength == "0.0") {
  571. return "vec3(0.0, 0.0, 0.0)";
  572. }
  573. let steps: string = "int(" + strength + " * 10 + 1)";
  574. let tex_name: string = "texblur_" + parser_material_node_name(node);
  575. node_shader_add_uniform(parser_material_curshader, "sampler2D " + tex_name, "_" + tex_name);
  576. let store: string = parser_material_store_var_name(node);
  577. node_shader_write(parser_material_curshader, "vec3 " + store + "_res = vec3(0.0, 0.0, 0.0);");
  578. node_shader_write(parser_material_curshader, "for (int i = -" + steps + "; i <= " + steps + "; ++i) {");
  579. node_shader_write(parser_material_curshader, "for (int j = -" + steps + "; j <= " + steps + "; ++j) {");
  580. node_shader_write(parser_material_curshader, store + "_res += texture(" + tex_name + ", texCoord + vec2(i, j) / vec2(textureSize(" + tex_name + ", 0))).rgb;");
  581. node_shader_write(parser_material_curshader, "}");
  582. node_shader_write(parser_material_curshader, "}");
  583. node_shader_write(parser_material_curshader, store + "_res /= (" + steps + " * 2 + 1) * (" + steps + " * 2 + 1);");
  584. return store + "_res";
  585. }
  586. else if (node.type == "HUE_SAT") {
  587. node_shader_add_function(parser_material_curshader, str_hue_sat);
  588. let hue: string = parser_material_parse_value_input(node.inputs[0]);
  589. let sat: string = parser_material_parse_value_input(node.inputs[1]);
  590. let val: string = parser_material_parse_value_input(node.inputs[2]);
  591. let fac: string = parser_material_parse_value_input(node.inputs[3]);
  592. let col: string = parser_material_parse_vector_input(node.inputs[4]);
  593. return "hue_sat(" + col + ", vec4(" + hue + "-0.5, " + sat + ", " + val + ", 1.0-" + fac + "))";
  594. }
  595. else if (node.type == "INVERT") {
  596. let fac: string = parser_material_parse_value_input(node.inputs[0]);
  597. let out_col: string = parser_material_parse_vector_input(node.inputs[1]);
  598. return "mix(" + out_col + ", vec3(1.0, 1.0, 1.0) - (" + out_col + "), " + fac + ")";
  599. }
  600. else if (node.type == "MIX_RGB") {
  601. let fac: string = parser_material_parse_value_input(node.inputs[0]);
  602. let fac_var: string = parser_material_node_name(node) + "_fac";
  603. node_shader_write(parser_material_curshader, "float " + fac_var + " = " + fac + ";");
  604. let col1: string = parser_material_parse_vector_input(node.inputs[1]);
  605. let col2: string = parser_material_parse_vector_input(node.inputs[2]);
  606. let but: zui_node_button_t = node.buttons[0]; // blend_type
  607. let blend: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  608. blend = string_replace_all(blend, " ", "_");
  609. let use_clamp: bool = node.buttons[1].default_value[0] > 0;
  610. let out_col: string = "";
  611. if (blend == "MIX") {
  612. out_col = "mix(" + col1 + ", " + col2 + ", " + fac_var + ")";
  613. }
  614. else if (blend == "DARKEN") {
  615. out_col = "min(" + col1 + ", " + col2 + " * " + fac_var + ")";
  616. }
  617. else if (blend == "MULTIPLY") {
  618. out_col = "mix(" + col1 + ", " + col1 + " * " + col2 + ", " + fac_var + ")";
  619. }
  620. else if (blend == "BURN") {
  621. out_col = "mix(" + col1 + ", vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - " + col1 + ") / " + col2 + ", " + fac_var + ")";
  622. }
  623. else if (blend == "LIGHTEN") {
  624. out_col = "max(" + col1 + ", " + col2 + " * " + fac_var + ")";
  625. }
  626. else if (blend == "SCREEN") {
  627. out_col = "(vec3(1.0, 1.0, 1.0) - (" + parser_material_to_vec3("1.0 - " + fac_var + "") + " + " + fac_var + " * (vec3(1.0, 1.0, 1.0) - " + col2 + ")) * (vec3(1.0, 1.0, 1.0) - " + col1 + "))";
  628. }
  629. else if (blend == "DODGE") {
  630. out_col = "mix(" + col1 + ", " + col1 + " / (vec3(1.0, 1.0, 1.0) - " + col2 + "), " + fac_var + ")";
  631. }
  632. else if (blend == "ADD") {
  633. out_col = "mix(" + col1 + ", " + col1 + " + " + col2 + ", " + fac_var + ")";
  634. }
  635. else if (blend == "OVERLAY") {
  636. out_col = "mix(" + col1 + ", vec3( \
  637. " + col1 + ".r < 0.5 ? 2.0 * " + col1 + ".r * " + col2 + ".r : 1.0 - 2.0 * (1.0 - " + col1 + ".r) * (1.0 - " + col2 + ".r), \
  638. " + col1 + ".g < 0.5 ? 2.0 * " + col1 + ".g * " + col2 + ".g : 1.0 - 2.0 * (1.0 - " + col1 + ".g) * (1.0 - " + col2 + ".g), \
  639. " + col1 + ".b < 0.5 ? 2.0 * " + col1 + ".b * " + col2 + ".b : 1.0 - 2.0 * (1.0 - " + col1 + ".b) * (1.0 - " + col2 + ".b) \
  640. ), " + fac_var + ")";
  641. }
  642. else if (blend == "SOFT_LIGHT") {
  643. out_col = "((1.0 - " + fac_var + ") * " + col1 + " + " + fac_var + " * ((vec3(1.0, 1.0, 1.0) - " + col1 + ") * " + col2 + " * " + col1 + " + " + col1 + " * (vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - " + col2 + ") * (vec3(1.0, 1.0, 1.0) - " + col1 + "))))";
  644. }
  645. else if (blend == "LINEAR_LIGHT") {
  646. out_col = "(" + col1 + " + " + fac_var + " * (vec3(2.0, 2.0, 2.0) * (" + col2 + " - vec3(0.5, 0.5, 0.5))))";
  647. }
  648. else if (blend == "DIFFERENCE") {
  649. out_col = "mix(" + col1 + ", abs(" + col1 + " - " + col2 + "), " + fac_var + ")";
  650. }
  651. else if (blend == "SUBTRACT") {
  652. out_col = "mix(" + col1 + ", " + col1 + " - " + col2 + ", " + fac_var + ")";
  653. }
  654. else if (blend == "DIVIDE") {
  655. let eps: f32 = 0.000001;
  656. col2 = "max(" + col2 + ", vec3(" + eps + ", " + eps + ", " + eps + "))";
  657. out_col = "(" + parser_material_to_vec3("(1.0 - " + fac_var + ") * " + col1 + " + " + fac_var + " * " + col1 + " / " + col2) + ")";
  658. }
  659. else if (blend == "HUE") {
  660. node_shader_add_function(parser_material_curshader, str_hue_sat);
  661. out_col = "mix(" + col1 + ", hsv_to_rgb(vec3(rgb_to_hsv(" + col2 + ").r, rgb_to_hsv(" + col1 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")";
  662. }
  663. else if (blend == "SATURATION") {
  664. node_shader_add_function(parser_material_curshader, str_hue_sat);
  665. out_col = "mix(" + col1 + ", hsv_to_rgb(vec3(rgb_to_hsv(" + col1 + ").r, rgb_to_hsv(" + col2 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")";
  666. }
  667. else if (blend == "COLOR") {
  668. node_shader_add_function(parser_material_curshader, str_hue_sat);
  669. out_col = "mix(" + col1 + ", hsv_to_rgb(vec3(rgb_to_hsv(" + col2 + ").r, rgb_to_hsv(" + col2 + ").g, rgb_to_hsv(" + col1 + ").b)), " + fac_var + ")";
  670. }
  671. else if (blend == "VALUE") {
  672. node_shader_add_function(parser_material_curshader, str_hue_sat);
  673. out_col = "mix(" + col1 + ", hsv_to_rgb(vec3(rgb_to_hsv(" + col1 + ").r, rgb_to_hsv(" + col1 + ").g, rgb_to_hsv(" + col2 + ").b)), " + fac_var + ")";
  674. }
  675. if (use_clamp) {
  676. return "clamp(" + out_col + ", vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0))";
  677. }
  678. else {
  679. return out_col;
  680. }
  681. }
  682. else if (node.type == "QUANTIZE") {
  683. let strength: string = parser_material_parse_value_input(node.inputs[0]);
  684. let col: string = parser_material_parse_vector_input(node.inputs[1]);
  685. return "(floor(100.0 * " + strength + " * " + col + ") / (100.0 * " + strength + "))";
  686. }
  687. else if (node.type == "VALTORGB") { // ColorRamp
  688. let fac: string = parser_material_parse_value_input(node.inputs[0]);
  689. let interp: string = node.buttons[0].data[0] == 0 ? "LINEAR" : "CONSTANT";
  690. let elems: f32[][] = null; //node.buttons[0].default_value;
  691. if (elems.length == 1) {
  692. // return parser_material_vec3(elems[0]);
  693. }
  694. // Write cols array
  695. let cols_var: string = parser_material_node_name(node) + "_cols";
  696. node_shader_write(parser_material_curshader, "vec3 " + cols_var + "[" + elems.length + "];"); // TODO: Make const
  697. for (let i: i32 = 0; i < elems.length; ++i) {
  698. // node_shader_write(parser_material_curshader, cols_var + "[" + i + "] = " + parser_material_vec3(elems[i]) + ";");
  699. }
  700. // Get index
  701. let fac_var: string = parser_material_node_name(node) + "_fac";
  702. node_shader_write(parser_material_curshader, "float " + fac_var + " = " + fac + ";");
  703. let index: string = "0";
  704. for (let i: i32 = 1; i < elems.length; ++i) {
  705. index += " + (" + fac_var + " > " + elems[i][4] + " ? 1 : 0)";
  706. }
  707. // Write index
  708. let index_var: string = parser_material_node_name(node) + "_i";
  709. node_shader_write(parser_material_curshader, "int " + index_var + " = " + index + ";");
  710. if (interp == "CONSTANT") {
  711. return "" + cols_var + "[" + index_var + "]";
  712. }
  713. else { // Linear
  714. // Write facs array
  715. let facs_var: string = parser_material_node_name(node) + "_facs";
  716. node_shader_write(parser_material_curshader, "float " + facs_var + "[" + elems + "length}];"); // TODO: Make const
  717. for (let i: i32 = 0; i < elems.length; ++i) {
  718. node_shader_write(parser_material_curshader, facs_var + "[" + i + "] = " + elems[i][4] + ";");
  719. }
  720. // Mix color
  721. // float f = (pos - start) * (1.0 / (finish - start))
  722. return "mix(" + cols_var + "[" + index_var + "], " + cols_var + "[" + index_var + " + 1], (" + fac_var + " - " + facs_var + "[" + index_var + "]) * (1.0 / (" + facs_var + "[" + index_var + " + 1] - " + facs_var + "[" + index_var + "]) ))";
  723. }
  724. }
  725. else if (node.type == "CURVE_VEC") {
  726. let fac: string = parser_material_parse_value_input(node.inputs[0]);
  727. let vec: string = parser_material_parse_vector_input(node.inputs[1]);
  728. let curves: any = node.buttons[0].default_value;
  729. let name: string = parser_material_node_name(node);
  730. let vc0: string = parser_material_vector_curve(name + "0", vec + ".x", curves[0]);
  731. let vc1: string = parser_material_vector_curve(name + "1", vec + ".y", curves[1]);
  732. let vc2: string = parser_material_vector_curve(name + "2", vec + ".z", curves[2]);
  733. // mapping.curves[0].points[0].handle_type // bezier curve
  734. return "(vec3(" + vc0 + ", " + vc1 + ", " + vc2 + ") * " + fac + ")";
  735. }
  736. else if (node.type == "CURVE_RGB") { // RGB Curves
  737. let fac: string = parser_material_parse_value_input(node.inputs[0]);
  738. let vec: string = parser_material_parse_vector_input(node.inputs[1]);
  739. let curves: any = node.buttons[0].default_value;
  740. let name: string = parser_material_node_name(node);
  741. // mapping.curves[0].points[0].handle_type
  742. let vc0: string = parser_material_vector_curve(name + "0", vec + ".x", curves[0]);
  743. let vc1: string = parser_material_vector_curve(name + "1", vec + ".y", curves[1]);
  744. let vc2: string = parser_material_vector_curve(name + "2", vec + ".z", curves[2]);
  745. let vc3a: string = parser_material_vector_curve(name + "3a", vec + ".x", curves[3]);
  746. let vc3b: string = parser_material_vector_curve(name + "3b", vec + ".y", curves[3]);
  747. let vc3c: string = parser_material_vector_curve(name + "3c", vec + ".z", curves[3]);
  748. return "(sqrt(vec3(" + vc0 + ", " + vc1 + ", " + vc2 + ") * vec3(" + vc3a + ", " + vc3b + ", " + vc3c + ")) * " + fac + ")";
  749. }
  750. else if (node.type == "COMBHSV") {
  751. node_shader_add_function(parser_material_curshader, str_hue_sat);
  752. let h: string = parser_material_parse_value_input(node.inputs[0]);
  753. let s: string = parser_material_parse_value_input(node.inputs[1]);
  754. let v: string = parser_material_parse_value_input(node.inputs[2]);
  755. return "hsv_to_rgb(vec3(" + h + ", " + s + ", " + v + "))";
  756. }
  757. else if (node.type == "COMBRGB") {
  758. let r: string = parser_material_parse_value_input(node.inputs[0]);
  759. let g: string = parser_material_parse_value_input(node.inputs[1]);
  760. let b: string = parser_material_parse_value_input(node.inputs[2]);
  761. return "vec3(" + r + ", " + g + ", " + b + ")";
  762. }
  763. else if (node.type == "WAVELENGTH") {
  764. node_shader_add_function(parser_material_curshader, str_wavelength_to_rgb);
  765. let wl: string = parser_material_parse_value_input(node.inputs[0]);
  766. node_shader_add_function(parser_material_curshader, str_wavelength_to_rgb);
  767. return "wavelength_to_rgb((" + wl + " - 450.0) / 150.0)";
  768. }
  769. else if (node.type == "CAMERA") {
  770. parser_material_curshader.vvec_cam = true;
  771. return "vVecCam";
  772. }
  773. else if (node.type == "LAYER") {
  774. let l: any = node.buttons[0].default_value;
  775. if (socket == node.outputs[0]) { // Base
  776. node_shader_add_uniform(parser_material_curshader, "sampler2D texpaint" + l, "_texpaint" + l);
  777. return "texture(texpaint" + l + ", texCoord).rgb";
  778. }
  779. else if (socket == node.outputs[5]) { // Normal
  780. node_shader_add_uniform(parser_material_curshader, "sampler2D texpaint_nor" + l, "_texpaint_nor" + l);
  781. return "texture(texpaint_nor" + l + ", texCoord).rgb";
  782. }
  783. }
  784. else if (node.type == "MATERIAL") {
  785. let result: string = "vec3(0.0, 0.0, 0.0)";
  786. let mi: any = node.buttons[0].default_value;
  787. if (mi >= project_materials.length) {
  788. return result;
  789. }
  790. let m: slot_material_t = project_materials[mi];
  791. let _nodes: zui_node_t[] = parser_material_nodes;
  792. let _links: zui_node_link_t[] = parser_material_links;
  793. parser_material_nodes = m.canvas.nodes;
  794. parser_material_links = m.canvas.links;
  795. array_push(parser_material_parents, node);
  796. let output_node: zui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR");
  797. if (socket == node.outputs[0]) { // Base
  798. result = parser_material_parse_vector_input(output_node.inputs[0]);
  799. }
  800. else if (socket == node.outputs[5]) { // Normal
  801. result = parser_material_parse_vector_input(output_node.inputs[5]);
  802. }
  803. parser_material_nodes = _nodes;
  804. parser_material_links = _links;
  805. parser_material_parents.pop();
  806. return result;
  807. }
  808. else if (node.type == "PICKER") {
  809. if (socket == node.outputs[0]) { // Base
  810. node_shader_add_uniform(parser_material_curshader, "vec3 pickerBase", "_pickerBase");
  811. return "pickerBase";
  812. }
  813. else if (socket == node.outputs[5]) { // Normal
  814. node_shader_add_uniform(parser_material_curshader, "vec3 pickerNormal", "_pickerNormal");
  815. return "pickerNormal";
  816. }
  817. }
  818. else if (node.type == "NEW_GEOMETRY") {
  819. if (socket == node.outputs[0]) { // Position
  820. parser_material_curshader.wposition = true;
  821. return "wposition";
  822. }
  823. else if (socket == node.outputs[1]) { // Normal
  824. parser_material_curshader.n = true;
  825. return "n";
  826. }
  827. else if (socket == node.outputs[2]) { // Tangent
  828. parser_material_curshader.wtangent = true;
  829. return "wtangent";
  830. }
  831. else if (socket == node.outputs[3]) { // True Normal
  832. parser_material_curshader.n = true;
  833. return "n";
  834. }
  835. else if (socket == node.outputs[4]) { // Incoming
  836. parser_material_curshader.vvec = true;
  837. return "vVec";
  838. }
  839. else if (socket == node.outputs[5]) { // Parametric
  840. parser_material_curshader.mposition = true;
  841. return "mposition";
  842. }
  843. }
  844. else if (node.type == "OBJECT_INFO") {
  845. if (socket == node.outputs[0]) { // Location
  846. parser_material_curshader.wposition = true;
  847. return "wposition";
  848. }
  849. else if (socket == node.outputs[1]) { // Color
  850. return "vec3(0.0, 0.0, 0.0)";
  851. }
  852. }
  853. // else if (node.type == "PARTICLE_INFO") {
  854. // if (socket == node.outputs[3]) { // Location
  855. // return "vec3(0.0, 0.0, 0.0)";
  856. // }
  857. // else if (socket == node.outputs[5]) { // Velocity
  858. // return "vec3(0.0, 0.0, 0.0)";
  859. // }
  860. // else if (socket == node.outputs[6]) { // Angular Velocity
  861. // return "vec3(0.0, 0.0, 0.0)";
  862. // }
  863. // }
  864. else if (node.type == "TANGENT") {
  865. parser_material_curshader.wtangent = true;
  866. return "wtangent";
  867. }
  868. else if (node.type == "TEX_COORD") {
  869. if (socket == node.outputs[0]) { // Generated - bounds
  870. parser_material_curshader.bposition = true;
  871. return "bposition";
  872. }
  873. else if (socket == node.outputs[1]) { // Normal
  874. parser_material_curshader.n = true;
  875. return "n";
  876. }
  877. else if (socket == node.outputs[2]) {// UV
  878. node_shader_context_add_elem(parser_material_curshader.context, "tex", "short2norm");
  879. return "vec3(texCoord.x, texCoord.y, 0.0)";
  880. }
  881. else if (socket == node.outputs[3]) { // Object
  882. parser_material_curshader.mposition = true;
  883. return "mposition";
  884. }
  885. else if (socket == node.outputs[4]) { // Camera
  886. parser_material_curshader.vposition = true;
  887. return "vposition";
  888. }
  889. else if (socket == node.outputs[5]) { // Window
  890. parser_material_curshader.wvpposition = true;
  891. return "wvpposition.xyz";
  892. }
  893. else if (socket == node.outputs[6]) { // Reflection
  894. return "vec3(0.0, 0.0, 0.0)";
  895. }
  896. }
  897. else if (node.type == "UVMAP") {
  898. node_shader_context_add_elem(parser_material_curshader.context, "tex", "short2norm");
  899. return "vec3(texCoord.x, texCoord.y, 0.0)";
  900. }
  901. else if (node.type == "BUMP") {
  902. let strength: string = parser_material_parse_value_input(node.inputs[0]);
  903. // let distance: string = parse_value_input(node.inputs[1]);
  904. let height: string = parser_material_parse_value_input(node.inputs[2]);
  905. let nor: string = parser_material_parse_vector_input(node.inputs[3]);
  906. let sample_bump_res: string = parser_material_store_var_name(node) + "_bump";
  907. node_shader_write(parser_material_curshader, "float " + sample_bump_res + "_x = dFdx(float(" + height + ")) * (" + strength + ") * 16.0;");
  908. node_shader_write(parser_material_curshader, "float " + sample_bump_res + "_y = dFdy(float(" + height + ")) * (" + strength + ") * 16.0;");
  909. return "(normalize(vec3(" + sample_bump_res + "_x, " + sample_bump_res + "_y, 1.0) + " + nor + ") * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5))";
  910. }
  911. else if (node.type == "MAPPING") {
  912. let out: string = parser_material_parse_vector_input(node.inputs[0]);
  913. let node_translation: string = parser_material_parse_vector_input(node.inputs[1]);
  914. let node_rotation: string = parser_material_parse_vector_input(node.inputs[2]);
  915. let node_scale: string = parser_material_parse_vector_input(node.inputs[3]);
  916. if (node_scale != "vec3(1, 1, 1)") {
  917. out = "(" + out + " * " + node_scale + ")";
  918. }
  919. if (node_rotation != "vec3(0, 0, 0)") {
  920. // ZYX rotation, Z axis for now..
  921. let a: string = node_rotation + ".z * (3.1415926535 / 180)";
  922. // x * cos(theta) - y * sin(theta)
  923. // x * sin(theta) + y * cos(theta)
  924. out = "vec3(" + out + ".x * cos(" + a + ") - " + out + ".y * sin(" + a + "), " + out + ".x * sin(" + a + ") + " + out + ".y * cos(" + a + "), 0.0)";
  925. }
  926. // if node.rotation[1] != 0.0:
  927. // a = node.rotation[1]
  928. // out = "vec3({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1}, 0.0)".format(out, math_cos(a), math_sin(a))
  929. // if node.rotation[0] != 0.0:
  930. // a = node.rotation[0]
  931. // out = "vec3({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1}, 0.0)".format(out, math_cos(a), math_sin(a))
  932. if (node_translation != "vec3(0, 0, 0)") {
  933. out = "(" + out + " + " + node_translation + ")";
  934. }
  935. // if node.use_min:
  936. // out = "max({0}, vec3({1}, {2}, {3}))".format(out, node.min[0], node.min[1])
  937. // if node.use_max:
  938. // out = "min({0}, vec3({1}, {2}, {3}))".format(out, node.max[0], node.max[1])
  939. return out;
  940. }
  941. else if (node.type == "NORMAL") {
  942. if (socket == node.outputs[0]) {
  943. return parser_material_vec3(node.outputs[0].default_value);
  944. }
  945. else if (socket == node.outputs[1]) {
  946. let nor: string = parser_material_parse_vector_input(node.inputs[0]);
  947. let norout: string = parser_material_vec3(node.outputs[0].default_value);
  948. return parser_material_to_vec3("dot(" + norout + ", " + nor + ")");
  949. }
  950. }
  951. else if (node.type == "NORMAL_MAP") {
  952. let strength: string = parser_material_parse_value_input(node.inputs[0]);
  953. let norm: string = parser_material_parse_vector_input(node.inputs[1]);
  954. let store: string = parser_material_store_var_name(node);
  955. node_shader_write(parser_material_curshader, "vec3 " + store + "_texn = " + norm + " * 2.0 - 1.0;");
  956. node_shader_write(parser_material_curshader, "" + store + "_texn.xy = " + strength + " * " + store + "_texn.xy;");
  957. node_shader_write(parser_material_curshader, "" + store + "_texn = normalize(" + store + "_texn);");
  958. return "(0.5 * " + store + "_texn + 0.5)";
  959. }
  960. else if (node.type == "MIX_NORMAL_MAP") {
  961. let nm1: string = parser_material_parse_vector_input(node.inputs[0]);
  962. let nm2: string = parser_material_parse_vector_input(node.inputs[1]);
  963. let but: zui_node_button_t = node.buttons[0];
  964. let blend: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0])); // blend_type
  965. blend = string_replace_all(blend, " ", "_");
  966. let store: string = parser_material_store_var_name(node);
  967. // The blending algorithms are based on the paper "Blending in Detail" by Colin Barré-Brisebois and Stephen Hill 2012
  968. // https://blog.selfshadow.com/publications/blending-in-detail/
  969. if (blend == "PARTIAL_DERIVATIVE") { //partial derivate blending
  970. node_shader_write(parser_material_curshader, "vec3 " + store + "_n1 = " + nm1 + " * 2.0 - 1.0;");
  971. node_shader_write(parser_material_curshader, "vec3 " + store + "_n2 = " + nm2 + " * 2.0 - 1.0;");
  972. return "0.5 * normalize(vec3(" + store + "_n1.xy * " + store + "_n2.z + " + store + "_n2.xy * " + store + "_n1.z, " + store + "_n1.z * " + store + "_n2.z)) + 0.5;";
  973. }
  974. else if (blend == "WHITEOUT") { //whiteout blending
  975. node_shader_write(parser_material_curshader, "vec3 " + store + "_n1 = " + nm1 + " * 2.0 - 1.0;");
  976. node_shader_write(parser_material_curshader, "vec3 " + store + "_n2 = " + nm2 + " * 2.0 - 1.0;");
  977. return "0.5 * normalize(vec3(" + store + "_n1.xy + " + store + "_n2.xy, " + store + "_n1.z * " + store + "_n2.z)) + 0.5;";
  978. }
  979. else if (blend == "REORIENTED") { //reoriented normal mapping
  980. node_shader_write(parser_material_curshader, "vec3 " + store + "_n1 = " + nm1 + " * 2.0 - vec3(1.0, 1.0, 0.0);");
  981. node_shader_write(parser_material_curshader, "vec3 " + store + "_n2 = " + nm2 + " * vec3(-2.0, -2.0, 2.0) - vec3(-1.0, -1.0, 1.0);");
  982. return "0.5 * normalize(" + store + "_n1 * dot(" + store + "_n1, " + store + "_n2) - " + store + "_n2 * " + store + "_n1.z) + 0.5";
  983. }
  984. }
  985. else if (node.type == "VECT_TRANSFORM") {
  986. // type = node.vector_type
  987. // conv_from = node.convert_from
  988. // conv_to = node.convert_to
  989. // // Pass throuh
  990. // return parse_vector_input(node.inputs[0])
  991. }
  992. else if (node.type == "COMBXYZ") {
  993. let x: string = parser_material_parse_value_input(node.inputs[0]);
  994. let y: string = parser_material_parse_value_input(node.inputs[1]);
  995. let z: string = parser_material_parse_value_input(node.inputs[2]);
  996. return "vec3(" + x + ", " + y + ", " + z + ")";
  997. }
  998. else if (node.type == "VECT_MATH") {
  999. let vec1: string = parser_material_parse_vector_input(node.inputs[0]);
  1000. let vec2: string = parser_material_parse_vector_input(node.inputs[1]);
  1001. let but: zui_node_button_t = node.buttons[0]; //operation;
  1002. let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  1003. op = string_replace_all(op, " ", "_");
  1004. if (op == "ADD") {
  1005. return "(" + vec1 + " + " + vec2 + ")";
  1006. }
  1007. else if (op == "SUBTRACT") {
  1008. return "(" + vec1 + " - " + vec2 + ")";
  1009. }
  1010. else if (op == "AVERAGE") {
  1011. return "((" + vec1 + " + " + vec2 + ") / 2.0)";
  1012. }
  1013. else if (op == "DOT_PRODUCT") {
  1014. return parser_material_to_vec3("dot(" + vec1 + ", " + vec2 + ")");
  1015. }
  1016. else if (op == "LENGTH") {
  1017. return parser_material_to_vec3("length(" + vec1 + ")");
  1018. }
  1019. else if (op == "DISTANCE") {
  1020. return parser_material_to_vec3("distance(" + vec1 + ", " + vec2 + ")");
  1021. }
  1022. else if (op == "CROSS_PRODUCT") {
  1023. return "cross(" + vec1 + ", " + vec2 + ")";
  1024. }
  1025. else if (op == "NORMALIZE") {
  1026. return "normalize(" + vec1 + ")";
  1027. }
  1028. else if (op == "MULTIPLY") {
  1029. return "(" + vec1 + " * " + vec2 + ")";
  1030. }
  1031. else if (op == "DIVIDE") {
  1032. return "vec3(" + vec1 + ".x / (" + vec2 + ".x == 0 ? 0.000001 : " + vec2 + ".x), " + vec1 + ".y / (" + vec2 + ".y == 0 ? 0.000001 : " + vec2 + ".y), " + vec1 + ".z / (" + vec2 + ".z == 0 ? 0.000001 : " + vec2 + ".z))";
  1033. }
  1034. else if (op == "PROJECT") {
  1035. return "(dot(" + vec1 + ", " + vec2 + ") / dot(" + vec2 + ", " + vec2 + ") * " + vec2 + ")";
  1036. }
  1037. else if (op == "REFLECT") {
  1038. return "reflect(" + vec1 + ", normalize(" + vec2 + "))";
  1039. }
  1040. else if (op == "SCALE") {
  1041. return "(" + vec2 + ".x * " + vec1 + ")";
  1042. }
  1043. else if (op == "ABSOLUTE") {
  1044. return "abs(" + vec1 + ")";
  1045. }
  1046. else if (op == "MINIMUM") {
  1047. return "min(" + vec1 + ", " + vec2 + ")";
  1048. }
  1049. else if (op == "MAXIMUM") {
  1050. return "max(" + vec1 + ", " + vec2 + ")";
  1051. }
  1052. else if (op == "FLOOR") {
  1053. return "floor(" + vec1 + ")";
  1054. }
  1055. else if (op == "CEIL") {
  1056. return "ceil(" + vec1 + ")";
  1057. }
  1058. else if (op == "FRACTION") {
  1059. return "fract(" + vec1 + ")";
  1060. }
  1061. else if (op == "MODULO") {
  1062. return "mod(" + vec1 + ", " + vec2 + ")";
  1063. }
  1064. else if(op == "SNAP") {
  1065. return "(floor(" + vec1 + " / " + vec2 + ") * " + vec2 + ")";
  1066. }
  1067. else if (op == "SINE") {
  1068. return "sin(" + vec1 + ")";
  1069. }
  1070. else if (op == "COSINE") {
  1071. return "cos(" + vec1 + ")";
  1072. }
  1073. else if (op == "TANGENT") {
  1074. return "tan(" + vec1 + ")";
  1075. }
  1076. }
  1077. else if (node.type == "Displacement") {
  1078. let height: string = parser_material_parse_value_input(node.inputs[0]);
  1079. return parser_material_to_vec3(height);
  1080. }
  1081. else if (map_get(parser_material_custom_nodes, node.type) != null) {
  1082. return map_get(parser_material_custom_nodes, node.type)(node, socket);
  1083. }
  1084. return "vec3(0.0, 0.0, 0.0)";
  1085. }
  1086. function parse_normal_map_color_input(inp: zui_node_socket_t) {
  1087. parser_material_frag.write_normal++;
  1088. parser_material_out_normaltan = parser_material_parse_vector_input(inp);
  1089. if (!parser_material_arm_export_tangents) {
  1090. node_shader_write(parser_material_frag, "vec3 texn = (" + parser_material_out_normaltan + ") * 2.0 - 1.0;");
  1091. node_shader_write(parser_material_frag, "texn.y = -texn.y;");
  1092. if (!parser_material_cotangent_frame_written) {
  1093. parser_material_cotangent_frame_written = true;
  1094. node_shader_add_function(parser_material_frag, str_cotangent_frame);
  1095. }
  1096. parser_material_frag.n = true;
  1097. ///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
  1098. node_shader_write(parser_material_frag, "mat3 TBN = cotangentFrame(n, vVec, texCoord);");
  1099. ///else
  1100. node_shader_write(parser_material_frag, "mat3 TBN = cotangentFrame(n, -vVec, texCoord);");
  1101. ///end
  1102. node_shader_write(parser_material_frag, "n = mul(normalize(texn), TBN);");
  1103. }
  1104. parser_material_frag.write_normal--;
  1105. }
  1106. function parser_material_parse_value_input(inp: zui_node_socket_t, vector_as_grayscale: bool = false) : string {
  1107. let l: zui_node_link_t = parser_material_get_input_link(inp);
  1108. let from_node: zui_node_t = l != null ? parser_material_get_node(l.from_id) : null;
  1109. if (from_node != null) {
  1110. if (from_node.type == "REROUTE") {
  1111. return parser_material_parse_value_input(from_node.inputs[0]);
  1112. }
  1113. let res_var: string = parser_material_write_result(l);
  1114. let st: string = from_node.outputs[l.from_socket].type;
  1115. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  1116. if (vector_as_grayscale) {
  1117. return "dot(" + res_var + ".rbg, vec3(0.299, 0.587, 0.114))";
  1118. }
  1119. else {
  1120. return res_var + ".x";
  1121. }
  1122. }
  1123. else { // VALUE
  1124. return res_var;
  1125. }
  1126. }
  1127. else {
  1128. return parser_material_vec1(inp.default_value[0]);
  1129. }
  1130. }
  1131. function parser_material_parse_value(node: zui_node_t, socket: zui_node_socket_t): string {
  1132. if (node.type == "GROUP") {
  1133. return parser_material_parse_group(node, socket);
  1134. }
  1135. else if (node.type == "GROUP_INPUT") {
  1136. return parser_material_parse_group_input(node, socket);
  1137. }
  1138. else if (node.type == "ATTRIBUTE") {
  1139. node_shader_add_uniform(parser_material_curshader, "float time", "_time");
  1140. return "time";
  1141. }
  1142. else if (node.type == "VERTEX_COLOR") {
  1143. return "1.0";
  1144. }
  1145. else if (node.type == "WIREFRAME") {
  1146. node_shader_add_uniform(parser_material_curshader, "sampler2D texuvmap", "_texuvmap");
  1147. // let use_pixel_size: bool = node.buttons[0].default_value == "true";
  1148. // let pixel_size: f32 = parse_value_input(node.inputs[0]);
  1149. return "textureLod(texuvmap, texCoord, 0.0).r";
  1150. }
  1151. else if (node.type == "CAMERA") {
  1152. if (socket == node.outputs[1]) { // View Z Depth
  1153. node_shader_add_uniform(parser_material_curshader, "vec2 cameraProj", "_camera_plane_proj");
  1154. ///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
  1155. parser_material_curshader.wvpposition = true;
  1156. return "(cameraProj.y / ((wvpposition.z / wvpposition.w) - cameraProj.x))";
  1157. ///else
  1158. return "(cameraProj.y / (gl_FragCoord.z - cameraProj.x))";
  1159. ///end
  1160. }
  1161. else { // View Distance
  1162. node_shader_add_uniform(parser_material_curshader, "vec3 eye", "_camera_pos");
  1163. parser_material_curshader.wposition = true;
  1164. return "distance(eye, wposition)";
  1165. }
  1166. }
  1167. else if (node.type == "LAYER") {
  1168. let l: any = node.buttons[0].default_value;
  1169. if (socket == node.outputs[1]) { // Opac
  1170. node_shader_add_uniform(parser_material_curshader, "sampler2D texpaint" + l, "_texpaint" + l);
  1171. return "texture(texpaint" + l + ", texCoord).a";
  1172. }
  1173. else if (socket == node.outputs[2]) { // Occ
  1174. node_shader_add_uniform(parser_material_curshader, "sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
  1175. return "texture(texpaint_pack" + l + ", texCoord).r";
  1176. }
  1177. else if (socket == node.outputs[3]) { // Rough
  1178. node_shader_add_uniform(parser_material_curshader, "sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
  1179. return "texture(texpaint_pack" + l + ", texCoord).g";
  1180. }
  1181. else if (socket == node.outputs[4]) { // Metal
  1182. node_shader_add_uniform(parser_material_curshader, "sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
  1183. return "texture(texpaint_pack" + l + ", texCoord).b";
  1184. }
  1185. else if (socket == node.outputs[7]) { // Height
  1186. node_shader_add_uniform(parser_material_curshader, "sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
  1187. return "texture(texpaint_pack" + l + ", texCoord).a";
  1188. }
  1189. }
  1190. else if (node.type == "LAYER_MASK") {
  1191. if (socket == node.outputs[0]) {
  1192. let l: any = node.buttons[0].default_value;
  1193. node_shader_add_uniform(parser_material_curshader, "sampler2D texpaint" + l, "_texpaint" + l);
  1194. return "texture(texpaint" + l + ", texCoord).r";
  1195. }
  1196. }
  1197. else if (node.type == "MATERIAL") {
  1198. let result: string = "0.0";
  1199. let mi: any = node.buttons[0].default_value;
  1200. if (mi >= project_materials.length) return result;
  1201. let m: slot_material_t = project_materials[mi];
  1202. let _nodes: zui_node_t[] = parser_material_nodes;
  1203. let _links: zui_node_link_t[] = parser_material_links;
  1204. parser_material_nodes = m.canvas.nodes;
  1205. parser_material_links = m.canvas.links;
  1206. array_push(parser_material_parents, node);
  1207. let output_node: zui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR");
  1208. if (socket == node.outputs[1]) { // Opac
  1209. result = parser_material_parse_value_input(output_node.inputs[1]);
  1210. }
  1211. else if (socket == node.outputs[2]) { // Occ
  1212. result = parser_material_parse_value_input(output_node.inputs[2]);
  1213. }
  1214. else if (socket == node.outputs[3]) { // Rough
  1215. result = parser_material_parse_value_input(output_node.inputs[3]);
  1216. }
  1217. else if (socket == node.outputs[4]) { // Metal
  1218. result = parser_material_parse_value_input(output_node.inputs[4]);
  1219. }
  1220. else if (socket == node.outputs[7]) { // Height
  1221. result = parser_material_parse_value_input(output_node.inputs[7]);
  1222. }
  1223. parser_material_nodes = _nodes;
  1224. parser_material_links = _links;
  1225. parser_material_parents.pop();
  1226. return result;
  1227. }
  1228. else if (node.type == "PICKER") {
  1229. if (socket == node.outputs[1]) {
  1230. node_shader_add_uniform(parser_material_curshader, "float pickerOpacity", "_pickerOpacity");
  1231. return "pickerOpacity";
  1232. }
  1233. else if (socket == node.outputs[2]) {
  1234. node_shader_add_uniform(parser_material_curshader, "float pickerOcclusion", "_pickerOcclusion");
  1235. return "pickerOcclusion";
  1236. }
  1237. else if (socket == node.outputs[3]) {
  1238. node_shader_add_uniform(parser_material_curshader, "float pickerRoughness", "_pickerRoughness");
  1239. return "pickerRoughness";
  1240. }
  1241. else if (socket == node.outputs[4]) {
  1242. node_shader_add_uniform(parser_material_curshader, "float pickerMetallic", "_pickerMetallic");
  1243. return "pickerMetallic";
  1244. }
  1245. else if (socket == node.outputs[7]) {
  1246. node_shader_add_uniform(parser_material_curshader, "float pickerHeight", "_pickerHeight");
  1247. return "pickerHeight";
  1248. }
  1249. }
  1250. else if (node.type == "FRESNEL") {
  1251. let ior: string = parser_material_parse_value_input(node.inputs[0]);
  1252. parser_material_curshader.dotnv = true;
  1253. return "pow(1.0 - dotNV, 7.25 / " + ior + ")";
  1254. }
  1255. else if (node.type == "NEW_GEOMETRY") {
  1256. if (socket == node.outputs[6]) { // Backfacing
  1257. ///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
  1258. return "0.0"; // SV_IsFrontFace
  1259. ///else
  1260. return "(1.0 - float(gl_FrontFacing))";
  1261. ///end
  1262. }
  1263. else if (socket == node.outputs[7]) { // Pointiness
  1264. let strength: f32 = 1.0;
  1265. let radius: f32 = 1.0;
  1266. let offset: f32 = 0.0;
  1267. let store: string = parser_material_store_var_name(node);
  1268. parser_material_curshader.n = true;
  1269. node_shader_write(parser_material_curshader, "vec3 " + store + "_dx = dFdx(n);");
  1270. node_shader_write(parser_material_curshader, "vec3 " + store + "_dy = dFdy(n);");
  1271. node_shader_write(parser_material_curshader, "float " + store + "_curvature = max(dot(" + store + "_dx, " + store + "_dx), dot(" + store + "_dy, " + store + "_dy));");
  1272. node_shader_write(parser_material_curshader, store + "_curvature = clamp(pow(" + store + "_curvature, (1.0 / " + radius + ") * 0.25) * " + strength + " * 2.0 + " + offset + " / 10.0, 0.0, 1.0);");
  1273. return store + "_curvature";
  1274. }
  1275. else if (socket == node.outputs[8]) { // Random Per Island
  1276. return "0.0";
  1277. }
  1278. }
  1279. else if (node.type == "HAIR_INFO") {
  1280. return "0.5";
  1281. }
  1282. else if (node.type == "LAYER_WEIGHT") {
  1283. let blend: string = parser_material_parse_value_input(node.inputs[0]);
  1284. if (socket == node.outputs[0]) { // Fresnel
  1285. parser_material_curshader.dotnv = true;
  1286. return "clamp(pow(1.0 - dotNV, (1.0 - " + blend + ") * 10.0), 0.0, 1.0)";
  1287. }
  1288. else if (socket == node.outputs[1]) { // Facing
  1289. parser_material_curshader.dotnv = true;
  1290. return "((1.0 - dotNV) * " + blend + ")";
  1291. }
  1292. }
  1293. else if (node.type == "OBJECT_INFO") {
  1294. if (socket == node.outputs[1]) { // Object Index
  1295. node_shader_add_uniform(parser_material_curshader, "float objectInfoIndex", "_object_info_index");
  1296. return "objectInfoIndex";
  1297. }
  1298. else if (socket == node.outputs[2]) { // Material Index
  1299. node_shader_add_uniform(parser_material_curshader, "float objectInfoMaterialIndex", "_object_info_material_index");
  1300. return "objectInfoMaterialIndex";
  1301. }
  1302. else if (socket == node.outputs[3]) { // Random
  1303. node_shader_add_uniform(parser_material_curshader, "float objectInfoRandom", "_object_info_random");
  1304. return "objectInfoRandom";
  1305. }
  1306. }
  1307. else if (node.type == "VALUE") {
  1308. return parser_material_vec1(node.outputs[0].default_value[0]);
  1309. }
  1310. else if (node.type == "TEX_BRICK") {
  1311. node_shader_add_function(parser_material_curshader, str_tex_brick);
  1312. let co: string = parser_material_get_coord(node);
  1313. let scale: string = parser_material_parse_value_input(node.inputs[4]);
  1314. let res: string = "tex_brick_f(" + co + " * " + scale + ")";
  1315. return res;
  1316. }
  1317. else if (node.type == "TEX_CHECKER") {
  1318. node_shader_add_function(parser_material_curshader, str_tex_checker);
  1319. let co: string = parser_material_get_coord(node);
  1320. let scale: string = parser_material_parse_value_input(node.inputs[3]);
  1321. let res: string = "tex_checker_f(" + co + ", " + scale + ")";
  1322. return res;
  1323. }
  1324. else if (node.type == "TEX_GRADIENT") {
  1325. let co: string = parser_material_get_coord(node);
  1326. let but: zui_node_button_t = node.buttons[0]; //gradient_type;
  1327. let grad: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  1328. grad = string_replace_all(grad, " ", "_");
  1329. let f: string = parser_material_get_gradient(grad, co);
  1330. let res: string = "(clamp(" + f + ", 0.0, 1.0))";
  1331. return res;
  1332. }
  1333. else if (node.type == "TEX_IMAGE") {
  1334. // Already fetched
  1335. if (array_index_of(parser_material_parsed, parser_material_res_var_name(node, node.outputs[0])) >= 0) { // TODO: node.outputs[1]
  1336. let varname: string = parser_material_store_var_name(node);
  1337. return varname + ".a";
  1338. }
  1339. let tex_name: string = parser_material_node_name(node);
  1340. let tex: bind_tex_t = parser_material_make_texture(node, tex_name);
  1341. if (tex != null) {
  1342. let color_space: i32 = node.buttons[1].default_value[0];
  1343. let texstore: string = parser_material_texture_store(node, tex, tex_name, color_space);
  1344. return texstore + ".a";
  1345. }
  1346. }
  1347. else if (node.type == "TEX_MAGIC") {
  1348. node_shader_add_function(parser_material_curshader, str_tex_magic);
  1349. let co: string = parser_material_get_coord(node);
  1350. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  1351. let res: string = "tex_magic_f(" + co + " * " + scale + " * 4.0)";
  1352. return res;
  1353. }
  1354. else if (node.type == "TEX_MUSGRAVE") {
  1355. node_shader_add_function(parser_material_curshader, str_tex_musgrave);
  1356. let co: string = parser_material_get_coord(node);
  1357. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  1358. let res: string = "tex_musgrave_f(" + co + " * " + scale + " * 0.5)";
  1359. return res;
  1360. }
  1361. else if (node.type == "TEX_NOISE") {
  1362. node_shader_add_function(parser_material_curshader, str_tex_noise);
  1363. let co: string = parser_material_get_coord(node);
  1364. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  1365. let res: string = "tex_noise(" + co + " * " + scale + ")";
  1366. return res;
  1367. }
  1368. else if (node.type == "TEX_VORONOI") {
  1369. node_shader_add_function(parser_material_curshader, str_tex_voronoi);
  1370. node_shader_add_uniform(parser_material_curshader, "sampler2D snoise256", "$noise256.k");
  1371. let co: string = parser_material_get_coord(node);
  1372. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  1373. let but: zui_node_button_t = node.buttons[0]; // coloring
  1374. let coloring: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  1375. coloring = string_replace_all(coloring, " ", "_");
  1376. let res: string = "";
  1377. if (coloring == "INTENSITY") {
  1378. res = "tex_voronoi(" + co + " * " + scale + ", texturePass(snoise256)).a";
  1379. }
  1380. else { // Cells
  1381. res = "tex_voronoi(" + co + " * " + scale + ", texturePass(snoise256)).r";
  1382. }
  1383. return res;
  1384. }
  1385. else if (node.type == "TEX_WAVE") {
  1386. node_shader_add_function(parser_material_curshader, str_tex_wave);
  1387. let co: string = parser_material_get_coord(node);
  1388. let scale: string = parser_material_parse_value_input(node.inputs[1]);
  1389. let res: string = "tex_wave_f(" + co + " * " + scale + ")";
  1390. return res;
  1391. }
  1392. else if (node.type == "BAKE_CURVATURE") {
  1393. if (parser_material_bake_passthrough) {
  1394. parser_material_bake_passthrough_strength = parser_material_parse_value_input(node.inputs[0]);
  1395. parser_material_bake_passthrough_radius = parser_material_parse_value_input(node.inputs[1]);
  1396. parser_material_bake_passthrough_offset = parser_material_parse_value_input(node.inputs[2]);
  1397. return "0.0";
  1398. }
  1399. let tex_name: string = "texbake_" + parser_material_node_name(node);
  1400. node_shader_add_uniform(parser_material_curshader, "sampler2D " + tex_name, "_" + tex_name);
  1401. let store: string = parser_material_store_var_name(node);
  1402. node_shader_write(parser_material_curshader, "float " + store + "_res = texture(" + tex_name + ", texCoord).r;");
  1403. return store + "_res";
  1404. }
  1405. else if (node.type == "NORMAL") {
  1406. let nor: string = parser_material_parse_vector_input(node.inputs[0]);
  1407. let norout: string = parser_material_vec3(node.outputs[0].default_value);
  1408. return "dot(" + norout + ", " + nor + ")";
  1409. }
  1410. else if (node.type == "COLMASK") {
  1411. let inputColor: string = parser_material_parse_vector_input(node.inputs[0]);
  1412. let maskColor: string = parser_material_parse_vector_input(node.inputs[1]);
  1413. let radius: string = parser_material_parse_value_input(node.inputs[2]);
  1414. let fuzziness: string = parser_material_parse_value_input(node.inputs[3]);
  1415. return "clamp(1.0 - (distance(" + inputColor + ", " + maskColor + ") - " + radius + ") / max(" + fuzziness + ", " + parser_material_eps + "), 0.0, 1.0)";
  1416. }
  1417. else if (node.type == "MATH") {
  1418. let val1: string = parser_material_parse_value_input(node.inputs[0]);
  1419. let val2: string = parser_material_parse_value_input(node.inputs[1]);
  1420. let but: zui_node_button_t = node.buttons[0]; // operation
  1421. let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  1422. op = string_replace_all(op, " ", "_");
  1423. let use_clamp: bool = node.buttons[1].default_value[0] > 0;
  1424. let out_val: string = "";
  1425. if (op == "ADD") {
  1426. out_val = "(" + val1 + " + " + val2 + ")";
  1427. }
  1428. else if (op == "SUBTRACT") {
  1429. out_val = "(" + val1 + " - " + val2 + ")";
  1430. }
  1431. else if (op == "MULTIPLY") {
  1432. out_val = "(" + val1 + " * " + val2 + ")";
  1433. }
  1434. else if (op == "DIVIDE") {
  1435. val2 = "(" + val2 + " == 0.0 ? " + parser_material_eps + " : " + val2 + ")";
  1436. out_val = "(" + val1 + " / " + val2 + ")";
  1437. }
  1438. else if (op == "POWER") {
  1439. out_val = "pow(" + val1 + ", " + val2 + ")";
  1440. }
  1441. else if (op == "LOGARITHM") {
  1442. out_val = "log(" + val1 + ")";
  1443. }
  1444. else if (op == "SQUARE_ROOT") {
  1445. out_val = "sqrt(" + val1 + ")";
  1446. }
  1447. else if(op == "INVERSE_SQUARE_ROOT") {
  1448. out_val = "inversesqrt(" + val1 + ")";
  1449. }
  1450. else if (op == "EXPONENT") {
  1451. out_val = "exp(" + val1 + ")";
  1452. }
  1453. else if (op == "ABSOLUTE") {
  1454. out_val = "abs(" + val1 + ")";
  1455. }
  1456. else if (op == "MINIMUM") {
  1457. out_val = "min(" + val1 + ", " + val2 + ")";
  1458. }
  1459. else if (op == "MAXIMUM") {
  1460. out_val = "max(" + val1 + ", " + val2 + ")";
  1461. }
  1462. else if (op == "LESS_THAN") {
  1463. out_val = "float(" + val1 + " < " + val2 + ")";
  1464. }
  1465. else if (op == "GREATER_THAN") {
  1466. out_val = "float(" + val1 + " > " + val2 + ")";
  1467. }
  1468. else if (op == "SIGN") {
  1469. out_val = "sign(" + val1 + ")";
  1470. }
  1471. else if (op == "ROUND") {
  1472. out_val = "floor(" + val1 + " + 0.5)";
  1473. }
  1474. else if (op == "FLOOR") {
  1475. out_val = "floor(" + val1 + ")";
  1476. }
  1477. else if (op == "CEIL") {
  1478. out_val = "ceil(" + val1 + ")";
  1479. }
  1480. else if(op == "SNAP") {
  1481. out_val = "(floor(" + val1 + " / " + val2 + ") * " + val2 + ")";
  1482. }
  1483. else if (op == "TRUNCATE") {
  1484. out_val = "trunc(" + val1 + ")";
  1485. }
  1486. else if (op == "FRACTION") {
  1487. out_val = "fract(" + val1 + ")";
  1488. }
  1489. else if (op == "MODULO") {
  1490. out_val = "mod(" + val1 + ", " + val2 + ")";
  1491. }
  1492. else if (op == "PING-PONG") {
  1493. out_val = "((" + val2 + " != 0.0) ? abs(fract((" + val1 + " - " + val2 + ") / (" + val2 + " * 2.0)) * " + val2 + " * 2.0 - " + val2 + ") : 0.0)";
  1494. }
  1495. else if (op == "SINE") {
  1496. out_val = "sin(" + val1 + ")";
  1497. }
  1498. else if (op == "COSINE") {
  1499. out_val = "cos(" + val1 + ")";
  1500. }
  1501. else if (op == "TANGENT") {
  1502. out_val = "tan(" + val1 + ")";
  1503. }
  1504. else if (op == "ARCSINE") {
  1505. out_val = "asin(" + val1 + ")";
  1506. }
  1507. else if (op == "ARCCOSINE") {
  1508. out_val = "acos(" + val1 + ")";
  1509. }
  1510. else if (op == "ARCTANGENT") {
  1511. out_val = "atan(" + val1 + ")";
  1512. }
  1513. else if (op == "ARCTAN2") {
  1514. out_val = "atan2(" + val1 + ", " + val2 + ")";
  1515. }
  1516. else if (op == "HYPERBOLIC_SINE") {
  1517. out_val = "sinh(" + val1 + ")";
  1518. }
  1519. else if (op == "HYPERBOLIC_COSINE") {
  1520. out_val = "cosh(" + val1 + ")";
  1521. }
  1522. else if (op == "HYPERBOLIC_TANGENT") {
  1523. out_val = "tanh(" + val1 + ")";
  1524. }
  1525. else if (op == "TO_RADIANS") {
  1526. out_val = "radians(" + val1 + ")";
  1527. }
  1528. else if (op == "TO_DEGREES") {
  1529. out_val = "degrees(" + val1 + ")";
  1530. }
  1531. if (use_clamp) {
  1532. return "clamp(" + out_val + ", 0.0, 1.0)";
  1533. }
  1534. else {
  1535. return out_val;
  1536. }
  1537. }
  1538. else if (node.type == "SCRIPT_CPU") {
  1539. if (parser_material_script_links == null) {
  1540. parser_material_script_links = map_create();
  1541. }
  1542. let script: any = node.buttons[0].default_value;
  1543. let link: string = parser_material_node_name(node);
  1544. map_set(parser_material_script_links, link, script);
  1545. node_shader_add_uniform(parser_material_curshader, "float " + link, "_" + link);
  1546. return link;
  1547. }
  1548. else if (node.type == "SHADER_GPU") {
  1549. let shader: any = node.buttons[0].default_value;
  1550. return shader == "" ? "0.0" : shader;
  1551. }
  1552. else if (node.type == "RGBTOBW") {
  1553. let col: string = parser_material_parse_vector_input(node.inputs[0]);
  1554. return "(((" + col + ".r * 0.3 + " + col + ".g * 0.59 + " + col + ".b * 0.11) / 3.0) * 2.5)";
  1555. }
  1556. else if (node.type == "SEPHSV") {
  1557. node_shader_add_function(parser_material_curshader, str_hue_sat);
  1558. let col: string = parser_material_parse_vector_input(node.inputs[0]);
  1559. if (socket == node.outputs[0]) {
  1560. return "rgb_to_hsv(" + col + ").r";
  1561. }
  1562. else if (socket == node.outputs[1]) {
  1563. return "rgb_to_hsv(" + col + ").g";
  1564. }
  1565. else if (socket == node.outputs[2]) {
  1566. return "rgb_to_hsv(" + col + ").b";
  1567. }
  1568. }
  1569. else if (node.type == "SEPRGB") {
  1570. let col: string = parser_material_parse_vector_input(node.inputs[0]);
  1571. if (socket == node.outputs[0]) {
  1572. return col + ".r";
  1573. }
  1574. else if (socket == node.outputs[1]) {
  1575. return col + ".g";
  1576. }
  1577. else if (socket == node.outputs[2]) {
  1578. return col + ".b";
  1579. }
  1580. }
  1581. else if (node.type == "SEPXYZ") {
  1582. let vec: string = parser_material_parse_vector_input(node.inputs[0]);
  1583. if (socket == node.outputs[0]) {
  1584. return vec + ".x";
  1585. }
  1586. else if (socket == node.outputs[1]) {
  1587. return vec + ".y";
  1588. }
  1589. else if (socket == node.outputs[2]) {
  1590. return vec + ".z";
  1591. }
  1592. }
  1593. else if (node.type == "VECT_MATH") {
  1594. let vec1: string = parser_material_parse_vector_input(node.inputs[0]);
  1595. let vec2: string = parser_material_parse_vector_input(node.inputs[1]);
  1596. let but: zui_node_button_t = node.buttons[0]; //operation;
  1597. let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  1598. op = string_replace_all(op, " ", "_");
  1599. if (op == "DOT_PRODUCT") {
  1600. return "dot(" + vec1 + ", " + vec2 + ")";
  1601. }
  1602. else if (op == "LENGTH") {
  1603. return "length(" + vec1 + ")";
  1604. }
  1605. else if (op == "DISTANCE") {
  1606. return "distance(" + vec1 + ", " + vec2 + ")";
  1607. }
  1608. else {
  1609. return "0.0";
  1610. }
  1611. }
  1612. else if (node.type == "CLAMP") {
  1613. let val: string = parser_material_parse_value_input(node.inputs[0]);
  1614. let min: string = parser_material_parse_value_input(node.inputs[1]);
  1615. let max: string = parser_material_parse_value_input(node.inputs[2]);
  1616. let but: zui_node_button_t = node.buttons[0]; //operation;
  1617. let op: string = to_upper_case(u8_array_string_at(but.data, but.default_value[0]));
  1618. op = string_replace_all(op, " ", "_");
  1619. if (op == "MIN_MAX") {
  1620. return "(clamp(" + val + ", " + min + ", " + max + "))";
  1621. }
  1622. else if (op == "RANGE") {
  1623. return "(clamp(" + val + ", min(" + min + ", " + max + "), max(" + min + ", " + max + ")))";
  1624. }
  1625. }
  1626. else if (node.type == "MAPRANGE") {
  1627. let val: string = parser_material_parse_value_input(node.inputs[0]);
  1628. let fmin: string = parser_material_parse_value_input(node.inputs[1]);
  1629. let fmax: string = parser_material_parse_value_input(node.inputs[2]);
  1630. let tmin: string = parser_material_parse_value_input(node.inputs[3]);
  1631. let tmax: string = parser_material_parse_value_input(node.inputs[4]);
  1632. let use_clamp: bool = node.buttons[0].default_value[0] > 0;
  1633. let a: string = "((" + tmin + " - " + tmax + ") / (" + fmin + " - " + fmax + "))";
  1634. let out_val: string = "(" + a + " * " + val + " + " + tmin + " - " + a + " * " + fmin + ")";
  1635. if (use_clamp) {
  1636. return "(clamp(" + out_val + ", " + tmin + ", " + tmax + "))";
  1637. }
  1638. else {
  1639. return out_val;
  1640. }
  1641. }
  1642. else if (map_get(parser_material_custom_nodes, node.type) != null) {
  1643. return map_get(parser_material_custom_nodes, node.type)(node, socket);
  1644. }
  1645. return "0.0";
  1646. }
  1647. function parser_material_get_coord(node: zui_node_t): string {
  1648. if (parser_material_get_input_link(node.inputs[0]) != null) {
  1649. return parser_material_parse_vector_input(node.inputs[0]);
  1650. }
  1651. else {
  1652. parser_material_curshader.bposition = true;
  1653. return "bposition";
  1654. }
  1655. }
  1656. function parser_material_get_gradient(grad: string, co: string): string {
  1657. if (grad == "LINEAR") {
  1658. return co + ".x";
  1659. }
  1660. else if (grad == "QUADRATIC") {
  1661. return "0.0";
  1662. }
  1663. else if (grad == "EASING") {
  1664. return "0.0";
  1665. }
  1666. else if (grad == "DIAGONAL") {
  1667. return "(" + co + ".x + " + co + ".y) * 0.5";
  1668. }
  1669. else if (grad == "RADIAL") {
  1670. return "atan2(" + co + ".x, " + co + ".y) / (3.141592 * 2.0) + 0.5";
  1671. }
  1672. else if (grad == "QUADRATIC_SPHERE") {
  1673. return "0.0";
  1674. }
  1675. else { // "SPHERICAL"
  1676. return "max(1.0 - sqrt(" + co + ".x * " + co + ".x + " + co + ".y * " + co + ".y + " + co + ".z * " + co + ".z), 0.0)";
  1677. }
  1678. }
  1679. function parser_material_vector_curve(name: string, fac: string, points: f32_array_t[]): string {
  1680. // Write Ys array
  1681. let ys_var: string = name + "_ys";
  1682. let num: i32 = points.length;
  1683. node_shader_write(parser_material_curshader, "float " + ys_var + "[" + num + "];"); // TODO: Make const
  1684. for (let i: i32 = 0; i < num; ++i) {
  1685. node_shader_write(parser_material_curshader, ys_var + "[" + i + "] = " + points[i][1] + ";");
  1686. }
  1687. // Get index
  1688. let fac_var: string = name + "_fac";
  1689. node_shader_write(parser_material_curshader, "float " + fac_var + " = " + fac + ";");
  1690. let index: string = "0";
  1691. for (let i: i32 = 1; i < num; ++i) {
  1692. index += " + (" + fac_var + " > " + points[i][0] + " ? 1 : 0)";
  1693. }
  1694. // Write index
  1695. let index_var: string = name + "_i";
  1696. node_shader_write(parser_material_curshader, "int " + index_var + " = " + index + ";");
  1697. // Linear
  1698. // Write Xs array
  1699. let facs_var: string = name + "_xs";
  1700. node_shader_write(parser_material_curshader, "float " + facs_var + "[" + num + "];"); // TODO: Make const
  1701. for (let i: i32 = 0; i < num; ++i) {
  1702. node_shader_write(parser_material_curshader, "" + facs_var + "[" + i + "] = " + points[i][0] + ";");
  1703. }
  1704. // Map vector
  1705. return "mix(" + ys_var + "[" + index_var + "], " + ys_var + "[" + index_var + " + 1], (" + fac_var + " - " + facs_var + "[" + index_var + "]) * (1.0 / (" + facs_var + "[" + index_var + " + 1] - " + facs_var + "[" + index_var + "])))";
  1706. }
  1707. function parser_material_res_var_name(node: zui_node_t, socket: zui_node_socket_t): string {
  1708. return parser_material_node_name(node) + "_" + parser_material_safesrc(socket.name) + "_res";
  1709. }
  1710. function parser_material_write_result(l: zui_node_link_t): string {
  1711. let from_node: zui_node_t = parser_material_get_node(l.from_id);
  1712. let from_socket: zui_node_socket_t = from_node.outputs[l.from_socket];
  1713. let res_var: string = parser_material_res_var_name(from_node, from_socket);
  1714. let st: string = from_socket.type;
  1715. if (array_index_of(parser_material_parsed, res_var) < 0) {
  1716. array_push(parser_material_parsed, res_var);
  1717. if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
  1718. let res: string = parser_material_parse_vector(from_node, from_socket);
  1719. if (res == null) {
  1720. return null;
  1721. }
  1722. map_set(parser_material_parsed_map, res_var, res);
  1723. node_shader_write(parser_material_curshader, "vec3 " + res_var + " = " + res + ";");
  1724. }
  1725. else if (st == "VALUE") {
  1726. let res: string = parser_material_parse_value(from_node, from_socket);
  1727. if (res == null) {
  1728. return null;
  1729. }
  1730. map_set(parser_material_parsed_map, res_var, res);
  1731. node_shader_write(parser_material_curshader, "float " + res_var + " = " + res + ";");
  1732. }
  1733. }
  1734. return res_var;
  1735. }
  1736. function parser_material_store_var_name(node: zui_node_t): string {
  1737. return parser_material_node_name(node) + "_store";
  1738. }
  1739. function parser_material_texture_store(node: zui_node_t, tex: bind_tex_t, tex_name: string, color_space: i32): string {
  1740. array_push(parser_material_matcon.bind_textures, tex);
  1741. node_shader_context_add_elem(parser_material_curshader.context, "tex", "short2norm");
  1742. node_shader_add_uniform(parser_material_curshader, "sampler2D " + tex_name);
  1743. let uv_name: string = "";
  1744. if (parser_material_get_input_link(node.inputs[0]) != null) {
  1745. uv_name = parser_material_parse_vector_input(node.inputs[0]);
  1746. }
  1747. else {
  1748. uv_name = parser_material_tex_coord;
  1749. }
  1750. let tex_store: string = parser_material_store_var_name(node);
  1751. if (parser_material_sample_keep_aspect) {
  1752. node_shader_write(parser_material_curshader, "vec2 " + tex_store + "_size = vec2(textureSize(" + tex_name + ", 0));");
  1753. node_shader_write(parser_material_curshader, "float " + tex_store + "_ax = " + tex_store + "_size.x / " + tex_store + "_size.y;");
  1754. node_shader_write(parser_material_curshader, "float " + tex_store + "_ay = " + tex_store + "_size.y / " + tex_store + "_size.x;");
  1755. node_shader_write(parser_material_curshader, "vec2 " + tex_store + "_uv = ((" + uv_name + ".xy / " + parser_material_sample_uv_scale + " - vec2(0.5, 0.5)) * vec2(max(" + tex_store + "_ay, 1.0), max(" + tex_store + "_ax, 1.0))) + vec2(0.5, 0.5);");
  1756. node_shader_write(parser_material_curshader, "if (" + tex_store + "_uv.x < 0.0 || " + tex_store + "_uv.y < 0.0 || " + tex_store + "_uv.x > 1.0 || " + tex_store + "_uv.y > 1.0) discard;");
  1757. node_shader_write(parser_material_curshader, "" + tex_store + "_uv *= " + parser_material_sample_uv_scale + ";");
  1758. uv_name = tex_store + "_uv";
  1759. }
  1760. if (parser_material_triplanar) {
  1761. node_shader_write(parser_material_curshader, "vec4 " + tex_store + " = vec4(0.0, 0.0, 0.0, 0.0);");
  1762. node_shader_write(parser_material_curshader, "if (texCoordBlend.x > 0) " + tex_store + " += texture(" + tex_name + ", " + uv_name + ".xy) * texCoordBlend.x;");
  1763. node_shader_write(parser_material_curshader, "if (texCoordBlend.y > 0) " + tex_store + " += texture(" + tex_name + ", " + uv_name + "1.xy) * texCoordBlend.y;");
  1764. node_shader_write(parser_material_curshader, "if (texCoordBlend.z > 0) " + tex_store + " += texture(" + tex_name + ", " + uv_name + "2.xy) * texCoordBlend.z;");
  1765. }
  1766. else {
  1767. if (parser_material_curshader == parser_material_frag) {
  1768. map_set(parser_material_texture_map, tex_store, "texture(" + tex_name + ", " + uv_name + ".xy)");
  1769. node_shader_write(parser_material_curshader, "vec4 " + tex_store + " = texture(" + tex_name + ", " + uv_name + ".xy);");
  1770. }
  1771. else {
  1772. map_set(parser_material_texture_map, tex_store, "textureLod(" + tex_name + ", " + uv_name + ".xy, 0.0)");
  1773. node_shader_write(parser_material_curshader, "vec4 " + tex_store + " = textureLod(" + tex_name + ", " + uv_name + ".xy, 0.0);");
  1774. }
  1775. if (!ends_with(tex.file, ".jpg")) { // Pre-mult alpha
  1776. node_shader_write(parser_material_curshader, tex_store + ".rgb *= " + tex_store + ".a;");
  1777. }
  1778. }
  1779. if (parser_material_transform_color_space) {
  1780. // Base color socket auto-converts from sRGB to linear
  1781. if (color_space == color_space_t.LINEAR && parser_material_parsing_basecolor) { // Linear to sRGB
  1782. node_shader_write(parser_material_curshader, tex_store + ".rgb = pow(" + tex_store + ".rgb, vec3(2.2, 2.2, 2.2));");
  1783. }
  1784. else if (color_space == color_space_t.SRGB && !parser_material_parsing_basecolor) { // sRGB to linear
  1785. node_shader_write(parser_material_curshader, tex_store + ".rgb = pow(" + tex_store + ".rgb, vec3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2));");
  1786. }
  1787. else if (color_space == color_space_t.DIRECTX_NORMAL_MAP) { // DirectX normal map to OpenGL normal map
  1788. node_shader_write(parser_material_curshader, tex_store + ".y = 1.0 - " + tex_store + ".y;");
  1789. }
  1790. }
  1791. return tex_store;
  1792. }
  1793. function parser_material_vec1(v: f32): string {
  1794. ///if krom_android
  1795. return "float(" + v + ")";
  1796. ///else
  1797. return v + "";
  1798. ///end
  1799. }
  1800. function parser_material_vec3(v: f32_array_t): string {
  1801. ///if krom_android
  1802. return "vec3(float(" + v[0] + "), float(" + v[1] + "), float(" + v[2] + "))";
  1803. ///else
  1804. return "vec3(" + v[0] + ", " + v[1] + ", " + v[2] + ")";
  1805. ///end
  1806. }
  1807. function parser_material_to_vec3(s: string): string {
  1808. ///if (krom_direct3d11 || krom_direct3d12)
  1809. return "(" + s + ").xxx";
  1810. ///else
  1811. return "vec3(" + s + ")";
  1812. ///end
  1813. }
  1814. function parser_material_node_by_type(nodes: zui_node_t[], ntype: string): zui_node_t {
  1815. for (let i: i32 = 0; i < nodes.length; ++i) {
  1816. let n: zui_node_t = nodes[i];
  1817. if (n.type == ntype) {
  1818. return n;
  1819. }
  1820. }
  1821. return null;
  1822. }
  1823. function parser_material_socket_index(node: zui_node_t, socket: zui_node_socket_t): i32 {
  1824. for (let i: i32 = 0; i < node.outputs.length; ++i) {
  1825. if (node.outputs[i] == socket) {
  1826. return i;
  1827. }
  1828. }
  1829. return -1;
  1830. }
  1831. function parser_material_node_name(node: zui_node_t, _parents: zui_node_t[] = null): string {
  1832. if (_parents == null) {
  1833. _parents = parser_material_parents;
  1834. }
  1835. let s: string = node.name;
  1836. for (let i: i32 = 0; i < _parents.length; ++i) {
  1837. let p: zui_node_t = _parents[i];
  1838. s = p.name + p.id + "_" + s;
  1839. }
  1840. s = parser_material_safesrc(s) + node.id;
  1841. return s;
  1842. }
  1843. function parser_material_safesrc(s: string): string {
  1844. for (let i: i32 = 0; i < s.length; ++i) {
  1845. let code: i32 = char_code_at(s, i);
  1846. let letter: bool = (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
  1847. let digit: bool = code >= 48 && code <= 57;
  1848. if (!letter && !digit) {
  1849. s = string_replace_all(s, char_at(s, i), "_");
  1850. }
  1851. if (i == 0 && digit) {
  1852. s = "_" + s;
  1853. }
  1854. }
  1855. ///if krom_opengl
  1856. while (string_index_of(s, "__") >= 0) {
  1857. s = string_replace_all(s, "__", "_");
  1858. }
  1859. ///end
  1860. return s;
  1861. }
  1862. function parser_material_enum_data(s: string): string {
  1863. for (let i: i32 = 0; i < project_assets.length; ++i) {
  1864. let a: asset_t = project_assets[i];
  1865. if (a.name == s) {
  1866. return a.file;
  1867. }
  1868. }
  1869. return "";
  1870. }
  1871. function parser_material_make_texture(image_node: zui_node_t, tex_name: string, matname: string = null): bind_tex_t {
  1872. let filepath: string = parser_material_enum_data(base_enum_texts(image_node.type)[image_node.buttons[0].default_value[0]]);
  1873. if (filepath == "" || string_index_of(filepath, ".") == -1) {
  1874. return null;
  1875. }
  1876. let tex: bind_tex_t = {
  1877. name: tex_name,
  1878. file: filepath
  1879. };
  1880. if (context_raw.texture_filter) {
  1881. tex.min_filter = "anisotropic";
  1882. tex.mag_filter = "linear";
  1883. tex.mipmap_filter = "linear";
  1884. tex.generate_mipmaps = true;
  1885. }
  1886. else {
  1887. tex.min_filter = "point";
  1888. tex.mag_filter = "point";
  1889. tex.mipmap_filter = "no";
  1890. }
  1891. tex.u_addressing = "repeat";
  1892. tex.v_addressing = "repeat";
  1893. return tex;
  1894. }
  1895. function parser_material_is_pow(num: i32): bool {
  1896. return ((num & (num - 1)) == 0) && num != 0;
  1897. }
  1898. function parser_material_asset_path(s: string): string {
  1899. return s;
  1900. }
  1901. function parser_material_extract_filename(s: string): string {
  1902. let ar: string[] = string_split(s, ".");
  1903. return ar[ar.length - 2] + "." + ar[ar.length - 1];
  1904. }
  1905. function parser_material_safestr(s: string): string {
  1906. return s;
  1907. }
  1908. function u8_array_string_at(a: u8_array_t, i: i32): string {
  1909. let s: string = u8_array_to_string(a);
  1910. let ss: string[] = string_split(s, "\0");
  1911. return ss[i];
  1912. }
  1913. type shader_out_t = {
  1914. out_basecol?: string;
  1915. out_roughness?: string;
  1916. out_metallic?: string;
  1917. out_occlusion?: string;
  1918. out_opacity?: string;
  1919. out_height?: string;
  1920. out_emission?: string;
  1921. out_subsurface?: string;
  1922. };
  1923. enum color_space_t {
  1924. AUTO, // sRGB for base color, otherwise linear
  1925. LINEAR,
  1926. SRGB,
  1927. DIRECTX_NORMAL_MAP,
  1928. }
  1929. ///if is_lab
  1930. type slot_material_t = any;
  1931. ///end