make_material.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. let make_material_default_scon: shader_context_t = null;
  2. let make_material_default_mcon: material_context_t = null;
  3. let make_material_height_used = false;
  4. let make_material_emis_used = false;
  5. let make_material_subs_used = false;
  6. function make_material_get_mout(): bool {
  7. for (let i: i32 = 0; i < ui_nodes_get_canvas_material().nodes.length; ++i) {
  8. let n: zui_node_t = ui_nodes_get_canvas_material().nodes[i];
  9. if (n.type == "OUTPUT_MATERIAL_PBR") {
  10. return true;
  11. }
  12. }
  13. return false;
  14. }
  15. function make_material_parse_mesh_material() {
  16. let m: material_data_t = project_materials[0].data;
  17. for (let i: i32 = 0; i < m._.shader._.contexts.length; ++i) {
  18. let c: shader_context_t = m._.shader._.contexts[i];
  19. if (c.name == "mesh") {
  20. array_remove(m._.shader.contexts, c);
  21. array_remove(m._.shader._.contexts, c);
  22. make_material_delete_context(c);
  23. break;
  24. }
  25. }
  26. if (make_mesh_layer_pass_count > 1) {
  27. let i: i32 = 0;
  28. while (i < m._.shader._.contexts.length) {
  29. let c: shader_context_t = m._.shader._.contexts[i];
  30. for (let j: i32 = 1; j < make_mesh_layer_pass_count; ++j) {
  31. if (c.name == "mesh" + j) {
  32. array_remove(m._.shader.contexts, c);
  33. array_remove(m._.shader._.contexts, c);
  34. make_material_delete_context(c);
  35. i--;
  36. break;
  37. }
  38. }
  39. i++;
  40. }
  41. i = 0;
  42. while (i < m._.contexts.length) {
  43. let c: material_context_t = m._.contexts[i];
  44. for (let j: i32 = 1; j < make_mesh_layer_pass_count; ++j) {
  45. if (c.name == "mesh" + j) {
  46. array_remove(m.contexts, c);
  47. array_remove(m._.contexts, c);
  48. i--;
  49. break;
  50. }
  51. }
  52. i++;
  53. }
  54. }
  55. let mm: material_t = { name: "Material", canvas: null };
  56. let con: node_shader_context_t = make_mesh_run(mm);
  57. let scon: shader_context_t = shader_context_create(con.data);
  58. let override_context: _shader_override_t = {};
  59. if (con.frag.shared_samplers.length > 0) {
  60. let sampler: string = con.frag.shared_samplers[0];
  61. override_context.shared_sampler = substring(sampler, string_last_index_of(sampler, " ") + 1, sampler.length);
  62. }
  63. if (!context_raw.texture_filter) {
  64. override_context.filter = "point";
  65. }
  66. scon._.override_context = override_context;
  67. array_push(m._.shader.contexts, scon);
  68. array_push(m._.shader._.contexts, scon);
  69. for (let i: i32 = 1; i < make_mesh_layer_pass_count; ++i) {
  70. let mm: material_t = { name: "Material", canvas: null };
  71. let con: node_shader_context_t = make_mesh_run(mm, i);
  72. let scon: shader_context_t = shader_context_create(con.data);
  73. let override_context: _shader_override_t = {};
  74. if (con.frag.shared_samplers.length > 0) {
  75. let sampler: string = con.frag.shared_samplers[0];
  76. override_context.shared_sampler = substring(sampler, string_last_index_of(sampler, " ") + 1, sampler.length);
  77. }
  78. if (!context_raw.texture_filter) {
  79. override_context.filter = "point";
  80. }
  81. scon._.override_context = override_context;
  82. array_push(m._.shader.contexts, scon);
  83. array_push(m._.shader._.contexts, scon);
  84. let mcon: material_context_t;
  85. let mmcon: material_context_t = { name: "mesh" + i, bind_textures: [] };
  86. mcon = material_context_create(mmcon);
  87. array_push(m.contexts, mcon);
  88. array_push(m._.contexts, mcon);
  89. }
  90. context_raw.ddirty = 2;
  91. ///if arm_voxels
  92. make_material_make_voxel(m);
  93. ///end
  94. ///if (krom_direct3d12 || krom_vulkan || krom_metal)
  95. render_path_raytrace_dirty = 1;
  96. ///end
  97. }
  98. function make_material_parse_particle_material() {
  99. let m: material_data_t = context_raw.particle_material;
  100. let sc: shader_context_t = null;
  101. for (let i: i32 = 0; i < m._.shader._.contexts.length; ++i) {
  102. let c: shader_context_t = m._.shader._.contexts[i];
  103. if (c.name == "mesh") {
  104. sc = c;
  105. break;
  106. }
  107. }
  108. if (sc != null) {
  109. array_remove(m._.shader.contexts, sc);
  110. array_remove(m._.shader._.contexts, sc);
  111. }
  112. let mm: material_t = { name: "MaterialParticle", canvas: null };
  113. let con: node_shader_context_t = make_particle_run(mm);
  114. if (sc != null) {
  115. make_material_delete_context(sc);
  116. }
  117. sc = shader_context_create(con.data);
  118. array_push(m._.shader.contexts, sc);
  119. array_push(m._.shader._.contexts, sc);
  120. }
  121. function make_material_parse_mesh_preview_material(md: material_data_t = null) {
  122. if (!make_material_get_mout()) {
  123. return;
  124. }
  125. let m: material_data_t = md == null ? project_materials[0].data : md;
  126. let scon: shader_context_t = null;
  127. for (let i: i32 = 0; i < m._.shader._.contexts.length; ++i) {
  128. let c: shader_context_t = m._.shader._.contexts[i];
  129. if (c.name == "mesh") {
  130. scon = c;
  131. break;
  132. }
  133. }
  134. array_remove(m._.shader.contexts, scon);
  135. array_remove(m._.shader._.contexts, scon);
  136. let mcon: material_context_t = { name: "mesh", bind_textures: [] };
  137. let sd: material_t = { name: "Material", canvas: null };
  138. let con: node_shader_context_t = make_mesh_preview_run(sd, mcon);
  139. for (let i: i32 = 0; i < m._.contexts.length; ++i) {
  140. if (m._.contexts[i].name == "mesh") {
  141. m._.contexts[i] = material_context_create(mcon);
  142. break;
  143. }
  144. }
  145. if (scon != null) {
  146. make_material_delete_context(scon);
  147. }
  148. let compile_error: bool = false;
  149. let _scon: shader_context_t = shader_context_create(con.data);
  150. if (_scon == null) {
  151. compile_error = true;
  152. }
  153. scon = _scon;
  154. if (compile_error) {
  155. return;
  156. }
  157. array_push(m._.shader.contexts, scon);
  158. array_push(m._.shader._.contexts, scon);
  159. }
  160. ///if arm_voxels
  161. function make_material_make_voxel(m: material_data_t) {
  162. let rebuild: bool = make_material_height_used;
  163. if (config_raw.rp_gi != false && rebuild) {
  164. let scon: shader_context_t = null;
  165. for (let i: i32 = 0; i < m._.shader._.contexts.length; ++i) {
  166. let c: shader_context_t = m._.shader._.contexts[i];
  167. if (c.name == "voxel") {
  168. scon = c;
  169. break;
  170. }
  171. }
  172. if (scon != null) {
  173. make_voxel_run(scon);
  174. }
  175. }
  176. }
  177. ///end
  178. function make_material_parse_paint_material(bake_previews: bool = true) {
  179. if (!make_material_get_mout()) return;
  180. if (bake_previews) {
  181. let current: image_t = _g2_current;
  182. let g2_in_use: bool = _g2_in_use;
  183. if (g2_in_use) g2_end();
  184. make_material_bake_node_previews();
  185. if (g2_in_use) g2_begin(current);
  186. }
  187. let m: material_data_t = project_materials[0].data;
  188. // let scon: TShaderContext = null;
  189. // let mcon: TMaterialContext = null;
  190. for (let i: i32 = 0; i < m._.shader._.contexts.length; ++i) {
  191. let c: shader_context_t = m._.shader._.contexts[i];
  192. if (c.name == "paint") {
  193. array_remove(m._.shader.contexts, c);
  194. array_remove(m._.shader._.contexts, c);
  195. if (c != make_material_default_scon) {
  196. make_material_delete_context(c);
  197. }
  198. break;
  199. }
  200. }
  201. for (let i: i32 = 0; i < m._.contexts.length; ++i) {
  202. let c: material_context_t = m._.contexts[i];
  203. if (c.name == "paint") {
  204. array_remove(m.contexts, c);
  205. array_remove(m._.contexts, c);
  206. break;
  207. }
  208. }
  209. let sdata: material_t = { name: "Material", canvas: ui_nodes_get_canvas_material() };
  210. let tmcon: material_context_t = { name: "paint", bind_textures: [] };
  211. let con: node_shader_context_t = make_paint_run(sdata, tmcon);
  212. let compile_error: bool = false;
  213. let scon: shader_context_t;
  214. let _scon: shader_context_t = shader_context_create(con.data);
  215. if (_scon == null) {
  216. compile_error = true;
  217. }
  218. scon = _scon;
  219. if (compile_error) {
  220. return;
  221. }
  222. let override_context: _shader_override_t = {};
  223. override_context.addressing = "repeat";
  224. scon._.override_context = override_context;
  225. let mcon: material_context_t = material_context_create(tmcon);
  226. array_push(m._.shader.contexts, scon);
  227. array_push(m._.shader._.contexts, scon);
  228. array_push(m.contexts, mcon);
  229. array_push(m._.contexts, mcon);
  230. if (make_material_default_scon == null) {
  231. make_material_default_scon = scon;
  232. }
  233. if (make_material_default_mcon == null) {
  234. make_material_default_mcon = mcon;
  235. }
  236. }
  237. function make_material_bake_node_previews() {
  238. context_raw.node_previews_used = [];
  239. if (context_raw.node_previews == null) {
  240. context_raw.node_previews = map_create();
  241. }
  242. make_material_traverse_nodes(ui_nodes_get_canvas_material().nodes, null, []);
  243. let keys: string[] = map_keys(context_raw.node_previews);
  244. for (let i: i32 = 0; i < keys.length; ++i) {
  245. let key: string = keys[i];
  246. if (array_index_of(context_raw.node_previews_used, key) == -1) {
  247. let image: image_t = map_get(context_raw.node_previews, key);
  248. app_notify_on_next_frame(function (image: image_t) {
  249. image_unload(image);
  250. }, image);
  251. map_delete(context_raw.node_previews, key);
  252. }
  253. }
  254. }
  255. function make_material_traverse_nodes(nodes: zui_node_t[], group: zui_node_canvas_t, parents: zui_node_t[]) {
  256. for (let i: i32 = 0; i < nodes.length; ++i) {
  257. let node: zui_node_t = nodes[i];
  258. make_material_bake_node_preview(node, group, parents);
  259. if (node.type == "GROUP") {
  260. for (let j: i32 = 0; j < project_material_groups.length; ++j) {
  261. let g: node_group_t = project_material_groups[j];
  262. if (g.canvas.name == node.name) {
  263. array_push(parents, node);
  264. make_material_traverse_nodes(g.canvas.nodes, g.canvas, parents);
  265. parents.pop();
  266. break;
  267. }
  268. }
  269. }
  270. }
  271. }
  272. function make_material_bake_node_preview(node: zui_node_t, group: zui_node_canvas_t, parents: zui_node_t[]) {
  273. if (node.type == "BLUR") {
  274. let id: string = parser_material_node_name(node, parents);
  275. let image: image_t = map_get(context_raw.node_previews, id);
  276. array_push(context_raw.node_previews_used, id);
  277. let resX: i32 = math_floor(config_get_texture_res_x() / 4);
  278. let resY: i32 = math_floor(config_get_texture_res_y() / 4);
  279. if (image == null || image.width != resX || image.height != resY) {
  280. if (image != null) {
  281. image_unload(image);
  282. }
  283. image = image_create_render_target(resX, resY);
  284. map_set(context_raw.node_previews, id, image);
  285. }
  286. parser_material_blur_passthrough = true;
  287. util_render_make_node_preview(ui_nodes_get_canvas_material(), node, image, group, parents);
  288. parser_material_blur_passthrough = false;
  289. }
  290. else if (node.type == "DIRECT_WARP") {
  291. let id: string = parser_material_node_name(node, parents);
  292. let image: image_t = map_get(context_raw.node_previews, id);
  293. array_push(context_raw.node_previews_used, id);
  294. let resX: i32 = math_floor(config_get_texture_res_x());
  295. let resY: i32 = math_floor(config_get_texture_res_y());
  296. if (image == null || image.width != resX || image.height != resY) {
  297. if (image != null) image_unload(image);
  298. image = image_create_render_target(resX, resY);
  299. map_set(context_raw.node_previews, id, image);
  300. }
  301. parser_material_warp_passthrough = true;
  302. util_render_make_node_preview(ui_nodes_get_canvas_material(), node, image, group, parents);
  303. parser_material_warp_passthrough = false;
  304. }
  305. else if (node.type == "BAKE_CURVATURE") {
  306. let id: string = parser_material_node_name(node, parents);
  307. let image: image_t = map_get(context_raw.node_previews, id);
  308. array_push(context_raw.node_previews_used, id);
  309. let resX: i32 = math_floor(config_get_texture_res_x());
  310. let resY: i32 = math_floor(config_get_texture_res_y());
  311. if (image == null || image.width != resX || image.height != resY) {
  312. if (image != null) image_unload(image);
  313. image = image_create_render_target(resX, resY, tex_format_t.R8);
  314. map_set(context_raw.node_previews, id, image);
  315. }
  316. if (render_path_paint_live_layer == null) {
  317. render_path_paint_live_layer = slot_layer_create("_live");
  318. }
  319. let _space: i32 = ui_header_worktab.position;
  320. let _tool: workspace_tool_t = context_raw.tool;
  321. let _bake_type: bake_type_t = context_raw.bake_type;
  322. ui_header_worktab.position = space_type_t.SPACE3D;
  323. context_raw.tool = workspace_tool_t.BAKE;
  324. context_raw.bake_type = bake_type_t.CURVATURE;
  325. parser_material_bake_passthrough = true;
  326. parser_material_start_node = node;
  327. parser_material_start_group = group;
  328. parser_material_start_parents = parents;
  329. make_material_parse_paint_material(false);
  330. parser_material_bake_passthrough = false;
  331. parser_material_start_node = null;
  332. parser_material_start_group = null;
  333. parser_material_start_parents = null;
  334. context_raw.pdirty = 1;
  335. render_path_paint_use_live_layer(true);
  336. render_path_paint_commands_paint(false);
  337. render_path_paint_dilate(true, false);
  338. render_path_paint_use_live_layer(false);
  339. context_raw.pdirty = 0;
  340. ui_header_worktab.position = _space;
  341. context_raw.tool = _tool;
  342. context_raw.bake_type = _bake_type;
  343. make_material_parse_paint_material(false);
  344. let rts: map_t<string, render_target_t> = render_path_render_targets;
  345. let texpaint_live: render_target_t = map_get(rts, "texpaint_live");
  346. g2_begin(image);
  347. g2_draw_image(texpaint_live._image, 0, 0);
  348. g2_end();
  349. }
  350. }
  351. function make_material_parse_node_preview_material(node: zui_node_t, group: zui_node_canvas_t = null, parents: zui_node_t[] = null): { scon: shader_context_t, mcon: material_context_t } {
  352. if (node.outputs.length == 0) {
  353. return null;
  354. }
  355. let sdata: material_t = { name: "Material", canvas: ui_nodes_get_canvas_material() };
  356. let mcon_raw: material_context_t = { name: "mesh", bind_textures: [] };
  357. let con: node_shader_context_t = make_node_preview_run(sdata, mcon_raw, node, group, parents);
  358. let compile_error: bool = false;
  359. let scon: shader_context_t;
  360. let _scon: shader_context_t = shader_context_create(con.data);
  361. if (_scon == null) {
  362. compile_error = true;
  363. }
  364. scon = _scon;
  365. if (compile_error) {
  366. return null;
  367. }
  368. let mcon: material_context_t = material_context_create(mcon_raw);
  369. return { scon: scon, mcon: mcon };
  370. }
  371. function make_material_parse_brush() {
  372. parser_logic_parse(context_raw.brush.canvas);
  373. }
  374. function make_material_blend_mode(frag: node_shader_t, blending: i32, cola: string, colb: string, opac: string): string {
  375. if (blending == blend_type_t.MIX) {
  376. return "mix(" + cola + ", " + colb + ", " + opac + ")";
  377. }
  378. else if (blending == blend_type_t.DARKEN) {
  379. return "mix(" + cola + ", min(" + cola + ", " + colb + "), " + opac + ")";
  380. }
  381. else if (blending == blend_type_t.MULTIPLY) {
  382. return "mix(" + cola + ", " + cola + " * " + colb + ", " + opac + ")";
  383. }
  384. else if (blending == blend_type_t.BURN) {
  385. return "mix(" + cola + ", vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - " + cola + ") / " + colb + ", " + opac + ")";
  386. }
  387. else if (blending == blend_type_t.LIGHTEN) {
  388. return "max(" + cola + ", " + colb + " * " + opac + ")";
  389. }
  390. else if (blending == blend_type_t.SCREEN) {
  391. return "(vec3(1.0, 1.0, 1.0) - (vec3(1.0 - " + opac + ", 1.0 - " + opac + ", 1.0 - " + opac + ") + " + opac + " * (vec3(1.0, 1.0, 1.0) - " + colb + ")) * (vec3(1.0, 1.0, 1.0) - " + cola + "))";
  392. }
  393. else if (blending == blend_type_t.DODGE) {
  394. return "mix(" + cola + ", " + cola + " / (vec3(1.0, 1.0, 1.0) - " + colb + "), " + opac + ")";
  395. }
  396. else if (blending == blend_type_t.ADD) {
  397. return "mix(" + cola + ", " + cola + " + " + colb + ", " + opac + ")";
  398. }
  399. else if (blending == blend_type_t.OVERLAY) {
  400. return "mix(" + cola + ", vec3( \
  401. " + cola + ".r < 0.5 ? 2.0 * " + cola + ".r * " + colb + ".r : 1.0 - 2.0 * (1.0 - " + cola + ".r) * (1.0 - " + colb + ".r), \
  402. " + cola + ".g < 0.5 ? 2.0 * " + cola + ".g * " + colb + ".g : 1.0 - 2.0 * (1.0 - " + cola + ".g) * (1.0 - " + colb + ".g), \
  403. " + cola + ".b < 0.5 ? 2.0 * " + cola + ".b * " + colb + ".b : 1.0 - 2.0 * (1.0 - " + cola + ".b) * (1.0 - " + colb + ".b) \
  404. ), " + opac + ")";
  405. }
  406. else if (blending == blend_type_t.SOFT_LIGHT) {
  407. return "((1.0 - " + opac + ") * " + cola + " + " + opac + " * ((vec3(1.0, 1.0, 1.0) - " + cola + ") * " + colb + " * " + cola + " + " + cola + " * (vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - " + colb + ") * (vec3(1.0, 1.0, 1.0) - " + cola + "))))";
  408. }
  409. else if (blending == blend_type_t.LINEAR_LIGHT) {
  410. return "(" + cola + " + " + opac + " * (vec3(2.0, 2.0, 2.0) * (" + colb + " - vec3(0.5, 0.5, 0.5))))";
  411. }
  412. else if (blending == blend_type_t.DIFFERENCE) {
  413. return "mix(" + cola + ", abs(" + cola + " - " + colb + "), " + opac + ")";
  414. }
  415. else if (blending == blend_type_t.SUBTRACT) {
  416. return "mix(" + cola + ", " + cola + " - " + colb + ", " + opac + ")";
  417. }
  418. else if (blending == blend_type_t.DIVIDE) {
  419. return "vec3(1.0 - " + opac + ", 1.0 - " + opac + ", 1.0 - " + opac + ") * " + cola + " + vec3(" + opac + ", " + opac + ", " + opac + ") * " + cola + " / " + colb + "";
  420. }
  421. else if (blending == blend_type_t.HUE) {
  422. node_shader_add_function(frag, str_hue_sat);
  423. return "mix(" + cola + ", hsv_to_rgb(vec3(rgb_to_hsv(" + colb + ").r, rgb_to_hsv(" + cola + ").g, rgb_to_hsv(" + cola + ").b)), " + opac + ")";
  424. }
  425. else if (blending == blend_type_t.SATURATION) {
  426. node_shader_add_function(frag, str_hue_sat);
  427. return "mix(" + cola + ", hsv_to_rgb(vec3(rgb_to_hsv(" + cola + ").r, rgb_to_hsv(" + colb + ").g, rgb_to_hsv(" + cola + ").b)), " + opac + ")";
  428. }
  429. else if (blending == blend_type_t.COLOR) {
  430. node_shader_add_function(frag, str_hue_sat);
  431. return "mix(" + cola + ", hsv_to_rgb(vec3(rgb_to_hsv(" + colb + ").r, rgb_to_hsv(" + colb + ").g, rgb_to_hsv(" + cola + ").b)), " + opac + ")";
  432. }
  433. else { // BlendValue
  434. node_shader_add_function(frag, str_hue_sat);
  435. return "mix(" + cola + ", hsv_to_rgb(vec3(rgb_to_hsv(" + cola + ").r, rgb_to_hsv(" + cola + ").g, rgb_to_hsv(" + colb + ").b)), " + opac + ")";
  436. }
  437. }
  438. function make_material_blend_mode_mask(frag: node_shader_t, blending: i32, cola: string, colb: string, opac: string): string {
  439. if (blending == blend_type_t.MIX) {
  440. return "mix(" + cola + ", " + colb + ", " + opac + ")";
  441. }
  442. else if (blending == blend_type_t.DARKEN) {
  443. return "mix(" + cola + ", min(" + cola + ", " + colb + "), " + opac + ")";
  444. }
  445. else if (blending == blend_type_t.MULTIPLY) {
  446. return "mix(" + cola + ", " + cola + " * " + colb + ", " + opac + ")";
  447. }
  448. else if (blending == blend_type_t.BURN) {
  449. return "mix(" + cola + ", 1.0 - (1.0 - " + cola + ") / " + colb + ", " + opac + ")";
  450. }
  451. else if (blending == blend_type_t.LIGHTEN) {
  452. return "max(" + cola + ", " + colb + " * " + opac + ")";
  453. }
  454. else if (blending == blend_type_t.SCREEN) {
  455. return "(1.0 - ((1.0 - " + opac + ") + " + opac + " * (1.0 - " + colb + ")) * (1.0 - " + cola + "))";
  456. }
  457. else if (blending == blend_type_t.DODGE) {
  458. return "mix(" + cola + ", " + cola + " / (1.0 - " + colb + "), " + opac + ")";
  459. }
  460. else if (blending == blend_type_t.ADD) {
  461. return "mix(" + cola + ", " + cola + " + " + colb + ", " + opac + ")";
  462. }
  463. else if (blending == blend_type_t.OVERLAY) {
  464. return "mix(" + cola + ", " + cola + " < 0.5 ? 2.0 * " + cola + " * " + colb + " : 1.0 - 2.0 * (1.0 - " + cola + ") * (1.0 - " + colb + "), " + opac + ")";
  465. }
  466. else if (blending == blend_type_t.SOFT_LIGHT) {
  467. return "((1.0 - " + opac + ") * " + cola + " + " + opac + " * ((1.0 - " + cola + ") * " + colb + " * " + cola + " + " + cola + " * (1.0 - (1.0 - " + colb + ") * (1.0 - " + cola + "))))";
  468. }
  469. else if (blending == blend_type_t.LINEAR_LIGHT) {
  470. return "(" + cola + " + " + opac + " * (2.0 * (" + colb + " - 0.5)))";
  471. }
  472. else if (blending == blend_type_t.DIFFERENCE) {
  473. return "mix(" + cola + ", abs(" + cola + " - " + colb + "), " + opac + ")";
  474. }
  475. else if (blending == blend_type_t.SUBTRACT) {
  476. return "mix(" + cola + ", " + cola + " - " + colb + ", " + opac + ")";
  477. }
  478. else if (blending == blend_type_t.DIVIDE) {
  479. return "(1.0 - " + opac + ") * " + cola + " + " + opac + " * " + cola + " / " + colb + "";
  480. }
  481. else { // BlendHue, BlendSaturation, BlendColor, BlendValue
  482. return "mix(" + cola + ", " + colb + ", " + opac + ")";
  483. }
  484. }
  485. function make_material_get_displace_strength(): f32 {
  486. let sc: f32 = context_main_object().base.transform.scale.x;
  487. return config_raw.displace_strength * 0.02 * sc;
  488. }
  489. function make_material_voxelgi_half_extents(): string {
  490. let ext: f32 = context_raw.vxao_ext;
  491. return "const vec3 voxelgiHalfExtents = vec3(" + ext + ", " + ext + ", " + ext + ");";
  492. }
  493. function make_material_delete_context(c: shader_context_t) {
  494. app_notify_on_next_frame(function (c: shader_context_t) { // Ensure pipeline is no longer in use
  495. shader_context_delete(c);
  496. }, c);
  497. }