luboslenco 1 an în urmă
părinte
comite
767474c934
53 a modificat fișierele cu 2477 adăugiri și 2398 ștergeri
  1. 2 2
      armorforge/Sources/tab_objects.ts
  2. 1 1
      armorlab/Sources/make_material.ts
  3. 127 127
      armorlab/Sources/make_mesh.ts
  4. 150 150
      armorlab/Sources/make_paint.ts
  5. 8 8
      armorlab/Sources/nodes_brush.ts
  6. 65 65
      armorpaint/Sources/make_bake.ts
  7. 57 57
      armorpaint/Sources/make_blur.ts
  8. 43 43
      armorpaint/Sources/make_brush.ts
  9. 21 21
      armorpaint/Sources/make_clone.ts
  10. 23 23
      armorpaint/Sources/make_colorid_picker.ts
  11. 22 22
      armorpaint/Sources/make_discard.ts
  12. 38 38
      armorpaint/Sources/make_material.ts
  13. 209 209
      armorpaint/Sources/make_mesh.ts
  14. 54 54
      armorpaint/Sources/make_mesh_preview.ts
  15. 10 10
      armorpaint/Sources/make_node_preview.ts
  16. 136 136
      armorpaint/Sources/make_paint.ts
  17. 74 74
      armorpaint/Sources/make_particle.ts
  18. 44 44
      armorpaint/Sources/make_texcoord.ts
  19. 2 2
      armorpaint/Sources/nodes_brush.ts
  20. 2 2
      armorpaint/Sources/tab_layers.ts
  21. 16 16
      armorsculpt/Sources/make_brush.ts
  22. 1 1
      armorsculpt/Sources/make_material.ts
  23. 154 154
      armorsculpt/Sources/make_mesh.ts
  24. 56 56
      armorsculpt/Sources/make_mesh_preview.ts
  25. 27 27
      armorsculpt/Sources/make_sculpt.ts
  26. 1 1
      armorsculpt/Sources/tab_layers.ts
  27. 73 0
      base/Sources/base.ts
  28. 7 7
      base/Sources/box_export.ts
  29. 14 13
      base/Sources/box_preferences.ts
  30. 1 1
      base/Sources/box_projects.ts
  31. 4 3
      base/Sources/config.ts
  32. 2 2
      base/Sources/export_texture.ts
  33. 7 7
      base/Sources/file.ts
  34. 1 1
      base/Sources/import_blend_material.ts
  35. 34 34
      base/Sources/make_voxel.ts
  36. 236 236
      base/Sources/node_shader.ts
  37. 7 7
      base/Sources/node_shader_context.ts
  38. 3 2
      base/Sources/operator.ts
  39. 2 2
      base/Sources/parser_blend.ts
  40. 230 230
      base/Sources/parser_material.ts
  41. 1 1
      base/Sources/path.ts
  42. 2 2
      base/Sources/physics_body.ts
  43. 1 1
      base/Sources/project.ts
  44. 479 479
      base/Sources/strings.ts
  45. 1 1
      base/Sources/tab_materials.ts
  46. 1 1
      base/Sources/tab_meshes.ts
  47. 1 1
      base/Sources/tab_textures.ts
  48. 12 10
      base/Sources/translator.ts
  49. 2 1
      base/Sources/ui_base.ts
  50. 2 2
      base/Sources/ui_files.ts
  51. 7 7
      base/Sources/ui_header.ts
  52. 3 3
      base/Sources/ui_menu.ts
  53. 1 1
      base/Sources/ui_nodes.ts

+ 2 - 2
armorforge/Sources/tab_objects.ts

@@ -61,7 +61,7 @@ function tab_objects_draw(htab: zui_handle_t) {
 				}
 
 				line_counter++;
-				// Undo applied offset for row drawing caused by endElement() in Zui.hx
+				// Undo applied offset for row drawing caused by end_element()
 				ui._y -= zui_ELEMENT_OFFSET(ui);
 
 				if (ui.is_released) {
@@ -125,7 +125,7 @@ function tab_objects_draw(htab: zui_handle_t) {
 			// ui.unindent();
 		}
 
-		if (zui_panel(zui_handle("tabobjects_2", {selected: true}), 'Properties')) {
+		if (zui_panel(zui_handle("tabobjects_2", {selected: true}), "Properties")) {
 			// ui.indent();
 
 			if (context_context_raw.selected_object != null) {

+ 1 - 1
armorlab/Sources/make_material.ts

@@ -119,7 +119,7 @@ function make_material_get_displace_strength(): f32 {
 
 function make_material_voxelgi_half_extents(): string {
 	let ext = context_raw.vxao_ext;
-	return `const vec3 voxelgiHalfExtents = vec3(${ext}, ${ext}, ${ext});`;
+	return "const vec3 voxelgiHalfExtents = vec3(" + ext + ", " + ext + ", " + ext + ");";
 }
 
 function make_material_delete_context(c: shader_context_t) {

+ 127 - 127
armorlab/Sources/make_mesh.ts

@@ -16,215 +16,215 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 	let frag = node_shader_context_make_frag(con_mesh);
 	frag.ins = vert.outs;
 
-	node_shader_add_out(vert, 'vec2 texCoord');
+	node_shader_add_out(vert, "vec2 texCoord");
 	frag.wvpposition = true;
-	node_shader_add_out(vert, 'vec4 prevwvpposition');
-	node_shader_add_uniform(vert, 'mat4 VP', '_view_proj_matrix');
-	node_shader_add_uniform(vert, 'mat4 prevWVP', '_prev_world_view_proj_matrix');
+	node_shader_add_out(vert, "vec4 prevwvpposition");
+	node_shader_add_uniform(vert, "mat4 VP", "_view_proj_matrix");
+	node_shader_add_uniform(vert, "mat4 prevWVP", "_prev_world_view_proj_matrix");
 	vert.wposition = true;
 
-	let textureCount = 0;
-	let displaceStrength = make_material_get_displace_strength();
-	if (make_material_height_used && displaceStrength > 0.0) {
+	let texture_count = 0;
+	let displace_strength = make_material_get_displace_strength();
+	if (make_material_height_used && displace_strength > 0.0) {
 		vert.n = true;
-		node_shader_write(vert, 'float height = 0.0;');
-		let numLayers = 1;
-		node_shader_write(vert, `wposition += wnormal * vec3(height, height, height) * vec3(${displaceStrength}, ${displaceStrength}, ${displaceStrength});`);
+		node_shader_write(vert, "float height = 0.0;");
+		let num_layers = 1;
+		node_shader_write(vert, "wposition += wnormal * vec3(height, height, height) * vec3(" + displace_strength +", " + displace_strength + ", " + displace_strength + ");");
 	}
 
-	node_shader_write(vert, 'gl_Position = mul(vec4(wposition.xyz, 1.0), VP);');
-	let brushScale = context_raw.brush_scale;
-	node_shader_add_uniform(vert, 'float texScale', '_tex_unpack');
-	node_shader_write(vert, `texCoord = tex * ${brushScale} * texScale;`);
-	if (make_material_height_used && displaceStrength > 0) {
-		node_shader_add_uniform(vert, 'mat4 invW', '_inv_world_matrix');
-		node_shader_write(vert, 'prevwvpposition = mul(mul(vec4(wposition, 1.0), invW), prevWVP);');
+	node_shader_write(vert, "gl_Position = mul(vec4(wposition.xyz, 1.0), VP);");
+	let brush_scale = context_raw.brush_scale;
+	node_shader_add_uniform(vert, "float texScale", "_tex_unpack");
+	node_shader_write(vert, "texCoord = tex * " + brush_scale + " * texScale;");
+	if (make_material_height_used && displace_strength > 0) {
+		node_shader_add_uniform(vert, "mat4 invW", "_inv_world_matrix");
+		node_shader_write(vert, "prevwvpposition = mul(mul(vec4(wposition, 1.0), invW), prevWVP);");
 	}
 	else {
-		node_shader_write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
+		node_shader_write(vert, "prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);");
 	}
 
-	node_shader_add_out(frag, 'vec4 fragColor[3]');
+	node_shader_add_out(frag, "vec4 fragColor[3]");
 	frag.n = true;
 	node_shader_add_function(frag, str_pack_float_int16);
 	node_shader_add_function(frag, str_octahedron_wrap);
 	node_shader_add_function(frag, str_cotangent_frame);
 
-	node_shader_write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-	node_shader_write(frag, 'float roughness = 0.0;');
-	node_shader_write(frag, 'float metallic = 0.0;');
-	node_shader_write(frag, 'float occlusion = 1.0;');
-	node_shader_write(frag, 'float opacity = 1.0;');
-	node_shader_write(frag, 'float matid = 0.0;');
-	node_shader_write(frag, 'vec3 ntex = vec3(0.5, 0.5, 1.0);');
-	node_shader_write(frag, 'float height = 0.0;');
+	node_shader_write(frag, "vec3 basecol = vec3(0.0, 0.0, 0.0);");
+	node_shader_write(frag, "float roughness = 0.0;");
+	node_shader_write(frag, "float metallic = 0.0;");
+	node_shader_write(frag, "float occlusion = 1.0;");
+	node_shader_write(frag, "float opacity = 1.0;");
+	node_shader_write(frag, "float matid = 0.0;");
+	node_shader_write(frag, "vec3 ntex = vec3(0.5, 0.5, 1.0);");
+	node_shader_write(frag, "float height = 0.0;");
 
-	node_shader_write(frag, 'vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);');
-	node_shader_write(frag, 'vec4 texpaint_nor_sample;');
-	node_shader_write(frag, 'vec4 texpaint_pack_sample;');
-	node_shader_write(frag, 'float texpaint_opac;');
+	node_shader_write(frag, "vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);");
+	node_shader_write(frag, "vec4 texpaint_nor_sample;");
+	node_shader_write(frag, "vec4 texpaint_pack_sample;");
+	node_shader_write(frag, "float texpaint_opac;");
 
 	if (make_material_height_used) {
-		node_shader_write(frag, 'float height0 = 0.0;');
-		node_shader_write(frag, 'float height1 = 0.0;');
-		node_shader_write(frag, 'float height2 = 0.0;');
-		node_shader_write(frag, 'float height3 = 0.0;');
+		node_shader_write(frag, "float height0 = 0.0;");
+		node_shader_write(frag, "float height1 = 0.0;");
+		node_shader_write(frag, "float height2 = 0.0;");
+		node_shader_write(frag, "float height3 = 0.0;");
 	}
 
 	if (context_raw.viewport_mode == viewport_mode_t.LIT && context_raw.render_mode == render_mode_t.FORWARD) {
-		node_shader_add_uniform(frag, 'sampler2D senvmapBrdf', "$brdf.k");
-		node_shader_add_uniform(frag, 'sampler2D senvmapRadiance', '_envmap_radiance');
-		node_shader_add_uniform(frag, 'sampler2D sltcMat', '_ltcMat');
-		node_shader_add_uniform(frag, 'sampler2D sltcMag', '_ltcMag');
+		node_shader_add_uniform(frag, "sampler2D senvmapBrdf", "$brdf.k");
+		node_shader_add_uniform(frag, "sampler2D senvmapRadiance", "_envmap_radiance");
+		node_shader_add_uniform(frag, "sampler2D sltcMat", "_ltcMat");
+		node_shader_add_uniform(frag, "sampler2D sltcMag", "_ltcMag");
 	}
 
-	node_shader_add_shared_sampler(frag, 'sampler2D texpaint');
-	node_shader_write(frag, 'texpaint_sample = textureLodShared(texpaint' + ', texCoord, 0.0);');
-	node_shader_write(frag, 'texpaint_opac = texpaint_sample.a;');
+	node_shader_add_shared_sampler(frag, "sampler2D texpaint");
+	node_shader_write(frag, "texpaint_sample = textureLodShared(texpaint" + ", texCoord, 0.0);");
+	node_shader_write(frag, "texpaint_opac = texpaint_sample.a;");
 
-	node_shader_write(frag, 'basecol = texpaint_sample.rgb * texpaint_opac;');
+	node_shader_write(frag, "basecol = texpaint_sample.rgb * texpaint_opac;");
 
-	node_shader_add_shared_sampler(frag, 'sampler2D texpaint_nor');
-	node_shader_write(frag, 'texpaint_nor_sample = textureLodShared(texpaint_nor' + ', texCoord, 0.0);');
+	node_shader_add_shared_sampler(frag, "sampler2D texpaint_nor");
+	node_shader_write(frag, "texpaint_nor_sample = textureLodShared(texpaint_nor" + ", texCoord, 0.0);");
 
-	node_shader_write(frag, 'ntex = mix(ntex, texpaint_nor_sample.rgb, texpaint_opac);');
+	node_shader_write(frag, "ntex = mix(ntex, texpaint_nor_sample.rgb, texpaint_opac);");
 
-	node_shader_add_shared_sampler(frag, 'sampler2D texpaint_pack');
-	node_shader_write(frag, 'texpaint_pack_sample = textureLodShared(texpaint_pack' + ', texCoord, 0.0);');
+	node_shader_add_shared_sampler(frag, "sampler2D texpaint_pack");
+	node_shader_write(frag, "texpaint_pack_sample = textureLodShared(texpaint_pack" + ", texCoord, 0.0);");
 
-	node_shader_write(frag, 'occlusion = mix(occlusion, texpaint_pack_sample.r, texpaint_opac);');
+	node_shader_write(frag, "occlusion = mix(occlusion, texpaint_pack_sample.r, texpaint_opac);");
 
-	node_shader_write(frag, 'roughness = mix(roughness, texpaint_pack_sample.g, texpaint_opac);');
+	node_shader_write(frag, "roughness = mix(roughness, texpaint_pack_sample.g, texpaint_opac);");
 
-	node_shader_write(frag, 'metallic = mix(metallic, texpaint_pack_sample.b, texpaint_opac);');
+	node_shader_write(frag, "metallic = mix(metallic, texpaint_pack_sample.b, texpaint_opac);");
 
-	node_shader_write(frag, 'height = texpaint_pack_sample.a * texpaint_opac;');
+	node_shader_write(frag, "height = texpaint_pack_sample.a * texpaint_opac;");
 
 	// if (l.paintHeight && heightUsed) {
 	// 	let assign = l.paintHeightBlend ? "+=" : "=";
-	// 	node_shader_write(frag, `height ${assign} texpaint_pack_sample.a * texpaint_opac;`);
-	// 	node_shader_write(frag, '{');
-	// 	node_shader_add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-	// 	node_shader_write(frag, 'float tex_step = 1.0 / texpaintSize.x;');
-	// 	node_shader_write(frag, `height0 ${assign} textureLodShared(texpaint_pack` + ', vec2(texCoord.x - tex_step, texCoord.y), 0.0).a * texpaint_opac;');
-	// 	node_shader_write(frag, `height1 ${assign} textureLodShared(texpaint_pack` + ', vec2(texCoord.x + tex_step, texCoord.y), 0.0).a * texpaint_opac;');
-	// 	node_shader_write(frag, `height2 ${assign} textureLodShared(texpaint_pack` + ', vec2(texCoord.x, texCoord.y - tex_step), 0.0).a * texpaint_opac;');
-	// 	node_shader_write(frag, `height3 ${assign} textureLodShared(texpaint_pack` + ', vec2(texCoord.x, texCoord.y + tex_step), 0.0).a * texpaint_opac;');
-	// 	node_shader_write(frag, '}');
+	// 	node_shader_write(frag, "height " + assign + " texpaint_pack_sample.a * texpaint_opac;");
+	// 	node_shader_write(frag, "{");
+	// 	node_shader_add_uniform(frag, "vec2 texpaintSize", "_texpaintSize");
+	// 	node_shader_write(frag, "float tex_step = 1.0 / texpaintSize.x;");
+	// 	node_shader_write(frag, "height0 " + assign + " textureLodShared(texpaint_pack" + ", vec2(texCoord.x - tex_step, texCoord.y), 0.0).a * texpaint_opac;");
+	// 	node_shader_write(frag, "height1 " + assign + " textureLodShared(texpaint_pack" + ", vec2(texCoord.x + tex_step, texCoord.y), 0.0).a * texpaint_opac;");
+	// 	node_shader_write(frag, "height2 " + assign + " textureLodShared(texpaint_pack" + ", vec2(texCoord.x, texCoord.y - tex_step), 0.0).a * texpaint_opac;");
+	// 	node_shader_write(frag, "height3 " + assign + " textureLodShared(texpaint_pack" + ", vec2(texCoord.x, texCoord.y + tex_step), 0.0).a * texpaint_opac;");
+	// 	node_shader_write(frag, "}");
 	// }
 
 	if (make_material_height_used) {
-		node_shader_write(frag, 'if (height > 0.0) {');
-		node_shader_write(frag, 'float height_dx = height0 - height1;');
-		node_shader_write(frag, 'float height_dy = height2 - height3;');
+		node_shader_write(frag, "if (height > 0.0) {");
+		node_shader_write(frag, "float height_dx = height0 - height1;");
+		node_shader_write(frag, "float height_dy = height2 - height3;");
 		// Whiteout blend
-		node_shader_write(frag, 'vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-		node_shader_write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-		node_shader_write(frag, 'ntex = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);');
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
+		node_shader_write(frag, "vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));");
+		node_shader_write(frag, "ntex = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);");
+		node_shader_write(frag, "}");
 	}
 
 	frag.vvec = true;
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+	node_shader_write(frag, "mat3 TBN = cotangentFrame(n, vVec, texCoord);");
 	///else
-	node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+	node_shader_write(frag, "mat3 TBN = cotangentFrame(n, -vVec, texCoord);");
 	///end
-	node_shader_write(frag, 'n = ntex * 2.0 - 1.0;');
-	node_shader_write(frag, 'n.y = -n.y;');
-	node_shader_write(frag, 'n = normalize(mul(n, TBN));');
+	node_shader_write(frag, "n = ntex * 2.0 - 1.0;");
+	node_shader_write(frag, "n.y = -n.y;");
+	node_shader_write(frag, "n = normalize(mul(n, TBN));");
 
 	if (context_raw.viewport_mode == viewport_mode_t.LIT || context_raw.viewport_mode == viewport_mode_t.PATH_TRACE) {
 
-		node_shader_write(frag, 'basecol = pow(basecol, vec3(2.2, 2.2, 2.2));');
+		node_shader_write(frag, "basecol = pow(basecol, vec3(2.2, 2.2, 2.2));");
 
 		if (context_raw.viewport_shader != null) {
 			let color = context_raw.viewport_shader(frag);
-			node_shader_write(frag, `fragColor[1] = vec4(${color}, 1.0);`);
+			node_shader_write(frag, "fragColor[1] = vec4(" + color + ", 1.0);");
 		}
 		else if (context_raw.render_mode == render_mode_t.FORWARD && context_raw.viewport_mode != viewport_mode_t.PATH_TRACE) {
 			frag.wposition = true;
-			node_shader_write(frag, 'vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);');
-			node_shader_write(frag, 'vec3 f0 = mix(vec3(0.04, 0.04, 0.04), basecol, metallic);');
+			node_shader_write(frag, "vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);");
+			node_shader_write(frag, "vec3 f0 = mix(vec3(0.04, 0.04, 0.04), basecol, metallic);");
 			frag.vvec = true;
-			node_shader_write(frag, 'float dotNV = max(0.0, dot(n, vVec));');
-			node_shader_write(frag, 'vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;');
-			node_shader_add_uniform(frag, 'int envmapNumMipmaps', '_envmap_num_mipmaps');
-			node_shader_add_uniform(frag, 'vec4 envmapData', '_envmapData'); // angle, sin(angle), cos(angle), strength
-			node_shader_write(frag, 'vec3 wreflect = reflect(-vVec, n);');
-			node_shader_write(frag, 'float envlod = roughness * float(envmapNumMipmaps);');
+			node_shader_write(frag, "float dotNV = max(0.0, dot(n, vVec));");
+			node_shader_write(frag, "vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;");
+			node_shader_add_uniform(frag, "int envmapNumMipmaps", "_envmap_num_mipmaps");
+			node_shader_add_uniform(frag, "vec4 envmapData", "_envmapData"); // angle, sin(angle), cos(angle), strength
+			node_shader_write(frag, "vec3 wreflect = reflect(-vVec, n);");
+			node_shader_write(frag, "float envlod = roughness * float(envmapNumMipmaps);");
 			node_shader_add_function(frag, str_envmap_equirect);
-			node_shader_write(frag, 'vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;');
-			node_shader_add_uniform(frag, 'vec3 lightArea0', '_light_area0');
-			node_shader_add_uniform(frag, 'vec3 lightArea1', '_light_area1');
-			node_shader_add_uniform(frag, 'vec3 lightArea2', '_light_area2');
-			node_shader_add_uniform(frag, 'vec3 lightArea3', '_light_area3');
+			node_shader_write(frag, "vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;");
+			node_shader_add_uniform(frag, "vec3 lightArea0", "_light_area0");
+			node_shader_add_uniform(frag, "vec3 lightArea1", "_light_area1");
+			node_shader_add_uniform(frag, "vec3 lightArea2", "_light_area2");
+			node_shader_add_uniform(frag, "vec3 lightArea3", "_light_area3");
 			node_shader_add_function(frag, str_ltc_evaluate);
-			node_shader_add_uniform(frag, 'vec3 lightPos', '_point_pos');
-			node_shader_add_uniform(frag, 'vec3 lightColor', '_point_color');
-			node_shader_write(frag, 'float ldist = distance(wposition, lightPos);');
-			node_shader_write(frag, 'const float LUT_SIZE = 64.0;');
-			node_shader_write(frag, 'const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;');
-			node_shader_write(frag, 'const float LUT_BIAS = 0.5 / LUT_SIZE;');
-			node_shader_write(frag, 'float theta = acos(dotNV);');
-			node_shader_write(frag, 'vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));');
-			node_shader_write(frag, 'tuv = tuv * LUT_SCALE + LUT_BIAS;');
-			node_shader_write(frag, 'vec4 t = textureLod(sltcMat, tuv, 0.0);');
-			node_shader_write(frag, 'mat3 minv = mat3(vec3(1.0, 0.0, t.y), vec3(0.0, t.z, 0.0), vec3(t.w, 0.0, t.x));');
-			node_shader_write(frag, 'float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);');
-			node_shader_write(frag, 'ltcspec *= textureLod(sltcMag, tuv, 0.0).a;');
-			node_shader_write(frag, 'mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);');
-			node_shader_write(frag, 'float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);');
-			node_shader_write(frag, 'vec3 direct = albedo * ltcdiff + ltcspec * 0.05;');
-			node_shader_write(frag, 'direct *= lightColor * (1.0 / (ldist * ldist));');
-
-			node_shader_add_uniform(frag, 'vec4 shirr[7]', '_envmap_irradiance');
+			node_shader_add_uniform(frag, "vec3 lightPos", "_point_pos");
+			node_shader_add_uniform(frag, "vec3 lightColor", "_point_color");
+			node_shader_write(frag, "float ldist = distance(wposition, lightPos);");
+			node_shader_write(frag, "const float LUT_SIZE = 64.0;");
+			node_shader_write(frag, "const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;");
+			node_shader_write(frag, "const float LUT_BIAS = 0.5 / LUT_SIZE;");
+			node_shader_write(frag, "float theta = acos(dotNV);");
+			node_shader_write(frag, "vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));");
+			node_shader_write(frag, "tuv = tuv * LUT_SCALE + LUT_BIAS;");
+			node_shader_write(frag, "vec4 t = textureLod(sltcMat, tuv, 0.0);");
+			node_shader_write(frag, "mat3 minv = mat3(vec3(1.0, 0.0, t.y), vec3(0.0, t.z, 0.0), vec3(t.w, 0.0, t.x));");
+			node_shader_write(frag, "float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);");
+			node_shader_write(frag, "ltcspec *= textureLod(sltcMag, tuv, 0.0).a;");
+			node_shader_write(frag, "mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);");
+			node_shader_write(frag, "float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);");
+			node_shader_write(frag, "vec3 direct = albedo * ltcdiff + ltcspec * 0.05;");
+			node_shader_write(frag, "direct *= lightColor * (1.0 / (ldist * ldist));");
+
+			node_shader_add_uniform(frag, "vec4 shirr[7]", "_envmap_irradiance");
 			node_shader_add_function(frag, str_sh_irradiance());
-			node_shader_write(frag, 'vec3 indirect = albedo * (shIrradiance(vec3(n.x * envmapData.z - n.y * envmapData.y, n.x * envmapData.y + n.y * envmapData.z, n.z), shirr) / 3.14159265);');
-			node_shader_write(frag, 'indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;');
-			node_shader_write(frag, 'indirect *= envmapData.w * occlusion;');
-			node_shader_write(frag, 'fragColor[1] = vec4(direct + indirect, 1.0);');
+			node_shader_write(frag, "vec3 indirect = albedo * (shIrradiance(vec3(n.x * envmapData.z - n.y * envmapData.y, n.x * envmapData.y + n.y * envmapData.z, n.z), shirr) / 3.14159265);");
+			node_shader_write(frag, "indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;");
+			node_shader_write(frag, "indirect *= envmapData.w * occlusion;");
+			node_shader_write(frag, "fragColor[1] = vec4(direct + indirect, 1.0);");
 		}
 		else { // Deferred, Pathtraced
-			node_shader_write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
+			node_shader_write(frag, "fragColor[1] = vec4(basecol, occlusion);");
 		}
 	}
 	else if (context_raw.viewport_mode == viewport_mode_t.BASE_COLOR) {
-		node_shader_write(frag, 'fragColor[1] = vec4(basecol, 1.0);');
+		node_shader_write(frag, "fragColor[1] = vec4(basecol, 1.0);");
 	}
 	else if (context_raw.viewport_mode == viewport_mode_t.NORMAL_MAP) {
-		node_shader_write(frag, 'fragColor[1] = vec4(ntex.rgb, 1.0);');
+		node_shader_write(frag, "fragColor[1] = vec4(ntex.rgb, 1.0);");
 	}
 	else if (context_raw.viewport_mode == viewport_mode_t.OCCLUSION) {
-		node_shader_write(frag, 'fragColor[1] = vec4(vec3(occlusion, occlusion, occlusion), 1.0);');
+		node_shader_write(frag, "fragColor[1] = vec4(vec3(occlusion, occlusion, occlusion), 1.0);");
 	}
 	else if (context_raw.viewport_mode == viewport_mode_t.ROUGHNESS) {
-		node_shader_write(frag, 'fragColor[1] = vec4(vec3(roughness, roughness, roughness), 1.0);');
+		node_shader_write(frag, "fragColor[1] = vec4(vec3(roughness, roughness, roughness), 1.0);");
 	}
 	else if (context_raw.viewport_mode == viewport_mode_t.METALLIC) {
-		node_shader_write(frag, 'fragColor[1] = vec4(vec3(metallic, metallic, metallic), 1.0);');
+		node_shader_write(frag, "fragColor[1] = vec4(vec3(metallic, metallic, metallic), 1.0);");
 	}
 	else if (context_raw.viewport_mode == viewport_mode_t.OPACITY) {
-		node_shader_write(frag, 'fragColor[1] = vec4(vec3(texpaint_sample.a, texpaint_sample.a, texpaint_sample.a), 1.0);');
+		node_shader_write(frag, "fragColor[1] = vec4(vec3(texpaint_sample.a, texpaint_sample.a, texpaint_sample.a), 1.0);");
 	}
 	else if (context_raw.viewport_mode == viewport_mode_t.HEIGHT) {
-		node_shader_write(frag, 'fragColor[1] = vec4(vec3(height, height, height), 1.0);');
+		node_shader_write(frag, "fragColor[1] = vec4(vec3(height, height, height), 1.0);");
 	}
 	else {
-		node_shader_write(frag, 'fragColor[1] = vec4(1.0, 0.0, 1.0, 1.0);'); // Pink
+		node_shader_write(frag, "fragColor[1] = vec4(1.0, 0.0, 1.0, 1.0);"); // Pink
 	}
 
 	if (context_raw.viewport_mode != viewport_mode_t.LIT && context_raw.viewport_mode != viewport_mode_t.PATH_TRACE) {
-		node_shader_write(frag, 'fragColor[1].rgb = pow(fragColor[1].rgb, vec3(2.2, 2.2, 2.2));');
+		node_shader_write(frag, "fragColor[1].rgb = pow(fragColor[1].rgb, vec3(2.2, 2.2, 2.2));");
 	}
 
-	node_shader_write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-	node_shader_write(frag, 'n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);');
-	node_shader_write(frag, 'fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, uint(int(matid * 255.0) % 3)));');
+	node_shader_write(frag, "n /= (abs(n.x) + abs(n.y) + abs(n.z));");
+	node_shader_write(frag, "n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);");
+	node_shader_write(frag, "fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, uint(int(matid * 255.0) % 3)));");
 
-	node_shader_write(frag, 'vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
-	node_shader_write(frag, 'vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;');
-	node_shader_write(frag, 'fragColor[2] = vec4(posa - posb, texCoord.xy);');
+	node_shader_write(frag, "vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;");
+	node_shader_write(frag, "vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;");
+	node_shader_write(frag, "fragColor[2] = vec4(posa - posb, texCoord.xy);");
 
 	parser_material_finalize(con_mesh);
 	con_mesh.data.shader_from_source = true;

+ 150 - 150
armorlab/Sources/make_paint.ts

@@ -24,26 +24,26 @@ function make_paint_run(data: material_t, matcon: material_context_t): NodeShade
 
 	if (context_raw.tool == workspace_tool_t.PICKER) {
 		// Mangle vertices to form full screen triangle
-		node_shader_write(vert, 'gl_Position = vec4(-1.0 + float((gl_VertexID & 1) << 2), -1.0 + float((gl_VertexID & 2) << 1), 0.0, 1.0);');
+		node_shader_write(vert, "gl_Position = vec4(-1.0 + float((gl_VertexID & 1) << 2), -1.0 + float((gl_VertexID & 2) << 1), 0.0, 1.0);");
 
-		node_shader_add_uniform(frag, 'sampler2D gbuffer2');
-		node_shader_add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
-		node_shader_add_uniform(frag, 'vec4 inp', '_inputBrush');
+		node_shader_add_uniform(frag, "sampler2D gbuffer2");
+		node_shader_add_uniform(frag, "vec2 gbufferSize", "_gbufferSize");
+		node_shader_add_uniform(frag, "vec4 inp", "_inputBrush");
 
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, inp.y * gbufferSize.y), 0).ba;');
+		node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, inp.y * gbufferSize.y), 0).ba;");
 		///else
-		node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, (1.0 - inp.y) * gbufferSize.y), 0).ba;');
+		node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, (1.0 - inp.y) * gbufferSize.y), 0).ba;");
 		///end
 
-		node_shader_add_out(frag, 'vec4 fragColor[4]');
-		node_shader_add_uniform(frag, 'sampler2D texpaint');
-		node_shader_add_uniform(frag, 'sampler2D texpaint_nor');
-		node_shader_add_uniform(frag, 'sampler2D texpaint_pack');
-		node_shader_write(frag, 'fragColor[0] = textureLod(texpaint, texCoordInp, 0.0);');
-		node_shader_write(frag, 'fragColor[1] = textureLod(texpaint_nor, texCoordInp, 0.0);');
-		node_shader_write(frag, 'fragColor[2] = textureLod(texpaint_pack, texCoordInp, 0.0);');
-		node_shader_write(frag, 'fragColor[3].rg = texCoordInp.xy;');
+		node_shader_add_out(frag, "vec4 fragColor[4]");
+		node_shader_add_uniform(frag, "sampler2D texpaint");
+		node_shader_add_uniform(frag, "sampler2D texpaint_nor");
+		node_shader_add_uniform(frag, "sampler2D texpaint_pack");
+		node_shader_write(frag, "fragColor[0] = textureLod(texpaint, texCoordInp, 0.0);");
+		node_shader_write(frag, "fragColor[1] = textureLod(texpaint_nor, texCoordInp, 0.0);");
+		node_shader_write(frag, "fragColor[2] = textureLod(texpaint_pack, texCoordInp, 0.0);");
+		node_shader_write(frag, "fragColor[3].rg = texCoordInp.xy;");
 		con_paint.data.shader_from_source = true;
 		con_paint.data.vertex_shader = node_shader_get(vert);
 		con_paint.data.fragment_shader = node_shader_get(frag);
@@ -51,218 +51,218 @@ function make_paint_run(data: material_t, matcon: material_context_t): NodeShade
 	}
 
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(vert, 'vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);');
-	// node_shader_write(vert, 'vec2 tpos = vec2(frac(tex.x * texScale) * 2.0 - 1.0, (1.0 - frac(tex.y * texScale)) * 2.0 - 1.0);'); // 3D View
+	node_shader_write(vert, "vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);");
+	// node_shader_write(vert, "vec2 tpos = vec2(frac(tex.x * texScale) * 2.0 - 1.0, (1.0 - frac(tex.y * texScale)) * 2.0 - 1.0);"); // 3D View
 	///else
-	node_shader_write(vert, 'vec2 tpos = vec2(tex.xy * 2.0 - 1.0);');
+	node_shader_write(vert, "vec2 tpos = vec2(tex.xy * 2.0 - 1.0);");
 	///end
 
-	node_shader_write(vert, 'gl_Position = vec4(tpos, 0.0, 1.0);');
+	node_shader_write(vert, "gl_Position = vec4(tpos, 0.0, 1.0);");
 
-	node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
+	node_shader_add_uniform(vert, "mat4 WVP", "_world_view_proj_matrix");
 
-	node_shader_add_out(vert, 'vec4 ndc');
-	node_shader_write_attrib(vert, 'ndc = mul(vec4(pos.xyz, 1.0), WVP);');
+	node_shader_add_out(vert, "vec4 ndc");
+	node_shader_write_attrib(vert, "ndc = mul(vec4(pos.xyz, 1.0), WVP);");
 
-	node_shader_write_attrib(frag, 'vec3 sp = vec3((ndc.xyz / ndc.w) * 0.5 + 0.5);');
-	node_shader_write_attrib(frag, 'sp.y = 1.0 - sp.y;');
-	node_shader_write_attrib(frag, 'sp.z -= 0.0001;'); // small bias
+	node_shader_write_attrib(frag, "vec3 sp = vec3((ndc.xyz / ndc.w) * 0.5 + 0.5);");
+	node_shader_write_attrib(frag, "sp.y = 1.0 - sp.y;");
+	node_shader_write_attrib(frag, "sp.z -= 0.0001;"); // small bias
 
-	node_shader_add_uniform(frag, 'vec4 inp', '_inputBrush');
-	node_shader_add_uniform(frag, 'vec4 inplast', '_inputBrushLast');
-	node_shader_add_uniform(frag, 'float aspectRatio', '_aspect_ratio_window');
-	node_shader_write(frag, 'vec2 bsp = sp.xy * 2.0 - 1.0;');
-	node_shader_write(frag, 'bsp.x *= aspectRatio;');
-	node_shader_write(frag, 'bsp = bsp * 0.5 + 0.5;');
+	node_shader_add_uniform(frag, "vec4 inp", "_inputBrush");
+	node_shader_add_uniform(frag, "vec4 inplast", "_inputBrushLast");
+	node_shader_add_uniform(frag, "float aspectRatio", "_aspect_ratio_window");
+	node_shader_write(frag, "vec2 bsp = sp.xy * 2.0 - 1.0;");
+	node_shader_write(frag, "bsp.x *= aspectRatio;");
+	node_shader_write(frag, "bsp = bsp * 0.5 + 0.5;");
 
-	node_shader_add_uniform(frag, 'sampler2D gbufferD');
+	node_shader_add_uniform(frag, "sampler2D gbufferD");
 
-	node_shader_add_out(frag, 'vec4 fragColor[4]');
+	node_shader_add_out(frag, "vec4 fragColor[4]");
 
-	node_shader_add_uniform(frag, 'float brushRadius', '_brushRadius');
-	node_shader_add_uniform(frag, 'float brushOpacity', '_brushOpacity');
-	node_shader_add_uniform(frag, 'float brushHardness', '_brushHardness');
+	node_shader_add_uniform(frag, "float brushRadius", "_brushRadius");
+	node_shader_add_uniform(frag, "float brushOpacity", "_brushOpacity");
+	node_shader_add_uniform(frag, "float brushHardness", "_brushHardness");
 
 	if (context_raw.tool == workspace_tool_t.ERASER ||
 		context_raw.tool == workspace_tool_t.CLONE  ||
 		context_raw.tool == workspace_tool_t.BLUR   ||
 		context_raw.tool == workspace_tool_t.SMUDGE) {
 
-		node_shader_write(frag, 'float dist = 0.0;');
+		node_shader_write(frag, "float dist = 0.0;");
 
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'float depth = textureLod(gbufferD, inp.xy, 0.0).r;');
+		node_shader_write(frag, "float depth = textureLod(gbufferD, inp.xy, 0.0).r;");
 		///else
-		node_shader_write(frag, 'float depth = textureLod(gbufferD, vec2(inp.x, 1.0 - inp.y), 0.0).r;');
+		node_shader_write(frag, "float depth = textureLod(gbufferD, vec2(inp.x, 1.0 - inp.y), 0.0).r;");
 		///end
 
-		node_shader_add_uniform(frag, 'mat4 invVP', '_inv_view_proj_matrix');
-		node_shader_write(frag, 'vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);');
-		node_shader_write(frag, 'winp = mul(winp, invVP);');
-		node_shader_write(frag, 'winp.xyz /= winp.w;');
+		node_shader_add_uniform(frag, "mat4 invVP", "_inv_view_proj_matrix");
+		node_shader_write(frag, "vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);");
+		node_shader_write(frag, "winp = mul(winp, invVP);");
+		node_shader_write(frag, "winp.xyz /= winp.w;");
 		frag.wposition = true;
 
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'float depthlast = textureLod(gbufferD, inplast.xy, 0.0).r;');
+		node_shader_write(frag, "float depthlast = textureLod(gbufferD, inplast.xy, 0.0).r;");
 		///else
-		node_shader_write(frag, 'float depthlast = textureLod(gbufferD, vec2(inplast.x, 1.0 - inplast.y), 0.0).r;');
+		node_shader_write(frag, "float depthlast = textureLod(gbufferD, vec2(inplast.x, 1.0 - inplast.y), 0.0).r;");
 		///end
 
-		node_shader_write(frag, 'vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);');
-		node_shader_write(frag, 'winplast = mul(winplast, invVP);');
-		node_shader_write(frag, 'winplast.xyz /= winplast.w;');
+		node_shader_write(frag, "vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);");
+		node_shader_write(frag, "winplast = mul(winplast, invVP);");
+		node_shader_write(frag, "winplast.xyz /= winplast.w;");
 
-		node_shader_write(frag, 'vec3 pa = wposition - winp.xyz;');
-		node_shader_write(frag, 'vec3 ba = winplast.xyz - winp.xyz;');
+		node_shader_write(frag, "vec3 pa = wposition - winp.xyz;");
+		node_shader_write(frag, "vec3 ba = winplast.xyz - winp.xyz;");
 
 		// Capsule
-		node_shader_write(frag, 'float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);');
-		node_shader_write(frag, 'dist = length(pa - ba * h);');
+		node_shader_write(frag, "float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);");
+		node_shader_write(frag, "dist = length(pa - ba * h);");
 
-		node_shader_write(frag, 'if (dist > brushRadius) discard;');
+		node_shader_write(frag, "if (dist > brushRadius) discard;");
 	}
 
-	// node_shader_add_uniform(vert, 'float brushScale', '_brushScale');
-	// node_shader_add_uniform(vert, 'float texScale', '_tex_unpack');
-	// node_shader_add_out(vert, 'vec2 texCoord');
-	// node_shader_write(vert, 'texCoord = tex * brushScale * texScale;');
+	// node_shader_add_uniform(vert, "float brushScale", "_brushScale");
+	// node_shader_add_uniform(vert, "float texScale", "_tex_unpack");
+	// node_shader_add_out(vert, "vec2 texCoord");
+	// node_shader_write(vert, "texCoord = tex * brushScale * texScale;");
 
 	if (context_raw.tool == workspace_tool_t.CLONE || context_raw.tool == workspace_tool_t.BLUR || context_raw.tool == workspace_tool_t.SMUDGE) {
-		node_shader_add_uniform(frag, 'sampler2D BLUR');
-		node_shader_add_uniform(frag, 'vec2 SMUDGE', '_gbufferSize');
-		node_shader_add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-		node_shader_add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
-		node_shader_add_uniform(frag, 'sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
+		node_shader_add_uniform(frag, "sampler2D BLUR");
+		node_shader_add_uniform(frag, "vec2 SMUDGE", "_gbufferSize");
+		node_shader_add_uniform(frag, "sampler2D texpaint_undo", "_texpaint_undo");
+		node_shader_add_uniform(frag, "sampler2D texpaint_nor_undo", "_texpaint_nor_undo");
+		node_shader_add_uniform(frag, "sampler2D texpaint_pack_undo", "_texpaint_pack_undo");
 
 		if (context_raw.tool == workspace_tool_t.CLONE) {
-			// node_shader_add_uniform(frag, 'vec2 BLUR', '_cloneDelta');
+			// node_shader_add_uniform(frag, "vec2 BLUR", "_cloneDelta");
 			// ///if (krom_direct3d11 || SMUDGE || krom_metal || krom_vulkan)
-			// node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.xy + cloneDelta) * gbufferSize), 0).ba;');
+			// node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.xy + cloneDelta) * gbufferSize), 0).ba;");
 			// ///else
-			// node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.x + cloneDelta.x) * gbufferSize.x, (1.0 - (sp.y + cloneDelta.y)) * gbufferSize.y), 0).ba;');
+			// node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.x + cloneDelta.x) * gbufferSize.x, (1.0 - (sp.y + cloneDelta.y)) * gbufferSize.y), 0).ba;");
 			// ///end
 
-			// node_shader_write(frag, 'vec3 texpaint_pack_sample = textureLod(texpaint_pack_undo, texCoordInp, 0.0).rgb;');
-			// let base = 'textureLod(texpaint_undo, texCoordInp, 0.0).rgb';
-			// let rough = 'texpaint_pack_sample.g';
-			// let met = 'texpaint_pack_sample.b';
-			// let occ = 'texpaint_pack_sample.r';
-			// let nortan = 'textureLod(texpaint_nor_undo, texCoordInp, 0.0).rgb';
-			// let height = '0.0';
-			// let opac = '1.0';
-			// node_shader_write(frag, `vec3 basecol = ${base};`);
-			// node_shader_write(frag, `float roughness = ${rough};`);
-			// node_shader_write(frag, `float metallic = ${met};`);
-			// node_shader_write(frag, `float occlusion = ${occ};`);
-			// node_shader_write(frag, `vec3 nortan = ${nortan};`);
-			// node_shader_write(frag, `float height = ${height};`);
-			// node_shader_write(frag, `float mat_opacity = ${opac};`);
-			// node_shader_write(frag, 'float opacity = mat_opacity * brushOpacity;');
+			// node_shader_write(frag, "vec3 texpaint_pack_sample = textureLod(texpaint_pack_undo, texCoordInp, 0.0).rgb;");
+			// let base = "textureLod(texpaint_undo, texCoordInp, 0.0).rgb";
+			// let rough = "texpaint_pack_sample.g";
+			// let met = "texpaint_pack_sample.b";
+			// let occ = "texpaint_pack_sample.r";
+			// let nortan = "textureLod(texpaint_nor_undo, texCoordInp, 0.0).rgb";
+			// let height = "0.0";
+			// let opac = "1.0";
+			// node_shader_write(frag, "vec3 basecol = " + base + ";");
+			// node_shader_write(frag, "float roughness = " + rough + ";");
+			// node_shader_write(frag, "float metallic = " + met + ";");
+			// node_shader_write(frag, "float occlusion = " + occ + ";");
+			// node_shader_write(frag, "vec3 nortan = " + nortan + ";");
+			// node_shader_write(frag, "float height = " + height + ";");
+			// node_shader_write(frag, "float mat_opacity = " + opac + ";");
+			// node_shader_write(frag, "float opacity = mat_opacity * brushOpacity;");
 		}
 		else { // Blur
 			// ///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			// node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, sp.y * gbufferSize.y), 0).ba;');
+			// node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, sp.y * gbufferSize.y), 0).ba;");
 			// ///else
-			// node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, (1.0 - sp.y) * gbufferSize.y), 0).ba;');
+			// node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, (1.0 - sp.y) * gbufferSize.y), 0).ba;");
 			// ///end
 
-			// node_shader_write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-			// node_shader_write(frag, 'float roughness = 0.0;');
-			// node_shader_write(frag, 'float metallic = 0.0;');
-			// node_shader_write(frag, 'float occlusion = 0.0;');
-			// node_shader_write(frag, 'vec3 nortan = vec3(0.0, 0.0, 0.0);');
-			// node_shader_write(frag, 'float height = 0.0;');
-			// node_shader_write(frag, 'float mat_opacity = 1.0;');
-			// node_shader_write(frag, 'float opacity = 0.0;');
-
-			// node_shader_add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-			// node_shader_write(frag, 'float blur_step = 1.0 / texpaintSize.x;');
+			// node_shader_write(frag, "vec3 basecol = vec3(0.0, 0.0, 0.0);");
+			// node_shader_write(frag, "float roughness = 0.0;");
+			// node_shader_write(frag, "float metallic = 0.0;");
+			// node_shader_write(frag, "float occlusion = 0.0;");
+			// node_shader_write(frag, "vec3 nortan = vec3(0.0, 0.0, 0.0);");
+			// node_shader_write(frag, "float height = 0.0;");
+			// node_shader_write(frag, "float mat_opacity = 1.0;");
+			// node_shader_write(frag, "float opacity = 0.0;");
+
+			// node_shader_add_uniform(frag, "vec2 texpaintSize", "_texpaintSize");
+			// node_shader_write(frag, "float blur_step = 1.0 / texpaintSize.x;");
 			// if (context_raw.blurDirectional) {
 			// 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal)
-			// 	node_shader_write(frag, 'const float blur_weight[7] = {1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0};');
+			// 	node_shader_write(frag, "const float blur_weight[7] = {1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0};");
 			// 	///else
-			// 	node_shader_write(frag, 'const float blur_weight[7] = float[](1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0);');
+			// 	node_shader_write(frag, "const float blur_weight[7] = float[](1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0);");
 			// 	///end
-			// 	node_shader_add_uniform(frag, 'vec3 brushDirection', '_brushDirection');
-			// 	node_shader_write(frag, 'vec2 blur_direction = brushDirection.yx;');
-			// 	node_shader_write(frag, 'for (int i = 0; i < 7; ++i) {');
+			// 	node_shader_add_uniform(frag, "vec3 brushDirection", "_brushDirection");
+			// 	node_shader_write(frag, "vec2 blur_direction = brushDirection.yx;");
+			// 	node_shader_write(frag, "for (int i = 0; i < 7; ++i) {");
 			// 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			// 	node_shader_write(frag, 'vec2 texCoordInp2 = texelFetch(gbuffer2, ivec2((sp.x + blur_direction.x * blur_step * float(i)) * gbufferSize.x, (sp.y + blur_direction.y * blur_step * float(i)) * gbufferSize.y), 0).ba;');
+			// 	node_shader_write(frag, "vec2 texCoordInp2 = texelFetch(gbuffer2, ivec2((sp.x + blur_direction.x * blur_step * float(i)) * gbufferSize.x, (sp.y + blur_direction.y * blur_step * float(i)) * gbufferSize.y), 0).ba;");
 			// 	///else
-			// 	node_shader_write(frag, 'vec2 texCoordInp2 = texelFetch(gbuffer2, ivec2((sp.x + blur_direction.x * blur_step * float(i)) * gbufferSize.x, (1.0 - (sp.y + blur_direction.y * blur_step * float(i))) * gbufferSize.y), 0).ba;');
+			// 	node_shader_write(frag, "vec2 texCoordInp2 = texelFetch(gbuffer2, ivec2((sp.x + blur_direction.x * blur_step * float(i)) * gbufferSize.x, (1.0 - (sp.y + blur_direction.y * blur_step * float(i))) * gbufferSize.y), 0).ba;");
 			// 	///end
-			// 	node_shader_write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp2);');
-			// 	node_shader_write(frag, 'opacity += texpaint_sample.a * blur_weight[i];');
-			// 	node_shader_write(frag, 'basecol += texpaint_sample.rgb * blur_weight[i];');
-			// 	node_shader_write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp2) * blur_weight[i];');
-			// 	node_shader_write(frag, 'roughness += texpaint_pack_sample.g;');
-			// 	node_shader_write(frag, 'metallic += texpaint_pack_sample.b;');
-			// 	node_shader_write(frag, 'occlusion += texpaint_pack_sample.r;');
-			// 	node_shader_write(frag, 'height += texpaint_pack_sample.a;');
-			// 	node_shader_write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp2).rgb * blur_weight[i];');
-			// 	node_shader_write(frag, '}');
+			// 	node_shader_write(frag, "vec4 texpaint_sample = texture(texpaint_undo, texCoordInp2);");
+			// 	node_shader_write(frag, "opacity += texpaint_sample.a * blur_weight[i];");
+			// 	node_shader_write(frag, "basecol += texpaint_sample.rgb * blur_weight[i];");
+			// 	node_shader_write(frag, "vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp2) * blur_weight[i];");
+			// 	node_shader_write(frag, "roughness += texpaint_pack_sample.g;");
+			// 	node_shader_write(frag, "metallic += texpaint_pack_sample.b;");
+			// 	node_shader_write(frag, "occlusion += texpaint_pack_sample.r;");
+			// 	node_shader_write(frag, "height += texpaint_pack_sample.a;");
+			// 	node_shader_write(frag, "nortan += texture(texpaint_nor_undo, texCoordInp2).rgb * blur_weight[i];");
+			// 	node_shader_write(frag, "}");
 			// }
 			// else {
 			// 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal)
-			// 	node_shader_write(frag, 'const float blur_weight[15] = {0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0, 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0, 0.034619 / 2.0};');
+			// 	node_shader_write(frag, "const float blur_weight[15] = {0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0, 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0, 0.034619 / 2.0};");
 			// 	///else
-			// 	node_shader_write(frag, 'const float blur_weight[15] = float[](0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0, 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0, 0.034619 / 2.0);');
+			// 	node_shader_write(frag, "const float blur_weight[15] = float[](0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0, 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0, 0.034619 / 2.0);");
 			// 	///end
 			// 	// X
-			// 	node_shader_write(frag, 'for (int i = -7; i <= 7; ++i) {');
-			// 	node_shader_write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(blur_step * float(i), 0.0));');
-			// 	node_shader_write(frag, 'opacity += texpaint_sample.a * blur_weight[i + 7];');
-			// 	node_shader_write(frag, 'basecol += texpaint_sample.rgb * blur_weight[i + 7];');
-			// 	node_shader_write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(blur_step * float(i), 0.0)) * blur_weight[i + 7];');
-			// 	node_shader_write(frag, 'roughness += texpaint_pack_sample.g;');
-			// 	node_shader_write(frag, 'metallic += texpaint_pack_sample.b;');
-			// 	node_shader_write(frag, 'occlusion += texpaint_pack_sample.r;');
-			// 	node_shader_write(frag, 'height += texpaint_pack_sample.a;');
-			// 	node_shader_write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp + vec2(blur_step * float(i), 0.0)).rgb * blur_weight[i + 7];');
-			// 	node_shader_write(frag, '}');
+			// 	node_shader_write(frag, "for (int i = -7; i <= 7; ++i) {");
+			// 	node_shader_write(frag, "vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(blur_step * float(i), 0.0));");
+			// 	node_shader_write(frag, "opacity += texpaint_sample.a * blur_weight[i + 7];");
+			// 	node_shader_write(frag, "basecol += texpaint_sample.rgb * blur_weight[i + 7];");
+			// 	node_shader_write(frag, "vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(blur_step * float(i), 0.0)) * blur_weight[i + 7];");
+			// 	node_shader_write(frag, "roughness += texpaint_pack_sample.g;");
+			// 	node_shader_write(frag, "metallic += texpaint_pack_sample.b;");
+			// 	node_shader_write(frag, "occlusion += texpaint_pack_sample.r;");
+			// 	node_shader_write(frag, "height += texpaint_pack_sample.a;");
+			// 	node_shader_write(frag, "nortan += texture(texpaint_nor_undo, texCoordInp + vec2(blur_step * float(i), 0.0)).rgb * blur_weight[i + 7];");
+			// 	node_shader_write(frag, "}");
 			// 	// Y
-			// 	node_shader_write(frag, 'for (int j = -7; j <= 7; ++j) {');
-			// 	node_shader_write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(0.0, blur_step * float(j)));');
-			// 	node_shader_write(frag, 'opacity += texpaint_sample.a * blur_weight[j + 7];');
-			// 	node_shader_write(frag, 'basecol += texpaint_sample.rgb * blur_weight[j + 7];');
-			// 	node_shader_write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(0.0, blur_step * float(j))) * blur_weight[j + 7];');
-			// 	node_shader_write(frag, 'roughness += texpaint_pack_sample.g;');
-			// 	node_shader_write(frag, 'metallic += texpaint_pack_sample.b;');
-			// 	node_shader_write(frag, 'occlusion += texpaint_pack_sample.r;');
-			// 	node_shader_write(frag, 'height += texpaint_pack_sample.a;');
-			// 	node_shader_write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp + vec2(0.0, blur_step * float(j))).rgb * blur_weight[j + 7];');
-			// 	node_shader_write(frag, '}');
+			// 	node_shader_write(frag, "for (int j = -7; j <= 7; ++j) {");
+			// 	node_shader_write(frag, "vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(0.0, blur_step * float(j)));");
+			// 	node_shader_write(frag, "opacity += texpaint_sample.a * blur_weight[j + 7];");
+			// 	node_shader_write(frag, "basecol += texpaint_sample.rgb * blur_weight[j + 7];");
+			// 	node_shader_write(frag, "vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(0.0, blur_step * float(j))) * blur_weight[j + 7];");
+			// 	node_shader_write(frag, "roughness += texpaint_pack_sample.g;");
+			// 	node_shader_write(frag, "metallic += texpaint_pack_sample.b;");
+			// 	node_shader_write(frag, "occlusion += texpaint_pack_sample.r;");
+			// 	node_shader_write(frag, "height += texpaint_pack_sample.a;");
+			// 	node_shader_write(frag, "nortan += texture(texpaint_nor_undo, texCoordInp + vec2(0.0, blur_step * float(j))).rgb * blur_weight[j + 7];");
+			// 	node_shader_write(frag, "}");
 			// }
-			// node_shader_write(frag, 'opacity *= brushOpacity;');
+			// node_shader_write(frag, "opacity *= brushOpacity;");
 		}
 	}
 
-	node_shader_write(frag, 'float opacity = 1.0;');
-	node_shader_write(frag, 'if (opacity == 0.0) discard;');
+	node_shader_write(frag, "float opacity = 1.0;");
+	node_shader_write(frag, "if (opacity == 0.0) discard;");
 
-	node_shader_write(frag, 'float str = clamp((brushRadius - dist) * brushHardness * 400.0, 0.0, 1.0) * opacity;');
+	node_shader_write(frag, "float str = clamp((brushRadius - dist) * brushHardness * 400.0, 0.0, 1.0) * opacity;");
 
 	// Manual blending to preserve memory
 	frag.wvpposition = true;
-	node_shader_write(frag, 'vec2 sample_tc = vec2(wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
+	node_shader_write(frag, "vec2 sample_tc = vec2(wvpposition.xy / wvpposition.w) * 0.5 + 0.5;");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'sample_tc.y = 1.0 - sample_tc.y;');
+	node_shader_write(frag, "sample_tc.y = 1.0 - sample_tc.y;");
 	///end
-	node_shader_add_uniform(frag, 'sampler2D paintmask');
-	node_shader_write(frag, 'float sample_mask = textureLod(paintmask, sample_tc, 0.0).r;');
-	node_shader_write(frag, 'str = max(str, sample_mask);');
+	node_shader_add_uniform(frag, "sampler2D paintmask");
+	node_shader_write(frag, "float sample_mask = textureLod(paintmask, sample_tc, 0.0).r;");
+	node_shader_write(frag, "str = max(str, sample_mask);");
 
-	node_shader_add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-	node_shader_write(frag, 'vec4 sample_undo = textureLod(texpaint_undo, sample_tc, 0.0);');
+	node_shader_add_uniform(frag, "sampler2D texpaint_undo", "_texpaint_undo");
+	node_shader_write(frag, "vec4 sample_undo = textureLod(texpaint_undo, sample_tc, 0.0);");
 
 	if (context_raw.tool == workspace_tool_t.ERASER) {
-		// node_shader_write(frag, 'fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);');
-		node_shader_write(frag, 'fragColor[0] = vec4(0.0, 0.0, 0.0, 0.0);');
-		node_shader_write(frag, 'fragColor[1] = vec4(0.5, 0.5, 1.0, 0.0);');
-		node_shader_write(frag, 'fragColor[2] = vec4(1.0, 0.0, 0.0, 0.0);');
+		// node_shader_write(frag, "fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);");
+		node_shader_write(frag, "fragColor[0] = vec4(0.0, 0.0, 0.0, 0.0);");
+		node_shader_write(frag, "fragColor[1] = vec4(0.5, 0.5, 1.0, 0.0);");
+		node_shader_write(frag, "fragColor[2] = vec4(1.0, 0.0, 0.0, 0.0);");
 	}
 
-	node_shader_write(frag, 'fragColor[3] = vec4(str, 0.0, 0.0, 1.0);');
+	node_shader_write(frag, "fragColor[3] = vec4(str, 0.0, 0.0, 1.0);");
 
 	parser_material_finalize(con_paint);
 	parser_material_sample_keep_aspect = false;

+ 8 - 8
armorlab/Sources/nodes_brush.ts

@@ -1,11 +1,11 @@
-/// <reference path='./nodes/image_texture_node.ts'/>
-/// <reference path='./nodes/rgb_node.ts'/>
-/// <reference path='./nodes/inpaint_node.ts'/>
-/// <reference path='./nodes/photo_to_pbr_node.ts'/>
-/// <reference path='./nodes/text_to_photo_node.ts'/>
-/// <reference path='./nodes/tiling_node.ts'/>
-/// <reference path='./nodes/upscale_node.ts'/>
-/// <reference path='./nodes/variance_node.ts'/>
+/// <reference path="./nodes/image_texture_node.ts"/>
+/// <reference path="./nodes/rgb_node.ts"/>
+/// <reference path="./nodes/inpaint_node.ts"/>
+/// <reference path="./nodes/photo_to_pbr_node.ts"/>
+/// <reference path="./nodes/text_to_photo_node.ts"/>
+/// <reference path="./nodes/tiling_node.ts"/>
+/// <reference path="./nodes/upscale_node.ts"/>
+/// <reference path="./nodes/variance_node.ts"/>
 
 let nodes_brush_categories: string[] = [_tr("Input"), _tr("Model")];
 

+ 65 - 65
armorpaint/Sources/make_bake.ts

@@ -8,29 +8,29 @@ function make_bake_run(con: node_shader_context_t, vert: node_shader_t, frag: no
 		frag.vvec = true;
 		node_shader_add_function(frag, str_cotangent_frame);
 		///if krom_direct3d11
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, vVec, texCoord);");
 		///else
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, -vVec, texCoord);");
 		///end
-		node_shader_write(frag, 'n = nortan * 2.0 - 1.0;');
-		node_shader_write(frag, 'n.y = -n.y;');
-		node_shader_write(frag, 'n = normalize(mul(n, TBN));');
+		node_shader_write(frag, "n = nortan * 2.0 - 1.0;");
+		node_shader_write(frag, "n.y = -n.y;");
+		node_shader_write(frag, "n = normalize(mul(n, TBN));");
 
 		node_shader_write(frag, make_material_voxelgi_half_extents());
-		node_shader_write(frag, 'vec3 voxpos = wposition / voxelgiHalfExtents;');
-		node_shader_add_uniform(frag, 'sampler3D voxels');
+		node_shader_write(frag, "vec3 voxpos = wposition / voxelgiHalfExtents;");
+		node_shader_add_uniform(frag, "sampler3D voxels");
 		node_shader_add_function(frag, str_trace_ao);
 		frag.n = true;
 		let strength: f32 = context_raw.bake_ao_strength;
 		let radius: f32 = context_raw.bake_ao_radius;
 		let offset: f32 = context_raw.bake_ao_offset;
-		node_shader_write(frag, `float ao = traceAO(voxpos, n, ${radius}, ${offset}) * ${strength};`);
+		node_shader_write(frag, "float ao = traceAO(voxpos, n, " + radius + ", " + offset + ") * " + strength + ";");
 		if (context_raw.bake_axis != bake_axis_t.XYZ) {
 			let axis: string = make_bake_axis_string(context_raw.bake_axis);
-			node_shader_write(frag, `ao *= dot(n, ${axis});`);
+			node_shader_write(frag, "ao *= dot(n, " + axis + ");");
 		}
-		node_shader_write(frag, 'ao = 1.0 - ao;');
-		node_shader_write(frag, 'fragColor[0] = vec4(ao, ao, ao, 1.0);');
+		node_shader_write(frag, "ao = 1.0 - ao;");
+		node_shader_write(frag, "fragColor[0] = vec4(ao, ao, ao, 1.0);");
 		///end
 	}
 	else if (context_raw.bake_type == bake_type_t.CURVATURE) {
@@ -38,100 +38,100 @@ function make_bake_run(con: node_shader_context_t, vert: node_shader_t, frag: no
 		let strength: string = pass ? parser_material_bake_passthrough_strength : context_raw.bake_curv_strength + "";
 		let radius: string = pass ? parser_material_bake_passthrough_radius : context_raw.bake_curv_radius + "";
 		let offset: string = pass ? parser_material_bake_passthrough_offset : context_raw.bake_curv_offset + "";
-		strength = `float(${strength})`;
-		radius = `float(${radius})`;
-		offset = `float(${offset})`;
+		strength = "float(" + strength + ")";
+		radius = "float(" + radius + ")";
+		offset = "float(" + offset + ")";
 		frag.n = true;
-		node_shader_write(frag, 'vec3 dx = dFdx(n);');
-		node_shader_write(frag, 'vec3 dy = dFdy(n);');
-		node_shader_write(frag, 'float curvature = max(dot(dx, dx), dot(dy, dy));');
-		node_shader_write(frag, 'curvature = clamp(pow(curvature, (1.0 / ' + radius + ') * 0.25) * ' + strength + ' * 2.0 + ' + offset + ' / 10.0, 0.0, 1.0);');
+		node_shader_write(frag, "vec3 dx = dFdx(n);");
+		node_shader_write(frag, "vec3 dy = dFdy(n);");
+		node_shader_write(frag, "float curvature = max(dot(dx, dx), dot(dy, dy));");
+		node_shader_write(frag, "curvature = clamp(pow(curvature, (1.0 / " + radius + ") * 0.25) * " + strength + " * 2.0 + " + offset + " / 10.0, 0.0, 1.0);");
 		if (context_raw.bake_axis != bake_axis_t.XYZ) {
 			let axis: string = make_bake_axis_string(context_raw.bake_axis);
-			node_shader_write(frag, `curvature *= dot(n, ${axis});`);
+			node_shader_write(frag, "curvature *= dot(n, " + axis + ");");
 		}
-		node_shader_write(frag, 'fragColor[0] = vec4(curvature, curvature, curvature, 1.0);');
+		node_shader_write(frag, "fragColor[0] = vec4(curvature, curvature, curvature, 1.0);");
 	}
 	else if (context_raw.bake_type == bake_type_t.NORMAL) { // Tangent
 		frag.n = true;
-		node_shader_add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo'); // Baked high-poly normals
-		node_shader_write(frag, 'vec3 n0 = textureLod(texpaint_undo, texCoord, 0.0).rgb * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
+		node_shader_add_uniform(frag, "sampler2D texpaint_undo", "_texpaint_undo"); // Baked high-poly normals
+		node_shader_write(frag, "vec3 n0 = textureLod(texpaint_undo, texCoord, 0.0).rgb * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
 		node_shader_add_function(frag, str_cotangent_frame);
-		node_shader_write(frag, 'mat3 invTBN = transpose(cotangentFrame(n, n, texCoord));');
-		node_shader_write(frag, 'vec3 res = normalize(mul(n0, invTBN)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);');
-		node_shader_write(frag, 'fragColor[0] = vec4(res, 1.0);');
+		node_shader_write(frag, "mat3 invTBN = transpose(cotangentFrame(n, n, texCoord));");
+		node_shader_write(frag, "vec3 res = normalize(mul(n0, invTBN)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);");
+		node_shader_write(frag, "fragColor[0] = vec4(res, 1.0);");
 	}
 	else if (context_raw.bake_type == bake_type_t.NORMAL_OBJECT) {
 		frag.n = true;
-		node_shader_write(frag, 'fragColor[0] = vec4(n * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5), 1.0);');
+		node_shader_write(frag, "fragColor[0] = vec4(n * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5), 1.0);");
 		if (context_raw.bake_up_axis == bake_up_axis_t.Y) {
-			node_shader_write(frag, 'fragColor[0].rgb = vec3(fragColor[0].r, fragColor[0].b, 1.0 - fragColor[0].g);');
+			node_shader_write(frag, "fragColor[0].rgb = vec3(fragColor[0].r, fragColor[0].b, 1.0 - fragColor[0].g);");
 		}
 	}
 	else if (context_raw.bake_type == bake_type_t.HEIGHT) {
 		frag.wposition = true;
-		node_shader_add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo'); // Baked high-poly positions
-		node_shader_write(frag, 'vec3 wpos0 = textureLod(texpaint_undo, texCoord, 0.0).rgb * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-		node_shader_write(frag, 'float res = distance(wpos0, wposition) * 10.0;');
-		node_shader_write(frag, 'fragColor[0] = vec4(res, res, res, 1.0);');
+		node_shader_add_uniform(frag, "sampler2D texpaint_undo", "_texpaint_undo"); // Baked high-poly positions
+		node_shader_write(frag, "vec3 wpos0 = textureLod(texpaint_undo, texCoord, 0.0).rgb * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
+		node_shader_write(frag, "float res = distance(wpos0, wposition) * 10.0;");
+		node_shader_write(frag, "fragColor[0] = vec4(res, res, res, 1.0);");
 	}
 	else if (context_raw.bake_type == bake_type_t.DERIVATIVE) {
-		node_shader_add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo'); // Baked height
-		node_shader_write(frag, 'vec2 texDx = dFdx(texCoord);');
-		node_shader_write(frag, 'vec2 texDy = dFdy(texCoord);');
-		node_shader_write(frag, 'float h0 = textureLod(texpaint_undo, texCoord, 0.0).r * 100;');
-		node_shader_write(frag, 'float h1 = textureLod(texpaint_undo, texCoord + texDx, 0.0).r * 100;');
-		node_shader_write(frag, 'float h2 = textureLod(texpaint_undo, texCoord + texDy, 0.0).r * 100;');
-		node_shader_write(frag, 'fragColor[0] = vec4((h1 - h0) * 0.5 + 0.5, (h2 - h0) * 0.5 + 0.5, 0.0, 1.0);');
+		node_shader_add_uniform(frag, "sampler2D texpaint_undo", "_texpaint_undo"); // Baked height
+		node_shader_write(frag, "vec2 texDx = dFdx(texCoord);");
+		node_shader_write(frag, "vec2 texDy = dFdy(texCoord);");
+		node_shader_write(frag, "float h0 = textureLod(texpaint_undo, texCoord, 0.0).r * 100;");
+		node_shader_write(frag, "float h1 = textureLod(texpaint_undo, texCoord + texDx, 0.0).r * 100;");
+		node_shader_write(frag, "float h2 = textureLod(texpaint_undo, texCoord + texDy, 0.0).r * 100;");
+		node_shader_write(frag, "fragColor[0] = vec4((h1 - h0) * 0.5 + 0.5, (h2 - h0) * 0.5 + 0.5, 0.0, 1.0);");
 	}
 	else if (context_raw.bake_type == bake_type_t.POSITION) {
 		frag.wposition = true;
-		node_shader_write(frag, 'fragColor[0] = vec4(wposition * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5), 1.0);');
+		node_shader_write(frag, "fragColor[0] = vec4(wposition * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5), 1.0);");
 		if (context_raw.bake_up_axis == bake_up_axis_t.Y) {
-			node_shader_write(frag, 'fragColor[0].rgb = vec3(fragColor[0].r, fragColor[0].b, 1.0 - fragColor[0].g);');
+			node_shader_write(frag, "fragColor[0].rgb = vec3(fragColor[0].r, fragColor[0].b, 1.0 - fragColor[0].g);");
 		}
 	}
 	else if (context_raw.bake_type == bake_type_t.TEXCOORD) {
-		node_shader_write(frag, 'fragColor[0] = vec4(texCoord.xy, 0.0, 1.0);');
+		node_shader_write(frag, "fragColor[0] = vec4(texCoord.xy, 0.0, 1.0);");
 	}
 	else if (context_raw.bake_type == bake_type_t.MATERIALID) {
-		node_shader_add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
-		node_shader_write(frag, 'float sample_matid = textureLod(texpaint_nor_undo, texCoord, 0.0).a + 1.0 / 255.0;');
-		node_shader_write(frag, 'float matid_r = fract(sin(dot(vec2(sample_matid, sample_matid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-		node_shader_write(frag, 'float matid_g = fract(sin(dot(vec2(sample_matid * 20.0, sample_matid), vec2(12.9898, 78.233))) * 43758.5453);');
-		node_shader_write(frag, 'float matid_b = fract(sin(dot(vec2(sample_matid, sample_matid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-		node_shader_write(frag, 'fragColor[0] = vec4(matid_r, matid_g, matid_b, 1.0);');
+		node_shader_add_uniform(frag, "sampler2D texpaint_nor_undo", "_texpaint_nor_undo");
+		node_shader_write(frag, "float sample_matid = textureLod(texpaint_nor_undo, texCoord, 0.0).a + 1.0 / 255.0;");
+		node_shader_write(frag, "float matid_r = fract(sin(dot(vec2(sample_matid, sample_matid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);");
+		node_shader_write(frag, "float matid_g = fract(sin(dot(vec2(sample_matid * 20.0, sample_matid), vec2(12.9898, 78.233))) * 43758.5453);");
+		node_shader_write(frag, "float matid_b = fract(sin(dot(vec2(sample_matid, sample_matid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);");
+		node_shader_write(frag, "fragColor[0] = vec4(matid_r, matid_g, matid_b, 1.0);");
 	}
 	else if (context_raw.bake_type == bake_type_t.OBJECTID) {
-		node_shader_add_uniform(frag, 'float objectId', '_objectId');
-		node_shader_write(frag, 'float obid = objectId + 1.0 / 255.0;');
-		node_shader_write(frag, 'float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-		node_shader_write(frag, 'float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);');
-		node_shader_write(frag, 'float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-		node_shader_write(frag, 'fragColor[0] = vec4(id_r, id_g, id_b, 1.0);');
+		node_shader_add_uniform(frag, "float objectId", "_objectId");
+		node_shader_write(frag, "float obid = objectId + 1.0 / 255.0;");
+		node_shader_write(frag, "float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);");
+		node_shader_write(frag, "float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);");
+		node_shader_write(frag, "float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);");
+		node_shader_write(frag, "fragColor[0] = vec4(id_r, id_g, id_b, 1.0);");
 	}
 	else if (context_raw.bake_type == bake_type_t.VERTEX_COLOR) {
 		if (con.allow_vcols) {
 			node_shader_context_add_elem(con, "col", "short4norm");
-			node_shader_write(frag, 'fragColor[0] = vec4(vcolor.r, vcolor.g, vcolor.b, 1.0);');
+			node_shader_write(frag, "fragColor[0] = vec4(vcolor.r, vcolor.g, vcolor.b, 1.0);");
 		}
 		else {
-			node_shader_write(frag, 'fragColor[0] = vec4(1.0, 1.0, 1.0, 1.0);');
+			node_shader_write(frag, "fragColor[0] = vec4(1.0, 1.0, 1.0, 1.0);");
 		}
 	}
 }
 
 function make_bake_position_normal(vert: node_shader_t, frag: node_shader_t) {
-	node_shader_add_out(vert, 'vec3 position');
-	node_shader_add_out(vert, 'vec3 normal');
-	node_shader_add_uniform(vert, 'mat4 W', '_world_matrix');
-	node_shader_write(vert, 'position = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;');
-	node_shader_write(vert, 'normal = vec3(nor.xy, pos.w);');
-	node_shader_write(vert, 'vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);');
-	node_shader_write(vert, 'gl_Position = vec4(tpos, 0.0, 1.0);');
-	node_shader_add_out(frag, 'vec4 fragColor[2]');
-	node_shader_write(frag, 'fragColor[0] = vec4(position, 1.0);');
-	node_shader_write(frag, 'fragColor[1] = vec4(normal, 1.0);');
+	node_shader_add_out(vert, "vec3 position");
+	node_shader_add_out(vert, "vec3 normal");
+	node_shader_add_uniform(vert, "mat4 W", "_world_matrix");
+	node_shader_write(vert, "position = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;");
+	node_shader_write(vert, "normal = vec3(nor.xy, pos.w);");
+	node_shader_write(vert, "vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);");
+	node_shader_write(vert, "gl_Position = vec4(tpos, 0.0, 1.0);");
+	node_shader_add_out(frag, "vec4 fragColor[2]");
+	node_shader_write(frag, "fragColor[0] = vec4(position, 1.0);");
+	node_shader_write(frag, "fragColor[1] = vec4(normal, 1.0);");
 }
 
 function make_bake_set_color_writes(con_paint: node_shader_context_t) {

+ 57 - 57
armorpaint/Sources/make_blur.ts

@@ -1,89 +1,89 @@
 
 function make_blur_run(vert: node_shader_t, frag: node_shader_t) {
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, sp.y * gbufferSize.y), 0).ba;');
+	node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, sp.y * gbufferSize.y), 0).ba;");
 	///else
-	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, (1.0 - sp.y) * gbufferSize.y), 0).ba;');
+	node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, (1.0 - sp.y) * gbufferSize.y), 0).ba;");
 	///end
 
-	node_shader_write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-	node_shader_write(frag, 'float roughness = 0.0;');
-	node_shader_write(frag, 'float metallic = 0.0;');
-	node_shader_write(frag, 'float occlusion = 0.0;');
-	node_shader_write(frag, 'vec3 nortan = vec3(0.0, 0.0, 0.0);');
-	node_shader_write(frag, 'float height = 0.0;');
-	node_shader_write(frag, 'float mat_opacity = 1.0;');
+	node_shader_write(frag, "vec3 basecol = vec3(0.0, 0.0, 0.0);");
+	node_shader_write(frag, "float roughness = 0.0;");
+	node_shader_write(frag, "float metallic = 0.0;");
+	node_shader_write(frag, "float occlusion = 0.0;");
+	node_shader_write(frag, "vec3 nortan = vec3(0.0, 0.0, 0.0);");
+	node_shader_write(frag, "float height = 0.0;");
+	node_shader_write(frag, "float mat_opacity = 1.0;");
 	let is_mask: bool = slot_layer_is_mask(context_raw.layer);
 	if (is_mask) {
-		node_shader_write(frag, 'float opacity = 1.0;');
+		node_shader_write(frag, "float opacity = 1.0;");
 	}
 	else {
-		node_shader_write(frag, 'float opacity = 0.0;');
+		node_shader_write(frag, "float opacity = 0.0;");
 	}
 	if (context_raw.material.paint_emis) {
-		node_shader_write(frag, 'float emis = 0.0;');
+		node_shader_write(frag, "float emis = 0.0;");
 	}
 	if (context_raw.material.paint_subs) {
-		node_shader_write(frag, 'float subs = 0.0;');
+		node_shader_write(frag, "float subs = 0.0;");
 	}
 
-	node_shader_add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-	node_shader_write(frag, 'float blur_step = 1.0 / texpaintSize.x;');
+	node_shader_add_uniform(frag, "vec2 texpaintSize", "_texpaintSize");
+	node_shader_write(frag, "float blur_step = 1.0 / texpaintSize.x;");
 	if (context_raw.tool == workspace_tool_t.SMUDGE) {
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal)
-		node_shader_write(frag, 'const float blur_weight[7] = {1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0};');
+		node_shader_write(frag, "const float blur_weight[7] = {1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0};");
 		///else
-		node_shader_write(frag, 'const float blur_weight[7] = float[](1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0);');
+		node_shader_write(frag, "const float blur_weight[7] = float[](1.0 / 28.0, 2.0 / 28.0, 3.0 / 28.0, 4.0 / 28.0, 5.0 / 28.0, 6.0 / 28.0, 7.0 / 28.0);");
 		///end
-		node_shader_add_uniform(frag, 'vec3 brushDirection', '_brushDirection');
-		node_shader_write(frag, 'vec2 blur_direction = brushDirection.yx;');
-		node_shader_write(frag, 'for (int i = 0; i < 7; ++i) {');
+		node_shader_add_uniform(frag, "vec3 brushDirection", "_brushDirection");
+		node_shader_write(frag, "vec2 blur_direction = brushDirection.yx;");
+		node_shader_write(frag, "for (int i = 0; i < 7; ++i) {");
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'vec2 texCoordInp2 = texelFetch(gbuffer2, ivec2((sp.x + blur_direction.x * blur_step * float(i)) * gbufferSize.x, (sp.y + blur_direction.y * blur_step * float(i)) * gbufferSize.y), 0).ba;');
+		node_shader_write(frag, "vec2 texCoordInp2 = texelFetch(gbuffer2, ivec2((sp.x + blur_direction.x * blur_step * float(i)) * gbufferSize.x, (sp.y + blur_direction.y * blur_step * float(i)) * gbufferSize.y), 0).ba;");
 		///else
-		node_shader_write(frag, 'vec2 texCoordInp2 = texelFetch(gbuffer2, ivec2((sp.x + blur_direction.x * blur_step * float(i)) * gbufferSize.x, (1.0 - (sp.y + blur_direction.y * blur_step * float(i))) * gbufferSize.y), 0).ba;');
+		node_shader_write(frag, "vec2 texCoordInp2 = texelFetch(gbuffer2, ivec2((sp.x + blur_direction.x * blur_step * float(i)) * gbufferSize.x, (1.0 - (sp.y + blur_direction.y * blur_step * float(i))) * gbufferSize.y), 0).ba;");
 		///end
-		node_shader_write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp2);');
-		node_shader_write(frag, 'opacity += texpaint_sample.a * blur_weight[i];');
-		node_shader_write(frag, 'basecol += texpaint_sample.rgb * blur_weight[i];');
-		node_shader_write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp2) * blur_weight[i];');
-		node_shader_write(frag, 'roughness += texpaint_pack_sample.g;');
-		node_shader_write(frag, 'metallic += texpaint_pack_sample.b;');
-		node_shader_write(frag, 'occlusion += texpaint_pack_sample.r;');
-		node_shader_write(frag, 'height += texpaint_pack_sample.a;');
-		node_shader_write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp2).rgb * blur_weight[i];');
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "vec4 texpaint_sample = texture(texpaint_undo, texCoordInp2);");
+		node_shader_write(frag, "opacity += texpaint_sample.a * blur_weight[i];");
+		node_shader_write(frag, "basecol += texpaint_sample.rgb * blur_weight[i];");
+		node_shader_write(frag, "vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp2) * blur_weight[i];");
+		node_shader_write(frag, "roughness += texpaint_pack_sample.g;");
+		node_shader_write(frag, "metallic += texpaint_pack_sample.b;");
+		node_shader_write(frag, "occlusion += texpaint_pack_sample.r;");
+		node_shader_write(frag, "height += texpaint_pack_sample.a;");
+		node_shader_write(frag, "nortan += texture(texpaint_nor_undo, texCoordInp2).rgb * blur_weight[i];");
+		node_shader_write(frag, "}");
 	}
 	else {
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal)
-		node_shader_write(frag, 'const float blur_weight[15] = {0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0, 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0, 0.034619 / 2.0};');
+		node_shader_write(frag, "const float blur_weight[15] = {0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0, 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0, 0.034619 / 2.0};");
 		///else
-		node_shader_write(frag, 'const float blur_weight[15] = float[](0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0, 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0, 0.034619 / 2.0);');
+		node_shader_write(frag, "const float blur_weight[15] = float[](0.034619 / 2.0, 0.044859 / 2.0, 0.055857 / 2.0, 0.066833 / 2.0, 0.076841 / 2.0, 0.084894 / 2.0, 0.090126 / 2.0, 0.09194 / 2.0, 0.090126 / 2.0, 0.084894 / 2.0, 0.076841 / 2.0, 0.066833 / 2.0, 0.055857 / 2.0, 0.044859 / 2.0, 0.034619 / 2.0);");
 		///end
 		// X
-		node_shader_write(frag, 'for (int i = -7; i <= 7; ++i) {');
-		node_shader_write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(blur_step * float(i), 0.0));');
-		node_shader_write(frag, 'opacity += texpaint_sample.a * blur_weight[i + 7];');
-		node_shader_write(frag, 'basecol += texpaint_sample.rgb * blur_weight[i + 7];');
-		node_shader_write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(blur_step * float(i), 0.0)) * blur_weight[i + 7];');
-		node_shader_write(frag, 'roughness += texpaint_pack_sample.g;');
-		node_shader_write(frag, 'metallic += texpaint_pack_sample.b;');
-		node_shader_write(frag, 'occlusion += texpaint_pack_sample.r;');
-		node_shader_write(frag, 'height += texpaint_pack_sample.a;');
-		node_shader_write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp + vec2(blur_step * float(i), 0.0)).rgb * blur_weight[i + 7];');
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "for (int i = -7; i <= 7; ++i) {");
+		node_shader_write(frag, "vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(blur_step * float(i), 0.0));");
+		node_shader_write(frag, "opacity += texpaint_sample.a * blur_weight[i + 7];");
+		node_shader_write(frag, "basecol += texpaint_sample.rgb * blur_weight[i + 7];");
+		node_shader_write(frag, "vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(blur_step * float(i), 0.0)) * blur_weight[i + 7];");
+		node_shader_write(frag, "roughness += texpaint_pack_sample.g;");
+		node_shader_write(frag, "metallic += texpaint_pack_sample.b;");
+		node_shader_write(frag, "occlusion += texpaint_pack_sample.r;");
+		node_shader_write(frag, "height += texpaint_pack_sample.a;");
+		node_shader_write(frag, "nortan += texture(texpaint_nor_undo, texCoordInp + vec2(blur_step * float(i), 0.0)).rgb * blur_weight[i + 7];");
+		node_shader_write(frag, "}");
 		// Y
-		node_shader_write(frag, 'for (int j = -7; j <= 7; ++j) {');
-		node_shader_write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(0.0, blur_step * float(j)));');
-		node_shader_write(frag, 'opacity += texpaint_sample.a * blur_weight[j + 7];');
-		node_shader_write(frag, 'basecol += texpaint_sample.rgb * blur_weight[j + 7];');
-		node_shader_write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(0.0, blur_step * float(j))) * blur_weight[j + 7];');
-		node_shader_write(frag, 'roughness += texpaint_pack_sample.g;');
-		node_shader_write(frag, 'metallic += texpaint_pack_sample.b;');
-		node_shader_write(frag, 'occlusion += texpaint_pack_sample.r;');
-		node_shader_write(frag, 'height += texpaint_pack_sample.a;');
-		node_shader_write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp + vec2(0.0, blur_step * float(j))).rgb * blur_weight[j + 7];');
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "for (int j = -7; j <= 7; ++j) {");
+		node_shader_write(frag, "vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(0.0, blur_step * float(j)));");
+		node_shader_write(frag, "opacity += texpaint_sample.a * blur_weight[j + 7];");
+		node_shader_write(frag, "basecol += texpaint_sample.rgb * blur_weight[j + 7];");
+		node_shader_write(frag, "vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(0.0, blur_step * float(j))) * blur_weight[j + 7];");
+		node_shader_write(frag, "roughness += texpaint_pack_sample.g;");
+		node_shader_write(frag, "metallic += texpaint_pack_sample.b;");
+		node_shader_write(frag, "occlusion += texpaint_pack_sample.r;");
+		node_shader_write(frag, "height += texpaint_pack_sample.a;");
+		node_shader_write(frag, "nortan += texture(texpaint_nor_undo, texCoordInp + vec2(0.0, blur_step * float(j))).rgb * blur_weight[j + 7];");
+		node_shader_write(frag, "}");
 	}
-	node_shader_write(frag, 'opacity *= brushOpacity;');
+	node_shader_write(frag, "opacity *= brushOpacity;");
 }

+ 43 - 43
armorpaint/Sources/make_brush.ts

@@ -1,7 +1,7 @@
 
 function make_brush_run(vert: node_shader_t, frag: node_shader_t) {
 
-	node_shader_write(frag, 'float dist = 0.0;');
+	node_shader_write(frag, "float dist = 0.0;");
 
 	if (context_raw.tool == workspace_tool_t.PARTICLE) {
 		return;
@@ -10,88 +10,88 @@ function make_brush_run(vert: node_shader_t, frag: node_shader_t) {
 	let fill_layer: bool = context_raw.layer.fill_layer != null;
 	let decal: bool = context_raw.tool == workspace_tool_t.DECAL || context_raw.tool == workspace_tool_t.TEXT;
 	if (decal && !fill_layer) {
-		node_shader_write(frag, 'if (decalMask.z > 0.0) {');
+		node_shader_write(frag, "if (decalMask.z > 0.0) {");
 	}
 
 	if (config_raw.brush_3d) {
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'float depth = textureLod(gbufferD, inp.xy, 0.0).r;');
+		node_shader_write(frag, "float depth = textureLod(gbufferD, inp.xy, 0.0).r;");
 		///else
-		node_shader_write(frag, 'float depth = textureLod(gbufferD, vec2(inp.x, 1.0 - inp.y), 0.0).r;');
+		node_shader_write(frag, "float depth = textureLod(gbufferD, vec2(inp.x, 1.0 - inp.y), 0.0).r;");
 		///end
 
-		node_shader_add_uniform(frag, 'mat4 invVP', '_inv_view_proj_matrix');
-		node_shader_write(frag, 'vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);');
-		node_shader_write(frag, 'winp = mul(winp, invVP);');
-		node_shader_write(frag, 'winp.xyz /= winp.w;');
+		node_shader_add_uniform(frag, "mat4 invVP", "_inv_view_proj_matrix");
+		node_shader_write(frag, "vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);");
+		node_shader_write(frag, "winp = mul(winp, invVP);");
+		node_shader_write(frag, "winp.xyz /= winp.w;");
 		frag.wposition = true;
 
 		if (config_raw.brush_angle_reject || context_raw.xray) {
 			node_shader_add_function(frag, str_octahedron_wrap);
-			node_shader_add_uniform(frag, 'sampler2D gbuffer0');
+			node_shader_add_uniform(frag, "sampler2D gbuffer0");
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			node_shader_write(frag, 'vec2 g0 = textureLod(gbuffer0, inp.xy, 0.0).rg;');
+			node_shader_write(frag, "vec2 g0 = textureLod(gbuffer0, inp.xy, 0.0).rg;");
 			///else
-			node_shader_write(frag, 'vec2 g0 = textureLod(gbuffer0, vec2(inp.x, 1.0 - inp.y), 0.0).rg;');
+			node_shader_write(frag, "vec2 g0 = textureLod(gbuffer0, vec2(inp.x, 1.0 - inp.y), 0.0).rg;");
 			///end
-			node_shader_write(frag, 'vec3 wn;');
-			node_shader_write(frag, 'wn.z = 1.0 - abs(g0.x) - abs(g0.y);');
-			node_shader_write(frag, 'wn.xy = wn.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);');
-			node_shader_write(frag, 'wn = normalize(wn);');
-			node_shader_write(frag, 'float planeDist = dot(wn, winp.xyz - wposition);');
+			node_shader_write(frag, "vec3 wn;");
+			node_shader_write(frag, "wn.z = 1.0 - abs(g0.x) - abs(g0.y);");
+			node_shader_write(frag, "wn.xy = wn.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);");
+			node_shader_write(frag, "wn = normalize(wn);");
+			node_shader_write(frag, "float planeDist = dot(wn, winp.xyz - wposition);");
 
 			if (config_raw.brush_angle_reject && !context_raw.xray) {
-				node_shader_write(frag, 'if (planeDist < -0.01) discard;');
+				node_shader_write(frag, "if (planeDist < -0.01) discard;");
 				frag.n = true;
 				let angle: f32 = context_raw.brush_angle_reject_dot;
-				node_shader_write(frag, `if (dot(wn, n) < ${angle}) discard;`);
+				node_shader_write(frag, "if (dot(wn, n) < " + angle + ") discard;");
 			}
 		}
 
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'float depthlast = textureLod(gbufferD, inplast.xy, 0.0).r;');
+		node_shader_write(frag, "float depthlast = textureLod(gbufferD, inplast.xy, 0.0).r;");
 		///else
-		node_shader_write(frag, 'float depthlast = textureLod(gbufferD, vec2(inplast.x, 1.0 - inplast.y), 0.0).r;');
+		node_shader_write(frag, "float depthlast = textureLod(gbufferD, vec2(inplast.x, 1.0 - inplast.y), 0.0).r;");
 		///end
 
-		node_shader_write(frag, 'vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);');
-		node_shader_write(frag, 'winplast = mul(winplast, invVP);');
-		node_shader_write(frag, 'winplast.xyz /= winplast.w;');
+		node_shader_write(frag, "vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);");
+		node_shader_write(frag, "winplast = mul(winplast, invVP);");
+		node_shader_write(frag, "winplast.xyz /= winplast.w;");
 
-		node_shader_write(frag, 'vec3 pa = wposition - winp.xyz;');
+		node_shader_write(frag, "vec3 pa = wposition - winp.xyz;");
 		if (context_raw.xray) {
-			node_shader_write(frag, 'pa += wn * vec3(planeDist, planeDist, planeDist);');
+			node_shader_write(frag, "pa += wn * vec3(planeDist, planeDist, planeDist);");
 		}
-		node_shader_write(frag, 'vec3 ba = winplast.xyz - winp.xyz;');
+		node_shader_write(frag, "vec3 ba = winplast.xyz - winp.xyz;");
 
 		if (context_raw.brush_lazy_radius > 0 && context_raw.brush_lazy_step > 0) {
 			// Sphere
-			node_shader_write(frag, 'dist = distance(wposition, winp.xyz);');
+			node_shader_write(frag, "dist = distance(wposition, winp.xyz);");
 		}
 		else {
 			// Capsule
-			node_shader_write(frag, 'float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);');
-			node_shader_write(frag, 'dist = length(pa - ba * h);');
+			node_shader_write(frag, "float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);");
+			node_shader_write(frag, "dist = length(pa - ba * h);");
 		}
 	}
 	else { // !brush3d
-		node_shader_write(frag, 'vec2 binp = inp.xy * 2.0 - 1.0;');
-		node_shader_write(frag, 'binp.x *= aspectRatio;');
-		node_shader_write(frag, 'binp = binp * 0.5 + 0.5;');
-
-		node_shader_write(frag, 'vec2 binplast = inplast.xy * 2.0 - 1.0;');
-		node_shader_write(frag, 'binplast.x *= aspectRatio;');
-		node_shader_write(frag, 'binplast = binplast * 0.5 + 0.5;');
-
-		node_shader_write(frag, 'vec2 pa = bsp.xy - binp.xy;');
-		node_shader_write(frag, 'vec2 ba = binplast.xy - binp.xy;');
-		node_shader_write(frag, 'float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);');
-		node_shader_write(frag, 'dist = length(pa - ba * h);');
+		node_shader_write(frag, "vec2 binp = inp.xy * 2.0 - 1.0;");
+		node_shader_write(frag, "binp.x *= aspectRatio;");
+		node_shader_write(frag, "binp = binp * 0.5 + 0.5;");
+
+		node_shader_write(frag, "vec2 binplast = inplast.xy * 2.0 - 1.0;");
+		node_shader_write(frag, "binplast.x *= aspectRatio;");
+		node_shader_write(frag, "binplast = binplast * 0.5 + 0.5;");
+
+		node_shader_write(frag, "vec2 pa = bsp.xy - binp.xy;");
+		node_shader_write(frag, "vec2 ba = binplast.xy - binp.xy;");
+		node_shader_write(frag, "float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);");
+		node_shader_write(frag, "dist = length(pa - ba * h);");
 	}
 
-	node_shader_write(frag, 'if (dist > brushRadius) discard;');
+	node_shader_write(frag, "if (dist > brushRadius) discard;");
 
 	if (decal && !fill_layer) {
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "}");
 	}
 }

+ 21 - 21
armorpaint/Sources/make_clone.ts

@@ -1,32 +1,32 @@
 
 function make_clone_run(vert: node_shader_t, frag: node_shader_t) {
-	node_shader_add_uniform(frag, 'vec2 cloneDelta', '_cloneDelta');
+	node_shader_add_uniform(frag, "vec2 cloneDelta", "_cloneDelta");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.xy + cloneDelta) * gbufferSize), 0).ba;');
+	node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.xy + cloneDelta) * gbufferSize), 0).ba;");
 	///else
-	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.x + cloneDelta.x) * gbufferSize.x, (1.0 - (sp.y + cloneDelta.y)) * gbufferSize.y), 0).ba;');
+	node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.x + cloneDelta.x) * gbufferSize.x, (1.0 - (sp.y + cloneDelta.y)) * gbufferSize.y), 0).ba;");
 	///end
 
-	node_shader_write(frag, 'vec3 texpaint_pack_sample = textureLod(texpaint_pack_undo, texCoordInp, 0.0).rgb;');
-	let base: string = 'textureLod(texpaint_undo, texCoordInp, 0.0).rgb';
-	let rough: string = 'texpaint_pack_sample.g';
-	let met: string = 'texpaint_pack_sample.b';
-	let occ: string = 'texpaint_pack_sample.r';
-	let nortan: string = 'textureLod(texpaint_nor_undo, texCoordInp, 0.0).rgb';
-	let height: string = '0.0';
-	let opac: string = '1.0';
-	node_shader_write(frag, `vec3 basecol = ${base};`);
-	node_shader_write(frag, `float roughness = ${rough};`);
-	node_shader_write(frag, `float metallic = ${met};`);
-	node_shader_write(frag, `float occlusion = ${occ};`);
-	node_shader_write(frag, `vec3 nortan = ${nortan};`);
-	node_shader_write(frag, `float height = ${height};`);
-	node_shader_write(frag, `float mat_opacity = ${opac};`);
-	node_shader_write(frag, 'float opacity = mat_opacity * brushOpacity;');
+	node_shader_write(frag, "vec3 texpaint_pack_sample = textureLod(texpaint_pack_undo, texCoordInp, 0.0).rgb;");
+	let base: string = "textureLod(texpaint_undo, texCoordInp, 0.0).rgb";
+	let rough: string = "texpaint_pack_sample.g";
+	let met: string = "texpaint_pack_sample.b";
+	let occ: string = "texpaint_pack_sample.r";
+	let nortan: string = "textureLod(texpaint_nor_undo, texCoordInp, 0.0).rgb";
+	let height: string = "0.0";
+	let opac: string = "1.0";
+	node_shader_write(frag, "vec3 basecol = " + base + ";");
+	node_shader_write(frag, "float roughness = " + rough + ";");
+	node_shader_write(frag, "float metallic = " + met + ";");
+	node_shader_write(frag, "float occlusion = " + occ + ";");
+	node_shader_write(frag, "vec3 nortan = " + nortan + ";");
+	node_shader_write(frag, "float height = " + height + ";");
+	node_shader_write(frag, "float mat_opacity = " + opac + ";");
+	node_shader_write(frag, "float opacity = mat_opacity * brushOpacity;");
 	if (context_raw.material.paint_emis) {
-		node_shader_write(frag, 'float emis = 0.0;');
+		node_shader_write(frag, "float emis = 0.0;");
 	}
 	if (context_raw.material.paint_subs) {
-		node_shader_write(frag, 'float subs = 0.0;');
+		node_shader_write(frag, "float subs = 0.0;");
 	}
 }

+ 23 - 23
armorpaint/Sources/make_colorid_picker.ts

@@ -1,43 +1,43 @@
 
 function make_colorid_picker_run(vert: node_shader_t, frag: node_shader_t) {
 	// Mangle vertices to form full screen triangle
-	node_shader_write(vert, 'gl_Position = vec4(-1.0 + float((gl_VertexID & 1) << 2), -1.0 + float((gl_VertexID & 2) << 1), 0.0, 1.0);');
+	node_shader_write(vert, "gl_Position = vec4(-1.0 + float((gl_VertexID & 1) << 2), -1.0 + float((gl_VertexID & 2) << 1), 0.0, 1.0);");
 
-	node_shader_add_uniform(frag, 'sampler2D gbuffer2');
-	node_shader_add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
-	node_shader_add_uniform(frag, 'vec4 inp', '_inputBrush');
+	node_shader_add_uniform(frag, "sampler2D gbuffer2");
+	node_shader_add_uniform(frag, "vec2 gbufferSize", "_gbufferSize");
+	node_shader_add_uniform(frag, "vec4 inp", "_inputBrush");
 
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, inp.y * gbufferSize.y), 0).ba;');
+	node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, inp.y * gbufferSize.y), 0).ba;");
 	///else
-	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, (1.0 - inp.y) * gbufferSize.y), 0).ba;');
+	node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, (1.0 - inp.y) * gbufferSize.y), 0).ba;");
 	///end
 
 	if (context_raw.tool == workspace_tool_t.COLORID) {
-		node_shader_add_out(frag, 'vec4 fragColor');
-		node_shader_add_uniform(frag, 'sampler2D texcolorid', '_texcolorid');
-		node_shader_write(frag, 'vec3 idcol = textureLod(texcolorid, texCoordInp, 0.0).rgb;');
-		node_shader_write(frag, 'fragColor = vec4(idcol, 1.0);');
+		node_shader_add_out(frag, "vec4 fragColor");
+		node_shader_add_uniform(frag, "sampler2D texcolorid", "_texcolorid");
+		node_shader_write(frag, "vec3 idcol = textureLod(texcolorid, texCoordInp, 0.0).rgb;");
+		node_shader_write(frag, "fragColor = vec4(idcol, 1.0);");
 	}
 	else if (context_raw.tool == workspace_tool_t.PICKER || context_raw.tool == workspace_tool_t.MATERIAL) {
 		if (context_raw.pick_pos_nor_tex) {
-			node_shader_add_out(frag, 'vec4 fragColor[2]');
-			node_shader_add_uniform(frag, 'sampler2D gbufferD');
-			node_shader_add_uniform(frag, 'mat4 invVP', '_inv_view_proj_matrix');
+			node_shader_add_out(frag, "vec4 fragColor[2]");
+			node_shader_add_uniform(frag, "sampler2D gbufferD");
+			node_shader_add_uniform(frag, "mat4 invVP", "_inv_view_proj_matrix");
 			node_shader_add_function(frag, str_get_pos_from_depth);
 			node_shader_add_function(frag, str_get_nor_from_depth);
-			node_shader_write(frag, 'fragColor[0] = vec4(get_pos_from_depth(vec2(inp.x, 1.0 - inp.y), invVP, texturePass(gbufferD)), texCoordInp.x);');
-			node_shader_write(frag, 'fragColor[1] = vec4(get_nor_from_depth(fragColor[0].rgb, vec2(inp.x, 1.0 - inp.y), invVP, vec2(1.0, 1.0) / gbufferSize, texturePass(gbufferD)), texCoordInp.y);');
+			node_shader_write(frag, "fragColor[0] = vec4(get_pos_from_depth(vec2(inp.x, 1.0 - inp.y), invVP, texturePass(gbufferD)), texCoordInp.x);");
+			node_shader_write(frag, "fragColor[1] = vec4(get_nor_from_depth(fragColor[0].rgb, vec2(inp.x, 1.0 - inp.y), invVP, vec2(1.0, 1.0) / gbufferSize, texturePass(gbufferD)), texCoordInp.y);");
 		}
 		else {
-			node_shader_add_out(frag, 'vec4 fragColor[4]');
-			node_shader_add_uniform(frag, 'sampler2D texpaint');
-			node_shader_add_uniform(frag, 'sampler2D texpaint_nor');
-			node_shader_add_uniform(frag, 'sampler2D texpaint_pack');
-			node_shader_write(frag, 'fragColor[0] = textureLod(texpaint, texCoordInp, 0.0);');
-			node_shader_write(frag, 'fragColor[1] = textureLod(texpaint_nor, texCoordInp, 0.0);');
-			node_shader_write(frag, 'fragColor[2] = textureLod(texpaint_pack, texCoordInp, 0.0);');
-			node_shader_write(frag, 'fragColor[3].rg = texCoordInp.xy;');
+			node_shader_add_out(frag, "vec4 fragColor[4]");
+			node_shader_add_uniform(frag, "sampler2D texpaint");
+			node_shader_add_uniform(frag, "sampler2D texpaint_nor");
+			node_shader_add_uniform(frag, "sampler2D texpaint_pack");
+			node_shader_write(frag, "fragColor[0] = textureLod(texpaint, texCoordInp, 0.0);");
+			node_shader_write(frag, "fragColor[1] = textureLod(texpaint_nor, texCoordInp, 0.0);");
+			node_shader_write(frag, "fragColor[2] = textureLod(texpaint_pack, texCoordInp, 0.0);");
+			node_shader_write(frag, "fragColor[3].rg = texCoordInp.xy;");
 		}
 	}
 }

+ 22 - 22
armorpaint/Sources/make_discard.ts

@@ -1,47 +1,47 @@
 
 function make_discard_color_id(vert: node_shader_t, frag: node_shader_t) {
-	node_shader_add_uniform(frag, 'sampler2D texpaint_colorid'); // 1x1 picker
-	node_shader_add_uniform(frag, 'sampler2D texcolorid', '_texcolorid'); // color map
-	node_shader_write(frag, 'vec3 colorid_c1 = texelFetch(texpaint_colorid, ivec2(0, 0), 0).rgb;');
-	node_shader_write(frag, 'vec3 colorid_c2 = textureLod(texcolorid, texCoordPick, 0).rgb;');
+	node_shader_add_uniform(frag, "sampler2D texpaint_colorid"); // 1x1 picker
+	node_shader_add_uniform(frag, "sampler2D texcolorid", "_texcolorid"); // color map
+	node_shader_write(frag, "vec3 colorid_c1 = texelFetch(texpaint_colorid, ivec2(0, 0), 0).rgb;");
+	node_shader_write(frag, "vec3 colorid_c2 = textureLod(texcolorid, texCoordPick, 0).rgb;");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal)
-	node_shader_write(frag, 'if (any(colorid_c1 != colorid_c2)) discard;');
+	node_shader_write(frag, "if (any(colorid_c1 != colorid_c2)) discard;");
 	///else
-	node_shader_write(frag, 'if (colorid_c1 != colorid_c2) discard;');
+	node_shader_write(frag, "if (colorid_c1 != colorid_c2) discard;");
 	///end
 }
 
 function make_discard_face(vert: node_shader_t, frag: node_shader_t) {
-	node_shader_add_uniform(frag, 'sampler2D gbuffer2');
-	node_shader_add_uniform(frag, 'sampler2D textrianglemap', '_textrianglemap');
-	node_shader_add_uniform(frag, 'vec2 textrianglemapSize', '_texpaintSize');
-	node_shader_add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
+	node_shader_add_uniform(frag, "sampler2D gbuffer2");
+	node_shader_add_uniform(frag, "sampler2D textrianglemap", "_textrianglemap");
+	node_shader_add_uniform(frag, "vec2 textrianglemapSize", "_texpaintSize");
+	node_shader_add_uniform(frag, "vec2 gbufferSize", "_gbufferSize");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, inp.y * gbufferSize.y), 0).ba;');
+	node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, inp.y * gbufferSize.y), 0).ba;");
 	///else
-	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, (1.0 - inp.y) * gbufferSize.y), 0).ba;');
+	node_shader_write(frag, "vec2 texCoordInp = texelFetch(gbuffer2, ivec2(inp.x * gbufferSize.x, (1.0 - inp.y) * gbufferSize.y), 0).ba;");
 	///end
-	node_shader_write(frag, 'vec4 face_c1 = texelFetch(textrianglemap, ivec2(texCoordInp * textrianglemapSize), 0);');
-	node_shader_write(frag, 'vec4 face_c2 = textureLod(textrianglemap, texCoordPick, 0);');
+	node_shader_write(frag, "vec4 face_c1 = texelFetch(textrianglemap, ivec2(texCoordInp * textrianglemapSize), 0);");
+	node_shader_write(frag, "vec4 face_c2 = textureLod(textrianglemap, texCoordPick, 0);");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal)
-	node_shader_write(frag, 'if (any(face_c1 != face_c2)) discard;');
+	node_shader_write(frag, "if (any(face_c1 != face_c2)) discard;");
 	///else
-	node_shader_write(frag, 'if (face_c1 != face_c2) discard;');
+	node_shader_write(frag, "if (face_c1 != face_c2) discard;");
 	///end
 }
 
 function make_discard_uv_island(vert: node_shader_t, frag: node_shader_t) {
-	node_shader_add_uniform(frag, 'sampler2D texuvislandmap', '_texuvislandmap');
-	node_shader_write(frag, 'if (textureLod(texuvislandmap, texCoordPick, 0).r == 0.0) discard;');
+	node_shader_add_uniform(frag, "sampler2D texuvislandmap", "_texuvislandmap");
+	node_shader_write(frag, "if (textureLod(texuvislandmap, texCoordPick, 0).r == 0.0) discard;");
 }
 
 function make_discard_material_id(vert: node_shader_t, frag: node_shader_t) {
 	frag.wvpposition = true;
-	node_shader_write(frag, 'vec2 picker_sample_tc = vec2(wvpposition.x / wvpposition.w, wvpposition.y / wvpposition.w) * 0.5 + 0.5;');
+	node_shader_write(frag, "vec2 picker_sample_tc = vec2(wvpposition.x / wvpposition.w, wvpposition.y / wvpposition.w) * 0.5 + 0.5;");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'picker_sample_tc.y = 1.0 - picker_sample_tc.y;');
+	node_shader_write(frag, "picker_sample_tc.y = 1.0 - picker_sample_tc.y;");
 	///end
-	node_shader_add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
+	node_shader_add_uniform(frag, "sampler2D texpaint_nor_undo", "_texpaint_nor_undo");
 	let matid: i32 = context_raw.materialid_picked / 255;
-	node_shader_write(frag, `if (${matid} != textureLod(texpaint_nor_undo, picker_sample_tc, 0.0).a) discard;`);
+	node_shader_write(frag, "if (" + matid + " != textureLod(texpaint_nor_undo, picker_sample_tc, 0.0).a) discard;");
 }

+ 38 - 38
armorpaint/Sources/make_material.ts

@@ -406,114 +406,114 @@ function make_material_parse_brush() {
 
 function make_material_blend_mode(frag: node_shader_t, blending: i32, cola: string, colb: string, opac: string): string {
 	if (blending == blend_type_t.MIX) {
-		return `mix(${cola}, ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.DARKEN) {
-		return `mix(${cola}, min(${cola}, ${colb}), ${opac})`;
+		return "mix(" + cola + ", min(" + cola + ", " + colb + "), " + opac + ")";
 	}
 	else if (blending == blend_type_t.MULTIPLY) {
-		return `mix(${cola}, ${cola} * ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + cola + " * " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.BURN) {
-		return `mix(${cola}, vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - ${cola}) / ${colb}, ${opac})`;
+		return "mix(" + cola + ", vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - " + cola + ") / " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.LIGHTEN) {
-		return `max(${cola}, ${colb} * ${opac})`;
+		return "max(" + cola + ", " + colb + " * " + opac + ")";
 	}
 	else if (blending == blend_type_t.SCREEN) {
-		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}))`;
+		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 + "))";
 	}
 	else if (blending == blend_type_t.DODGE) {
-		return `mix(${cola}, ${cola} / (vec3(1.0, 1.0, 1.0) - ${colb}), ${opac})`;
+		return "mix(" + cola + ", " + cola + " / (vec3(1.0, 1.0, 1.0) - " + colb + "), " + opac + ")";
 	}
 	else if (blending == blend_type_t.ADD) {
-		return `mix(${cola}, ${cola} + ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + cola + " + " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.OVERLAY) {
-		return `mix(${cola}, vec3(
-			${cola}.r < 0.5 ? 2.0 * ${cola}.r * ${colb}.r : 1.0 - 2.0 * (1.0 - ${cola}.r) * (1.0 - ${colb}.r),
-			${cola}.g < 0.5 ? 2.0 * ${cola}.g * ${colb}.g : 1.0 - 2.0 * (1.0 - ${cola}.g) * (1.0 - ${colb}.g),
-			${cola}.b < 0.5 ? 2.0 * ${cola}.b * ${colb}.b : 1.0 - 2.0 * (1.0 - ${cola}.b) * (1.0 - ${colb}.b)
-		), ${opac})`;
+		return "mix(" + cola + ", vec3( \
+			" + cola + ".r < 0.5 ? 2.0 * " + cola + ".r * " + colb + ".r : 1.0 - 2.0 * (1.0 - " + cola + ".r) * (1.0 - " + colb + ".r), \
+			" + cola + ".g < 0.5 ? 2.0 * " + cola + ".g * " + colb + ".g : 1.0 - 2.0 * (1.0 - " + cola + ".g) * (1.0 - " + colb + ".g), \
+			" + cola + ".b < 0.5 ? 2.0 * " + cola + ".b * " + colb + ".b : 1.0 - 2.0 * (1.0 - " + cola + ".b) * (1.0 - " + colb + ".b) \
+		), " + opac + ")";
 	}
 	else if (blending == blend_type_t.SOFT_LIGHT) {
-		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}))))`;
+		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 + "))))";
 	}
 	else if (blending == blend_type_t.LINEAR_LIGHT) {
-		return `(${cola} + ${opac} * (vec3(2.0, 2.0, 2.0) * (${colb} - vec3(0.5, 0.5, 0.5))))`;
+		return "(" + cola + " + " + opac + " * (vec3(2.0, 2.0, 2.0) * (" + colb + " - vec3(0.5, 0.5, 0.5))))";
 	}
 	else if (blending == blend_type_t.DIFFERENCE) {
-		return `mix(${cola}, abs(${cola} - ${colb}), ${opac})`;
+		return "mix(" + cola + ", abs(" + cola + " - " + colb + "), " + opac + ")";
 	}
 	else if (blending == blend_type_t.SUBTRACT) {
-		return `mix(${cola}, ${cola} - ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + cola + " - " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.DIVIDE) {
-		return `vec3(1.0 - ${opac}, 1.0 - ${opac}, 1.0 - ${opac}) * ${cola} + vec3(${opac}, ${opac}, ${opac}) * ${cola} / ${colb}`;
+		return "vec3(1.0 - " + opac + ", 1.0 - " + opac + ", 1.0 - " + opac + ") * " + cola + " + vec3(" + opac + ", " + opac + ", " + opac + ") * " + cola + " / " + colb + "";
 	}
 	else if (blending == blend_type_t.HUE) {
 		node_shader_add_function(frag, str_hue_sat);
-		return `mix(${cola}, hsv_to_rgb(vec3(rgb_to_hsv(${colb}).r, rgb_to_hsv(${cola}).g, rgb_to_hsv(${cola}).b)), ${opac})`;
+		return "mix(" + cola + ", hsv_to_rgb(vec3(rgb_to_hsv(" + colb + ").r, rgb_to_hsv(" + cola + ").g, rgb_to_hsv(" + cola + ").b)), " + opac + ")";
 	}
 	else if (blending == blend_type_t.SATURATION) {
 		node_shader_add_function(frag, str_hue_sat);
-		return `mix(${cola}, hsv_to_rgb(vec3(rgb_to_hsv(${cola}).r, rgb_to_hsv(${colb}).g, rgb_to_hsv(${cola}).b)), ${opac})`;
+		return "mix(" + cola + ", hsv_to_rgb(vec3(rgb_to_hsv(" + cola + ").r, rgb_to_hsv(" + colb + ").g, rgb_to_hsv(" + cola + ").b)), " + opac + ")";
 	}
 	else if (blending == blend_type_t.COLOR) {
 		node_shader_add_function(frag, str_hue_sat);
-		return `mix(${cola}, hsv_to_rgb(vec3(rgb_to_hsv(${colb}).r, rgb_to_hsv(${colb}).g, rgb_to_hsv(${cola}).b)), ${opac})`;
+		return "mix(" + cola + ", hsv_to_rgb(vec3(rgb_to_hsv(" + colb + ").r, rgb_to_hsv(" + colb + ").g, rgb_to_hsv(" + cola + ").b)), " + opac + ")";
 	}
 	else { // BlendValue
 		node_shader_add_function(frag, str_hue_sat);
-		return `mix(${cola}, hsv_to_rgb(vec3(rgb_to_hsv(${cola}).r, rgb_to_hsv(${cola}).g, rgb_to_hsv(${colb}).b)), ${opac})`;
+		return "mix(" + cola + ", hsv_to_rgb(vec3(rgb_to_hsv(" + cola + ").r, rgb_to_hsv(" + cola + ").g, rgb_to_hsv(" + colb + ").b)), " + opac + ")";
 	}
 }
 
 function make_material_blend_mode_mask(frag: node_shader_t, blending: i32, cola: string, colb: string, opac: string): string {
 	if (blending == blend_type_t.MIX) {
-		return `mix(${cola}, ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.DARKEN) {
-		return `mix(${cola}, min(${cola}, ${colb}), ${opac})`;
+		return "mix(" + cola + ", min(" + cola + ", " + colb + "), " + opac + ")";
 	}
 	else if (blending == blend_type_t.MULTIPLY) {
-		return `mix(${cola}, ${cola} * ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + cola + " * " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.BURN) {
-		return `mix(${cola}, 1.0 - (1.0 - ${cola}) / ${colb}, ${opac})`;
+		return "mix(" + cola + ", 1.0 - (1.0 - " + cola + ") / " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.LIGHTEN) {
-		return `max(${cola}, ${colb} * ${opac})`;
+		return "max(" + cola + ", " + colb + " * " + opac + ")";
 	}
 	else if (blending == blend_type_t.SCREEN) {
-		return `(1.0 - ((1.0 - ${opac}) + ${opac} * (1.0 - ${colb})) * (1.0 - ${cola}))`;
+		return "(1.0 - ((1.0 - " + opac + ") + " + opac + " * (1.0 - " + colb + ")) * (1.0 - " + cola + "))";
 	}
 	else if (blending == blend_type_t.DODGE) {
-		return `mix(${cola}, ${cola} / (1.0 - ${colb}), ${opac})`;
+		return "mix(" + cola + ", " + cola + " / (1.0 - " + colb + "), " + opac + ")";
 	}
 	else if (blending == blend_type_t.ADD) {
-		return `mix(${cola}, ${cola} + ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + cola + " + " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.OVERLAY) {
-		return `mix(${cola}, ${cola} < 0.5 ? 2.0 * ${cola} * ${colb} : 1.0 - 2.0 * (1.0 - ${cola}) * (1.0 - ${colb}), ${opac})`;
+		return "mix(" + cola + ", " + cola + " < 0.5 ? 2.0 * " + cola + " * " + colb + " : 1.0 - 2.0 * (1.0 - " + cola + ") * (1.0 - " + colb + "), " + opac + ")";
 	}
 	else if (blending == blend_type_t.SOFT_LIGHT) {
-		return `((1.0 - ${opac}) * ${cola} + ${opac} * ((1.0 - ${cola}) * ${colb} * ${cola} + ${cola} * (1.0 - (1.0 - ${colb}) * (1.0 - ${cola}))))`;
+		return "((1.0 - " + opac + ") * " + cola + " + " + opac + " * ((1.0 - " + cola + ") * " + colb + " * " + cola + " + " + cola + " * (1.0 - (1.0 - " + colb + ") * (1.0 - " + cola + "))))";
 	}
 	else if (blending == blend_type_t.LINEAR_LIGHT) {
-		return `(${cola} + ${opac} * (2.0 * (${colb} - 0.5)))`;
+		return "(" + cola + " + " + opac + " * (2.0 * (" + colb + " - 0.5)))";
 	}
 	else if (blending == blend_type_t.DIFFERENCE) {
-		return `mix(${cola}, abs(${cola} - ${colb}), ${opac})`;
+		return "mix(" + cola + ", abs(" + cola + " - " + colb + "), " + opac + ")";
 	}
 	else if (blending == blend_type_t.SUBTRACT) {
-		return `mix(${cola}, ${cola} - ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + cola + " - " + colb + ", " + opac + ")";
 	}
 	else if (blending == blend_type_t.DIVIDE) {
-		return `(1.0 - ${opac}) * ${cola} + ${opac} * ${cola} / ${colb}`;
+		return "(1.0 - " + opac + ") * " + cola + " + " + opac + " * " + cola + " / " + colb + "";
 	}
 	else { // BlendHue, BlendSaturation, BlendColor, BlendValue
-		return `mix(${cola}, ${colb}, ${opac})`;
+		return "mix(" + cola + ", " + colb + ", " + opac + ")";
 	}
 }
 
@@ -524,7 +524,7 @@ function make_material_get_displace_strength(): f32 {
 
 function make_material_voxelgi_half_extents(): string {
 	let ext: f32 = context_raw.vxao_ext;
-	return `const vec3 voxelgiHalfExtents = vec3(${ext}, ${ext}, ${ext});`;
+	return "const vec3 voxelgiHalfExtents = vec3(" + ext + ", " + ext + ", " + ext + ");";
 }
 
 function make_material_delete_context(c: shader_context_t) {

+ 209 - 209
armorpaint/Sources/make_mesh.ts

@@ -17,18 +17,18 @@ function make_mesh_run(data: material_t, layerPass = 0): node_shader_context_t {
 	let frag: node_shader_t = node_shader_context_make_frag(con_mesh);
 	frag.ins = vert.outs;
 
-	node_shader_add_out(vert, 'vec2 texCoord');
+	node_shader_add_out(vert, "vec2 texCoord");
 	frag.wvpposition = true;
-	node_shader_add_out(vert, 'vec4 prevwvpposition');
-	node_shader_add_uniform(vert, 'mat4 VP', '_view_proj_matrix');
-	node_shader_add_uniform(vert, 'mat4 prevWVP', '_prev_world_view_proj_matrix');
+	node_shader_add_out(vert, "vec4 prevwvpposition");
+	node_shader_add_uniform(vert, "mat4 VP", "_view_proj_matrix");
+	node_shader_add_uniform(vert, "mat4 prevWVP", "_prev_world_view_proj_matrix");
 	vert.wposition = true;
 
 	let texture_count: i32 = 0;
 	let displace_strength: f32 = make_material_get_displace_strength();
 	if (make_material_height_used && displace_strength > 0.0) {
 		vert.n = true;
-		node_shader_write(vert, 'float height = 0.0;');
+		node_shader_write(vert, "float height = 0.0;");
 		let num_layers: i32 = 0;
 		for (let i: i32 = 0; i < project_layers.length; ++i) {
 			let l: slot_layer_t = project_layers[i];
@@ -40,8 +40,8 @@ function make_mesh_run(data: material_t, layerPass = 0): node_shader_context_t {
 			}
 			num_layers++;
 			texture_count++;
-			node_shader_add_uniform(vert, 'sampler2D texpaint_pack_vert' + l.id, '_texpaint_pack_vert' + l.id);
-			node_shader_write(vert, 'height += textureLod(texpaint_pack_vert' + l.id + ', tex, 0.0).a;');
+			node_shader_add_uniform(vert, "sampler2D texpaint_pack_vert" + l.id, "_texpaint_pack_vert" + l.id);
+			node_shader_write(vert, "height += textureLod(texpaint_pack_vert" + l.id + ", tex, 0.0).a;");
 			let masks: slot_layer_t[] = slot_layer_get_masks(l);
 			if (masks != null) {
 				for (let i: i32 = 0; i < masks.length; ++i) {
@@ -50,83 +50,83 @@ function make_mesh_run(data: material_t, layerPass = 0): node_shader_context_t {
 						continue;
 					}
 					texture_count++;
-					node_shader_add_uniform(vert, 'sampler2D texpaint_vert' + m.id, '_texpaint_vert' + m.id);
-					node_shader_write(vert, 'height *= textureLod(texpaint_vert' + m.id + ', tex, 0.0).r;');
+					node_shader_add_uniform(vert, "sampler2D texpaint_vert" + m.id, "_texpaint_vert" + m.id);
+					node_shader_write(vert, "height *= textureLod(texpaint_vert" + m.id + ", tex, 0.0).r;");
 				}
 			}
 		}
-		node_shader_write(vert, `wposition += wnormal * vec3(height, height, height) * vec3(${displace_strength}, ${displace_strength}, ${displace_strength});`);
+		node_shader_write(vert, "wposition += wnormal * vec3(height, height, height) * vec3(" + displace_strength + ", " + displace_strength + ", " + displace_strength + ");");
 	}
 
-	node_shader_write(vert, 'gl_Position = mul(vec4(wposition.xyz, 1.0), VP);');
-	node_shader_write(vert, 'texCoord = tex;');
+	node_shader_write(vert, "gl_Position = mul(vec4(wposition.xyz, 1.0), VP);");
+	node_shader_write(vert, "texCoord = tex;");
 	if (make_material_height_used && displace_strength > 0) {
-		node_shader_add_uniform(vert, 'mat4 invW', '_inv_world_matrix');
-		node_shader_write(vert, 'prevwvpposition = mul(mul(vec4(wposition, 1.0), invW), prevWVP);');
+		node_shader_add_uniform(vert, "mat4 invW", "_inv_world_matrix");
+		node_shader_write(vert, "prevwvpposition = mul(mul(vec4(wposition, 1.0), invW), prevWVP);");
 	}
 	else {
-		node_shader_write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
+		node_shader_write(vert, "prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);");
 	}
 
-	node_shader_add_out(frag, 'vec4 fragColor[3]');
+	node_shader_add_out(frag, "vec4 fragColor[3]");
 	frag.n = true;
 	node_shader_add_function(frag, str_pack_float_int16);
 
 	if (context_raw.tool == workspace_tool_t.COLORID) {
 		texture_count++;
-		node_shader_add_uniform(frag, 'sampler2D texcolorid', '_texcolorid');
-		node_shader_write(frag, 'fragColor[0] = vec4(n.xy, 1.0, packFloatInt16(0.0, uint(0)));');
-		node_shader_write(frag, 'vec3 idcol = pow(textureLod(texcolorid, texCoord, 0.0).rgb, vec3(2.2, 2.2, 2.2));');
-		node_shader_write(frag, 'fragColor[1] = vec4(idcol.rgb, 1.0);'); // occ
+		node_shader_add_uniform(frag, "sampler2D texcolorid", "_texcolorid");
+		node_shader_write(frag, "fragColor[0] = vec4(n.xy, 1.0, packFloatInt16(0.0, uint(0)));");
+		node_shader_write(frag, "vec3 idcol = pow(textureLod(texcolorid, texCoord, 0.0).rgb, vec3(2.2, 2.2, 2.2));");
+		node_shader_write(frag, "fragColor[1] = vec4(idcol.rgb, 1.0);"); // occ
 	}
 	else {
 		node_shader_add_function(frag, str_octahedron_wrap);
 		node_shader_add_function(frag, str_cotangent_frame);
 		if (layerPass > 0) {
-			node_shader_add_uniform(frag, 'sampler2D gbuffer0');
-			node_shader_add_uniform(frag, 'sampler2D gbuffer1');
-			node_shader_add_uniform(frag, 'sampler2D gbuffer2');
-			node_shader_write(frag, 'vec2 fragcoord = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
+			node_shader_add_uniform(frag, "sampler2D gbuffer0");
+			node_shader_add_uniform(frag, "sampler2D gbuffer1");
+			node_shader_add_uniform(frag, "sampler2D gbuffer2");
+			node_shader_write(frag, "vec2 fragcoord = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;");
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			node_shader_write(frag, 'fragcoord.y = 1.0 - fragcoord.y;');
+			node_shader_write(frag, "fragcoord.y = 1.0 - fragcoord.y;");
 			///end
-			node_shader_write(frag, 'vec4 gbuffer0_sample = textureLod(gbuffer0, fragcoord, 0.0);');
-			node_shader_write(frag, 'vec4 gbuffer1_sample = textureLod(gbuffer1, fragcoord, 0.0);');
-			node_shader_write(frag, 'vec4 gbuffer2_sample = textureLod(gbuffer2, fragcoord, 0.0);');
-			node_shader_write(frag, 'vec3 basecol = gbuffer0_sample.rgb;');
-			node_shader_write(frag, 'float roughness = gbuffer2_sample.g;');
-			node_shader_write(frag, 'float metallic = gbuffer2_sample.b;');
-			node_shader_write(frag, 'float occlusion = gbuffer2_sample.r;');
-			node_shader_write(frag, 'float opacity = 1.0;//gbuffer0_sample.a;');
-			node_shader_write(frag, 'float matid = gbuffer1_sample.a;');
-			node_shader_write(frag, 'vec3 ntex = gbuffer1_sample.rgb;');
-			node_shader_write(frag, 'float height = gbuffer2_sample.a;');
+			node_shader_write(frag, "vec4 gbuffer0_sample = textureLod(gbuffer0, fragcoord, 0.0);");
+			node_shader_write(frag, "vec4 gbuffer1_sample = textureLod(gbuffer1, fragcoord, 0.0);");
+			node_shader_write(frag, "vec4 gbuffer2_sample = textureLod(gbuffer2, fragcoord, 0.0);");
+			node_shader_write(frag, "vec3 basecol = gbuffer0_sample.rgb;");
+			node_shader_write(frag, "float roughness = gbuffer2_sample.g;");
+			node_shader_write(frag, "float metallic = gbuffer2_sample.b;");
+			node_shader_write(frag, "float occlusion = gbuffer2_sample.r;");
+			node_shader_write(frag, "float opacity = 1.0;//gbuffer0_sample.a;");
+			node_shader_write(frag, "float matid = gbuffer1_sample.a;");
+			node_shader_write(frag, "vec3 ntex = gbuffer1_sample.rgb;");
+			node_shader_write(frag, "float height = gbuffer2_sample.a;");
 		}
 		else {
-			node_shader_write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-			node_shader_write(frag, 'float roughness = 0.0;');
-			node_shader_write(frag, 'float metallic = 0.0;');
-			node_shader_write(frag, 'float occlusion = 1.0;');
-			node_shader_write(frag, 'float opacity = 1.0;');
-			node_shader_write(frag, 'float matid = 0.0;');
-			node_shader_write(frag, 'vec3 ntex = vec3(0.5, 0.5, 1.0);');
-			node_shader_write(frag, 'float height = 0.0;');
+			node_shader_write(frag, "vec3 basecol = vec3(0.0, 0.0, 0.0);");
+			node_shader_write(frag, "float roughness = 0.0;");
+			node_shader_write(frag, "float metallic = 0.0;");
+			node_shader_write(frag, "float occlusion = 1.0;");
+			node_shader_write(frag, "float opacity = 1.0;");
+			node_shader_write(frag, "float matid = 0.0;");
+			node_shader_write(frag, "vec3 ntex = vec3(0.5, 0.5, 1.0);");
+			node_shader_write(frag, "float height = 0.0;");
 		}
-		node_shader_write(frag, 'vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);');
-		node_shader_write(frag, 'vec4 texpaint_nor_sample;');
-		node_shader_write(frag, 'vec4 texpaint_pack_sample;');
-		node_shader_write(frag, 'float texpaint_opac;');
+		node_shader_write(frag, "vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);");
+		node_shader_write(frag, "vec4 texpaint_nor_sample;");
+		node_shader_write(frag, "vec4 texpaint_pack_sample;");
+		node_shader_write(frag, "float texpaint_opac;");
 
 		if (make_material_height_used) {
-			node_shader_write(frag, 'float height0 = 0.0;');
-			node_shader_write(frag, 'float height1 = 0.0;');
-			node_shader_write(frag, 'float height2 = 0.0;');
-			node_shader_write(frag, 'float height3 = 0.0;');
+			node_shader_write(frag, "float height0 = 0.0;");
+			node_shader_write(frag, "float height1 = 0.0;");
+			node_shader_write(frag, "float height2 = 0.0;");
+			node_shader_write(frag, "float height3 = 0.0;");
 		}
 
 		if (context_raw.draw_wireframe) {
 			texture_count++;
-			node_shader_add_uniform(frag, 'sampler2D texuvmap', '_texuvmap');
+			node_shader_add_uniform(frag, "sampler2D texuvmap", "_texuvmap");
 		}
 
 		if (context_raw.viewport_mode == viewport_mode_t.MASK && slot_layer_get_masks(context_raw.layer) != null) {
@@ -136,16 +136,16 @@ function make_mesh_run(data: material_t, layerPass = 0): node_shader_context_t {
 					continue;
 				}
 				texture_count++;
-				node_shader_add_uniform(frag, 'sampler2D texpaint_view_mask' + m.id, '_texpaint' + array_index_of(project_layers, m));
+				node_shader_add_uniform(frag, "sampler2D texpaint_view_mask" + m.id, "_texpaint" + array_index_of(project_layers, m));
 			}
 		}
 
 		if (context_raw.viewport_mode == viewport_mode_t.LIT && context_raw.render_mode == render_mode_t.FORWARD) {
 			texture_count += 4;
-			node_shader_add_uniform(frag, 'sampler2D senvmapBrdf', "$brdf.k");
-			node_shader_add_uniform(frag, 'sampler2D senvmapRadiance', '_envmap_radiance');
-			node_shader_add_uniform(frag, 'sampler2D sltcMat', '_ltcMat');
-			node_shader_add_uniform(frag, 'sampler2D sltcMag', '_ltcMag');
+			node_shader_add_uniform(frag, "sampler2D senvmapBrdf", "$brdf.k");
+			node_shader_add_uniform(frag, "sampler2D senvmapRadiance", "_envmap_radiance");
+			node_shader_add_uniform(frag, "sampler2D sltcMat", "_ltcMat");
+			node_shader_add_uniform(frag, "sampler2D sltcMag", "_ltcMag");
 		}
 
 		// Get layers for this pass
@@ -182,30 +182,30 @@ function make_mesh_run(data: material_t, layerPass = 0): node_shader_context_t {
 		for (let i: i32 = 0; i < layers.length; ++i) {
 			let l: slot_layer_t = layers[i];
 			if (slot_layer_get_object_mask(l) > 0) {
-				node_shader_add_uniform(frag, 'int uid', '_uid');
+				node_shader_add_uniform(frag, "int uid", "_uid");
 				if (slot_layer_get_object_mask(l) > project_paint_objects.length) { // Atlas
 					let visibles: mesh_object_t[] = project_get_atlas_objects(slot_layer_get_object_mask(l));
-					node_shader_write(frag, 'if (');
+					node_shader_write(frag, "if (");
 					for (let i: i32 = 0; i < visibles.length; ++i) {
 						if (i > 0) {
-							node_shader_write(frag, ' || ');
+							node_shader_write(frag, " || ");
 						}
-						node_shader_write(frag, `${visibles[i].base.uid} == uid`);
+						node_shader_write(frag, visibles[i].base.uid + " == uid");
 					}
-					node_shader_write(frag, ') {');
+					node_shader_write(frag, ") {");
 				}
 				else { // Object mask
 					let uid: i32 = project_paint_objects[slot_layer_get_object_mask(l) - 1].base.uid;
-					node_shader_write(frag, `if (${uid} == uid) {`);
+					node_shader_write(frag, "if (" + uid + " == uid) {");
 				}
 			}
 
-			node_shader_add_shared_sampler(frag, 'sampler2D texpaint' + l.id);
-			node_shader_write(frag, 'texpaint_sample = textureLodShared(texpaint' + l.id + ', texCoord, 0.0);');
-			node_shader_write(frag, 'texpaint_opac = texpaint_sample.a;');
+			node_shader_add_shared_sampler(frag, "sampler2D texpaint" + l.id);
+			node_shader_write(frag, "texpaint_sample = textureLodShared(texpaint" + l.id + ", texCoord, 0.0);");
+			node_shader_write(frag, "texpaint_opac = texpaint_sample.a;");
 			// ///if (krom_direct3d12 || krom_vulkan)
 			// if (raw.viewportMode == ViewLit) {
-			// 	write(frag, 'if (texpaint_opac < 0.1) discard;');
+			// 	write(frag, "if (texpaint_opac < 0.1) discard;");
 			// }
 			// ///end
 
@@ -220,122 +220,122 @@ function make_mesh_run(data: material_t, layerPass = 0): node_shader_context_t {
 					}
 				}
 				if (has_visible) {
-					let texpaint_mask: string = 'texpaint_mask' + l.id;
-					node_shader_write(frag, `float ${texpaint_mask} = 0.0;`);
+					let texpaint_mask: string = "texpaint_mask" + l.id;
+					node_shader_write(frag, "float " + texpaint_mask + " = 0.0;");
 					for (let i: i32 = 0; i < masks.length; ++i) {
 						let m: slot_layer_t = masks[i];
 						if (!slot_layer_is_visible(m)) {
 							continue;
 						}
-						node_shader_add_shared_sampler(frag, 'sampler2D texpaint' + m.id);
-						node_shader_write(frag, '{'); // Group mask is sampled across multiple layers
-						node_shader_write(frag, 'float texpaint_mask_sample' + m.id + ' = textureLodShared(texpaint' + m.id + ', texCoord, 0.0).r;');
-						node_shader_write(frag, `${texpaint_mask} = ` + make_material_blend_mode_mask(frag, m.blending, `${texpaint_mask}`, 'texpaint_mask_sample' + m.id, 'float(' + slot_layer_get_opacity(m) + ')') + ';');
-						node_shader_write(frag, '}');
+						node_shader_add_shared_sampler(frag, "sampler2D texpaint" + m.id);
+						node_shader_write(frag, "{"); // Group mask is sampled across multiple layers
+						node_shader_write(frag, "float texpaint_mask_sample" + m.id + " = textureLodShared(texpaint" + m.id + ", texCoord, 0.0).r;");
+						node_shader_write(frag, texpaint_mask + " = " + make_material_blend_mode_mask(frag, m.blending, texpaint_mask, "texpaint_mask_sample" + m.id, "float(" + slot_layer_get_opacity(m) + ")") + ";");
+						node_shader_write(frag, "}");
 					}
-					node_shader_write(frag, `texpaint_opac *= clamp(${texpaint_mask}, 0.0, 1.0);`);
+					node_shader_write(frag, "texpaint_opac *= clamp(" + texpaint_mask + ", 0.0, 1.0);");
 				}
 			}
 
 			if (slot_layer_get_opacity(l) < 1) {
-				node_shader_write(frag, `texpaint_opac *= ${slot_layer_get_opacity(l)};`);
+				node_shader_write(frag, "texpaint_opac *= " + slot_layer_get_opacity(l) + ";");
 			}
 
 			if (l.paint_base) {
 				if (l == project_layers[0]) {
-					node_shader_write(frag, 'basecol = texpaint_sample.rgb * texpaint_opac;');
+					node_shader_write(frag, "basecol = texpaint_sample.rgb * texpaint_opac;");
 				}
 				else {
-					node_shader_write(frag, 'basecol = ' + make_material_blend_mode(frag, l.blending, 'basecol', 'texpaint_sample.rgb', 'texpaint_opac') + ';');
+					node_shader_write(frag, "basecol = " + make_material_blend_mode(frag, l.blending, "basecol", "texpaint_sample.rgb", "texpaint_opac") + ";");
 				}
 			}
 
 			if (l.paint_nor || make_material_emis_used) {
-				node_shader_add_shared_sampler(frag, 'sampler2D texpaint_nor' + l.id);
-				node_shader_write(frag, 'texpaint_nor_sample = textureLodShared(texpaint_nor' + l.id + ', texCoord, 0.0);');
+				node_shader_add_shared_sampler(frag, "sampler2D texpaint_nor" + l.id);
+				node_shader_write(frag, "texpaint_nor_sample = textureLodShared(texpaint_nor" + l.id + ", texCoord, 0.0);");
 
 				if (make_material_emis_used) {
-					node_shader_write(frag, 'if (texpaint_opac > 0.0) matid = texpaint_nor_sample.a;');
+					node_shader_write(frag, "if (texpaint_opac > 0.0) matid = texpaint_nor_sample.a;");
 				}
 
 				if (l.paint_nor) {
 					if (l.paint_nor_blend) {
 						// Whiteout blend
-						node_shader_write(frag, '{');
-						node_shader_write(frag, 'vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-						node_shader_write(frag, 'vec3 n2 = mix(vec3(0.5, 0.5, 1.0), texpaint_nor_sample.rgb, texpaint_opac) * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-						node_shader_write(frag, 'ntex = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);');
-						node_shader_write(frag, '}');
+						node_shader_write(frag, "{");
+						node_shader_write(frag, "vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
+						node_shader_write(frag, "vec3 n2 = mix(vec3(0.5, 0.5, 1.0), texpaint_nor_sample.rgb, texpaint_opac) * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
+						node_shader_write(frag, "ntex = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);");
+						node_shader_write(frag, "}");
 					}
 					else {
-						node_shader_write(frag, 'ntex = mix(ntex, texpaint_nor_sample.rgb, texpaint_opac);');
+						node_shader_write(frag, "ntex = mix(ntex, texpaint_nor_sample.rgb, texpaint_opac);");
 					}
 				}
 			}
 
 			if (l.paint_occ || l.paint_rough || l.paint_met || (l.paint_height && make_material_height_used)) {
-				node_shader_add_shared_sampler(frag, 'sampler2D texpaint_pack' + l.id);
-				node_shader_write(frag, 'texpaint_pack_sample = textureLodShared(texpaint_pack' + l.id + ', texCoord, 0.0);');
+				node_shader_add_shared_sampler(frag, "sampler2D texpaint_pack" + l.id);
+				node_shader_write(frag, "texpaint_pack_sample = textureLodShared(texpaint_pack" + l.id + ", texCoord, 0.0);");
 
 				if (l.paint_occ) {
-					node_shader_write(frag, 'occlusion = mix(occlusion, texpaint_pack_sample.r, texpaint_opac);');
+					node_shader_write(frag, "occlusion = mix(occlusion, texpaint_pack_sample.r, texpaint_opac);");
 				}
 				if (l.paint_rough) {
-					node_shader_write(frag, 'roughness = mix(roughness, texpaint_pack_sample.g, texpaint_opac);');
+					node_shader_write(frag, "roughness = mix(roughness, texpaint_pack_sample.g, texpaint_opac);");
 				}
 				if (l.paint_met) {
-					node_shader_write(frag, 'metallic = mix(metallic, texpaint_pack_sample.b, texpaint_opac);');
+					node_shader_write(frag, "metallic = mix(metallic, texpaint_pack_sample.b, texpaint_opac);");
 				}
 				if (l.paint_height && make_material_height_used) {
 					let assign: string = l.paint_height_blend ? "+=" : "=";
-					node_shader_write(frag, `height ${assign} texpaint_pack_sample.a * texpaint_opac;`);
-					node_shader_write(frag, '{');
-					node_shader_add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-					node_shader_write(frag, 'float tex_step = 1.0 / texpaintSize.x;');
-					node_shader_write(frag, `height0 ${assign} textureLodShared(texpaint_pack` + l.id + ', vec2(texCoord.x - tex_step, texCoord.y), 0.0).a * texpaint_opac;');
-					node_shader_write(frag, `height1 ${assign} textureLodShared(texpaint_pack` + l.id + ', vec2(texCoord.x + tex_step, texCoord.y), 0.0).a * texpaint_opac;');
-					node_shader_write(frag, `height2 ${assign} textureLodShared(texpaint_pack` + l.id + ', vec2(texCoord.x, texCoord.y - tex_step), 0.0).a * texpaint_opac;');
-					node_shader_write(frag, `height3 ${assign} textureLodShared(texpaint_pack` + l.id + ', vec2(texCoord.x, texCoord.y + tex_step), 0.0).a * texpaint_opac;');
-					node_shader_write(frag, '}');
+					node_shader_write(frag, "height " + assign + " texpaint_pack_sample.a * texpaint_opac;");
+					node_shader_write(frag, "{");
+					node_shader_add_uniform(frag, "vec2 texpaintSize", "_texpaintSize");
+					node_shader_write(frag, "float tex_step = 1.0 / texpaintSize.x;");
+					node_shader_write(frag, "height0 " + assign + " textureLodShared(texpaint_pack" + l.id + ", vec2(texCoord.x - tex_step, texCoord.y), 0.0).a * texpaint_opac;");
+					node_shader_write(frag, "height1 " + assign + " textureLodShared(texpaint_pack" + l.id + ", vec2(texCoord.x + tex_step, texCoord.y), 0.0).a * texpaint_opac;");
+					node_shader_write(frag, "height2 " + assign + " textureLodShared(texpaint_pack" + l.id + ", vec2(texCoord.x, texCoord.y - tex_step), 0.0).a * texpaint_opac;");
+					node_shader_write(frag, "height3 " + assign + " textureLodShared(texpaint_pack" + l.id + ", vec2(texCoord.x, texCoord.y + tex_step), 0.0).a * texpaint_opac;");
+					node_shader_write(frag, "}");
 				}
 			}
 
 			if (slot_layer_get_object_mask(l) > 0) {
-				node_shader_write(frag, '}');
+				node_shader_write(frag, "}");
 			}
 		}
 
 		if (last_pass && context_raw.draw_texels) {
-			node_shader_add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-			node_shader_write(frag, 'vec2 texel0 = texCoord * texpaintSize * 0.01;');
-			node_shader_write(frag, 'vec2 texel1 = texCoord * texpaintSize * 0.1;');
-			node_shader_write(frag, 'vec2 texel2 = texCoord * texpaintSize;');
-			node_shader_write(frag, 'basecol *= max(float(mod(int(texel0.x), 2.0) == mod(int(texel0.y), 2.0)), 0.9);');
-			node_shader_write(frag, 'basecol *= max(float(mod(int(texel1.x), 2.0) == mod(int(texel1.y), 2.0)), 0.9);');
-			node_shader_write(frag, 'basecol *= max(float(mod(int(texel2.x), 2.0) == mod(int(texel2.y), 2.0)), 0.9);');
+			node_shader_add_uniform(frag, "vec2 texpaintSize", "_texpaintSize");
+			node_shader_write(frag, "vec2 texel0 = texCoord * texpaintSize * 0.01;");
+			node_shader_write(frag, "vec2 texel1 = texCoord * texpaintSize * 0.1;");
+			node_shader_write(frag, "vec2 texel2 = texCoord * texpaintSize;");
+			node_shader_write(frag, "basecol *= max(float(mod(int(texel0.x), 2.0) == mod(int(texel0.y), 2.0)), 0.9);");
+			node_shader_write(frag, "basecol *= max(float(mod(int(texel1.x), 2.0) == mod(int(texel1.y), 2.0)), 0.9);");
+			node_shader_write(frag, "basecol *= max(float(mod(int(texel2.x), 2.0) == mod(int(texel2.y), 2.0)), 0.9);");
 		}
 
 		if (last_pass && context_raw.draw_wireframe) {
-			node_shader_write(frag, 'basecol *= 1.0 - textureLod(texuvmap, texCoord, 0.0).r;');
+			node_shader_write(frag, "basecol *= 1.0 - textureLod(texuvmap, texCoord, 0.0).r;");
 		}
 
 		if (make_material_height_used) {
-			node_shader_write(frag, 'if (height > 0.0) {');
-			// write(frag, 'float height_dx = dFdx(height * 16.0);');
-			// write(frag, 'float height_dy = dFdy(height * 16.0);');
-			node_shader_write(frag, 'float height_dx = height0 - height1;');
-			node_shader_write(frag, 'float height_dy = height2 - height3;');
+			node_shader_write(frag, "if (height > 0.0) {");
+			// write(frag, "float height_dx = dFdx(height * 16.0);");
+			// write(frag, "float height_dy = dFdy(height * 16.0);");
+			node_shader_write(frag, "float height_dx = height0 - height1;");
+			node_shader_write(frag, "float height_dy = height2 - height3;");
 			// Whiteout blend
-			node_shader_write(frag, 'vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-			node_shader_write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-			node_shader_write(frag, 'ntex = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);');
-			node_shader_write(frag, '}');
+			node_shader_write(frag, "vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
+			node_shader_write(frag, "vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));");
+			node_shader_write(frag, "ntex = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);");
+			node_shader_write(frag, "}");
 		}
 
 		if (!last_pass) {
-			node_shader_write(frag, 'fragColor[0] = vec4(basecol, opacity);');
-			node_shader_write(frag, 'fragColor[1] = vec4(ntex, matid);');
-			node_shader_write(frag, 'fragColor[2] = vec4(occlusion, roughness, metallic, height);');
+			node_shader_write(frag, "fragColor[0] = vec4(basecol, opacity);");
+			node_shader_write(frag, "fragColor[1] = vec4(ntex, matid);");
+			node_shader_write(frag, "fragColor[2] = vec4(occlusion, roughness, metallic, height);");
 			parser_material_finalize(con_mesh);
 			con_mesh.data.shader_from_source = true;
 			con_mesh.data.vertex_shader = node_shader_get(vert);
@@ -345,157 +345,157 @@ function make_mesh_run(data: material_t, layerPass = 0): node_shader_context_t {
 
 		frag.vvec = true;
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, vVec, texCoord);");
 		///else
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, -vVec, texCoord);");
 		///end
-		node_shader_write(frag, 'n = ntex * 2.0 - 1.0;');
-		node_shader_write(frag, 'n.y = -n.y;');
-		node_shader_write(frag, 'n = normalize(mul(n, TBN));');
+		node_shader_write(frag, "n = ntex * 2.0 - 1.0;");
+		node_shader_write(frag, "n.y = -n.y;");
+		node_shader_write(frag, "n = normalize(mul(n, TBN));");
 
 		if (context_raw.viewport_mode == viewport_mode_t.LIT || context_raw.viewport_mode == viewport_mode_t.PATH_TRACE) {
-			node_shader_write(frag, 'basecol = pow(basecol, vec3(2.2, 2.2, 2.2));');
+			node_shader_write(frag, "basecol = pow(basecol, vec3(2.2, 2.2, 2.2));");
 
 			if (context_raw.viewport_shader != null) {
 				let color: string = context_raw.viewport_shader(frag);
-				node_shader_write(frag, `fragColor[1] = vec4(${color}, 1.0);`);
+				node_shader_write(frag, "fragColor[1] = vec4(" + color + ", 1.0);");
 			}
 			else if (context_raw.render_mode == render_mode_t.FORWARD && context_raw.viewport_mode != viewport_mode_t.PATH_TRACE) {
 				frag.wposition = true;
-				node_shader_write(frag, 'vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);');
-				node_shader_write(frag, 'vec3 f0 = mix(vec3(0.04, 0.04, 0.04), basecol, metallic);');
+				node_shader_write(frag, "vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);");
+				node_shader_write(frag, "vec3 f0 = mix(vec3(0.04, 0.04, 0.04), basecol, metallic);");
 				frag.vvec = true;
-				node_shader_write(frag, 'float dotNV = max(0.0, dot(n, vVec));');
-				node_shader_write(frag, 'vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;');
-				node_shader_add_uniform(frag, 'int envmapNumMipmaps', '_envmap_num_mipmaps');
-				node_shader_add_uniform(frag, 'vec4 envmapData', '_envmapData'); // angle, sin(angle), cos(angle), strength
-				node_shader_write(frag, 'vec3 wreflect = reflect(-vVec, n);');
-				node_shader_write(frag, 'float envlod = roughness * float(envmapNumMipmaps);');
+				node_shader_write(frag, "float dotNV = max(0.0, dot(n, vVec));");
+				node_shader_write(frag, "vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;");
+				node_shader_add_uniform(frag, "int envmapNumMipmaps", "_envmap_num_mipmaps");
+				node_shader_add_uniform(frag, "vec4 envmapData", "_envmapData"); // angle, sin(angle), cos(angle), strength
+				node_shader_write(frag, "vec3 wreflect = reflect(-vVec, n);");
+				node_shader_write(frag, "float envlod = roughness * float(envmapNumMipmaps);");
 				node_shader_add_function(frag, str_envmap_equirect);
-				node_shader_write(frag, 'vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;');
-				node_shader_add_uniform(frag, 'vec3 lightArea0', '_light_area0');
-				node_shader_add_uniform(frag, 'vec3 lightArea1', '_light_area1');
-				node_shader_add_uniform(frag, 'vec3 lightArea2', '_light_area2');
-				node_shader_add_uniform(frag, 'vec3 lightArea3', '_light_area3');
+				node_shader_write(frag, "vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;");
+				node_shader_add_uniform(frag, "vec3 lightArea0", "_light_area0");
+				node_shader_add_uniform(frag, "vec3 lightArea1", "_light_area1");
+				node_shader_add_uniform(frag, "vec3 lightArea2", "_light_area2");
+				node_shader_add_uniform(frag, "vec3 lightArea3", "_light_area3");
 				node_shader_add_function(frag, str_ltc_evaluate);
-				node_shader_add_uniform(frag, 'vec3 lightPos', '_point_pos');
-				node_shader_add_uniform(frag, 'vec3 lightColor', '_point_color');
-				// write(frag, 'float dotNL = max(dot(n, normalize(lightPos - wposition)), 0.0);');
-				// write(frag, 'vec3 direct = albedo * dotNL;');
-				node_shader_write(frag, 'float ldist = distance(wposition, lightPos);');
-				node_shader_write(frag, 'const float LUT_SIZE = 64.0;');
-				node_shader_write(frag, 'const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;');
-				node_shader_write(frag, 'const float LUT_BIAS = 0.5 / LUT_SIZE;');
-				node_shader_write(frag, 'float theta = acos(dotNV);');
-				node_shader_write(frag, 'vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));');
-				node_shader_write(frag, 'tuv = tuv * LUT_SCALE + LUT_BIAS;');
-				node_shader_write(frag, 'vec4 t = textureLod(sltcMat, tuv, 0.0);');
-				node_shader_write(frag, 'mat3 minv = mat3(vec3(1.0, 0.0, t.y), vec3(0.0, t.z, 0.0), vec3(t.w, 0.0, t.x));');
-				node_shader_write(frag, 'float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);');
-				node_shader_write(frag, 'ltcspec *= textureLod(sltcMag, tuv, 0.0).a;');
-				node_shader_write(frag, 'mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);');
-				node_shader_write(frag, 'float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);');
-				node_shader_write(frag, 'vec3 direct = albedo * ltcdiff + ltcspec * 0.05;');
-				node_shader_write(frag, 'direct *= lightColor * (1.0 / (ldist * ldist));');
-
-				node_shader_add_uniform(frag, 'vec4 shirr[7]', '_envmap_irradiance');
+				node_shader_add_uniform(frag, "vec3 lightPos", "_point_pos");
+				node_shader_add_uniform(frag, "vec3 lightColor", "_point_color");
+				// write(frag, "float dotNL = max(dot(n, normalize(lightPos - wposition)), 0.0);");
+				// write(frag, "vec3 direct = albedo * dotNL;");
+				node_shader_write(frag, "float ldist = distance(wposition, lightPos);");
+				node_shader_write(frag, "const float LUT_SIZE = 64.0;");
+				node_shader_write(frag, "const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;");
+				node_shader_write(frag, "const float LUT_BIAS = 0.5 / LUT_SIZE;");
+				node_shader_write(frag, "float theta = acos(dotNV);");
+				node_shader_write(frag, "vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));");
+				node_shader_write(frag, "tuv = tuv * LUT_SCALE + LUT_BIAS;");
+				node_shader_write(frag, "vec4 t = textureLod(sltcMat, tuv, 0.0);");
+				node_shader_write(frag, "mat3 minv = mat3(vec3(1.0, 0.0, t.y), vec3(0.0, t.z, 0.0), vec3(t.w, 0.0, t.x));");
+				node_shader_write(frag, "float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);");
+				node_shader_write(frag, "ltcspec *= textureLod(sltcMag, tuv, 0.0).a;");
+				node_shader_write(frag, "mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);");
+				node_shader_write(frag, "float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);");
+				node_shader_write(frag, "vec3 direct = albedo * ltcdiff + ltcspec * 0.05;");
+				node_shader_write(frag, "direct *= lightColor * (1.0 / (ldist * ldist));");
+
+				node_shader_add_uniform(frag, "vec4 shirr[7]", "_envmap_irradiance");
 				node_shader_add_function(frag, str_sh_irradiance());
-				node_shader_write(frag, 'vec3 indirect = albedo * (shIrradiance(vec3(n.x * envmapData.z - n.y * envmapData.y, n.x * envmapData.y + n.y * envmapData.z, n.z), shirr) / 3.14159265);');
-				node_shader_write(frag, 'indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;');
-				node_shader_write(frag, 'indirect *= envmapData.w * occlusion;');
-				node_shader_write(frag, 'fragColor[1] = vec4(direct + indirect, 1.0);');
+				node_shader_write(frag, "vec3 indirect = albedo * (shIrradiance(vec3(n.x * envmapData.z - n.y * envmapData.y, n.x * envmapData.y + n.y * envmapData.z, n.z), shirr) / 3.14159265);");
+				node_shader_write(frag, "indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;");
+				node_shader_write(frag, "indirect *= envmapData.w * occlusion;");
+				node_shader_write(frag, "fragColor[1] = vec4(direct + indirect, 1.0);");
 			}
 			else { // Deferred, Pathtraced
 				if (make_material_emis_used) {
-					node_shader_write(frag, 'if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;'); // Boost for bloom
+					node_shader_write(frag, "if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;"); // Boost for bloom
 				}
-				node_shader_write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
+				node_shader_write(frag, "fragColor[1] = vec4(basecol, occlusion);");
 			}
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.BASE_COLOR && context_raw.layer.paint_base) {
-			node_shader_write(frag, 'fragColor[1] = vec4(basecol, 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(basecol, 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.NORMAL_MAP && context_raw.layer.paint_nor) {
-			node_shader_write(frag, 'fragColor[1] = vec4(ntex.rgb, 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(ntex.rgb, 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.OCCLUSION && context_raw.layer.paint_occ) {
-			node_shader_write(frag, 'fragColor[1] = vec4(vec3(occlusion, occlusion, occlusion), 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(vec3(occlusion, occlusion, occlusion), 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.ROUGHNESS && context_raw.layer.paint_rough) {
-			node_shader_write(frag, 'fragColor[1] = vec4(vec3(roughness, roughness, roughness), 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(vec3(roughness, roughness, roughness), 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.METALLIC && context_raw.layer.paint_met) {
-			node_shader_write(frag, 'fragColor[1] = vec4(vec3(metallic, metallic, metallic), 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(vec3(metallic, metallic, metallic), 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.OPACITY && context_raw.layer.paint_opac) {
-			node_shader_write(frag, 'fragColor[1] = vec4(vec3(texpaint_sample.a, texpaint_sample.a, texpaint_sample.a), 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(vec3(texpaint_sample.a, texpaint_sample.a, texpaint_sample.a), 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.HEIGHT && context_raw.layer.paint_height) {
-			node_shader_write(frag, 'fragColor[1] = vec4(vec3(height, height, height), 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(vec3(height, height, height), 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.EMISSION) {
-			node_shader_write(frag, 'float emis = int(matid * 255.0) % 3 == 1 ? 1.0 : 0.0;');
-			node_shader_write(frag, 'fragColor[1] = vec4(vec3(emis, emis, emis), 1.0);');
+			node_shader_write(frag, "float emis = int(matid * 255.0) % 3 == 1 ? 1.0 : 0.0;");
+			node_shader_write(frag, "fragColor[1] = vec4(vec3(emis, emis, emis), 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.SUBSURFACE) {
-			node_shader_write(frag, 'float subs = int(matid * 255.0) % 3 == 2 ? 1.0 : 0.0;');
-			node_shader_write(frag, 'fragColor[1] = vec4(vec3(subs, subs, subs), 1.0);');
+			node_shader_write(frag, "float subs = int(matid * 255.0) % 3 == 2 ? 1.0 : 0.0;");
+			node_shader_write(frag, "fragColor[1] = vec4(vec3(subs, subs, subs), 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.TEXCOORD) {
-			node_shader_write(frag, 'fragColor[1] = vec4(texCoord, 0.0, 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(texCoord, 0.0, 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.OBJECT_NORMAL) {
 			frag.nattr = true;
-			node_shader_write(frag, 'fragColor[1] = vec4(nAttr, 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(nAttr, 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.MATERIAL_ID) {
-			node_shader_add_shared_sampler(frag, 'sampler2D texpaint_nor' + context_raw.layer.id);
-			node_shader_add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-			node_shader_write(frag, 'float sample_matid = texelFetch(texpaint_nor' + context_raw.layer.id + ', ivec2(texCoord * texpaintSize), 0).a + 1.0 / 255.0;');
-			node_shader_write(frag, 'float matid_r = fract(sin(dot(vec2(sample_matid, sample_matid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'float matid_g = fract(sin(dot(vec2(sample_matid * 20.0, sample_matid), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'float matid_b = fract(sin(dot(vec2(sample_matid, sample_matid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'fragColor[1] = vec4(matid_r, matid_g, matid_b, 1.0);');
+			node_shader_add_shared_sampler(frag, "sampler2D texpaint_nor" + context_raw.layer.id);
+			node_shader_add_uniform(frag, "vec2 texpaintSize", "_texpaintSize");
+			node_shader_write(frag, "float sample_matid = texelFetch(texpaint_nor" + context_raw.layer.id + ", ivec2(texCoord * texpaintSize), 0).a + 1.0 / 255.0;");
+			node_shader_write(frag, "float matid_r = fract(sin(dot(vec2(sample_matid, sample_matid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "float matid_g = fract(sin(dot(vec2(sample_matid * 20.0, sample_matid), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "float matid_b = fract(sin(dot(vec2(sample_matid, sample_matid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "fragColor[1] = vec4(matid_r, matid_g, matid_b, 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.OBJECT_ID) {
-			node_shader_add_uniform(frag, 'float objectId', '_objectId');
-			node_shader_write(frag, 'float obid = objectId + 1.0 / 255.0;');
-			node_shader_write(frag, 'float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'fragColor[1] = vec4(id_r, id_g, id_b, 1.0);');
+			node_shader_add_uniform(frag, "float objectId", "_objectId");
+			node_shader_write(frag, "float obid = objectId + 1.0 / 255.0;");
+			node_shader_write(frag, "float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "fragColor[1] = vec4(id_r, id_g, id_b, 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.MASK && (slot_layer_get_masks(context_raw.layer) != null || slot_layer_is_mask(context_raw.layer))) {
 			if (slot_layer_is_mask(context_raw.layer)) {
-				node_shader_write(frag, 'float mask_view = textureLodShared(texpaint' + context_raw.layer.id + ', texCoord, 0.0).r;');
+				node_shader_write(frag, "float mask_view = textureLodShared(texpaint" + context_raw.layer.id + ", texCoord, 0.0).r;");
 			}
 			else {
-				node_shader_write(frag, 'float mask_view = 0.0;');
+				node_shader_write(frag, "float mask_view = 0.0;");
 				for (let i: i32 = 0; i < slot_layer_get_masks(context_raw.layer).length; ++i) {
 					let m: slot_layer_t = slot_layer_get_masks(context_raw.layer)[i];
 					if (!slot_layer_is_visible(m)) continue;
-					node_shader_write(frag, 'float mask_sample' + m.id + ' = textureLodShared(texpaint_view_mask' + m.id + ', texCoord, 0.0).r;');
-					node_shader_write(frag, 'mask_view = ' + make_material_blend_mode_mask(frag, m.blending, 'mask_view', 'mask_sample' + m.id, 'float(' + slot_layer_get_opacity(m) + ')') + ';');
+					node_shader_write(frag, "float mask_sample" + m.id + " = textureLodShared(texpaint_view_mask" + m.id + ", texCoord, 0.0).r;");
+					node_shader_write(frag, "mask_view = " + make_material_blend_mode_mask(frag, m.blending, "mask_view", "mask_sample" + m.id, "float(" + slot_layer_get_opacity(m) + ")") + ";");
 				}
 			}
-			node_shader_write(frag, 'fragColor[1] = vec4(mask_view, mask_view, mask_view, 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(mask_view, mask_view, mask_view, 1.0);");
 		}
 		else {
-			node_shader_write(frag, 'fragColor[1] = vec4(1.0, 0.0, 1.0, 1.0);'); // Pink
+			node_shader_write(frag, "fragColor[1] = vec4(1.0, 0.0, 1.0, 1.0);"); // Pink
 		}
 
 		if (context_raw.viewport_mode != viewport_mode_t.LIT && context_raw.viewport_mode != viewport_mode_t.PATH_TRACE) {
-			node_shader_write(frag, 'fragColor[1].rgb = pow(fragColor[1].rgb, vec3(2.2, 2.2, 2.2));');
+			node_shader_write(frag, "fragColor[1].rgb = pow(fragColor[1].rgb, vec3(2.2, 2.2, 2.2));");
 		}
 
-		node_shader_write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-		node_shader_write(frag, 'n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);');
-		node_shader_write(frag, 'fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, uint(int(matid * 255.0) % 3)));');
+		node_shader_write(frag, "n /= (abs(n.x) + abs(n.y) + abs(n.z));");
+		node_shader_write(frag, "n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);");
+		node_shader_write(frag, "fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, uint(int(matid * 255.0) % 3)));");
 	}
 
-	node_shader_write(frag, 'vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
-	node_shader_write(frag, 'vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;');
-	node_shader_write(frag, 'fragColor[2] = vec4(posa - posb, texCoord.xy);');
+	node_shader_write(frag, "vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;");
+	node_shader_write(frag, "vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;");
+	node_shader_write(frag, "fragColor[2] = vec4(posa - posb, texCoord.xy);");
 
 	parser_material_finalize(con_mesh);
 	con_mesh.data.shader_from_source = true;

+ 54 - 54
armorpaint/Sources/make_mesh_preview.ts

@@ -22,28 +22,28 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): no
 	let skin: bool = mesh_data_get_vertex_array(context_raw.paint_object.data, "bone") != null;
 	if (skin) {
 		pos = "spos";
-		node_shader_context_add_elem(con_mesh, "bone", 'short4norm');
-		node_shader_context_add_elem(con_mesh, "weight", 'short4norm');
+		node_shader_context_add_elem(con_mesh, "bone", "short4norm");
+		node_shader_context_add_elem(con_mesh, "weight", "short4norm");
 		node_shader_add_function(vert, str_get_skinning_dual_quat);
-		node_shader_add_uniform(vert, 'vec4 skinBones[128 * 2]', '_skin_bones');
-		node_shader_add_uniform(vert, 'float posUnpack', '_pos_unpack');
-		node_shader_write_attrib(vert, 'vec4 skinA;');
-		node_shader_write_attrib(vert, 'vec4 skinB;');
-		node_shader_write_attrib(vert, 'getSkinningDualQuat(ivec4(bone * 32767), weight, skinA, skinB);');
-		node_shader_write_attrib(vert, 'vec3 spos = pos.xyz;');
-		node_shader_write_attrib(vert, 'spos.xyz *= posUnpack;');
-		node_shader_write_attrib(vert, 'spos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, spos.xyz) + skinA.w * spos.xyz);');
-		node_shader_write_attrib(vert, 'spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz));');
-		node_shader_write_attrib(vert, 'spos.xyz /= posUnpack;');
+		node_shader_add_uniform(vert, "vec4 skinBones[128 * 2]", "_skin_bones");
+		node_shader_add_uniform(vert, "float posUnpack", "_pos_unpack");
+		node_shader_write_attrib(vert, "vec4 skinA;");
+		node_shader_write_attrib(vert, "vec4 skinB;");
+		node_shader_write_attrib(vert, "getSkinningDualQuat(ivec4(bone * 32767), weight, skinA, skinB);");
+		node_shader_write_attrib(vert, "vec3 spos = pos.xyz;");
+		node_shader_write_attrib(vert, "spos.xyz *= posUnpack;");
+		node_shader_write_attrib(vert, "spos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, spos.xyz) + skinA.w * spos.xyz);");
+		node_shader_write_attrib(vert, "spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz));");
+		node_shader_write_attrib(vert, "spos.xyz /= posUnpack;");
 	}
 	///end
 
-	node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
-	node_shader_write_attrib(vert, `gl_Position = mul(vec4(${pos}.xyz, 1.0), WVP);`);
+	node_shader_add_uniform(vert, "mat4 WVP", "_world_view_proj_matrix");
+	node_shader_write_attrib(vert, "gl_Position = mul(vec4(" + pos + ".xyz, 1.0), WVP);");
 
 	let brush_scale: string = (context_raw.brush_scale * context_raw.brush_nodes_scale) + "";
-	node_shader_add_out(vert, 'vec2 texCoord');
-	node_shader_write_attrib(vert, `texCoord = tex * float(${brush_scale});`);
+	node_shader_add_out(vert, "vec2 texCoord");
+	node_shader_write_attrib(vert, "texCoord = tex * float(" + brush_scale + ");");
 
 	let decal: bool = context_raw.decal_preview;
 	parser_material_sample_keep_aspect = decal;
@@ -61,36 +61,36 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): no
 	let opac: string = sout.out_opacity;
 	let height: string = sout.out_height;
 	let nortan: string = parser_material_out_normaltan;
-	node_shader_write(frag, `vec3 basecol = pow(${base}, vec3(2.2, 2.2, 2.2));`);
-	node_shader_write(frag, `float roughness = ${rough};`);
-	node_shader_write(frag, `float metallic = ${met};`);
-	node_shader_write(frag, `float occlusion = ${occ};`);
-	node_shader_write(frag, `float opacity = ${opac};`);
-	node_shader_write(frag, `vec3 nortan = ${nortan};`);
-	node_shader_write(frag, `float height = ${height};`);
+	node_shader_write(frag, "vec3 basecol = pow(" + base + ", vec3(2.2, 2.2, 2.2));");
+	node_shader_write(frag, "float roughness = " + rough + ";");
+	node_shader_write(frag, "float metallic = " + met + ";");
+	node_shader_write(frag, "float occlusion = " + occ + ";");
+	node_shader_write(frag, "float opacity = " + opac + ";");
+	node_shader_write(frag, "vec3 nortan = " + nortan + ";");
+	node_shader_write(frag, "float height = " + height + ";");
 
 	// parse_height_as_channel = false;
-	// write(vert, `float vheight = ${height};`);
-	// add_out(vert, 'float height');
-	// write(vert, 'height = vheight;');
+	// write(vert, "float vheight = " + height + ";");
+	// add_out(vert, "float height");
+	// write(vert, "height = vheight;");
 	// let displaceStrength: f32 = 0.1;
 	// if (heightUsed && displaceStrength > 0.0) {
-	// 	write(vert, `vec3 pos2 = ${pos}.xyz + vec3(nor.xy, pos.w) * vec3(${height}, ${height}, ${height}) * vec3(${displaceStrength}, ${displaceStrength}, ${displaceStrength});`);
-	// 	write(vert, 'gl_Position = mul(vec4(pos2.xyz, 1.0), WVP);');
+	// 	write(vert, "vec3 pos2 = " + pos + ".xyz + vec3(nor.xy, pos.w) * vec3(" + height + ", " + height + ", " + height + ") * vec3(" + displaceStrength + ", " + displaceStrength + ", " + displaceStrength + ");");
+	// 	write(vert, "gl_Position = mul(vec4(pos2.xyz, 1.0), WVP);");
 	// }
 
 	if (decal) {
 		if (context_raw.tool == workspace_tool_t.TEXT) {
-			node_shader_add_uniform(frag, 'sampler2D textexttool', '_textexttool');
-			node_shader_write(frag, `opacity *= textureLod(textexttool, texCoord / float(${brush_scale}), 0.0).r;`);
+			node_shader_add_uniform(frag, "sampler2D textexttool", "_textexttool");
+			node_shader_write(frag, "opacity *= textureLod(textexttool, texCoord / float(" + brush_scale + "), 0.0).r;");
 		}
 	}
 	if (decal) {
 		let opac: f32 = make_mesh_preview_opacity_discard_decal;
-		node_shader_write(frag, `if (opacity < ${opac}) discard;`);
+		node_shader_write(frag, "if (opacity < " + opac + ") discard;");
 	}
 
-	node_shader_add_out(frag, 'vec4 fragColor[3]');
+	node_shader_add_out(frag, "vec4 fragColor[3]");
 	frag.n = true;
 
 	node_shader_add_function(frag, str_pack_float_int16);
@@ -98,16 +98,16 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): no
 	node_shader_add_function(frag, str_octahedron_wrap);
 
 	if (make_material_height_used) {
-		node_shader_write(frag, 'if (height > 0.0) {');
-		node_shader_write(frag, 'float height_dx = dFdx(height * 2.0);');
-		node_shader_write(frag, 'float height_dy = dFdy(height * 2.0);');
-		// write(frag, 'float height_dx = height0 - height1;');
-		// write(frag, 'float height_dy = height2 - height3;');
+		node_shader_write(frag, "if (height > 0.0) {");
+		node_shader_write(frag, "float height_dx = dFdx(height * 2.0);");
+		node_shader_write(frag, "float height_dy = dFdy(height * 2.0);");
+		// write(frag, "float height_dx = height0 - height1;");
+		// write(frag, "float height_dy = height2 - height3;");
 		// Whiteout blend
-		node_shader_write(frag, 'vec3 n1 = nortan * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-		node_shader_write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-		node_shader_write(frag, 'nortan = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);');
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "vec3 n1 = nortan * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
+		node_shader_write(frag, "vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));");
+		node_shader_write(frag, "nortan = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);");
+		node_shader_write(frag, "}");
 	}
 
 	// Apply normal channel
@@ -117,34 +117,34 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): no
 	else {
 		frag.vvec = true;
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, vVec, texCoord);");
 		///else
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, -vVec, texCoord);");
 		///end
-		node_shader_write(frag, 'n = nortan * 2.0 - 1.0;');
-		node_shader_write(frag, 'n.y = -n.y;');
-		node_shader_write(frag, 'n = normalize(mul(n, TBN));');
+		node_shader_write(frag, "n = nortan * 2.0 - 1.0;");
+		node_shader_write(frag, "n.y = -n.y;");
+		node_shader_write(frag, "n = normalize(mul(n, TBN));");
 	}
 
-	node_shader_write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-	node_shader_write(frag, 'n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);');
+	node_shader_write(frag, "n /= (abs(n.x) + abs(n.y) + abs(n.z));");
+	node_shader_write(frag, "n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);");
 	// uint matid = 0;
 
 	if (decal) {
-		node_shader_write(frag, 'fragColor[0] = vec4(n.x, n.y, roughness, packFloatInt16(metallic, uint(0)));'); // metallic/matid
-		node_shader_write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
+		node_shader_write(frag, "fragColor[0] = vec4(n.x, n.y, roughness, packFloatInt16(metallic, uint(0)));"); // metallic/matid
+		node_shader_write(frag, "fragColor[1] = vec4(basecol, occlusion);");
 	}
 	else {
-		node_shader_write(frag, 'fragColor[0] = vec4(n.x, n.y, mix(1.0, roughness, opacity), packFloatInt16(mix(1.0, metallic, opacity), uint(0)));'); // metallic/matid
-		node_shader_write(frag, 'fragColor[1] = vec4(mix(vec3(0.0, 0.0, 0.0), basecol, opacity), occlusion);');
+		node_shader_write(frag, "fragColor[0] = vec4(n.x, n.y, mix(1.0, roughness, opacity), packFloatInt16(mix(1.0, metallic, opacity), uint(0)));"); // metallic/matid
+		node_shader_write(frag, "fragColor[1] = vec4(mix(vec3(0.0, 0.0, 0.0), basecol, opacity), occlusion);");
 	}
-	node_shader_write(frag, 'fragColor[2] = vec4(0.0, 0.0, 0.0, 0.0);'); // veloc
+	node_shader_write(frag, "fragColor[2] = vec4(0.0, 0.0, 0.0, 0.0);"); // veloc
 
 	parser_material_finalize(con_mesh);
 
 	///if arm_skin
 	if (skin) {
-		node_shader_write(vert, 'wnormal = normalize(mul(vec3(nor.xy, pos.w) + 2.0 * cross(skinA.xyz, cross(skinA.xyz, vec3(nor.xy, pos.w)) + skinA.w * vec3(nor.xy, pos.w)), N));');
+		node_shader_write(vert, "wnormal = normalize(mul(vec3(nor.xy, pos.w) + 2.0 * cross(skinA.xyz, cross(skinA.xyz, vec3(nor.xy, pos.w)) + skinA.w * vec3(nor.xy, pos.w)), N));");
 	}
 	///end
 

+ 10 - 10
armorpaint/Sources/make_node_preview.ts

@@ -15,12 +15,12 @@ function make_node_preview_run(data: material_t, matcon: material_context_t, nod
 	let frag: node_shader_t = node_shader_context_make_frag(con_mesh);
 	frag.ins = vert.outs;
 
-	node_shader_write_attrib(vert, 'gl_Position = vec4(pos.xy * 3.0, 0.0, 1.0);'); // Pos unpack
-	node_shader_write_attrib(vert, 'const vec2 madd = vec2(0.5, 0.5);');
-	node_shader_add_out(vert, 'vec2 texCoord');
-	node_shader_write_attrib(vert, 'texCoord = gl_Position.xy * madd + madd;');
+	node_shader_write_attrib(vert, "gl_Position = vec4(pos.xy * 3.0, 0.0, 1.0);"); // Pos unpack
+	node_shader_write_attrib(vert, "const vec2 madd = vec2(0.5, 0.5);");
+	node_shader_add_out(vert, "vec2 texCoord");
+	node_shader_write_attrib(vert, "texCoord = gl_Position.xy * madd + madd;");
 	///if (!krom_opengl)
-	node_shader_write_attrib(vert, 'texCoord.y = 1.0 - texCoord.y;');
+	node_shader_write_attrib(vert, "texCoord.y = 1.0 - texCoord.y;");
 	///end
 
 	parser_material_init();
@@ -50,13 +50,13 @@ function make_node_preview_run(data: material_t, matcon: material_context_t, nod
 	}
 	array_remove(links, link);
 
-	node_shader_add_out(frag, 'vec4 fragColor');
-	node_shader_write(frag, `vec3 basecol = ${res};`);
-	node_shader_write(frag, 'fragColor = vec4(basecol.rgb, 1.0);');
+	node_shader_add_out(frag, "vec4 fragColor");
+	node_shader_write(frag, "vec3 basecol = " + res + ";");
+	node_shader_write(frag, "fragColor = vec4(basecol.rgb, 1.0);");
 
 	// frag.ndcpos = true;
-	// add_out(vert, 'vec4 ndc');
-	// write_attrib(vert, 'ndc = vec4(gl_Position.xyz * vec3(0.5, 0.5, 0.0) + vec3(0.5, 0.5, 0.0), 1.0);');
+	// add_out(vert, "vec4 ndc");
+	// write_attrib(vert, "ndc = vec4(gl_Position.xyz * vec3(0.5, 0.5, 0.0) + vec3(0.5, 0.5, 0.0), 1.0);");
 
 	parser_material_finalize(con_mesh);
 

+ 136 - 136
armorpaint/Sources/make_paint.ts

@@ -31,7 +31,7 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 	con_paint.data.color_writes_green = [true, true, true, true];
 	con_paint.data.color_writes_blue = [true, true, true, true];
 	con_paint.data.color_writes_alpha = [true, true, true, true];
-	con_paint.allow_vcols = mesh_data_get_vertex_array(context_raw.paint_object.data, 'col') != null;
+	con_paint.allow_vcols = mesh_data_get_vertex_array(context_raw.paint_object.data, "col") != null;
 
 	let vert: node_shader_t = node_shader_context_make_vert(con_paint);
 	let frag: node_shader_t = node_shader_context_make_frag(con_paint);
@@ -65,47 +65,47 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 	let decal: bool = context_raw.tool == workspace_tool_t.DECAL || context_raw.tool == workspace_tool_t.TEXT;
 
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(vert, 'vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);');
+	node_shader_write(vert, "vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);");
 	///else
-	node_shader_write(vert, 'vec2 tpos = vec2(tex.xy * 2.0 - 1.0);');
+	node_shader_write(vert, "vec2 tpos = vec2(tex.xy * 2.0 - 1.0);");
 	///end
 
-	node_shader_write(vert, 'gl_Position = vec4(tpos, 0.0, 1.0);');
+	node_shader_write(vert, "gl_Position = vec4(tpos, 0.0, 1.0);");
 
 	let decal_layer: bool = context_raw.layer.fill_layer != null && context_raw.layer.uv_type == uv_type_t.PROJECT;
 	if (decal_layer) {
-		node_shader_add_uniform(vert, 'mat4 WVP', '_decalLayerMatrix');
+		node_shader_add_uniform(vert, "mat4 WVP", "_decalLayerMatrix");
 	}
 	else {
-		node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
+		node_shader_add_uniform(vert, "mat4 WVP", "_world_view_proj_matrix");
 	}
 
-	node_shader_add_out(vert, 'vec4 ndc');
-	node_shader_write_attrib(vert, 'ndc = mul(vec4(pos.xyz, 1.0), WVP);');
+	node_shader_add_out(vert, "vec4 ndc");
+	node_shader_write_attrib(vert, "ndc = mul(vec4(pos.xyz, 1.0), WVP);");
 
-	node_shader_write_attrib(frag, 'vec3 sp = vec3((ndc.xyz / ndc.w) * 0.5 + 0.5);');
-	node_shader_write_attrib(frag, 'sp.y = 1.0 - sp.y;');
-	node_shader_write_attrib(frag, 'sp.z -= 0.0001;'); // small bias
+	node_shader_write_attrib(frag, "vec3 sp = vec3((ndc.xyz / ndc.w) * 0.5 + 0.5);");
+	node_shader_write_attrib(frag, "sp.y = 1.0 - sp.y;");
+	node_shader_write_attrib(frag, "sp.z -= 0.0001;"); // small bias
 
 	let uv_type: uv_type_t = context_raw.layer.fill_layer != null ? context_raw.layer.uv_type : context_raw.brush_paint;
 	if (uv_type == uv_type_t.PROJECT) {
 		frag.ndcpos = true;
 	}
 
-	node_shader_add_uniform(frag, 'vec4 inp', '_inputBrush');
-	node_shader_add_uniform(frag, 'vec4 inplast', '_inputBrushLast');
-	node_shader_add_uniform(frag, 'float aspectRatio', '_aspect_ratio_window');
-	node_shader_write(frag, 'vec2 bsp = sp.xy * 2.0 - 1.0;');
-	node_shader_write(frag, 'bsp.x *= aspectRatio;');
-	node_shader_write(frag, 'bsp = bsp * 0.5 + 0.5;');
+	node_shader_add_uniform(frag, "vec4 inp", "_inputBrush");
+	node_shader_add_uniform(frag, "vec4 inplast", "_inputBrushLast");
+	node_shader_add_uniform(frag, "float aspectRatio", "_aspect_ratio_window");
+	node_shader_write(frag, "vec2 bsp = sp.xy * 2.0 - 1.0;");
+	node_shader_write(frag, "bsp.x *= aspectRatio;");
+	node_shader_write(frag, "bsp = bsp * 0.5 + 0.5;");
 
-	node_shader_add_uniform(frag, 'sampler2D gbufferD');
+	node_shader_add_uniform(frag, "sampler2D gbufferD");
 
-	node_shader_add_out(frag, 'vec4 fragColor[4]');
+	node_shader_add_out(frag, "vec4 fragColor[4]");
 
-	node_shader_add_uniform(frag, 'float brushRadius', '_brushRadius');
-	node_shader_add_uniform(frag, 'float brushOpacity', '_brushOpacity');
-	node_shader_add_uniform(frag, 'float brushHardness', '_brushHardness');
+	node_shader_add_uniform(frag, "float brushRadius", "_brushRadius");
+	node_shader_add_uniform(frag, "float brushOpacity", "_brushOpacity");
+	node_shader_add_uniform(frag, "float brushHardness", "_brushHardness");
 
 	if (context_raw.tool == workspace_tool_t.BRUSH  ||
 		context_raw.tool == workspace_tool_t.ERASER ||
@@ -130,42 +130,42 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 
 		if (depth_reject) {
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			node_shader_write(frag, 'if (sp.z > textureLod(gbufferD, sp.xy, 0.0).r + 0.0005) discard;');
+			node_shader_write(frag, "if (sp.z > textureLod(gbufferD, sp.xy, 0.0).r + 0.0005) discard;");
 			///else
-			node_shader_write(frag, 'if (sp.z > textureLod(gbufferD, vec2(sp.x, 1.0 - sp.y), 0.0).r + 0.0005) discard;');
+			node_shader_write(frag, "if (sp.z > textureLod(gbufferD, vec2(sp.x, 1.0 - sp.y), 0.0).r + 0.0005) discard;");
 			///end
 		}
 
 		make_brush_run(vert, frag);
 	}
 	else { // Fill, Bake
-		node_shader_write(frag, 'float dist = 0.0;');
+		node_shader_write(frag, "float dist = 0.0;");
 		let angle_fill: bool = context_raw.tool == workspace_tool_t.FILL && context_raw.fill_type_handle.position == fill_type_t.ANGLE;
 		if (angle_fill) {
 			node_shader_add_function(frag, str_octahedron_wrap);
-			node_shader_add_uniform(frag, 'sampler2D gbuffer0');
-			node_shader_write(frag, 'vec2 g0 = textureLod(gbuffer0, inp.xy, 0.0).rg;');
-			node_shader_write(frag, 'vec3 wn;');
-			node_shader_write(frag, 'wn.z = 1.0 - abs(g0.x) - abs(g0.y);');
-			node_shader_write(frag, 'wn.xy = wn.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);');
-			node_shader_write(frag, 'wn = normalize(wn);');
+			node_shader_add_uniform(frag, "sampler2D gbuffer0");
+			node_shader_write(frag, "vec2 g0 = textureLod(gbuffer0, inp.xy, 0.0).rg;");
+			node_shader_write(frag, "vec3 wn;");
+			node_shader_write(frag, "wn.z = 1.0 - abs(g0.x) - abs(g0.y);");
+			node_shader_write(frag, "wn.xy = wn.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);");
+			node_shader_write(frag, "wn = normalize(wn);");
 			frag.n = true;
 			let angle: f32 = context_raw.brush_angle_reject_dot;
-			node_shader_write(frag, `if (dot(wn, n) < ${angle}) discard;`);
+			node_shader_write(frag, "if (dot(wn, n) < " + angle + ") discard;");
 		}
 		let stencil_fill: bool = context_raw.tool == workspace_tool_t.FILL && context_raw.brush_stencil_image != null;
 		if (stencil_fill) {
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			node_shader_write(frag, 'if (sp.z > textureLod(gbufferD, sp.xy, 0.0).r + 0.0005) discard;');
+			node_shader_write(frag, "if (sp.z > textureLod(gbufferD, sp.xy, 0.0).r + 0.0005) discard;");
 			///else
-			node_shader_write(frag, 'if (sp.z > textureLod(gbufferD, vec2(sp.x, 1.0 - sp.y), 0.0).r + 0.0005) discard;');
+			node_shader_write(frag, "if (sp.z > textureLod(gbufferD, vec2(sp.x, 1.0 - sp.y), 0.0).r + 0.0005) discard;");
 			///end
 		}
 	}
 
 	if (context_raw.colorid_picked || face_fill || uv_island_fill) {
-		node_shader_add_out(vert, 'vec2 texCoordPick');
-		node_shader_write(vert, 'texCoordPick = tex;');
+		node_shader_add_out(vert, "vec2 texCoordPick");
+		node_shader_write(vert, "texCoordPick = tex;");
 		if (context_raw.colorid_picked) {
 			make_discard_color_id(vert, frag);
 		}
@@ -184,11 +184,11 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 	make_texcoord_run(vert, frag);
 
 	if (context_raw.tool == workspace_tool_t.CLONE || context_raw.tool == workspace_tool_t.BLUR || context_raw.tool == workspace_tool_t.SMUDGE) {
-		node_shader_add_uniform(frag, 'sampler2D gbuffer2');
-		node_shader_add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
-		node_shader_add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-		node_shader_add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
-		node_shader_add_uniform(frag, 'sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
+		node_shader_add_uniform(frag, "sampler2D gbuffer2");
+		node_shader_add_uniform(frag, "vec2 gbufferSize", "_gbufferSize");
+		node_shader_add_uniform(frag, "sampler2D texpaint_undo", "_texpaint_undo");
+		node_shader_add_uniform(frag, "sampler2D texpaint_nor_undo", "_texpaint_nor_undo");
+		node_shader_add_uniform(frag, "sampler2D texpaint_pack_undo", "_texpaint_pack_undo");
 
 		if (context_raw.tool == workspace_tool_t.CLONE) {
 			make_clone_run(vert, frag);
@@ -205,7 +205,7 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 		let uv_type: uv_type_t = context_raw.layer.fill_layer != null ? context_raw.layer.uv_type : context_raw.brush_paint;
 		parser_material_triplanar = uv_type == uv_type_t.TRIPLANAR && !decal;
 		parser_material_sample_keep_aspect = decal;
-		parser_material_sample_uv_scale = 'brushScale';
+		parser_material_sample_uv_scale = "brushScale";
 		let sout: shader_out_t = parser_material_parse(ui_nodes_get_canvas_material(), con_paint, vert, frag, matcon);
 		parser_material_parse_emission = false;
 		parser_material_parse_subsurface = false;
@@ -220,22 +220,22 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 		let opac: string = sout.out_opacity;
 		let emis: string = sout.out_emission;
 		let subs: string = sout.out_subsurface;
-		node_shader_write(frag, `vec3 basecol = ${base};`);
-		node_shader_write(frag, `float roughness = ${rough};`);
-		node_shader_write(frag, `float metallic = ${met};`);
-		node_shader_write(frag, `float occlusion = ${occ};`);
-		node_shader_write(frag, `vec3 nortan = ${nortan};`);
-		node_shader_write(frag, `float height = ${height};`);
-		node_shader_write(frag, `float mat_opacity = ${opac};`);
-		node_shader_write(frag, 'float opacity = mat_opacity;');
+		node_shader_write(frag, "vec3 basecol = " + base + ";");
+		node_shader_write(frag, "float roughness = " + rough + ";");
+		node_shader_write(frag, "float metallic = " + met + ";");
+		node_shader_write(frag, "float occlusion = " + occ + ";");
+		node_shader_write(frag, "vec3 nortan = " + nortan + ";");
+		node_shader_write(frag, "float height = " + height + ";");
+		node_shader_write(frag, "float mat_opacity = " + opac + ";");
+		node_shader_write(frag, "float opacity = mat_opacity;");
 		if (context_raw.layer.fill_layer == null) {
-			node_shader_write(frag, 'opacity *= brushOpacity;');
+			node_shader_write(frag, "opacity *= brushOpacity;");
 		}
 		if (context_raw.material.paint_emis) {
-			node_shader_write(frag, `float emis = ${emis};`);
+			node_shader_write(frag, "float emis = " + emis + ";");
 		}
 		if (context_raw.material.paint_subs) {
-			node_shader_write(frag, `float subs = ${subs};`);
+			node_shader_write(frag, "float subs = " + subs + ";");
 		}
 		if (parse_float(height) != 0.0 && !make_material_height_used) {
 			make_material_height_used = true;
@@ -251,18 +251,18 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 	}
 
 	if (context_raw.brush_mask_image != null && context_raw.tool == workspace_tool_t.DECAL) {
-		node_shader_add_uniform(frag, 'sampler2D texbrushmask', '_texbrushmask');
-		node_shader_write(frag, 'vec4 mask_sample = textureLod(texbrushmask, uvsp, 0.0);');
+		node_shader_add_uniform(frag, "sampler2D texbrushmask", "_texbrushmask");
+		node_shader_write(frag, "vec4 mask_sample = textureLod(texbrushmask, uvsp, 0.0);");
 		if (context_raw.brush_mask_image_is_alpha) {
-			node_shader_write(frag, 'opacity *= mask_sample.a;');
+			node_shader_write(frag, "opacity *= mask_sample.a;");
 		}
 		else {
-			node_shader_write(frag, 'opacity *= mask_sample.r * mask_sample.a;');
+			node_shader_write(frag, "opacity *= mask_sample.r * mask_sample.a;");
 		}
 	}
 	else if (context_raw.tool == workspace_tool_t.TEXT) {
-		node_shader_add_uniform(frag, 'sampler2D textexttool', '_textexttool');
-		node_shader_write(frag, 'opacity *= textureLod(textexttool, uvsp, 0.0).r;');
+		node_shader_add_uniform(frag, "sampler2D textexttool", "_textexttool");
+		node_shader_write(frag, "opacity *= textureLod(textexttool, uvsp, 0.0).r;");
 	}
 
 	if (context_raw.brush_stencil_image != null && (
@@ -274,124 +274,124 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 		context_raw.tool == workspace_tool_t.SMUDGE   ||
 		context_raw.tool == workspace_tool_t.PARTICLE ||
 		decal)) {
-		node_shader_add_uniform(frag, 'sampler2D texbrushstencil', '_texbrushstencil');
-		node_shader_add_uniform(frag, 'vec4 stencilTransform', '_stencilTransform');
-		node_shader_write(frag, 'vec2 stencil_uv = vec2((sp.xy - stencilTransform.xy) / stencilTransform.z * vec2(aspectRatio, 1.0));');
-		node_shader_write(frag, 'vec2 stencil_size = vec2(textureSize(texbrushstencil, 0));');
-		node_shader_write(frag, 'float stencil_ratio = stencil_size.y / stencil_size.x;');
-		node_shader_write(frag, 'stencil_uv -= vec2(0.5 / stencil_ratio, 0.5);');
-		node_shader_write(frag, `stencil_uv = vec2(stencil_uv.x * cos(stencilTransform.w) - stencil_uv.y * sin(stencilTransform.w),
-										stencil_uv.x * sin(stencilTransform.w) + stencil_uv.y * cos(stencilTransform.w));`);
-		node_shader_write(frag, 'stencil_uv += vec2(0.5 / stencil_ratio, 0.5);');
-		node_shader_write(frag, 'stencil_uv.x *= stencil_ratio;');
-		node_shader_write(frag, 'if (stencil_uv.x < 0 || stencil_uv.x > 1 || stencil_uv.y < 0 || stencil_uv.y > 1) discard;');
-		node_shader_write(frag, 'vec4 texbrushstencil_sample = textureLod(texbrushstencil, stencil_uv, 0.0);');
+		node_shader_add_uniform(frag, "sampler2D texbrushstencil", "_texbrushstencil");
+		node_shader_add_uniform(frag, "vec4 stencilTransform", "_stencilTransform");
+		node_shader_write(frag, "vec2 stencil_uv = vec2((sp.xy - stencilTransform.xy) / stencilTransform.z * vec2(aspectRatio, 1.0));");
+		node_shader_write(frag, "vec2 stencil_size = vec2(textureSize(texbrushstencil, 0));");
+		node_shader_write(frag, "float stencil_ratio = stencil_size.y / stencil_size.x;");
+		node_shader_write(frag, "stencil_uv -= vec2(0.5 / stencil_ratio, 0.5);");
+		node_shader_write(frag, "stencil_uv = vec2(stencil_uv.x * cos(stencilTransform.w) - stencil_uv.y * sin(stencilTransform.w),\
+												   stencil_uv.x * sin(stencilTransform.w) + stencil_uv.y * cos(stencilTransform.w));");
+		node_shader_write(frag, "stencil_uv += vec2(0.5 / stencil_ratio, 0.5);");
+		node_shader_write(frag, "stencil_uv.x *= stencil_ratio;");
+		node_shader_write(frag, "if (stencil_uv.x < 0 || stencil_uv.x > 1 || stencil_uv.y < 0 || stencil_uv.y > 1) discard;");
+		node_shader_write(frag, "vec4 texbrushstencil_sample = textureLod(texbrushstencil, stencil_uv, 0.0);");
 		if (context_raw.brush_stencil_image_is_alpha) {
-			node_shader_write(frag, 'opacity *= texbrushstencil_sample.a;');
+			node_shader_write(frag, "opacity *= texbrushstencil_sample.a;");
 		}
 		else {
-			node_shader_write(frag, 'opacity *= texbrushstencil_sample.r * texbrushstencil_sample.a;');
+			node_shader_write(frag, "opacity *= texbrushstencil_sample.r * texbrushstencil_sample.a;");
 		}
 	}
 
 	if (context_raw.brush_mask_image != null && (context_raw.tool == workspace_tool_t.BRUSH || context_raw.tool == workspace_tool_t.ERASER)) {
-		node_shader_add_uniform(frag, 'sampler2D texbrushmask', '_texbrushmask');
-		node_shader_write(frag, 'vec2 binp_mask = inp.xy * 2.0 - 1.0;');
-		node_shader_write(frag, 'binp_mask.x *= aspectRatio;');
-		node_shader_write(frag, 'binp_mask = binp_mask * 0.5 + 0.5;');
-		node_shader_write(frag, 'vec2 pa_mask = bsp.xy - binp_mask.xy;');
+		node_shader_add_uniform(frag, "sampler2D texbrushmask", "_texbrushmask");
+		node_shader_write(frag, "vec2 binp_mask = inp.xy * 2.0 - 1.0;");
+		node_shader_write(frag, "binp_mask.x *= aspectRatio;");
+		node_shader_write(frag, "binp_mask = binp_mask * 0.5 + 0.5;");
+		node_shader_write(frag, "vec2 pa_mask = bsp.xy - binp_mask.xy;");
 		if (context_raw.brush_directional) {
-			node_shader_add_uniform(frag, 'vec3 brushDirection', '_brushDirection');
-			node_shader_write(frag, 'if (brushDirection.z == 0.0) discard;');
-			node_shader_write(frag, 'pa_mask = vec2(pa_mask.x * brushDirection.x - pa_mask.y * brushDirection.y, pa_mask.x * brushDirection.y + pa_mask.y * brushDirection.x);');
+			node_shader_add_uniform(frag, "vec3 brushDirection", "_brushDirection");
+			node_shader_write(frag, "if (brushDirection.z == 0.0) discard;");
+			node_shader_write(frag, "pa_mask = vec2(pa_mask.x * brushDirection.x - pa_mask.y * brushDirection.y, pa_mask.x * brushDirection.y + pa_mask.y * brushDirection.x);");
 		}
 		let angle: f32 = context_raw.brush_angle + context_raw.brush_nodes_angle;
 		if (angle != 0.0) {
-			node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-			node_shader_write(frag, 'pa_mask.xy = vec2(pa_mask.x * brushAngle.x - pa_mask.y * brushAngle.y, pa_mask.x * brushAngle.y + pa_mask.y * brushAngle.x);');
+			node_shader_add_uniform(frag, "vec2 brushAngle", "_brushAngle");
+			node_shader_write(frag, "pa_mask.xy = vec2(pa_mask.x * brushAngle.x - pa_mask.y * brushAngle.y, pa_mask.x * brushAngle.y + pa_mask.y * brushAngle.x);");
 		}
-		node_shader_write(frag, 'pa_mask /= brushRadius;');
+		node_shader_write(frag, "pa_mask /= brushRadius;");
 		if (config_raw.brush_3d) {
-			node_shader_add_uniform(frag, 'vec3 eye', '_camera_pos');
-			node_shader_write(frag, 'pa_mask *= distance(eye, winp.xyz) / 1.5;');
+			node_shader_add_uniform(frag, "vec3 eye", "_camera_pos");
+			node_shader_write(frag, "pa_mask *= distance(eye, winp.xyz) / 1.5;");
 		}
-		node_shader_write(frag, 'pa_mask = pa_mask.xy * 0.5 + 0.5;');
-		node_shader_write(frag, 'vec4 mask_sample = textureLod(texbrushmask, pa_mask, 0.0);');
+		node_shader_write(frag, "pa_mask = pa_mask.xy * 0.5 + 0.5;");
+		node_shader_write(frag, "vec4 mask_sample = textureLod(texbrushmask, pa_mask, 0.0);");
 		if (context_raw.brush_mask_image_is_alpha) {
-			node_shader_write(frag, 'opacity *= mask_sample.a;');
+			node_shader_write(frag, "opacity *= mask_sample.a;");
 		}
 		else {
-			node_shader_write(frag, 'opacity *= mask_sample.r * mask_sample.a;');
+			node_shader_write(frag, "opacity *= mask_sample.r * mask_sample.a;");
 		}
 	}
 
-	node_shader_write(frag, 'if (opacity == 0.0) discard;');
+	node_shader_write(frag, "if (opacity == 0.0) discard;");
 
 	if (context_raw.tool == workspace_tool_t.PARTICLE) { // Particle mask
 		make_particle_mask(vert, frag);
 	}
 	else { // Brush cursor mask
-		node_shader_write(frag, 'float str = clamp((brushRadius - dist) * brushHardness * 400.0, 0.0, 1.0) * opacity;');
+		node_shader_write(frag, "float str = clamp((brushRadius - dist) * brushHardness * 400.0, 0.0, 1.0) * opacity;");
 	}
 
 	// Manual blending to preserve memory
 	frag.wvpposition = true;
-	node_shader_write(frag, 'vec2 sample_tc = vec2(wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
+	node_shader_write(frag, "vec2 sample_tc = vec2(wvpposition.xy / wvpposition.w) * 0.5 + 0.5;");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'sample_tc.y = 1.0 - sample_tc.y;');
+	node_shader_write(frag, "sample_tc.y = 1.0 - sample_tc.y;");
 	///end
-	node_shader_add_uniform(frag, 'sampler2D paintmask');
-	node_shader_write(frag, 'float sample_mask = textureLod(paintmask, sample_tc, 0.0).r;');
-	node_shader_write(frag, 'str = max(str, sample_mask);');
-	// write(frag, 'str = clamp(str + sample_mask, 0.0, 1.0);');
+	node_shader_add_uniform(frag, "sampler2D paintmask");
+	node_shader_write(frag, "float sample_mask = textureLod(paintmask, sample_tc, 0.0).r;");
+	node_shader_write(frag, "str = max(str, sample_mask);");
+	// write(frag, "str = clamp(str + sample_mask, 0.0, 1.0);");
 
-	node_shader_add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-	node_shader_write(frag, 'vec4 sample_undo = textureLod(texpaint_undo, sample_tc, 0.0);');
+	node_shader_add_uniform(frag, "sampler2D texpaint_undo", "_texpaint_undo");
+	node_shader_write(frag, "vec4 sample_undo = textureLod(texpaint_undo, sample_tc, 0.0);");
 
 	let matid: f32 = context_raw.material.id / 255;
 	if (context_raw.picker_mask_handle.position == picker_mask_t.MATERIAL) {
 		matid = context_raw.materialid_picked / 255; // Keep existing material id in place when mask is set
 	}
 	let matid_string: string = parser_material_vec1(matid * 3.0);
-	node_shader_write(frag, `float matid = ${matid_string};`);
+	node_shader_write(frag, "float matid = " + matid_string + ";");
 
 	// matid % 3 == 0 - normal, 1 - emission, 2 - subsurface
 	if (context_raw.material.paint_emis) {
-		node_shader_write(frag, 'if (emis > 0.0) {');
-		node_shader_write(frag, '	matid += 1.0 / 255.0;');
-		node_shader_write(frag, '	if (str == 0.0) discard;');
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "if (emis > 0.0) {");
+		node_shader_write(frag, "	matid += 1.0 / 255.0;");
+		node_shader_write(frag, "	if (str == 0.0) discard;");
+		node_shader_write(frag, "}");
 	}
 	else if (context_raw.material.paint_subs) {
-		node_shader_write(frag, 'if (subs > 0.0) {');
-		node_shader_write(frag, '    matid += 2.0 / 255.0;');
-		node_shader_write(frag, '	if (str == 0.0) discard;');
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "if (subs > 0.0) {");
+		node_shader_write(frag, "    matid += 2.0 / 255.0;");
+		node_shader_write(frag, "	if (str == 0.0) discard;");
+		node_shader_write(frag, "}");
 	}
 
 	let is_mask: bool = slot_layer_is_mask(context_raw.layer);
 	let layered: bool = context_raw.layer != project_layers[0];
 	if (layered && !is_mask) {
 		if (context_raw.tool == workspace_tool_t.ERASER) {
-			node_shader_write(frag, 'fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);');
-			node_shader_write(frag, 'nortan = vec3(0.5, 0.5, 1.0);');
-			node_shader_write(frag, 'occlusion = 1.0;');
-			node_shader_write(frag, 'roughness = 0.0;');
-			node_shader_write(frag, 'metallic = 0.0;');
-			node_shader_write(frag, 'matid = 0.0;');
+			node_shader_write(frag, "fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);");
+			node_shader_write(frag, "nortan = vec3(0.5, 0.5, 1.0);");
+			node_shader_write(frag, "occlusion = 1.0;");
+			node_shader_write(frag, "roughness = 0.0;");
+			node_shader_write(frag, "metallic = 0.0;");
+			node_shader_write(frag, "matid = 0.0;");
 		}
 		else if (context_raw.tool == workspace_tool_t.PARTICLE || decal || context_raw.brush_mask_image != null) {
-			node_shader_write(frag, 'fragColor[0] = vec4(' + make_material_blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'str') + ', max(str, sample_undo.a));');
+			node_shader_write(frag, "fragColor[0] = vec4(" + make_material_blend_mode(frag, context_raw.brush_blending, "sample_undo.rgb", "basecol", "str") + ", max(str, sample_undo.a));");
 		}
 		else {
 			if (context_raw.layer.fill_layer != null) {
-				node_shader_write(frag, 'fragColor[0] = vec4(' + make_material_blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'opacity') + ', mat_opacity);');
+				node_shader_write(frag, "fragColor[0] = vec4(" + make_material_blend_mode(frag, context_raw.brush_blending, "sample_undo.rgb", "basecol", "opacity") + ", mat_opacity);");
 			}
 			else {
-				node_shader_write(frag, 'fragColor[0] = vec4(' + make_material_blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'opacity') + ', max(str, sample_undo.a));');
+				node_shader_write(frag, "fragColor[0] = vec4(" + make_material_blend_mode(frag, context_raw.brush_blending, "sample_undo.rgb", "basecol", "opacity") + ", max(str, sample_undo.a));");
 			}
 		}
-		node_shader_write(frag, 'fragColor[1] = vec4(nortan, matid);');
+		node_shader_write(frag, "fragColor[1] = vec4(nortan, matid);");
 
 		let height: string = "0.0";
 		if (context_raw.material.paint_height && make_material_height_used) {
@@ -399,36 +399,36 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 		}
 
 		if (decal) {
-			node_shader_add_uniform(frag, 'sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
-			node_shader_write(frag, 'vec4 sample_pack_undo = textureLod(texpaint_pack_undo, sample_tc, 0.0);');
-			node_shader_write(frag, `fragColor[2] = mix(sample_pack_undo, vec4(occlusion, roughness, metallic, ${height}), str);`);
+			node_shader_add_uniform(frag, "sampler2D texpaint_pack_undo", "_texpaint_pack_undo");
+			node_shader_write(frag, "vec4 sample_pack_undo = textureLod(texpaint_pack_undo, sample_tc, 0.0);");
+			node_shader_write(frag, "fragColor[2] = mix(sample_pack_undo, vec4(occlusion, roughness, metallic, " + height + "), str);");
 		}
 		else {
-			node_shader_write(frag, `fragColor[2] = vec4(occlusion, roughness, metallic, ${height});`);
+			node_shader_write(frag, "fragColor[2] = vec4(occlusion, roughness, metallic, " + height + ");");
 		}
 	}
 	else {
 		if (context_raw.tool == workspace_tool_t.ERASER) {
-			node_shader_write(frag, 'fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);');
-			node_shader_write(frag, 'fragColor[1] = vec4(0.5, 0.5, 1.0, 0.0);');
-			node_shader_write(frag, 'fragColor[2] = vec4(1.0, 0.0, 0.0, 0.0);');
+			node_shader_write(frag, "fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);");
+			node_shader_write(frag, "fragColor[1] = vec4(0.5, 0.5, 1.0, 0.0);");
+			node_shader_write(frag, "fragColor[2] = vec4(1.0, 0.0, 0.0, 0.0);");
 		}
 		else {
-			node_shader_add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
-			node_shader_add_uniform(frag, 'sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
-			node_shader_write(frag, 'vec4 sample_nor_undo = textureLod(texpaint_nor_undo, sample_tc, 0.0);');
-			node_shader_write(frag, 'vec4 sample_pack_undo = textureLod(texpaint_pack_undo, sample_tc, 0.0);');
-			node_shader_write(frag, 'fragColor[0] = vec4(' + make_material_blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'str') + ', max(str, sample_undo.a));');
-			node_shader_write(frag, 'fragColor[1] = vec4(mix(sample_nor_undo.rgb, nortan, str), matid);');
+			node_shader_add_uniform(frag, "sampler2D texpaint_nor_undo", "_texpaint_nor_undo");
+			node_shader_add_uniform(frag, "sampler2D texpaint_pack_undo", "_texpaint_pack_undo");
+			node_shader_write(frag, "vec4 sample_nor_undo = textureLod(texpaint_nor_undo, sample_tc, 0.0);");
+			node_shader_write(frag, "vec4 sample_pack_undo = textureLod(texpaint_pack_undo, sample_tc, 0.0);");
+			node_shader_write(frag, "fragColor[0] = vec4(" + make_material_blend_mode(frag, context_raw.brush_blending, "sample_undo.rgb", "basecol", "str") + ", max(str, sample_undo.a));");
+			node_shader_write(frag, "fragColor[1] = vec4(mix(sample_nor_undo.rgb, nortan, str), matid);");
 			if (context_raw.material.paint_height && make_material_height_used) {
-				node_shader_write(frag, 'fragColor[2] = mix(sample_pack_undo, vec4(occlusion, roughness, metallic, height), str);');
+				node_shader_write(frag, "fragColor[2] = mix(sample_pack_undo, vec4(occlusion, roughness, metallic, height), str);");
 			}
 			else {
-				node_shader_write(frag, 'fragColor[2] = vec4(mix(sample_pack_undo.rgb, vec3(occlusion, roughness, metallic), str), 0.0);');
+				node_shader_write(frag, "fragColor[2] = vec4(mix(sample_pack_undo.rgb, vec3(occlusion, roughness, metallic), str), 0.0);");
 			}
 		}
 	}
-	node_shader_write(frag, 'fragColor[3] = vec4(str, 0.0, 0.0, 1.0);');
+	node_shader_write(frag, "fragColor[3] = vec4(str, 0.0, 0.0, 1.0);");
 
 	if (!context_raw.material.paint_base) {
 		con_paint.data.color_writes_red[0] = false;
@@ -459,7 +459,7 @@ function make_paint_run(data: material_t, matcon: material_context_t): node_shad
 	// Base color only as mask
 	if (is_mask) {
 		// TODO: Apply opacity into base
-		// write(frag, 'fragColor[0].rgb *= fragColor[0].a;');
+		// write(frag, "fragColor[0].rgb *= fragColor[0].a;");
 		con_paint.data.color_writes_green[0] = false;
 		con_paint.data.color_writes_blue[0] = false;
 		con_paint.data.color_writes_alpha[0] = false;

+ 74 - 74
armorpaint/Sources/make_particle.ts

@@ -14,66 +14,66 @@ function make_particle_run(data: material_t): node_shader_context_t {
 	let frag: node_shader_t = node_shader_context_make_frag(con_part);
 	frag.ins = vert.outs;
 
-	node_shader_write_attrib(vert, 'vec4 spos = vec4(pos.xyz, 1.0);');
+	node_shader_write_attrib(vert, "vec4 spos = vec4(pos.xyz, 1.0);");
 
-	node_shader_add_uniform(vert, 'float brushRadius', '_brushRadius');
-	node_shader_write_attrib(vert, 'vec3 emitFrom = vec3(fhash(gl_InstanceID), fhash(gl_InstanceID * 2), fhash(gl_InstanceID * 3));');
-	node_shader_write_attrib(vert, 'emitFrom = emitFrom * brushRadius - brushRadius / 2.0;');
-	node_shader_write_attrib(vert, 'spos.xyz += emitFrom * vec3(256.0, 256.0, 256.0);');
+	node_shader_add_uniform(vert, "float brushRadius", "_brushRadius");
+	node_shader_write_attrib(vert, "vec3 emitFrom = vec3(fhash(gl_InstanceID), fhash(gl_InstanceID * 2), fhash(gl_InstanceID * 3));");
+	node_shader_write_attrib(vert, "emitFrom = emitFrom * brushRadius - brushRadius / 2.0;");
+	node_shader_write_attrib(vert, "spos.xyz += emitFrom * vec3(256.0, 256.0, 256.0);");
 
-	node_shader_add_uniform(vert, 'mat4 pd', '_particle_data');
+	node_shader_add_uniform(vert, "mat4 pd", "_particle_data");
 
 	let str_tex_hash: string = "float fhash(int n) { return fract(sin(float(n)) * 43758.5453); }\n";
 	node_shader_add_function(vert, str_tex_hash);
-	node_shader_add_out(vert, 'float p_age');
-	node_shader_write(vert, 'p_age = pd[3][3] - float(gl_InstanceID) * pd[0][1];');
-	node_shader_write(vert, 'p_age -= p_age * fhash(gl_InstanceID) * pd[2][3];');
-
-	node_shader_write(vert, 'if (pd[0][0] > 0.0 && p_age < 0.0) p_age += float(int(-p_age / pd[0][0]) + 1) * pd[0][0];');
-
-	node_shader_add_out(vert, 'float p_lifetime');
-	node_shader_write(vert, 'p_lifetime = pd[0][2];');
-	node_shader_write(vert, 'if (p_age < 0.0 || p_age > p_lifetime) {');
-	// write(vert, 'SPIRV_Cross_Output stage_output;');
-	// write(vert, 'stage_output.svpos /= 0.0;');
-	// write(vert, 'return stage_output;');
-	node_shader_write(vert, 'spos /= 0.0;');
-	node_shader_write(vert, '}');
-
-	node_shader_add_out(vert, 'vec3 p_velocity');
-	node_shader_write(vert, 'p_velocity = vec3(pd[1][0], pd[1][1], pd[1][2]);');
-	node_shader_write(vert, 'p_velocity.x += fhash(gl_InstanceID)                     * pd[1][3] - pd[1][3] / 2.0;');
-	node_shader_write(vert, 'p_velocity.y += fhash(gl_InstanceID +     int(pd[0][3])) * pd[1][3] - pd[1][3] / 2.0;');
-	node_shader_write(vert, 'p_velocity.z += fhash(gl_InstanceID + 2 * int(pd[0][3])) * pd[1][3] - pd[1][3] / 2.0;');
-	node_shader_write(vert, 'p_velocity.x += (pd[2][0] * p_age) / 5.0;');
-	node_shader_write(vert, 'p_velocity.y += (pd[2][1] * p_age) / 5.0;');
-	node_shader_write(vert, 'p_velocity.z += (pd[2][2] * p_age) / 5.0;');
-
-	node_shader_add_out(vert, 'vec3 p_location');
-	node_shader_write(vert, 'p_location = p_velocity * p_age;');
-	node_shader_write(vert, 'spos.xyz += p_location;');
-	node_shader_write(vert, 'spos.xyz *= vec3(0.01, 0.01, 0.01);');
-
-	node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
-	node_shader_write(vert, 'gl_Position = mul(spos, WVP);');
-
-	node_shader_add_uniform(vert, 'vec4 inp', '_inputBrush');
-	node_shader_write(vert, 'vec2 binp = vec2(inp.x, 1.0 - inp.y);');
-	node_shader_write(vert, 'binp = binp * 2.0 - 1.0;');
-	node_shader_write(vert, 'binp *= gl_Position.w;');
-	node_shader_write(vert, 'gl_Position.xy += binp;');
-
-	node_shader_add_out(vert, 'float p_fade');
-	node_shader_write(vert, 'p_fade = sin(min((p_age / 8.0) * 3.141592, 3.141592));');
-
-	node_shader_add_out(frag, 'float fragColor');
-	node_shader_write(frag, 'fragColor = p_fade;');
-
-	// add_out(vert, 'vec4 wvpposition');
-	// write(vert, 'wvpposition = gl_Position;');
-	// write(frag, 'vec2 texCoord = wvpposition.xy / wvpposition.w;');
-	// add_uniform(frag, 'sampler2D gbufferD');
-	// write(frag, 'fragColor *= 1.0 - clamp(distance(textureLod(gbufferD, texCoord, 0.0).r, wvpposition.z), 0.0, 1.0);');
+	node_shader_add_out(vert, "float p_age");
+	node_shader_write(vert, "p_age = pd[3][3] - float(gl_InstanceID) * pd[0][1];");
+	node_shader_write(vert, "p_age -= p_age * fhash(gl_InstanceID) * pd[2][3];");
+
+	node_shader_write(vert, "if (pd[0][0] > 0.0 && p_age < 0.0) p_age += float(int(-p_age / pd[0][0]) + 1) * pd[0][0];");
+
+	node_shader_add_out(vert, "float p_lifetime");
+	node_shader_write(vert, "p_lifetime = pd[0][2];");
+	node_shader_write(vert, "if (p_age < 0.0 || p_age > p_lifetime) {");
+	// write(vert, "SPIRV_Cross_Output stage_output;");
+	// write(vert, "stage_output.svpos /= 0.0;");
+	// write(vert, "return stage_output;");
+	node_shader_write(vert, "spos /= 0.0;");
+	node_shader_write(vert, "}");
+
+	node_shader_add_out(vert, "vec3 p_velocity");
+	node_shader_write(vert, "p_velocity = vec3(pd[1][0], pd[1][1], pd[1][2]);");
+	node_shader_write(vert, "p_velocity.x += fhash(gl_InstanceID)                     * pd[1][3] - pd[1][3] / 2.0;");
+	node_shader_write(vert, "p_velocity.y += fhash(gl_InstanceID +     int(pd[0][3])) * pd[1][3] - pd[1][3] / 2.0;");
+	node_shader_write(vert, "p_velocity.z += fhash(gl_InstanceID + 2 * int(pd[0][3])) * pd[1][3] - pd[1][3] / 2.0;");
+	node_shader_write(vert, "p_velocity.x += (pd[2][0] * p_age) / 5.0;");
+	node_shader_write(vert, "p_velocity.y += (pd[2][1] * p_age) / 5.0;");
+	node_shader_write(vert, "p_velocity.z += (pd[2][2] * p_age) / 5.0;");
+
+	node_shader_add_out(vert, "vec3 p_location");
+	node_shader_write(vert, "p_location = p_velocity * p_age;");
+	node_shader_write(vert, "spos.xyz += p_location;");
+	node_shader_write(vert, "spos.xyz *= vec3(0.01, 0.01, 0.01);");
+
+	node_shader_add_uniform(vert, "mat4 WVP", "_world_view_proj_matrix");
+	node_shader_write(vert, "gl_Position = mul(spos, WVP);");
+
+	node_shader_add_uniform(vert, "vec4 inp", "_inputBrush");
+	node_shader_write(vert, "vec2 binp = vec2(inp.x, 1.0 - inp.y);");
+	node_shader_write(vert, "binp = binp * 2.0 - 1.0;");
+	node_shader_write(vert, "binp *= gl_Position.w;");
+	node_shader_write(vert, "gl_Position.xy += binp;");
+
+	node_shader_add_out(vert, "float p_fade");
+	node_shader_write(vert, "p_fade = sin(min((p_age / 8.0) * 3.141592, 3.141592));");
+
+	node_shader_add_out(frag, "float fragColor");
+	node_shader_write(frag, "fragColor = p_fade;");
+
+	// add_out(vert, "vec4 wvpposition");
+	// write(vert, "wvpposition = gl_Position;");
+	// write(frag, "vec2 texCoord = wvpposition.xy / wvpposition.w;");
+	// add_uniform(frag, "sampler2D gbufferD");
+	// write(frag, "fragColor *= 1.0 - clamp(distance(textureLod(gbufferD, texCoord, 0.0).r, wvpposition.z), 0.0, 1.0);");
 
 	// Material.finalize(con_part);
 	con_part.data.shader_from_source = true;
@@ -86,30 +86,30 @@ function make_particle_run(data: material_t): node_shader_context_t {
 function make_particle_mask(vert: node_shader_t, frag: node_shader_t) {
 	///if arm_physics
 	if (context_raw.particle_physics) {
-		node_shader_add_out(vert, 'vec4 wpos');
-		node_shader_add_uniform(vert, 'mat4 W', '_world_matrix');
-		node_shader_write_attrib(vert, 'wpos = mul(vec4(pos.xyz, 1.0), W);');
-		node_shader_add_uniform(frag, 'vec3 particleHit', '_particleHit');
-		node_shader_add_uniform(frag, 'vec3 particleHitLast', '_particleHitLast');
-
-		node_shader_write(frag, 'vec3 pa = wpos.xyz - particleHit;');
-		node_shader_write(frag, 'vec3 ba = particleHitLast - particleHit;');
-		node_shader_write(frag, 'float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);');
-		node_shader_write(frag, 'dist = length(pa - ba * h) * 10.0;');
-		// write(frag, 'dist = distance(particleHit, wpos.xyz) * 10.0;');
-
-		node_shader_write(frag, 'if (dist > 1.0) discard;');
-		node_shader_write(frag, 'float str = clamp(pow(1.0 / dist * brushHardness * 0.2, 4.0), 0.0, 1.0) * opacity;');
-		node_shader_write(frag, 'if (particleHit.x == 0.0 && particleHit.y == 0.0 && particleHit.z == 0.0) str = 0.0;');
-		node_shader_write(frag, 'if (str == 0.0) discard;');
+		node_shader_add_out(vert, "vec4 wpos");
+		node_shader_add_uniform(vert, "mat4 W", "_world_matrix");
+		node_shader_write_attrib(vert, "wpos = mul(vec4(pos.xyz, 1.0), W);");
+		node_shader_add_uniform(frag, "vec3 particleHit", "_particleHit");
+		node_shader_add_uniform(frag, "vec3 particleHitLast", "_particleHitLast");
+
+		node_shader_write(frag, "vec3 pa = wpos.xyz - particleHit;");
+		node_shader_write(frag, "vec3 ba = particleHitLast - particleHit;");
+		node_shader_write(frag, "float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);");
+		node_shader_write(frag, "dist = length(pa - ba * h) * 10.0;");
+		// write(frag, "dist = distance(particleHit, wpos.xyz) * 10.0;");
+
+		node_shader_write(frag, "if (dist > 1.0) discard;");
+		node_shader_write(frag, "float str = clamp(pow(1.0 / dist * brushHardness * 0.2, 4.0), 0.0, 1.0) * opacity;");
+		node_shader_write(frag, "if (particleHit.x == 0.0 && particleHit.y == 0.0 && particleHit.z == 0.0) str = 0.0;");
+		node_shader_write(frag, "if (str == 0.0) discard;");
 		return;
 	}
 	///end
 
-	node_shader_add_uniform(frag, 'sampler2D texparticle', '_texparticle');
+	node_shader_add_uniform(frag, "sampler2D texparticle", "_texparticle");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(frag, 'float str = textureLod(texparticle, sp.xy, 0.0).r;');
+	node_shader_write(frag, "float str = textureLod(texparticle, sp.xy, 0.0).r;");
 	///else
-	node_shader_write(frag, 'float str = textureLod(texparticle, vec2(sp.x, (1.0 - sp.y)), 0.0).r;');
+	node_shader_write(frag, "float str = textureLod(texparticle, vec2(sp.x, (1.0 - sp.y)), 0.0).r;");
 	///end
 }

+ 44 - 44
armorpaint/Sources/make_texcoord.ts

@@ -8,89 +8,89 @@ function make_texcoord_run(vert: node_shader_t, frag: node_shader_t) {
 	let uv_angle: f32 = fill_layer ? context_raw.layer.angle : angle;
 
 	if (uv_type == uv_type_t.PROJECT || decal) { // TexCoords - project
-		node_shader_add_uniform(frag, 'float brushScale', '_brushScale');
-		node_shader_write_attrib(frag, 'vec2 uvsp = sp.xy;');
+		node_shader_add_uniform(frag, "float brushScale", "_brushScale");
+		node_shader_write_attrib(frag, "vec2 uvsp = sp.xy;");
 
 		if (fill_layer) { // Decal layer
-			node_shader_write_attrib(frag, 'if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) discard;');
+			node_shader_write_attrib(frag, "if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) discard;");
 
 			if (uv_angle != 0.0) {
-				node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-				node_shader_write_attrib(frag, 'uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);');
+				node_shader_add_uniform(frag, "vec2 brushAngle", "_brushAngle");
+				node_shader_write_attrib(frag, "uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);");
 			}
 
 			frag.n = true;
-			node_shader_add_uniform(frag, 'vec3 decalLayerNor', '_decalLayerNor');
+			node_shader_add_uniform(frag, "vec3 decalLayerNor", "_decalLayerNor");
 			let dot_angle: f32 = context_raw.brush_angle_reject_dot;
-			node_shader_write(frag, `if (abs(dot(n, decalLayerNor) - 1.0) > ${dot_angle}) discard;`);
+			node_shader_write(frag, "if (abs(dot(n, decalLayerNor) - 1.0) > " + dot_angle + ") discard;");
 
 			frag.wposition = true;
-			node_shader_add_uniform(frag, 'vec3 decalLayerLoc', '_decalLayerLoc');
-			node_shader_add_uniform(frag, 'float decalLayerDim', '_decalLayerDim');
-			node_shader_write_attrib(frag, 'if (abs(dot(decalLayerNor, decalLayerLoc - wposition)) > decalLayerDim) discard;');
+			node_shader_add_uniform(frag, "vec3 decalLayerLoc", "_decalLayerLoc");
+			node_shader_add_uniform(frag, "float decalLayerDim", "_decalLayerDim");
+			node_shader_write_attrib(frag, "if (abs(dot(decalLayerNor, decalLayerLoc - wposition)) > decalLayerDim) discard;");
 		}
 		else if (decal) {
-			node_shader_add_uniform(frag, 'vec4 decalMask', '_decalMask');
-			node_shader_write_attrib(frag, 'uvsp -= decalMask.xy;');
-			node_shader_write_attrib(frag, 'uvsp.x *= aspectRatio;');
-			node_shader_write_attrib(frag, 'uvsp *= 0.21 / (decalMask.w * 0.9);'); // Decal radius
+			node_shader_add_uniform(frag, "vec4 decalMask", "_decalMask");
+			node_shader_write_attrib(frag, "uvsp -= decalMask.xy;");
+			node_shader_write_attrib(frag, "uvsp.x *= aspectRatio;");
+			node_shader_write_attrib(frag, "uvsp *= 0.21 / (decalMask.w * 0.9);"); // Decal radius
 
 			if (context_raw.brush_directional) {
-				node_shader_add_uniform(frag, 'vec3 brushDirection', '_brushDirection');
-				node_shader_write_attrib(frag, 'if (brushDirection.z == 0.0) discard;');
-				node_shader_write_attrib(frag, 'uvsp = vec2(uvsp.x * brushDirection.x - uvsp.y * brushDirection.y, uvsp.x * brushDirection.y + uvsp.y * brushDirection.x);');
+				node_shader_add_uniform(frag, "vec3 brushDirection", "_brushDirection");
+				node_shader_write_attrib(frag, "if (brushDirection.z == 0.0) discard;");
+				node_shader_write_attrib(frag, "uvsp = vec2(uvsp.x * brushDirection.x - uvsp.y * brushDirection.y, uvsp.x * brushDirection.y + uvsp.y * brushDirection.x);");
 			}
 
 			if (uv_angle != 0.0) {
-				node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-				node_shader_write_attrib(frag, 'uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);');
+				node_shader_add_uniform(frag, "vec2 brushAngle", "_brushAngle");
+				node_shader_write_attrib(frag, "uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);");
 			}
 
-			node_shader_add_uniform(frag, 'float brushScaleX', '_brushScaleX');
-			node_shader_write_attrib(frag, 'uvsp.x *= brushScaleX;');
+			node_shader_add_uniform(frag, "float brushScaleX", "_brushScaleX");
+			node_shader_write_attrib(frag, "uvsp.x *= brushScaleX;");
 
-			node_shader_write_attrib(frag, 'uvsp += vec2(0.5, 0.5);');
+			node_shader_write_attrib(frag, "uvsp += vec2(0.5, 0.5);");
 
-			node_shader_write_attrib(frag, 'if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) discard;');
+			node_shader_write_attrib(frag, "if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) discard;");
 		}
 		else {
-			node_shader_write_attrib(frag, 'uvsp.x *= aspectRatio;');
+			node_shader_write_attrib(frag, "uvsp.x *= aspectRatio;");
 
 			if (uv_angle != 0.0) {
-				node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-				node_shader_write_attrib(frag, 'uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);');
+				node_shader_add_uniform(frag, "vec2 brushAngle", "_brushAngle");
+				node_shader_write_attrib(frag, "uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);");
 			}
 		}
 
-		node_shader_write_attrib(frag, 'vec2 texCoord = uvsp * brushScale;');
+		node_shader_write_attrib(frag, "vec2 texCoord = uvsp * brushScale;");
 	}
 	else if (uv_type == uv_type_t.UVMAP) { // TexCoords - uvmap
-		node_shader_add_uniform(vert, 'float brushScale', '_brushScale');
-		node_shader_add_out(vert, 'vec2 texCoord');
-		node_shader_write(vert, 'texCoord = tex * brushScale;');
+		node_shader_add_uniform(vert, "float brushScale", "_brushScale");
+		node_shader_add_out(vert, "vec2 texCoord");
+		node_shader_write(vert, "texCoord = tex * brushScale;");
 
 		if (uv_angle > 0.0) {
-			node_shader_add_uniform(vert, 'vec2 brushAngle', '_brushAngle');
-			node_shader_write(vert, 'texCoord = vec2(texCoord.x * brushAngle.x - texCoord.y * brushAngle.y, texCoord.x * brushAngle.y + texCoord.y * brushAngle.x);');
+			node_shader_add_uniform(vert, "vec2 brushAngle", "_brushAngle");
+			node_shader_write(vert, "texCoord = vec2(texCoord.x * brushAngle.x - texCoord.y * brushAngle.y, texCoord.x * brushAngle.y + texCoord.y * brushAngle.x);");
 		}
 	}
 	else { // TexCoords - triplanar
 		frag.wposition = true;
 		frag.n = true;
-		node_shader_add_uniform(frag, 'float brushScale', '_brushScale');
-		node_shader_write_attrib(frag, 'vec3 triWeight = wnormal * wnormal;'); // n * n
-		node_shader_write_attrib(frag, 'float triMax = max(triWeight.x, max(triWeight.y, triWeight.z));');
-		node_shader_write_attrib(frag, 'triWeight = max(triWeight - triMax * 0.75, 0.0);');
-		node_shader_write_attrib(frag, 'vec3 texCoordBlend = triWeight * (1.0 / (triWeight.x + triWeight.y + triWeight.z));');
-		node_shader_write_attrib(frag, 'vec2 texCoord = wposition.yz * brushScale * 0.5;');
-		node_shader_write_attrib(frag, 'vec2 texCoord1 = wposition.xz * brushScale * 0.5;');
-		node_shader_write_attrib(frag, 'vec2 texCoord2 = wposition.xy * brushScale * 0.5;');
+		node_shader_add_uniform(frag, "float brushScale", "_brushScale");
+		node_shader_write_attrib(frag, "vec3 triWeight = wnormal * wnormal;"); // n * n
+		node_shader_write_attrib(frag, "float triMax = max(triWeight.x, max(triWeight.y, triWeight.z));");
+		node_shader_write_attrib(frag, "triWeight = max(triWeight - triMax * 0.75, 0.0);");
+		node_shader_write_attrib(frag, "vec3 texCoordBlend = triWeight * (1.0 / (triWeight.x + triWeight.y + triWeight.z));");
+		node_shader_write_attrib(frag, "vec2 texCoord = wposition.yz * brushScale * 0.5;");
+		node_shader_write_attrib(frag, "vec2 texCoord1 = wposition.xz * brushScale * 0.5;");
+		node_shader_write_attrib(frag, "vec2 texCoord2 = wposition.xy * brushScale * 0.5;");
 
 		if (uv_angle != 0.0) {
-			node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-			node_shader_write_attrib(frag, 'texCoord = vec2(texCoord.x * brushAngle.x - texCoord.y * brushAngle.y, texCoord.x * brushAngle.y + texCoord.y * brushAngle.x);');
-			node_shader_write_attrib(frag, 'texCoord1 = vec2(texCoord1.x * brushAngle.x - texCoord1.y * brushAngle.y, texCoord1.x * brushAngle.y + texCoord1.y * brushAngle.x);');
-			node_shader_write_attrib(frag, 'texCoord2 = vec2(texCoord2.x * brushAngle.x - texCoord2.y * brushAngle.y, texCoord2.x * brushAngle.y + texCoord2.y * brushAngle.x);');
+			node_shader_add_uniform(frag, "vec2 brushAngle", "_brushAngle");
+			node_shader_write_attrib(frag, "texCoord = vec2(texCoord.x * brushAngle.x - texCoord.y * brushAngle.y, texCoord.x * brushAngle.y + texCoord.y * brushAngle.x);");
+			node_shader_write_attrib(frag, "texCoord1 = vec2(texCoord1.x * brushAngle.x - texCoord1.y * brushAngle.y, texCoord1.x * brushAngle.y + texCoord1.y * brushAngle.x);");
+			node_shader_write_attrib(frag, "texCoord2 = vec2(texCoord2.x * brushAngle.x - texCoord2.y * brushAngle.y, texCoord2.x * brushAngle.y + texCoord2.y * brushAngle.x);");
 		}
 	}
 }

+ 2 - 2
armorpaint/Sources/nodes_brush.ts

@@ -1,5 +1,5 @@
-/// <reference path='./nodes/tex_image_node.ts'/>
-/// <reference path='./nodes/input_node.ts'/>
+/// <reference path="./nodes/tex_image_node.ts"/>
+/// <reference path="./nodes/input_node.ts"/>
 
 let nodes_brush_categories = [_tr("Nodes")];
 

+ 2 - 2
armorpaint/Sources/tab_layers.ts

@@ -55,7 +55,7 @@ function tab_layers_button_2d_view() {
 		ui_base_show_2d_view(view_2d_type_t.LAYER);
 	}
 	else if (ui.is_hovered) {
-		zui_tooltip(tr("Show 2D View") + ` (${config_keymap.toggle_2d_view})`);
+		zui_tooltip(tr("Show 2D View") + " (" + config_keymap.toggle_2d_view + ")");
 	}
 }
 
@@ -216,7 +216,7 @@ function tab_layers_remap_layer_pointers(nodes: zui_node_t[], pointer_map: map_t
 		let n: zui_node_t = nodes[i];
 		if (n.type == "LAYER" || n.type == "LAYER_MASK") {
 			let i: any = n.buttons[0].default_value;
-			if (pointer_map.has(i)) {
+			if (map_get(pointer_map, i) != null) {
 				n.buttons[0].default_value = map_get(pointer_map, i);
 			}
 		}

+ 16 - 16
armorsculpt/Sources/make_brush.ts

@@ -1,36 +1,36 @@
 
 function make_brush_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 
-	node_shader_write(frag, 'float dist = 0.0;');
+	node_shader_write(frag, "float dist = 0.0;");
 
 	if (config_raw.brush_3d) {
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'float depth = textureLod(gbufferD, inp.xy, 0.0).r;');
+		node_shader_write(frag, "float depth = textureLod(gbufferD, inp.xy, 0.0).r;");
 		///else
-		node_shader_write(frag, 'float depth = textureLod(gbufferD, vec2(inp.x, 1.0 - inp.y), 0.0).r;');
+		node_shader_write(frag, "float depth = textureLod(gbufferD, vec2(inp.x, 1.0 - inp.y), 0.0).r;");
 		///end
 
-		node_shader_add_uniform(frag, 'mat4 invVP', '_inv_view_proj_matrix');
-		node_shader_write(frag, 'vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);');
-		node_shader_write(frag, 'winp = mul(winp, invVP);');
-		node_shader_write(frag, 'winp.xyz /= winp.w;');
+		node_shader_add_uniform(frag, "mat4 invVP", "_inv_view_proj_matrix");
+		node_shader_write(frag, "vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);");
+		node_shader_write(frag, "winp = mul(winp, invVP);");
+		node_shader_write(frag, "winp.xyz /= winp.w;");
 
-		node_shader_add_uniform(frag, 'mat4 W', '_world_matrix');
+		node_shader_add_uniform(frag, "mat4 W", "_world_matrix");
 
-		node_shader_write_attrib(frag, 'vec3 wposition = mul(texelFetch(texpaint_undo, ivec2(texCoord.x * textureSize(texpaint_undo, 0).x, texCoord.y * textureSize(texpaint_undo, 0).y), 0), W).xyz;');
+		node_shader_write_attrib(frag, "vec3 wposition = mul(texelFetch(texpaint_undo, ivec2(texCoord.x * textureSize(texpaint_undo, 0).x, texCoord.y * textureSize(texpaint_undo, 0).y), 0), W).xyz;");
 
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'float depthlast = textureLod(gbufferD, inplast.xy, 0.0).r;');
+		node_shader_write(frag, "float depthlast = textureLod(gbufferD, inplast.xy, 0.0).r;");
 		///else
-		node_shader_write(frag, 'float depthlast = textureLod(gbufferD, vec2(inplast.x, 1.0 - inplast.y), 0.0).r;');
+		node_shader_write(frag, "float depthlast = textureLod(gbufferD, vec2(inplast.x, 1.0 - inplast.y), 0.0).r;");
 		///end
 
-		node_shader_write(frag, 'vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);');
-		node_shader_write(frag, 'winplast = mul(winplast, invVP);');
-		node_shader_write(frag, 'winplast.xyz /= winplast.w;');
+		node_shader_write(frag, "vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);");
+		node_shader_write(frag, "winplast = mul(winplast, invVP);");
+		node_shader_write(frag, "winplast.xyz /= winplast.w;");
 
-		node_shader_write(frag, 'dist = distance(wposition, winp.xyz);');
+		node_shader_write(frag, "dist = distance(wposition, winp.xyz);");
 	}
 
-	node_shader_write(frag, 'if (dist > brushRadius) discard;');
+	node_shader_write(frag, "if (dist > brushRadius) discard;");
 }

+ 1 - 1
armorsculpt/Sources/make_material.ts

@@ -366,7 +366,7 @@ function make_material_get_displace_strength(): f32 {
 
 function make_material_voxelgi_half_extents(): string {
 	let ext = context_raw.vxao_ext;
-	return `const vec3 voxelgiHalfExtents = vec3(${ext}, ${ext}, ${ext});`;
+	return "const vec3 voxelgiHalfExtents = vec3(" + ext + ", " + ext + ", " + ext + ");";
 }
 
 function make_material_delete_context(c: shader_context_t) {

+ 154 - 154
armorsculpt/Sources/make_mesh.ts

@@ -17,96 +17,96 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 	let frag = node_shader_context_make_frag(con_mesh);
 	frag.ins = vert.outs;
 
-	node_shader_add_out(vert, 'vec2 texCoord');
+	node_shader_add_out(vert, "vec2 texCoord");
 	frag.wvpposition = true;
-	node_shader_add_out(vert, 'vec4 prevwvpposition');
-	node_shader_add_uniform(vert, 'mat4 VP', '_view_proj_matrix');
-	node_shader_add_uniform(vert, 'mat4 prevWVP', '_prev_world_view_proj_matrix');
+	node_shader_add_out(vert, "vec4 prevwvpposition");
+	node_shader_add_uniform(vert, "mat4 VP", "_view_proj_matrix");
+	node_shader_add_uniform(vert, "mat4 prevWVP", "_prev_world_view_proj_matrix");
 	vert.wposition = true;
 
 	let texture_count: i32 = 0;
 
-	node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
-	node_shader_add_uniform(vert, 'sampler2D texpaint_vert', '_texpaint_vert' + project_layers[0].id);
-	node_shader_write(vert, 'vec3 meshpos = texelFetch(texpaint_vert, ivec2(gl_VertexID % textureSize(texpaint_vert, 0).x, gl_VertexID / textureSize(texpaint_vert, 0).y), 0).xyz;');
+	node_shader_add_uniform(vert, "mat4 WVP", "_world_view_proj_matrix");
+	node_shader_add_uniform(vert, "sampler2D texpaint_vert", "_texpaint_vert" + project_layers[0].id);
+	node_shader_write(vert, "vec3 meshpos = texelFetch(texpaint_vert, ivec2(gl_VertexID % textureSize(texpaint_vert, 0).x, gl_VertexID / textureSize(texpaint_vert, 0).y), 0).xyz;");
 	// + pos.xyz * 0.000001
-	node_shader_write(vert, 'gl_Position = mul(vec4(meshpos.xyz, 1.0), WVP);');
+	node_shader_write(vert, "gl_Position = mul(vec4(meshpos.xyz, 1.0), WVP);");
 
-	node_shader_write(vert, 'texCoord = vec2(0.0, 0.0);');
+	node_shader_write(vert, "texCoord = vec2(0.0, 0.0);");
 
-	node_shader_write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
+	node_shader_write(vert, "prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);");
 
-	node_shader_add_out(frag, 'vec4 fragColor[3]');
+	node_shader_add_out(frag, "vec4 fragColor[3]");
 
 	node_shader_add_uniform(vert, "mat3 N", "_normal_matrix");
 	node_shader_add_out(vert, "vec3 wnormal");
 
-	node_shader_write_attrib(vert, 'int baseVertex0 = gl_VertexID - (gl_VertexID % 3);');
-	node_shader_write_attrib(vert, 'int baseVertex1 = baseVertex0 + 1;');
-	node_shader_write_attrib(vert, 'int baseVertex2 = baseVertex0 + 2;');
-	node_shader_write_attrib(vert, 'vec3 meshpos0 = texelFetch(texpaint_vert, ivec2(baseVertex0 % textureSize(texpaint_vert, 0).x, baseVertex0 / textureSize(texpaint_vert, 0).y), 0).xyz;');
-	node_shader_write_attrib(vert, 'vec3 meshpos1 = texelFetch(texpaint_vert, ivec2(baseVertex1 % textureSize(texpaint_vert, 0).x, baseVertex1 / textureSize(texpaint_vert, 0).y), 0).xyz;');
-	node_shader_write_attrib(vert, 'vec3 meshpos2 = texelFetch(texpaint_vert, ivec2(baseVertex2 % textureSize(texpaint_vert, 0).x, baseVertex2 / textureSize(texpaint_vert, 0).y), 0).xyz;');
-	node_shader_write_attrib(vert, 'vec3 meshnor = normalize(cross(meshpos2 - meshpos1, meshpos0 - meshpos1));');
-	node_shader_write_attrib(vert, 'wnormal = mul(meshnor, N);');
-	node_shader_write_attrib(frag, 'vec3 n = normalize(wnormal);');
+	node_shader_write_attrib(vert, "int baseVertex0 = gl_VertexID - (gl_VertexID % 3);");
+	node_shader_write_attrib(vert, "int baseVertex1 = baseVertex0 + 1;");
+	node_shader_write_attrib(vert, "int baseVertex2 = baseVertex0 + 2;");
+	node_shader_write_attrib(vert, "vec3 meshpos0 = texelFetch(texpaint_vert, ivec2(baseVertex0 % textureSize(texpaint_vert, 0).x, baseVertex0 / textureSize(texpaint_vert, 0).y), 0).xyz;");
+	node_shader_write_attrib(vert, "vec3 meshpos1 = texelFetch(texpaint_vert, ivec2(baseVertex1 % textureSize(texpaint_vert, 0).x, baseVertex1 / textureSize(texpaint_vert, 0).y), 0).xyz;");
+	node_shader_write_attrib(vert, "vec3 meshpos2 = texelFetch(texpaint_vert, ivec2(baseVertex2 % textureSize(texpaint_vert, 0).x, baseVertex2 / textureSize(texpaint_vert, 0).y), 0).xyz;");
+	node_shader_write_attrib(vert, "vec3 meshnor = normalize(cross(meshpos2 - meshpos1, meshpos0 - meshpos1));");
+	node_shader_write_attrib(vert, "wnormal = mul(meshnor, N);");
+	node_shader_write_attrib(frag, "vec3 n = normalize(wnormal);");
 
 	node_shader_add_function(frag, str_pack_float_int16);
 	node_shader_add_function(frag, str_octahedron_wrap);
 	node_shader_add_function(frag, str_cotangent_frame);
 	if (layer_pass > 0) {
-		node_shader_add_uniform(frag, 'sampler2D gbuffer0');
-		node_shader_add_uniform(frag, 'sampler2D gbuffer1');
-		node_shader_add_uniform(frag, 'sampler2D gbuffer2');
-		node_shader_write(frag, 'vec2 fragcoord = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
+		node_shader_add_uniform(frag, "sampler2D gbuffer0");
+		node_shader_add_uniform(frag, "sampler2D gbuffer1");
+		node_shader_add_uniform(frag, "sampler2D gbuffer2");
+		node_shader_write(frag, "vec2 fragcoord = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;");
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'fragcoord.y = 1.0 - fragcoord.y;');
+		node_shader_write(frag, "fragcoord.y = 1.0 - fragcoord.y;");
 		///end
-		node_shader_write(frag, 'vec4 gbuffer0_sample = textureLod(gbuffer0, fragcoord, 0.0);');
-		node_shader_write(frag, 'vec4 gbuffer1_sample = textureLod(gbuffer1, fragcoord, 0.0);');
-		node_shader_write(frag, 'vec4 gbuffer2_sample = textureLod(gbuffer2, fragcoord, 0.0);');
-		node_shader_write(frag, 'vec3 basecol = gbuffer0_sample.rgb;');
-		node_shader_write(frag, 'float roughness = gbuffer2_sample.g;');
-		node_shader_write(frag, 'float metallic = gbuffer2_sample.b;');
-		node_shader_write(frag, 'float occlusion = gbuffer2_sample.r;');
-		node_shader_write(frag, 'float opacity = 1.0;//gbuffer0_sample.a;');
-		node_shader_write(frag, 'float matid = gbuffer1_sample.a;');
-		node_shader_write(frag, 'vec3 ntex = gbuffer1_sample.rgb;');
-		node_shader_write(frag, 'float height = gbuffer2_sample.a;');
+		node_shader_write(frag, "vec4 gbuffer0_sample = textureLod(gbuffer0, fragcoord, 0.0);");
+		node_shader_write(frag, "vec4 gbuffer1_sample = textureLod(gbuffer1, fragcoord, 0.0);");
+		node_shader_write(frag, "vec4 gbuffer2_sample = textureLod(gbuffer2, fragcoord, 0.0);");
+		node_shader_write(frag, "vec3 basecol = gbuffer0_sample.rgb;");
+		node_shader_write(frag, "float roughness = gbuffer2_sample.g;");
+		node_shader_write(frag, "float metallic = gbuffer2_sample.b;");
+		node_shader_write(frag, "float occlusion = gbuffer2_sample.r;");
+		node_shader_write(frag, "float opacity = 1.0;//gbuffer0_sample.a;");
+		node_shader_write(frag, "float matid = gbuffer1_sample.a;");
+		node_shader_write(frag, "vec3 ntex = gbuffer1_sample.rgb;");
+		node_shader_write(frag, "float height = gbuffer2_sample.a;");
 	}
 	else {
-		node_shader_write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-		node_shader_write(frag, 'float roughness = 0.3;');
-		node_shader_write(frag, 'float metallic = 0.0;');
-		node_shader_write(frag, 'float occlusion = 1.0;');
-		node_shader_write(frag, 'float opacity = 1.0;');
-		node_shader_write(frag, 'float matid = 0.0;');
-		node_shader_write(frag, 'vec3 ntex = vec3(0.5, 0.5, 1.0);');
-		node_shader_write(frag, 'float height = 0.0;');
+		node_shader_write(frag, "vec3 basecol = vec3(0.0, 0.0, 0.0);");
+		node_shader_write(frag, "float roughness = 0.3;");
+		node_shader_write(frag, "float metallic = 0.0;");
+		node_shader_write(frag, "float occlusion = 1.0;");
+		node_shader_write(frag, "float opacity = 1.0;");
+		node_shader_write(frag, "float matid = 0.0;");
+		node_shader_write(frag, "vec3 ntex = vec3(0.5, 0.5, 1.0);");
+		node_shader_write(frag, "float height = 0.0;");
 	}
-	node_shader_write(frag, 'vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);');
-	node_shader_write(frag, 'vec4 texpaint_nor_sample;');
-	node_shader_write(frag, 'vec4 texpaint_pack_sample;');
-	node_shader_write(frag, 'float texpaint_opac;');
+	node_shader_write(frag, "vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);");
+	node_shader_write(frag, "vec4 texpaint_nor_sample;");
+	node_shader_write(frag, "vec4 texpaint_pack_sample;");
+	node_shader_write(frag, "float texpaint_opac;");
 
 	if (make_material_height_used) {
-		node_shader_write(frag, 'float height0 = 0.0;');
-		node_shader_write(frag, 'float height1 = 0.0;');
-		node_shader_write(frag, 'float height2 = 0.0;');
-		node_shader_write(frag, 'float height3 = 0.0;');
+		node_shader_write(frag, "float height0 = 0.0;");
+		node_shader_write(frag, "float height1 = 0.0;");
+		node_shader_write(frag, "float height2 = 0.0;");
+		node_shader_write(frag, "float height3 = 0.0;");
 	}
 
 	if (context_raw.draw_wireframe) {
 		texture_count++;
-		node_shader_add_uniform(frag, 'sampler2D texuvmap', '_texuvmap');
+		node_shader_add_uniform(frag, "sampler2D texuvmap", "_texuvmap");
 	}
 
 	if (context_raw.viewport_mode == viewport_mode_t.LIT && context_raw.render_mode == render_mode_t.FORWARD) {
 		texture_count += 4;
-		node_shader_add_uniform(frag, 'sampler2D senvmapBrdf', "$brdf.k");
-		node_shader_add_uniform(frag, 'sampler2D senvmapRadiance', '_envmap_radiance');
-		node_shader_add_uniform(frag, 'sampler2D sltcMat', '_ltcMat');
-		node_shader_add_uniform(frag, 'sampler2D sltcMag', '_ltcMag');
+		node_shader_add_uniform(frag, "sampler2D senvmapBrdf", "$brdf.k");
+		node_shader_add_uniform(frag, "sampler2D senvmapRadiance", "_envmap_radiance");
+		node_shader_add_uniform(frag, "sampler2D sltcMat", "_ltcMat");
+		node_shader_add_uniform(frag, "sampler2D sltcMag", "_ltcMag");
 	}
 
 	// Get layers for this pass
@@ -139,27 +139,27 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 	for (let i: i32 = 0; i < layers.length; ++i) {
 		let l = layers[i];
 		if (slot_layer_get_object_mask(l) > 0) {
-			node_shader_add_uniform(frag, 'int uid', '_uid');
+			node_shader_add_uniform(frag, "int uid", "_uid");
 			if (slot_layer_get_object_mask(l) > project_paint_objects.length) { // Atlas
 				let visibles = project_get_atlas_objects(slot_layer_get_object_mask(l));
-				node_shader_write(frag, 'if (');
+				node_shader_write(frag, "if (");
 				for (let i: i32 = 0; i < visibles.length; ++i) {
 					if (i > 0) {
-						node_shader_write(frag, ' || ');
+						node_shader_write(frag, " || ");
 					}
-					node_shader_write(frag, `${visibles[i].base.uid} == uid`);
+					node_shader_write(frag, visibles[i].base.uid + " == uid");
 				}
-				node_shader_write(frag, ') {');
+				node_shader_write(frag, ") {");
 			}
 			else { // Object mask
 				let uid = project_paint_objects[slot_layer_get_object_mask(l) - 1].base.uid;
-				node_shader_write(frag, `if (${uid} == uid) {`);
+				node_shader_write(frag, "if (" + uid + " == uid) {");
 			}
 		}
 
-		node_shader_add_shared_sampler(frag, 'sampler2D texpaint' + l.id);
-		node_shader_write(frag, 'texpaint_sample = vec4(0.8, 0.8, 0.8, 1.0);');
-		node_shader_write(frag, 'texpaint_opac = texpaint_sample.a;');
+		node_shader_add_shared_sampler(frag, "sampler2D texpaint" + l.id);
+		node_shader_write(frag, "texpaint_sample = vec4(0.8, 0.8, 0.8, 1.0);");
+		node_shader_write(frag, "texpaint_opac = texpaint_sample.a;");
 
 		let masks = slot_layer_get_masks(l);
 		if (masks != null) {
@@ -172,61 +172,61 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 				}
 			}
 			if (has_visible) {
-				let texpaint_mask = 'texpaint_mask' + l.id;
-				node_shader_write(frag, `float ${texpaint_mask} = 0.0;`);
+				let texpaint_mask = "texpaint_mask" + l.id;
+				node_shader_write(frag, "float " + texpaint_mask + " = 0.0;");
 				for (let i: i32 = 0; i < masks.length; ++i) {
 					let m = masks[i];
 					if (!slot_layer_is_visible(m)) continue;
-					node_shader_add_shared_sampler(frag, 'sampler2D texpaint' + m.id);
-					node_shader_write(frag, '{'); // Group mask is sampled across multiple layers
-					node_shader_write(frag, 'float texpaint_mask_sample' + m.id + ' = textureLodShared(texpaint' + m.id + ', texCoord, 0.0).r;');
-					node_shader_write(frag, '}');
+					node_shader_add_shared_sampler(frag, "sampler2D texpaint" + m.id);
+					node_shader_write(frag, "{"); // Group mask is sampled across multiple layers
+					node_shader_write(frag, "float texpaint_mask_sample" + m.id + " = textureLodShared(texpaint" + m.id + ", texCoord, 0.0).r;");
+					node_shader_write(frag, "}");
 				}
-				node_shader_write(frag, `texpaint_opac *= clamp(${texpaint_mask}, 0.0, 1.0);`);
+				node_shader_write(frag, "texpaint_opac *= clamp(" + texpaint_mask + ", 0.0, 1.0);");
 			}
 		}
 
 		if (slot_layer_get_opacity(l) < 1) {
-			node_shader_write(frag, `texpaint_opac *= ${slot_layer_get_opacity(l)};`);
+			node_shader_write(frag, "texpaint_opac *= " + slot_layer_get_opacity(l) + ";");
 		}
 
 		if (l == project_layers[0]) {
-			node_shader_write(frag, 'basecol = vec3(0.8, 0.8, 0.8);// texpaint_sample.rgb * texpaint_opac;');
+			node_shader_write(frag, "basecol = vec3(0.8, 0.8, 0.8);// texpaint_sample.rgb * texpaint_opac;");
 		}
 
 		if (slot_layer_get_object_mask(l) > 0) {
-			node_shader_write(frag, '}');
+			node_shader_write(frag, "}");
 		}
 
 		if (last_pass && context_raw.draw_texels) {
-			node_shader_add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-			node_shader_write(frag, 'vec2 texel0 = texCoord * texpaintSize * 0.01;');
-			node_shader_write(frag, 'vec2 texel1 = texCoord * texpaintSize * 0.1;');
-			node_shader_write(frag, 'vec2 texel2 = texCoord * texpaintSize;');
-			node_shader_write(frag, 'basecol *= max(float(mod(int(texel0.x), 2.0) == mod(int(texel0.y), 2.0)), 0.9);');
-			node_shader_write(frag, 'basecol *= max(float(mod(int(texel1.x), 2.0) == mod(int(texel1.y), 2.0)), 0.9);');
-			node_shader_write(frag, 'basecol *= max(float(mod(int(texel2.x), 2.0) == mod(int(texel2.y), 2.0)), 0.9);');
+			node_shader_add_uniform(frag, "vec2 texpaintSize", "_texpaintSize");
+			node_shader_write(frag, "vec2 texel0 = texCoord * texpaintSize * 0.01;");
+			node_shader_write(frag, "vec2 texel1 = texCoord * texpaintSize * 0.1;");
+			node_shader_write(frag, "vec2 texel2 = texCoord * texpaintSize;");
+			node_shader_write(frag, "basecol *= max(float(mod(int(texel0.x), 2.0) == mod(int(texel0.y), 2.0)), 0.9);");
+			node_shader_write(frag, "basecol *= max(float(mod(int(texel1.x), 2.0) == mod(int(texel1.y), 2.0)), 0.9);");
+			node_shader_write(frag, "basecol *= max(float(mod(int(texel2.x), 2.0) == mod(int(texel2.y), 2.0)), 0.9);");
 		}
 
 		if (last_pass && context_raw.draw_wireframe) {
-			node_shader_write(frag, 'basecol *= 1.0 - textureLod(texuvmap, texCoord, 0.0).r;');
+			node_shader_write(frag, "basecol *= 1.0 - textureLod(texuvmap, texCoord, 0.0).r;");
 		}
 
 		if (make_material_height_used) {
-			node_shader_write(frag, 'if (height > 0.0) {');
-			node_shader_write(frag, 'float height_dx = height0 - height1;');
-			node_shader_write(frag, 'float height_dy = height2 - height3;');
+			node_shader_write(frag, "if (height > 0.0) {");
+			node_shader_write(frag, "float height_dx = height0 - height1;");
+			node_shader_write(frag, "float height_dy = height2 - height3;");
 			// Whiteout blend
-			node_shader_write(frag, 'vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-			node_shader_write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-			node_shader_write(frag, 'ntex = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);');
-			node_shader_write(frag, '}');
+			node_shader_write(frag, "vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
+			node_shader_write(frag, "vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));");
+			node_shader_write(frag, "ntex = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);");
+			node_shader_write(frag, "}");
 		}
 
 		if (!last_pass) {
-			node_shader_write(frag, 'fragColor[0] = vec4(basecol, opacity);');
-			node_shader_write(frag, 'fragColor[1] = vec4(ntex, matid);');
-			node_shader_write(frag, 'fragColor[2] = vec4(occlusion, roughness, metallic, height);');
+			node_shader_write(frag, "fragColor[0] = vec4(basecol, opacity);");
+			node_shader_write(frag, "fragColor[1] = vec4(ntex, matid);");
+			node_shader_write(frag, "fragColor[2] = vec4(occlusion, roughness, metallic, height);");
 			parser_material_finalize(con_mesh);
 			con_mesh.data.shader_from_source = true;
 			con_mesh.data.vertex_shader = node_shader_get(vert);
@@ -236,100 +236,100 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 
 		frag.vvec = true;
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, vVec, texCoord);");
 		///else
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, -vVec, texCoord);");
 		///end
-		node_shader_write(frag, 'n = ntex * 2.0 - 1.0;');
-		node_shader_write(frag, 'n.y = -n.y;');
-		node_shader_write(frag, 'n = normalize(mul(n, TBN));');
+		node_shader_write(frag, "n = ntex * 2.0 - 1.0;");
+		node_shader_write(frag, "n.y = -n.y;");
+		node_shader_write(frag, "n = normalize(mul(n, TBN));");
 
 		if (context_raw.viewport_mode == viewport_mode_t.LIT) {
 
-			node_shader_write(frag, 'basecol = pow(basecol, vec3(2.2, 2.2, 2.2));');
+			node_shader_write(frag, "basecol = pow(basecol, vec3(2.2, 2.2, 2.2));");
 
 			if (context_raw.viewport_shader != null) {
 				let color = context_raw.viewport_shader(frag);
-				node_shader_write(frag, `fragColor[1] = vec4(${color}, 1.0);`);
+				node_shader_write(frag, "fragColor[1] = vec4(" + color + ", 1.0);");
 			}
 			else if (context_raw.render_mode == render_mode_t.FORWARD) {
 				frag.wposition = true;
-				node_shader_write(frag, 'vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);');
-				node_shader_write(frag, 'vec3 f0 = mix(vec3(0.04, 0.04, 0.04), basecol, metallic);');
+				node_shader_write(frag, "vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);");
+				node_shader_write(frag, "vec3 f0 = mix(vec3(0.04, 0.04, 0.04), basecol, metallic);");
 				frag.vvec = true;
-				node_shader_write(frag, 'float dotNV = max(0.0, dot(n, vVec));');
-				node_shader_write(frag, 'vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;');
-				node_shader_add_uniform(frag, 'int envmapNumMipmaps', '_envmap_num_mipmaps');
-				node_shader_add_uniform(frag, 'vec4 envmapData', '_envmapData'); // angle, sin(angle), cos(angle), strength
-				node_shader_write(frag, 'vec3 wreflect = reflect(-vVec, n);');
-				node_shader_write(frag, 'float envlod = roughness * float(envmapNumMipmaps);');
+				node_shader_write(frag, "float dotNV = max(0.0, dot(n, vVec));");
+				node_shader_write(frag, "vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;");
+				node_shader_add_uniform(frag, "int envmapNumMipmaps", "_envmap_num_mipmaps");
+				node_shader_add_uniform(frag, "vec4 envmapData", "_envmapData"); // angle, sin(angle), cos(angle), strength
+				node_shader_write(frag, "vec3 wreflect = reflect(-vVec, n);");
+				node_shader_write(frag, "float envlod = roughness * float(envmapNumMipmaps);");
 				node_shader_add_function(frag, str_envmap_equirect);
-				node_shader_write(frag, 'vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;');
-				node_shader_add_uniform(frag, 'vec3 lightArea0', '_light_area0');
-				node_shader_add_uniform(frag, 'vec3 lightArea1', '_light_area1');
-				node_shader_add_uniform(frag, 'vec3 lightArea2', '_light_area2');
-				node_shader_add_uniform(frag, 'vec3 lightArea3', '_light_area3');
+				node_shader_write(frag, "vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;");
+				node_shader_add_uniform(frag, "vec3 lightArea0", "_light_area0");
+				node_shader_add_uniform(frag, "vec3 lightArea1", "_light_area1");
+				node_shader_add_uniform(frag, "vec3 lightArea2", "_light_area2");
+				node_shader_add_uniform(frag, "vec3 lightArea3", "_light_area3");
 				node_shader_add_function(frag, str_ltc_evaluate);
-				node_shader_add_uniform(frag, 'vec3 lightPos', '_point_pos');
-				node_shader_add_uniform(frag, 'vec3 lightColor', '_point_color');
-				node_shader_write(frag, 'float ldist = distance(wposition, lightPos);');
-				node_shader_write(frag, 'const float LUT_SIZE = 64.0;');
-				node_shader_write(frag, 'const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;');
-				node_shader_write(frag, 'const float LUT_BIAS = 0.5 / LUT_SIZE;');
-				node_shader_write(frag, 'float theta = acos(dotNV);');
-				node_shader_write(frag, 'vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));');
-				node_shader_write(frag, 'tuv = tuv * LUT_SCALE + LUT_BIAS;');
-				node_shader_write(frag, 'vec4 t = textureLod(sltcMat, tuv, 0.0);');
-				node_shader_write(frag, 'mat3 minv = mat3(vec3(1.0, 0.0, t.y), vec3(0.0, t.z, 0.0), vec3(t.w, 0.0, t.x));');
-				node_shader_write(frag, 'float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);');
-				node_shader_write(frag, 'ltcspec *= textureLod(sltcMag, tuv, 0.0).a;');
-				node_shader_write(frag, 'mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);');
-				node_shader_write(frag, 'float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);');
-				node_shader_write(frag, 'vec3 direct = albedo * ltcdiff + ltcspec * 0.05;');
-				node_shader_write(frag, 'direct *= lightColor * (1.0 / (ldist * ldist));');
-
-				node_shader_add_uniform(frag, 'vec4 shirr[7]', '_envmap_irradiance');
+				node_shader_add_uniform(frag, "vec3 lightPos", "_point_pos");
+				node_shader_add_uniform(frag, "vec3 lightColor", "_point_color");
+				node_shader_write(frag, "float ldist = distance(wposition, lightPos);");
+				node_shader_write(frag, "const float LUT_SIZE = 64.0;");
+				node_shader_write(frag, "const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;");
+				node_shader_write(frag, "const float LUT_BIAS = 0.5 / LUT_SIZE;");
+				node_shader_write(frag, "float theta = acos(dotNV);");
+				node_shader_write(frag, "vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));");
+				node_shader_write(frag, "tuv = tuv * LUT_SCALE + LUT_BIAS;");
+				node_shader_write(frag, "vec4 t = textureLod(sltcMat, tuv, 0.0);");
+				node_shader_write(frag, "mat3 minv = mat3(vec3(1.0, 0.0, t.y), vec3(0.0, t.z, 0.0), vec3(t.w, 0.0, t.x));");
+				node_shader_write(frag, "float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);");
+				node_shader_write(frag, "ltcspec *= textureLod(sltcMag, tuv, 0.0).a;");
+				node_shader_write(frag, "mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);");
+				node_shader_write(frag, "float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);");
+				node_shader_write(frag, "vec3 direct = albedo * ltcdiff + ltcspec * 0.05;");
+				node_shader_write(frag, "direct *= lightColor * (1.0 / (ldist * ldist));");
+
+				node_shader_add_uniform(frag, "vec4 shirr[7]", "_envmap_irradiance");
 				node_shader_add_function(frag, str_sh_irradiance());
-				node_shader_write(frag, 'vec3 indirect = albedo * (shIrradiance(vec3(n.x * envmapData.z - n.y * envmapData.y, n.x * envmapData.y + n.y * envmapData.z, n.z), shirr) / 3.14159265);');
-				node_shader_write(frag, 'indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;');
-				node_shader_write(frag, 'indirect *= envmapData.w * occlusion;');
-				node_shader_write(frag, 'fragColor[1] = vec4(direct + indirect, 1.0);');
+				node_shader_write(frag, "vec3 indirect = albedo * (shIrradiance(vec3(n.x * envmapData.z - n.y * envmapData.y, n.x * envmapData.y + n.y * envmapData.z, n.z), shirr) / 3.14159265);");
+				node_shader_write(frag, "indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;");
+				node_shader_write(frag, "indirect *= envmapData.w * occlusion;");
+				node_shader_write(frag, "fragColor[1] = vec4(direct + indirect, 1.0);");
 			}
 			else { // Deferred, Pathtraced
 				if (make_material_emis_used) {
-					node_shader_write(frag, 'if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;'); // Boost for bloom
+					node_shader_write(frag, "if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;"); // Boost for bloom
 				}
-				node_shader_write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
+				node_shader_write(frag, "fragColor[1] = vec4(basecol, occlusion);");
 			}
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.OBJECT_NORMAL) {
 			frag.nattr = true;
-			node_shader_write(frag, 'fragColor[1] = vec4(nAttr, 1.0);');
+			node_shader_write(frag, "fragColor[1] = vec4(nAttr, 1.0);");
 		}
 		else if (context_raw.viewport_mode == viewport_mode_t.OBJECT_ID) {
-			node_shader_add_uniform(frag, 'float objectId', '_objectId');
-			node_shader_write(frag, 'float obid = objectId + 1.0 / 255.0;');
-			node_shader_write(frag, 'float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			node_shader_write(frag, 'fragColor[1] = vec4(id_r, id_g, id_b, 1.0);');
+			node_shader_add_uniform(frag, "float objectId", "_objectId");
+			node_shader_write(frag, "float obid = objectId + 1.0 / 255.0;");
+			node_shader_write(frag, "float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);");
+			node_shader_write(frag, "fragColor[1] = vec4(id_r, id_g, id_b, 1.0);");
 		}
 		else {
-			node_shader_write(frag, 'fragColor[1] = vec4(1.0, 0.0, 1.0, 1.0);'); // Pink
+			node_shader_write(frag, "fragColor[1] = vec4(1.0, 0.0, 1.0, 1.0);"); // Pink
 		}
 
 		if (context_raw.viewport_mode != viewport_mode_t.LIT && context_raw.viewport_mode != viewport_mode_t.PATH_TRACE) {
-			node_shader_write(frag, 'fragColor[1].rgb = pow(fragColor[1].rgb, vec3(2.2, 2.2, 2.2));');
+			node_shader_write(frag, "fragColor[1].rgb = pow(fragColor[1].rgb, vec3(2.2, 2.2, 2.2));");
 		}
 
-		node_shader_write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-		node_shader_write(frag, 'n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);');
-		node_shader_write(frag, 'fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, uint(int(matid * 255.0) % 3)));');
+		node_shader_write(frag, "n /= (abs(n.x) + abs(n.y) + abs(n.z));");
+		node_shader_write(frag, "n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);");
+		node_shader_write(frag, "fragColor[0] = vec4(n.xy, roughness, packFloatInt16(metallic, uint(int(matid * 255.0) % 3)));");
 	}
 
-	node_shader_write(frag, 'vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
-	node_shader_write(frag, 'vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;');
-	node_shader_write(frag, 'fragColor[2] = vec4(posa - posb, texCoord.xy);');
+	node_shader_write(frag, "vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;");
+	node_shader_write(frag, "vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;");
+	node_shader_write(frag, "fragColor[2] = vec4(posa - posb, texCoord.xy);");
 
 	parser_material_finalize(con_mesh);
 	con_mesh.data.shader_from_source = true;

+ 56 - 56
armorsculpt/Sources/make_mesh_preview.ts

@@ -22,28 +22,28 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): No
 	let skin = mesh_data_get_vertex_array(context_raw.paint_object.data, "bone") != null;
 	if (skin) {
 		pos = "spos";
-		node_shader_context_add_elem(con_mesh, "bone", 'short4norm');
-		node_shader_context_add_elem(con_mesh, "weight", 'short4norm');
+		node_shader_context_add_elem(con_mesh, "bone", "short4norm");
+		node_shader_context_add_elem(con_mesh, "weight", "short4norm");
 		node_shader_add_function(vert, str_get_skinning_dual_quat);
-		node_shader_add_uniform(vert, 'vec4 skinBones[128 * 2]', '_skin_bones');
-		node_shader_add_uniform(vert, 'float posUnpack', '_pos_unpack');
-		node_shader_write_attrib(vert, 'vec4 skinA;');
-		node_shader_write_attrib(vert, 'vec4 skinB;');
-		node_shader_write_attrib(vert, 'getSkinningDualQuat(ivec4(bone * 32767), weight, skinA, skinB);');
-		node_shader_write_attrib(vert, 'vec3 spos = pos.xyz;');
-		node_shader_write_attrib(vert, 'spos.xyz *= posUnpack;');
-		node_shader_write_attrib(vert, 'spos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, spos.xyz) + skinA.w * spos.xyz);');
-		node_shader_write_attrib(vert, 'spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz));');
-		node_shader_write_attrib(vert, 'spos.xyz /= posUnpack;');
+		node_shader_add_uniform(vert, "vec4 skinBones[128 * 2]", "_skin_bones");
+		node_shader_add_uniform(vert, "float posUnpack", "_pos_unpack");
+		node_shader_write_attrib(vert, "vec4 skinA;");
+		node_shader_write_attrib(vert, "vec4 skinB;");
+		node_shader_write_attrib(vert, "getSkinningDualQuat(ivec4(bone * 32767), weight, skinA, skinB);");
+		node_shader_write_attrib(vert, "vec3 spos = pos.xyz;");
+		node_shader_write_attrib(vert, "spos.xyz *= posUnpack;");
+		node_shader_write_attrib(vert, "spos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, spos.xyz) + skinA.w * spos.xyz);");
+		node_shader_write_attrib(vert, "spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz));");
+		node_shader_write_attrib(vert, "spos.xyz /= posUnpack;");
 	}
 	///end
 
-	node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
-	node_shader_write_attrib(vert, `gl_Position = mul(vec4(${pos}.xyz, 1.0), WVP);`);
+	node_shader_add_uniform(vert, "mat4 WVP", "_world_view_proj_matrix");
+	node_shader_write_attrib(vert, "gl_Position = mul(vec4(" + pos + ".xyz, 1.0), WVP);");
 
 	let brush_scale = (context_raw.brush_scale * context_raw.brush_nodes_scale) + "";
-	node_shader_add_out(vert, 'vec2 texCoord');
-	node_shader_write_attrib(vert, `texCoord = tex * float(${brush_scale});`);
+	node_shader_add_out(vert, "vec2 texCoord");
+	node_shader_write_attrib(vert, "texCoord = tex * float(" + brush_scale + ");");
 
 	let decal = context_raw.decal_preview;
 	parser_material_sample_keep_aspect = decal;
@@ -61,36 +61,36 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): No
 	let opac = "0.0";//sout.out_opacity;
 	let height = "0.0";//sout.out_height;
 	let nortan = "vec3(1.0, 1.0, 1.0)";//parser_material_out_normaltan;
-	node_shader_write(frag, `vec3 basecol = pow(${base}, vec3(2.2, 2.2, 2.2));`);
-	node_shader_write(frag, `float roughness = ${rough};`);
-	node_shader_write(frag, `float metallic = ${met};`);
-	node_shader_write(frag, `float occlusion = ${occ};`);
-	node_shader_write(frag, `float opacity = ${opac};`);
-	node_shader_write(frag, `vec3 nortan = ${nortan};`);
-	node_shader_write(frag, `float height = ${height};`);
+	node_shader_write(frag, "vec3 basecol = pow(" + base + ", vec3(2.2, 2.2, 2.2));");
+	node_shader_write(frag, "float roughness = " + rough + ";");
+	node_shader_write(frag, "float metallic = " + met + ";");
+	node_shader_write(frag, "float occlusion = " + occ + ";");
+	node_shader_write(frag, "float opacity = " + opac + ";");
+	node_shader_write(frag, "vec3 nortan = " + nortan + ";");
+	node_shader_write(frag, "float height = " + height + ";");
 
 	// parser_material_parse_height_as_channel = false;
-	// node_shader_write(vert, `float vheight = ${height};`);
-	// node_shader_add_out(vert, 'float height');
-	// node_shader_write(vert, 'height = vheight;');
-	// let displaceStrength = 0.1;
-	// if (heightUsed && displaceStrength > 0.0) {
-	// 	node_shader_write(vert, `vec3 pos2 = ${pos}.xyz + vec3(nor.xy, pos.w) * vec3(${height}, ${height}, ${height}) * vec3(${displaceStrength}, ${displaceStrength}, ${displaceStrength});`);
-	// 	node_shader_write(vert, 'gl_Position = mul(vec4(pos2.xyz, 1.0), WVP);');
+	// node_shader_write(vert, "float vheight = " + height + ";");
+	// node_shader_add_out(vert, "float height");
+	// node_shader_write(vert, "height = vheight;");
+	// let displace_strength = 0.1;
+	// if (heightUsed && displace_strength > 0.0) {
+	// 	node_shader_write(vert, "vec3 pos2 = " + pos + ".xyz + vec3(nor.xy, pos.w) * vec3(" + height + ", " + height + ", " + height + ") * vec3(" + displace_strength + ", " + displace_strength + ", " + displace_strength + ");");
+	// 	node_shader_write(vert, "gl_Position = mul(vec4(pos2.xyz, 1.0), WVP);");
 	// }
 
 	if (decal) {
 		if (context_raw.tool == workspace_tool_t.TEXT) {
-			node_shader_add_uniform(frag, 'sampler2D textexttool', '_textexttool');
-			node_shader_write(frag, `opacity *= textureLod(textexttool, texCoord / float(${brush_scale}), 0.0).r;`);
+			node_shader_add_uniform(frag, "sampler2D textexttool", "_textexttool");
+			node_shader_write(frag, "opacity *= textureLod(textexttool, texCoord / float(" + brush_scale + "), 0.0).r;");
 		}
 	}
 	if (decal) {
 		let opac = make_mesh_preview_opacity_discard_decal;
-		node_shader_write(frag, `if (opacity < ${opac}) discard;`);
+		node_shader_write(frag, "if (opacity < " + opac + ") discard;");
 	}
 
-	node_shader_add_out(frag, 'vec4 fragColor[3]');
+	node_shader_add_out(frag, "vec4 fragColor[3]");
 	frag.n = true;
 
 	node_shader_add_function(frag, str_pack_float_int16);
@@ -98,16 +98,16 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): No
 	node_shader_add_function(frag, str_octahedron_wrap);
 
 	if (make_material_height_used) {
-		node_shader_write(frag, 'if (height > 0.0) {');
-		node_shader_write(frag, 'float height_dx = dFdx(height * 2.0);');
-		node_shader_write(frag, 'float height_dy = dFdy(height * 2.0);');
-		// node_shader_write(frag, 'float height_dx = height0 - height1;');
-		// node_shader_write(frag, 'float height_dy = height2 - height3;');
+		node_shader_write(frag, "if (height > 0.0) {");
+		node_shader_write(frag, "float height_dx = dFdx(height * 2.0);");
+		node_shader_write(frag, "float height_dy = dFdy(height * 2.0);");
+		// node_shader_write(frag, "float height_dx = height0 - height1;");
+		// node_shader_write(frag, "float height_dy = height2 - height3;");
 		// Whiteout blend
-		node_shader_write(frag, 'vec3 n1 = nortan * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-		node_shader_write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-		node_shader_write(frag, 'nortan = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);');
-		node_shader_write(frag, '}');
+		node_shader_write(frag, "vec3 n1 = nortan * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);");
+		node_shader_write(frag, "vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));");
+		node_shader_write(frag, "nortan = normalize(vec3(n1.xy + n2.xy, n1.z * n2.z)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);");
+		node_shader_write(frag, "}");
 	}
 
 	// Apply normal channel
@@ -117,34 +117,34 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): No
 	else {
 		frag.vvec = true;
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, vVec, texCoord);");
 		///else
-		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+		node_shader_write(frag, "mat3 TBN = cotangentFrame(n, -vVec, texCoord);");
 		///end
-		node_shader_write(frag, 'n = nortan * 2.0 - 1.0;');
-		node_shader_write(frag, 'n.y = -n.y;');
-		node_shader_write(frag, 'n = normalize(mul(n, TBN));');
+		node_shader_write(frag, "n = nortan * 2.0 - 1.0;");
+		node_shader_write(frag, "n.y = -n.y;");
+		node_shader_write(frag, "n = normalize(mul(n, TBN));");
 	}
 
-	node_shader_write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-	node_shader_write(frag, 'n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);');
+	node_shader_write(frag, "n /= (abs(n.x) + abs(n.y) + abs(n.z));");
+	node_shader_write(frag, "n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);");
 	// uint matid = 0;
 
 	if (decal) {
-		node_shader_write(frag, 'fragColor[0] = vec4(n.x, n.y, roughness, packFloatInt16(metallic, uint(0)));'); // metallic/matid
-		node_shader_write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
+		node_shader_write(frag, "fragColor[0] = vec4(n.x, n.y, roughness, packFloatInt16(metallic, uint(0)));"); // metallic/matid
+		node_shader_write(frag, "fragColor[1] = vec4(basecol, occlusion);");
 	}
 	else {
-		node_shader_write(frag, 'fragColor[0] = vec4(n.x, n.y, mix(1.0, roughness, opacity), packFloatInt16(mix(1.0, metallic, opacity), uint(0)));'); // metallic/matid
-		node_shader_write(frag, 'fragColor[1] = vec4(mix(vec3(0.0, 0.0, 0.0), basecol, opacity), occlusion);');
+		node_shader_write(frag, "fragColor[0] = vec4(n.x, n.y, mix(1.0, roughness, opacity), packFloatInt16(mix(1.0, metallic, opacity), uint(0)));"); // metallic/matid
+		node_shader_write(frag, "fragColor[1] = vec4(mix(vec3(0.0, 0.0, 0.0), basecol, opacity), occlusion);");
 	}
-	node_shader_write(frag, 'fragColor[2] = vec4(0.0, 0.0, 0.0, 0.0);'); // veloc
+	node_shader_write(frag, "fragColor[2] = vec4(0.0, 0.0, 0.0, 0.0);"); // veloc
 
 	parser_material_finalize(con_mesh);
 
 	///if arm_skin
 	if (skin) {
-		node_shader_write(vert, 'wnormal = normalize(mul(vec3(nor.xy, pos.w) + 2.0 * cross(skinA.xyz, cross(skinA.xyz, vec3(nor.xy, pos.w)) + skinA.w * vec3(nor.xy, pos.w)), N));');
+		node_shader_write(vert, "wnormal = normalize(mul(vec3(nor.xy, pos.w) + 2.0 * cross(skinA.xyz, cross(skinA.xyz, vec3(nor.xy, pos.w)) + skinA.w * vec3(nor.xy, pos.w)), N));");
 	}
 	///end
 

+ 27 - 27
armorsculpt/Sources/make_sculpt.ts

@@ -24,24 +24,24 @@ function make_sculpt_run(data: material_t, matcon: material_context_t): NodeShad
 	let faceFill = context_raw.tool == workspace_tool_t.FILL && context_raw.fill_type_handle.position == fill_type_t.FACE;
 	let decal = context_raw.tool == workspace_tool_t.DECAL || context_raw.tool == workspace_tool_t.TEXT;
 
-	node_shader_add_out(vert, 'vec2 texCoord');
-	node_shader_write(vert, 'const vec2 madd = vec2(0.5, 0.5);');
-	node_shader_write(vert, 'texCoord = pos.xy * madd + madd;');
+	node_shader_add_out(vert, "vec2 texCoord");
+	node_shader_write(vert, "const vec2 madd = vec2(0.5, 0.5);");
+	node_shader_write(vert, "texCoord = pos.xy * madd + madd;");
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-	node_shader_write(vert, 'texCoord.y = 1.0 - texCoord.y;');
+	node_shader_write(vert, "texCoord.y = 1.0 - texCoord.y;");
 	///end
-	node_shader_write(vert, 'gl_Position = vec4(pos.xy, 0.0, 1.0);');
+	node_shader_write(vert, "gl_Position = vec4(pos.xy, 0.0, 1.0);");
 
-	node_shader_add_uniform(frag, 'vec4 inp', '_inputBrush');
-	node_shader_add_uniform(frag, 'vec4 inplast', '_inputBrushLast');
+	node_shader_add_uniform(frag, "vec4 inp", "_inputBrush");
+	node_shader_add_uniform(frag, "vec4 inplast", "_inputBrushLast");
 
-	node_shader_add_uniform(frag, 'sampler2D gbufferD');
+	node_shader_add_uniform(frag, "sampler2D gbufferD");
 
-	node_shader_add_out(frag, 'vec4 fragColor[2]');
+	node_shader_add_out(frag, "vec4 fragColor[2]");
 
-	node_shader_add_uniform(frag, 'float brushRadius', '_brushRadius');
-	node_shader_add_uniform(frag, 'float brushOpacity', '_brushOpacity');
-	node_shader_add_uniform(frag, 'float brushHardness', '_brushHardness');
+	node_shader_add_uniform(frag, "float brushRadius", "_brushRadius");
+	node_shader_add_uniform(frag, "float brushOpacity", "_brushOpacity");
+	node_shader_add_uniform(frag, "float brushHardness", "_brushHardness");
 
 	if (context_raw.tool == workspace_tool_t.BRUSH  ||
 		context_raw.tool == workspace_tool_t.ERASER ||
@@ -56,28 +56,28 @@ function make_sculpt_run(data: material_t, matcon: material_context_t): NodeShad
 		make_brush_run(vert, frag);
 	}
 
-	node_shader_write(frag, 'vec3 basecol = vec3(1.0, 1.0, 1.0);');
-	node_shader_write(frag, 'float opacity = 1.0;');
-	node_shader_write(frag, 'if (opacity == 0.0) discard;');
+	node_shader_write(frag, "vec3 basecol = vec3(1.0, 1.0, 1.0);");
+	node_shader_write(frag, "float opacity = 1.0;");
+	node_shader_write(frag, "if (opacity == 0.0) discard;");
 
-	node_shader_write(frag, 'float str = clamp((brushRadius - dist) * brushHardness * 400.0, 0.0, 1.0) * opacity;');
+	node_shader_write(frag, "float str = clamp((brushRadius - dist) * brushHardness * 400.0, 0.0, 1.0) * opacity;");
 
-	node_shader_add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-	node_shader_write(frag, 'vec4 sample_undo = textureLod(texpaint_undo, texCoord, 0.0);');
+	node_shader_add_uniform(frag, "sampler2D texpaint_undo", "_texpaint_undo");
+	node_shader_write(frag, "vec4 sample_undo = textureLod(texpaint_undo, texCoord, 0.0);");
 
-	node_shader_write(frag, 'if (sample_undo.r == 0 && sample_undo.g == 0 && sample_undo.b == 0) discard;');
+	node_shader_write(frag, "if (sample_undo.r == 0 && sample_undo.g == 0 && sample_undo.b == 0) discard;");
 
 	node_shader_add_function(frag, str_octahedron_wrap);
-	node_shader_add_uniform(frag, 'sampler2D gbuffer0_undo');
-	node_shader_write(frag, 'vec2 g0_undo = textureLod(gbuffer0_undo, inp.xy, 0.0).rg;');
-	node_shader_write(frag, 'vec3 wn;');
-	node_shader_write(frag, 'wn.z = 1.0 - abs(g0_undo.x) - abs(g0_undo.y);');
-	node_shader_write(frag, 'wn.xy = wn.z >= 0.0 ? g0_undo.xy : octahedronWrap(g0_undo.xy);');
-	node_shader_write(frag, 'vec3 n = normalize(wn);');
+	node_shader_add_uniform(frag, "sampler2D gbuffer0_undo");
+	node_shader_write(frag, "vec2 g0_undo = textureLod(gbuffer0_undo, inp.xy, 0.0).rg;");
+	node_shader_write(frag, "vec3 wn;");
+	node_shader_write(frag, "wn.z = 1.0 - abs(g0_undo.x) - abs(g0_undo.y);");
+	node_shader_write(frag, "wn.xy = wn.z >= 0.0 ? g0_undo.xy : octahedronWrap(g0_undo.xy);");
+	node_shader_write(frag, "vec3 n = normalize(wn);");
 
-	node_shader_write(frag, 'fragColor[0] = vec4(sample_undo.rgb + n * 0.1 * str, 1.0);');
+	node_shader_write(frag, "fragColor[0] = vec4(sample_undo.rgb + n * 0.1 * str, 1.0);");
 
-	node_shader_write(frag, 'fragColor[1] = vec4(str, 0.0, 0.0, 1.0);');
+	node_shader_write(frag, "fragColor[1] = vec4(str, 0.0, 0.0, 1.0);");
 
 	parser_material_finalize(con_paint);
 	con_paint.data.shader_from_source = true;

+ 1 - 1
armorsculpt/Sources/tab_layers.ts

@@ -95,7 +95,7 @@ function tab_layers_remap_layer_pointers(nodes: zui_node_t[], pointer_map: map_t
 		let n = nodes[i];
 		if (n.type == "LAYER" || n.type == "LAYER_MASK") {
 			let i = n.buttons[0].default_value;
-			if (pointer_map.has(i)) {
+			if (map_get(pointer_map, i) != null) {
 				n.buttons[0].default_value = map_get(pointer_map, i);
 			}
 		}

+ 73 - 0
base/Sources/base.ts

@@ -175,6 +175,79 @@ let base_default_keymap: any = {
 	///end
 };
 
+let base_keymap_keys: string[] = [
+	"action_paint",
+	"action_rotate",
+	"action_pan",
+	"action_zoom",
+	"rotate_light",
+	"rotate_envmap",
+	"set_clone_source",
+	"stencil_transform",
+	"stencil_hide",
+	"brush_radius",
+	"brush_radius_decrease",
+	"brush_radius_increase",
+	"brush_ruler",
+	"file_new",
+	"file_open",
+	"file_open_recent",
+	"file_save",
+	"file_save_as",
+	"file_reimport_mesh",
+	"file_reimport_textures",
+	"file_import_assets",
+	"file_export_textures",
+	"file_export_textures_as",
+	"edit_undo",
+	"edit_redo",
+	"edit_prefs",
+	"view_reset",
+	"view_front",
+	"view_back",
+	"view_right",
+	"view_left",
+	"view_top",
+	"view_bottom",
+	"view_camera_type",
+	"view_orbit_left",
+	"view_orbit_right",
+	"view_orbit_up",
+	"view_orbit_down",
+	"view_orbit_opposite",
+	"view_zoom_in",
+	"view_zoom_out",
+	"view_distract_free",
+	"viewport_mode",
+	"toggle_node_editor",
+	"toggle_2d_view",
+	"toggle_browser",
+	"node_search",
+	"operator_search",
+	///if (is_paint || is_sculpt)
+	"decal_mask",
+	"select_material",
+	"select_layer",
+	"brush_opacity",
+	"brush_angle",
+	"tool_brush",
+	"tool_eraser",
+	"tool_fill",
+	"tool_decal",
+	"tool_text",
+	"tool_clone",
+	"tool_blur",
+	"tool_smudge",
+	"tool_particle",
+	"tool_colorid",
+	"tool_picker",
+	"tool_bake",
+	"tool_gizmo",
+	"tool_material",
+	"swap_brush_eraser",
+	///end
+];
+
 function base_init() {
 	base_last_window_width = sys_width();
 	base_last_window_height = sys_height();

+ 7 - 7
base/Sources/box_export.ts

@@ -171,7 +171,7 @@ function box_export_tab_export_textures(ui: zui_t, title: string, bake_material:
 			}
 		}
 		if (ui.is_hovered) {
-			zui_tooltip(tr("Export texture files") + ` (${config_keymap.file_export_textures})`);
+			zui_tooltip(tr("Export texture files") + " (" + config_keymap.file_export_textures + ")");
 		}
 	}
 }
@@ -470,12 +470,12 @@ function box_export_parse_preset() {
 
 function box_export_new_preset(name: string) {
 	let template: string =
-`{
-"textures": [
-	{ "name": "base", "channels": ["base_r", "base_g", "base_b", "1.0"], "color_space": "linear" }
-]
-}
-`;
+"{\
+\"textures\": [\
+	{ \"name\": \"base\", \"channels\": [\"base_r\", \"base_g\", \"base_b\", \"1.0\"], \"color_space\": \"linear\" }\
+]\
+}\
+";
 	if (!ends_with(name, ".json")) {
 		name += ".json";
 	}

+ 14 - 13
base/Sources/box_preferences.ts

@@ -609,10 +609,11 @@ function box_preferences_show() {
 
 			zui_separator(8, false);
 
-			let i: i32 = 0;
+			let index: i32 = 0;
 			ui.changed = false;
-			for (let key in config_keymap) {
-				let h: zui_handle_t = zui_nest(zui_handle("boxpreferences_53"), i++);
+			for (let i: i32 = 0; i < base_keymap_keys.length; ++i) {
+				let key: string = base_keymap_keys[i];
+				let h: zui_handle_t = zui_nest(zui_handle("boxpreferences_53"), index++);
 				h.text = config_keymap[key];
 				let text: string = zui_text_input(h, key, zui_align_t.LEFT);
 				config_keymap[key] = text;
@@ -632,16 +633,16 @@ function box_preferences_show() {
 						let plugin_name: string = zui_text_input(zui_handle("boxpreferences_55", { text: "new_plugin" }), tr("Name"));
 						if (zui_button(tr("OK")) || ui.is_return_down) {
 							let template: string =
-`let plugin = create();
-let h1 = zui_handle_create();
-plugin.draw_ui = function (ui) {
-	if (zui_panel(h1, 'New Plugin')) {
-		if (zui_button('Button')) {
-			console.error('Hello');
-		}
-	}
-}
-`;
+"let plugin = create();\
+let h1 = zui_handle_create();\
+plugin.draw_ui = function (ui) {\
+	if (zui_panel(h1, \"New Plugin\")) {\
+		if (zui_button(\"Button\")) {\
+			console.error(\"Hello\");\
+		}\
+	}\
+}\
+";
 							if (!ends_with(plugin_name, ".js")) {
 								plugin_name += ".js";
 							}

+ 1 - 1
base/Sources/box_projects.ts

@@ -98,7 +98,7 @@ function box_projects_tab(ui: zui_t) {
 
 				///if krom_ios
 				let document_directory: string = krom_save_dialog("", "");
-				document_directory = substring(document_directory, 0, document_directory.length - 8); // Strip /'untitled'
+				document_directory = substring(document_directory, 0, document_directory.length - 8); // Strip /"untitled"
 				path = document_directory + path;
 				///end
 

+ 4 - 3
base/Sources/config.ts

@@ -188,10 +188,11 @@ function config_load_keymap() {
 		let blob: buffer_t = data_get_blob("keymap_presets/" + config_raw.keymap);
 		config_keymap = json_parse(sys_buffer_to_string(blob));
 		// Fill in undefined keys with defaults
-		for (let field in base_default_keymap) {
-			if (!(field in config_keymap)) {
+		for (let i: i32 = 0; i < base_keymap_keys.length; ++i) {
+			let key: string = base_keymap_keys[i];
+			if (!(key in config_keymap)) {
 				let adefault_keymap: any = base_default_keymap;
-				config_keymap[field] = adefault_keymap[field];
+				config_keymap[key] = adefault_keymap[key];
 			}
 		}
 	}

+ 2 - 2
base/Sources/export_texture.ts

@@ -91,9 +91,9 @@ function export_texture_run(path: string, bake_material: bool = false) {
 	///end
 
 	///if krom_ios
-	console_info(tr("Textures exported") + " ('Files/On My iPad/" + manifest_title + "')");
+	console_info(tr("Textures exported") + " (\"Files/On My iPad/" + manifest_title + "\")");
 	///elseif krom_android
-	console_info(tr("Textures exported") + " ('Files/Internal storage/Pictures/" + manifest_title + "')");
+	console_info(tr("Textures exported") + " (\"Files/Internal storage/Pictures/" + manifest_title + "\")");
 	///else
 	console_info(tr("Textures exported"));
 	///end

+ 7 - 7
base/Sources/file.ts

@@ -36,20 +36,20 @@ function file_read_directory(path: string, folders_only: bool = false): string[]
 }
 
 function file_create_directory(path: string) {
-	krom_sys_command(file_cmd_mkdir + ' "' + path + '"');
+	krom_sys_command(file_cmd_mkdir + " \"" + path + "\"");
 }
 
 function file_copy(srcPath: string, dst_path: string) {
-	krom_sys_command(file_cmd_copy + ' "' + srcPath + '" "' + dst_path + '"');
+	krom_sys_command(file_cmd_copy + " \"" + srcPath + "\" \"" + dst_path + "\"");
 }
 
 function file_start(path: string) {
 	///if krom_windows
-	krom_sys_command('start "" "' + path + '"');
+	krom_sys_command("start \"\" \"" + path + "\"");
 	///elseif krom_linux
-	krom_sys_command('xdg-open "' + path + '"');
+	krom_sys_command("xdg-open \"" + path + "\"");
 	///else
-	krom_sys_command('open "' + path + '"');
+	krom_sys_command("open \"" + path + "\"");
 	///end
 }
 
@@ -74,10 +74,10 @@ function file_download(url: string, dstPath: string, done: ()=>void, size: i32 =
 		done();
 	});
 	///elseif krom_linux
-	krom_sys_command('wget -O "' + dstPath + '" "' + url + '"');
+	krom_sys_command("wget -O \"" + dstPath + "\" \"" + url + "\"");
 	done();
 	///else
-	krom_sys_command('curl -L ' + url + ' -o "' + dstPath + '"');
+	krom_sys_command("curl -L " + url + " -o \"" + dstPath + "\"");
 	done();
 	///end
 }

+ 1 - 1
base/Sources/import_blend_material.ts

@@ -121,7 +121,7 @@ function import_blend_material_run(path: string) {
 				// Fill button values
 				if (search == "teximage") {
 					let img: any = bl_handle_get(node, "id", 0, "Image");
-					let file: string = bl_handle_get(img, "name"); // '//desktop\logo.png'
+					let file: string = bl_handle_get(img, "name"); // "//desktop\logo.png"
 					file = substring(file, 2, file.length);
 					file = path_base_dir(path) + file;
 					import_texture_run(file);

+ 34 - 34
base/Sources/make_voxel.ts

@@ -20,8 +20,8 @@ function make_voxel_run(data: shader_context_t) {
 	// if (skin) {
 	// 	g4_vertex_structure_add(structure, "bone", vertex_data_t.I16_4X_Normalized);
 	// 	g4_vertex_structure_add(structure, "weight", vertex_data_t.I16_4X_Normalized);
-	// 	array_push(data.raw.vertex_elements, { name: "bone", data: 'short4norm' });
-	// 	array_push(data.raw.vertex_elements, { name: "weight", data: 'short4norm' });
+	// 	array_push(data.raw.vertex_elements, { name: "bone", data: "short4norm" });
+	// 	array_push(data.raw.vertex_elements, { name: "weight", data: "short4norm" });
 	// }
 	// ///end
 
@@ -50,39 +50,39 @@ function make_voxel_run(data: shader_context_t) {
 function make_voxel_source(): string {
 	let ds: f32 = make_material_get_displace_strength();
 	///if krom_direct3d11
-	return `#define vec3 float3
-	uniform float4x4 W;
-	uniform float3x3 N;
-	Texture2D<float4> texpaint_pack;
-	SamplerState _texpaint_pack_sampler;
-	struct SPIRV_Cross_Input { float4 pos : TEXCOORD1; float2 nor : TEXCOORD0; float2 tex : TEXCOORD2; };
-	struct SPIRV_Cross_Output { float4 svpos : SV_POSITION; };
-	SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) {
-		SPIRV_Cross_Output stage_output;
-		${make_material_voxelgi_half_extents()}
-		stage_output.svpos.xyz = mul(float4(stage_input.pos.xyz, 1.0), W).xyz / voxelgiHalfExtents.xxx;
-		float3 wnormal = normalize(mul(float3(stage_input.nor.xy, stage_input.pos.w), N));
-		float height = texpaint_pack.SampleLevel(_texpaint_pack_sampler, stage_input.tex, 0.0).a;
-		stage_output.svpos.xyz += wnormal * height.xxx * float3(${ds}, ${ds}, ${ds});
-		stage_output.svpos.w = 1.0;
-		return stage_output;
-	}`;
+	return "#define vec3 float3 \
+	uniform float4x4 W; \
+	uniform float3x3 N; \
+	Texture2D<float4> texpaint_pack; \
+	SamplerState _texpaint_pack_sampler; \
+	struct SPIRV_Cross_Input { float4 pos : TEXCOORD1; float2 nor : TEXCOORD0; float2 tex : TEXCOORD2; }; \
+	struct SPIRV_Cross_Output { float4 svpos : SV_POSITION; }; \
+	SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) { \
+		SPIRV_Cross_Output stage_output; \
+		" + make_material_voxelgi_half_extents + ")} \
+		stage_output.svpos.xyz = mul(float4(stage_input.pos.xyz, 1.0), W).xyz / voxelgiHalfExtents.xxx; \
+		float3 wnormal = normalize(mul(float3(stage_input.nor.xy, stage_input.pos.w), N)); \
+		float height = texpaint_pack.SampleLevel(_texpaint_pack_sampler, stage_input.tex, 0.0).a; \
+		stage_output.svpos.xyz += wnormal * height.xxx * float3(" + ds + ", " + ds + ", " + ds + "); \
+		stage_output.svpos.w = 1.0; \
+		return stage_output; \
+	}";
 	///else
-	return `#version 450
-	in vec4 pos;
-	in vec2 nor;
-	in vec2 tex;
-	out vec3 voxpositionGeom;
-	uniform mat4 W;
-	uniform mat3 N;
-	uniform sampler2D texpaint_pack;
-	void main() {
-		${make_material_voxelgi_half_extents()}
-		voxpositionGeom = vec3(W * vec4(pos.xyz, 1.0)) / voxelgiHalfExtents;
-		vec3 wnormal = normalize(N * vec3(nor.xy, pos.w));
-		float height = textureLod(texpaint_pack, tex, 0.0).a;
-		voxpositionGeom += wnormal * vec3(height) * vec3(${ds});
-	}`;
+	return "#version 450 \
+	in vec4 pos; \
+	in vec2 nor; \
+	in vec2 tex; \
+	out vec3 voxpositionGeom; \
+	uniform mat4 W; \
+	uniform mat3 N; \
+	uniform sampler2D texpaint_pack; \
+	void main() { \
+		" + make_material_voxelgi_half_extents + ")} \
+		voxpositionGeom = vec3(W * vec4(pos.xyz, 1.0)) / voxelgiHalfExtents; \
+		vec3 wnormal = normalize(N * vec3(nor.xy, pos.w)); \
+		float height = textureLod(texpaint_pack, tex, 0.0).a; \
+		voxpositionGeom += wnormal * vec3(height) * vec3(" + ds + "); \
+	}";
 	///end
 }
 ///end

+ 236 - 236
base/Sources/node_shader.ts

@@ -47,13 +47,13 @@ function node_shader_create(context: node_shader_context_t, shader_type: string)
 	raw.shared_samplers = [];
 	raw.uniforms = [];
 	raw.functions = map_create();
-	raw.main = '';
-	raw.main_init = '';
-	raw.main_end = '';
-	raw.main_normal = '';
-	raw.main_textures = '';
-	raw.main_attribs = '';
-	raw.header = '';
+	raw.main = "";
+	raw.main_init = "";
+	raw.main_end = "";
+	raw.main_normal = "";
+	raw.main_textures = "";
+	raw.main_attribs = "";
+	raw.header = "";
 	raw.write_pre = false;
 	raw.write_normal = 0;
 	raw.write_textures = 0;
@@ -74,23 +74,23 @@ function node_shader_add_out(raw: node_shader_t, s: string) {
 }
 
 function node_shader_add_uniform(raw: node_shader_t, s: string, link: string = null, included: bool = false) {
-	let ar: string[] = string_split(s, ' ');
+	let ar: string[] = string_split(s, " ");
 	// layout(RGBA8) image3D voxels
 	let utype: string = ar[ar.length - 2];
 	let uname: string = ar[ar.length - 1];
-	if (starts_with(utype, 'sampler') || starts_with(utype, 'image') || starts_with(utype, 'uimage')) {
-		let is_image: bool = (starts_with(utype, 'image') || starts_with(utype, 'uimage')) ? true : false;
+	if (starts_with(utype, "sampler") || starts_with(utype, "image") || starts_with(utype, "uimage")) {
+		let is_image: bool = (starts_with(utype, "image") || starts_with(utype, "uimage")) ? true : false;
 		node_shader_context_add_texture_unit(raw.context, utype, uname, link, is_image);
 	}
 	else {
 		// Prefer vec4[] for d3d to avoid padding
-		if (ar[0] == 'float' && string_index_of(ar[1], '[') >= 0) {
-			ar[0] = 'floats';
-			ar[1] = string_split(ar[1], '[')[0];
+		if (ar[0] == "float" && string_index_of(ar[1], "[") >= 0) {
+			ar[0] = "floats";
+			ar[1] = string_split(ar[1], "[")[0];
 		}
-		else if (ar[0] == 'vec4' && string_index_of(ar[1], '[') >= 0) {
-			ar[0] = 'floats';
-			ar[1] = string_split(ar[1], '[')[0];
+		else if (ar[0] == "vec4" && string_index_of(ar[1], "[") >= 0) {
+			ar[0] = "floats";
+			ar[1] = string_split(ar[1], "[")[0];
 		}
 		node_shader_context_add_constant(raw.context, ar[0], ar[1], link);
 	}
@@ -102,7 +102,7 @@ function node_shader_add_uniform(raw: node_shader_t, s: string, link: string = n
 function node_shader_add_shared_sampler(raw: node_shader_t, s: string) {
 	if (array_index_of(raw.shared_samplers, s) == -1) {
 		array_push(raw.shared_samplers, s);
-		let ar: string[] = string_split(s, ' ');
+		let ar: string[] = string_split(s, " ");
 		// layout(RGBA8) sampler2D tex
 		let utype: string = ar[ar.length - 2];
 		let uname: string = ar[ar.length - 1];
@@ -111,8 +111,8 @@ function node_shader_add_shared_sampler(raw: node_shader_t, s: string) {
 }
 
 function node_shader_add_function(raw: node_shader_t, s: string) {
-	let fname: string = string_split(s, '(')[0];
-	if (raw.functions.has(fname)) {
+	let fname: string = string_split(s, "(")[0];
+	if (map_get(raw.functions, fname) != null) {
 		return;
 	}
 	map_set(raw.functions, fname, s);
@@ -128,7 +128,7 @@ function node_shader_contains(raw: node_shader_t, s: string): bool {
 }
 
 function node_shader_write_init(raw: node_shader_t, s: string) {
-	raw.main_init = s + '\n' + raw.main_init;
+	raw.main_init = s + "\n" + raw.main_init;
 }
 
 function node_shader_write(raw: node_shader_t, s: string) {
@@ -136,110 +136,110 @@ function node_shader_write(raw: node_shader_t, s: string) {
 		return;
 	}
 	if (raw.write_textures > 0) {
-		raw.main_textures += s + '\n';
+		raw.main_textures += s + "\n";
 	}
 	else if (raw.write_normal > 0) {
-		raw.main_normal += s + '\n';
+		raw.main_normal += s + "\n";
 	}
 	else if (raw.write_pre) {
-		raw.main_init += s + '\n';
+		raw.main_init += s + "\n";
 	}
 	else {
-		raw.main += s + '\n';
+		raw.main += s + "\n";
 	}
 }
 
 function node_shader_write_header(raw: node_shader_t, s: string) {
-	raw.header += s + '\n';
+	raw.header += s + "\n";
 }
 
 function node_shader_write_end(raw: node_shader_t, s: string) {
-	raw.main_end += s + '\n';
+	raw.main_end += s + "\n";
 }
 
 function node_shader_write_attrib(raw: node_shader_t, s: string) {
-	raw.main_attribs += s + '\n';
+	raw.main_attribs += s + "\n";
 }
 
 function node_shader_data_size(raw: node_shader_t, data: string): string {
-	if (data == 'float1') {
-		return '1';
+	if (data == "float1") {
+		return "1";
 	}
-	else if (data == 'float2') {
-		return '2';
+	else if (data == "float2") {
+		return "2";
 	}
-	else if (data == 'float3') {
-		return '3';
+	else if (data == "float3") {
+		return "3";
 	}
-	else if (data == 'float4') {
-		return '4';
+	else if (data == "float4") {
+		return "4";
 	}
-	else if (data == 'short2norm') {
-		return '2';
+	else if (data == "short2norm") {
+		return "2";
 	}
-	else if (data == 'short4norm') {
-		return '4';
+	else if (data == "short4norm") {
+		return "4";
 	}
 	else {
-		return '1';
+		return "1";
 	}
 }
 
 function node_shader_vstruct_to_vsin(raw: node_shader_t) {
-	// if self.shader_type != 'vert' or self.ins != [] or not self.vstruct_as_vsin: # Vertex structure as vertex shader input
+	// if self.shader_type != "vert" or self.ins != [] or not self.vstruct_as_vsin: # Vertex structure as vertex shader input
 		// return
 	let vs: vertex_element_t[] = raw.context.data.vertex_elements;
 	for (let i: i32 = 0; i < vs.length; ++i) {
 		let e: vertex_element_t = vs[i];
-		node_shader_add_in(raw, 'vec' + node_shader_data_size(raw, e.data) + ' ' + e.name);
+		node_shader_add_in(raw, "vec" + node_shader_data_size(raw, e.data) + " " + e.name);
 	}
 }
 
 ///if (krom_direct3d11 || krom_direct3d12)
 function node_shader_get_hlsl(raw: node_shader_t, shared_sampler: string): string {
-	let s: string = '#define HLSL\n';
-	s += '#define textureArg(tex) Texture2D tex,SamplerState tex ## _sampler\n';
-	s += '#define texturePass(tex) tex,tex ## _sampler\n';
-	s += '#define sampler2D Texture2D\n';
-	s += '#define sampler3D Texture3D\n';
-	s += '#define texture(tex, coord) tex.Sample(tex ## _sampler, coord)\n';
-	s += `#define textureShared(tex, coord) tex.Sample(${shared_sampler}, coord)\n`;
-	s += '#define textureLod(tex, coord, lod) tex.SampleLevel(tex ## _sampler, coord, lod)\n';
-	s += `#define textureLodShared(tex, coord, lod) tex.SampleLevel(${shared_sampler}, coord, lod)\n`;
-	s += '#define texelFetch(tex, coord, lod) tex.Load(float3(coord.xy, lod))\n';
-	s += 'uint2 _GetDimensions(Texture2D tex, uint lod) { uint x, y; tex.GetDimensions(x, y); return uint2(x, y); }\n';
-	s += '#define textureSize _GetDimensions\n';
-	s += '#define mod(a, b) (a % b)\n';
-	s += '#define vec2 float2\n';
-	s += '#define vec3 float3\n';
-	s += '#define vec4 float4\n';
-	s += '#define ivec2 int2\n';
-	s += '#define ivec3 int3\n';
-	s += '#define ivec4 int4\n';
-	s += '#define mat2 float2x2\n';
-	s += '#define mat3 float3x3\n';
-	s += '#define mat4 float4x4\n';
-	s += '#define dFdx ddx\n';
-	s += '#define dFdy ddy\n';
-	s += '#define inversesqrt rsqrt\n';
-	s += '#define fract frac\n';
-	s += '#define mix lerp\n';
-	// s += '#define fma mad\n';
+	let s: string = "#define HLSL\n";
+	s += "#define textureArg(tex) Texture2D tex,SamplerState tex ## _sampler\n";
+	s += "#define texturePass(tex) tex,tex ## _sampler\n";
+	s += "#define sampler2D Texture2D\n";
+	s += "#define sampler3D Texture3D\n";
+	s += "#define texture(tex, coord) tex.Sample(tex ## _sampler, coord)\n";
+	s += "#define textureShared(tex, coord) tex.Sample(" + shared_sampler + ", coord)\n";
+	s += "#define textureLod(tex, coord, lod) tex.SampleLevel(tex ## _sampler, coord, lod)\n";
+	s += "#define textureLodShared(tex, coord, lod) tex.SampleLevel(" + shared_sampler + ", coord, lod)\n";
+	s += "#define texelFetch(tex, coord, lod) tex.Load(float3(coord.xy, lod))\n";
+	s += "uint2 _GetDimensions(Texture2D tex, uint lod) { uint x, y; tex.GetDimensions(x, y); return uint2(x, y); }\n";
+	s += "#define textureSize _GetDimensions\n";
+	s += "#define mod(a, b) (a % b)\n";
+	s += "#define vec2 float2\n";
+	s += "#define vec3 float3\n";
+	s += "#define vec4 float4\n";
+	s += "#define ivec2 int2\n";
+	s += "#define ivec3 int3\n";
+	s += "#define ivec4 int4\n";
+	s += "#define mat2 float2x2\n";
+	s += "#define mat3 float3x3\n";
+	s += "#define mat4 float4x4\n";
+	s += "#define dFdx ddx\n";
+	s += "#define dFdy ddy\n";
+	s += "#define inversesqrt rsqrt\n";
+	s += "#define fract frac\n";
+	s += "#define mix lerp\n";
+	// s += "#define fma mad\n";
 
 	s += raw.header;
 
-	let in_ext: string = '';
-	let out_ext: string = '';
+	let in_ext: string = "";
+	let out_ext: string = "";
 
 	for (let i: i32 = 0; i < raw.includes.length; ++i) {
 		let a: string = raw.includes[i];
-		s += '#include "' + a + '"\n';
+		s += "#include \"" + a + "\"\n";
 	}
 
 	// Input structure
 	let index: i32 = 0;
 	if (raw.ins.length > 0) {
-		s += 'struct SPIRV_Cross_Input {\n';
+		s += "struct SPIRV_Cross_Input {\n";
 		index = 0;
 		array_sort(raw.ins, function (a, b): i32 {
 			// Sort inputs by name
@@ -247,113 +247,113 @@ function node_shader_get_hlsl(raw: node_shader_t, shared_sampler: string): strin
 		});
 		for (let i: i32 = 0; i < raw.ins.length; ++i) {
 			let a: string = raw.ins[i];
-			s += `${a}${in_ext} : TEXCOORD${index};\n`;
+			s += a + in_ext + " : TEXCOORD" + index + ";\n";
 			index++;
 		}
 		// Built-ins
-		if (raw.shader_type == 'vert' && string_index_of(raw.main, "gl_VertexID") >= 0) {
-			s += 'uint gl_VertexID : SV_VertexID;\n';
-			array_push(raw.ins, 'uint gl_VertexID');
+		if (raw.shader_type == "vert" && string_index_of(raw.main, "gl_VertexID") >= 0) {
+			s += "uint gl_VertexID : SV_VertexID;\n";
+			array_push(raw.ins, "uint gl_VertexID");
 		}
-		if (raw.shader_type == 'vert' && string_index_of(raw.main, "gl_InstanceID") >= 0) {
-			s += 'uint gl_InstanceID : SV_InstanceID;\n';
-			array_push(raw.ins, 'uint gl_InstanceID');
+		if (raw.shader_type == "vert" && string_index_of(raw.main, "gl_InstanceID") >= 0) {
+			s += "uint gl_InstanceID : SV_InstanceID;\n";
+			array_push(raw.ins, "uint gl_InstanceID");
 		}
-		s += '};\n';
+		s += "};\n";
 	}
 
 	// Output structure
 	let num: i32 = 0;
-	if (raw.outs.length > 0 || raw.shader_type == 'vert') {
-		s += 'struct SPIRV_Cross_Output {\n';
+	if (raw.outs.length > 0 || raw.shader_type == "vert") {
+		s += "struct SPIRV_Cross_Output {\n";
 		array_sort(raw.outs, function (a, b): i32 {
 			// Sort outputs by name
 			return substring(a, 4, a.length) >= substring(b, 4, b.length) ? 1 : -1;
 		});
 		index = 0;
-		if (raw.shader_type == 'vert') {
+		if (raw.shader_type == "vert") {
 			for (let i: i32 = 0; i < raw.outs.length; ++i) {
 				let a: string = raw.outs[i];
-				s += `${a}${out_ext} : TEXCOORD${index};\n`;
+				s += a + out_ext + " : TEXCOORD" + index + ";\n";
 				index++;
 			}
-			s += 'float4 svpos : SV_POSITION;\n';
+			s += "float4 svpos : SV_POSITION;\n";
 		}
 		else {
 			let out: string = raw.outs[0];
 			// Multiple render targets
-			if (char_at(out, out.length - 1) == ']') {
+			if (char_at(out, out.length - 1) == "]") {
 				num = parse_int(char_at(out, out.length - 2));
-				s += `vec4 fragColor[${num}] : SV_TARGET0;\n`;
+				s += "vec4 fragColor[" + num + "] : SV_TARGET0;\n";
 			}
 			else {
-				s += 'vec4 fragColor : SV_TARGET0;\n';
+				s += "vec4 fragColor : SV_TARGET0;\n";
 			}
 		}
-		s += '};\n';
+		s += "};\n";
 	}
 
 	for (let i: i32 = 0; i < raw.uniforms.length; ++i) {
 		let a: string = raw.uniforms[i];
-		s += 'uniform ' + a + ';\n';
-		if (starts_with(a, 'sampler')) {
-			s += 'SamplerState ' + string_split(a, ' ')[1] + '_sampler;\n';
+		s += "uniform " + a + ";\n";
+		if (starts_with(a, "sampler")) {
+			s += "SamplerState " + string_split(a, " ")[1] + "_sampler;\n";
 		}
 	}
 
 	if (raw.shared_samplers.length > 0) {
-		for (let i: i32 = 0; o < raw.shared_samplers.length; ++i) {
+		for (let i: i32 = 0; i < raw.shared_samplers.length; ++i) {
 			let a: string = raw.shared_samplers[i];
-			s += 'uniform ' + a + ';\n';
+			s += "uniform " + a + ";\n";
 		}
-		s += `SamplerState ${shared_sampler};\n`;
+		s += "SamplerState " + shared_sampler + ";\n";
 	}
 
 	let values: string[] = map_to_array(raw.functions);
 	for (let i: i32 = 0; i < values.length; ++i) {
 		let f: string = values[i];
-		s += f + '\n';
+		s += f + "\n";
 	}
 
 	// Begin main
-	if (raw.outs.length > 0 || raw.shader_type == 'vert') {
+	if (raw.outs.length > 0 || raw.shader_type == "vert") {
 		if (raw.ins.length > 0) {
-			s += 'SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) {\n';
+			s += "SPIRV_Cross_Output main(SPIRV_Cross_Input stage_input) {\n";
 		}
 		else {
-			s += 'SPIRV_Cross_Output main() {\n';
+			s += "SPIRV_Cross_Output main() {\n";
 		}
 	}
 	else {
 		if (raw.ins.length > 0) {
-			s += 'void main(SPIRV_Cross_Input stage_input) {\n';
+			s += "void main(SPIRV_Cross_Input stage_input) {\n";
 		}
 		else {
-			s += 'void main() {\n';
+			s += "void main() {\n";
 		}
 	}
 
 	// Declare inputs
 	for (let i: i32 = 0; i < raw.ins.length; ++i) {
 		let a: string = raw.ins[i];
-		let b: string = substring(a, 5, a.length); // Remove type 'vec4 '
-		s += `${a} = stage_input.${b};\n`;
+		let b: string = substring(a, 5, a.length); // Remove type "vec4 "
+		s += a + " = stage_input." + b + ";\n";
 	}
 
-	if (raw.shader_type == 'vert') {
-		s += 'vec4 gl_Position;\n';
+	if (raw.shader_type == "vert") {
+		s += "vec4 gl_Position;\n";
 		for (let i: i32 = 0; i < raw.outs.length; ++i) {
 			let a: string = raw.outs[i];
-			s += `${a};\n`;
+			s += a + ";\n";
 		}
 	}
 	else {
 		if (raw.outs.length > 0) {
 			if (num > 0) {
-				s += `vec4 fragColor[${num}];\n`;
+				s += "vec4 fragColor[" + num + "];\n";
 			}
 			else {
-				s += 'vec4 fragColor;\n';
+				s += "vec4 fragColor;\n";
 			}
 		}
 	}
@@ -366,71 +366,71 @@ function node_shader_get_hlsl(raw: node_shader_t, shared_sampler: string): strin
 	s += raw.main_end;
 
 	// Write output structure
-	if (raw.outs.length > 0 || raw.shader_type == 'vert') {
-		s += 'SPIRV_Cross_Output stage_output;\n';
-		if (raw.shader_type == 'vert') {
-			s += 'gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n';
-			s += 'stage_output.svpos = gl_Position;\n';
+	if (raw.outs.length > 0 || raw.shader_type == "vert") {
+		s += "SPIRV_Cross_Output stage_output;\n";
+		if (raw.shader_type == "vert") {
+			s += "gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n";
+			s += "stage_output.svpos = gl_Position;\n";
 			for (let i: i32 = 0; i < raw.outs.length; ++i) {
 				let a: string = raw.outs[i];
-				let b: string = substring(a, 5, a.length); // Remove type 'vec4 '
-				s += `stage_output.${b} = ${b};\n`;
+				let b: string = substring(a, 5, a.length); // Remove type "vec4 "
+				s += "stage_output." + b + " = " + b + ";\n";
 			}
 		}
 		else {
 			if (num > 0) {
 				for (let i: i32 = 0; i < num; ++i) {
-					s += `stage_output.fragColor[${i}] = fragColor[${i}];\n`;
+					s += "stage_output.fragColor[" + i + "] = fragColor[" + i + "];\n";
 				}
 			}
 			else {
-				s += 'stage_output.fragColor = fragColor;\n';
+				s += "stage_output.fragColor = fragColor;\n";
 			}
 		}
-		s += 'return stage_output;\n';
+		s += "return stage_output;\n";
 	}
-	s += '}\n';
+	s += "}\n";
 	return s;
 }
 ///end
 
 ///if krom_metal
 function node_shader_get_msl(raw: node_shader_t, shared_sampler: string): string {
-	let s: string = '#define METAL\n';
-	s += '#include <metal_stdlib>\n';
-	s += '#include <simd/simd.h>\n';
-	s += 'using namespace metal;\n';
-
-	s += '#define textureArg(tex) texture2d<float> tex,sampler tex ## _sampler\n';
-	s += '#define texturePass(tex) tex,tex ## _sampler\n';
-	s += '#define sampler2D texture2d<float>\n';
-	s += '#define sampler3D texture3d<float>\n';
-	s += '#define texture(tex, coord) tex.sample(tex ## _sampler, coord)\n';
-	s += `#define textureShared(tex, coord) tex.sample(${shared_sampler}, coord)\n`;
-	s += '#define textureLod(tex, coord, lod) tex.sample(tex ## _sampler, coord, level(lod))\n';
-	s += `#define textureLodShared(tex, coord, lod) tex.sample(${shared_sampler}, coord, level(lod))\n`;
-	s += '#define texelFetch(tex, coord, lod) tex.read(uint2(coord), uint(lod))\n';
-	s += 'float2 _getDimensions(texture2d<float> tex, uint lod) { return float2(tex.get_width(lod), tex.get_height(lod)); }\n';
-	s += '#define textureSize _getDimensions\n';
-	s += '#define mod(a, b) fmod(a, b)\n';
-	s += '#define vec2 float2\n';
-	s += '#define vec3 float3\n';
-	s += '#define vec4 float4\n';
-	s += '#define ivec2 int2\n';
-	s += '#define ivec3 int3\n';
-	s += '#define ivec4 int4\n';
-	s += '#define mat2 float2x2\n';
-	s += '#define mat3 float3x3\n';
-	s += '#define mat4 float4x4\n';
-	s += '#define dFdx dfdx\n';
-	s += '#define dFdy dfdy\n';
-	s += '#define inversesqrt rsqrt\n';
-	s += '#define mul(a, b) b * a\n';
-	s += '#define discard discard_fragment()\n';
+	let s: string = "#define METAL\n";
+	s += "#include <metal_stdlib>\n";
+	s += "#include <simd/simd.h>\n";
+	s += "using namespace metal;\n";
+
+	s += "#define textureArg(tex) texture2d<float> tex,sampler tex ## _sampler\n";
+	s += "#define texturePass(tex) tex,tex ## _sampler\n";
+	s += "#define sampler2D texture2d<float>\n";
+	s += "#define sampler3D texture3d<float>\n";
+	s += "#define texture(tex, coord) tex.sample(tex ## _sampler, coord)\n";
+	s += "#define textureShared(tex, coord) tex.sample(" + shared_sampler + ", coord)\n";
+	s += "#define textureLod(tex, coord, lod) tex.sample(tex ## _sampler, coord, level(lod))\n";
+	s += "#define textureLodShared(tex, coord, lod) tex.sample(" + shared_sampler + ", coord, level(lod))\n";
+	s += "#define texelFetch(tex, coord, lod) tex.read(uint2(coord), uint(lod))\n";
+	s += "float2 _getDimensions(texture2d<float> tex, uint lod) { return float2(tex.get_width(lod), tex.get_height(lod)); }\n";
+	s += "#define textureSize _getDimensions\n";
+	s += "#define mod(a, b) fmod(a, b)\n";
+	s += "#define vec2 float2\n";
+	s += "#define vec3 float3\n";
+	s += "#define vec4 float4\n";
+	s += "#define ivec2 int2\n";
+	s += "#define ivec3 int3\n";
+	s += "#define ivec4 int4\n";
+	s += "#define mat2 float2x2\n";
+	s += "#define mat3 float3x3\n";
+	s += "#define mat4 float4x4\n";
+	s += "#define dFdx dfdx\n";
+	s += "#define dFdy dfdy\n";
+	s += "#define inversesqrt rsqrt\n";
+	s += "#define mul(a, b) b * a\n";
+	s += "#define discard discard_fragment()\n";
 
 	for (let i: i32 = 0; i < raw.includes.length; ++i) {
 		let a: string = raw.includes[i];
-		s += '#include "' + a + '"\n';
+		s += "#include \"" + a + "\"\n";
 	}
 
 	s += raw.header;
@@ -438,163 +438,163 @@ function node_shader_get_msl(raw: node_shader_t, shared_sampler: string): string
 	// Input structure
 	let index: i32 = 0;
 	//if (ins.length > 0) {
-		s += 'struct main_in {\n';
+		s += "struct main_in {\n";
 		index = 0;
 		array_sort(raw.ins, function (a, b): i32 {
 			// Sort inputs by name
 			return substring(a, 4, a.length) >= substring(b, 4, b.length) ? 1 : -1;
 		});
-		if (raw.shader_type == 'vert') {
+		if (raw.shader_type == "vert") {
 			for (let i: i32 = 0; i < raw.ins.length; ++i) {
 				let a: string = raw.ins[i];
-				s += `${a} [[attribute(${index})]];\n`;
+				s += a + " [[attribute(" + index + ")]];\n";
 				index++;
 			}
 		}
 		else {
 			for (let i: i32 = 0; i < raw.ins.length; ++i) {
 				let a: string = raw.ins[i];
-				s += `${a} [[user(locn${index})]];\n`;
+				s += a + " [[user(locn" + index + ")]];\n";
 				index++;
 			}
 		}
-		s += '};\n';
+		s += "};\n";
 	//}
 
 	// Output structure
 	let num: i32 = 0;
-	if (raw.outs.length > 0 || raw.shader_type == 'vert') {
-		s += 'struct main_out {\n';
+	if (raw.outs.length > 0 || raw.shader_type == "vert") {
+		s += "struct main_out {\n";
 		array_sort(raw.outs, function (a, b): i32 {
 			// Sort outputs by name
 			return substring(a, 4, a.length) >= substring(b, 4, b.length) ? 1 : -1;
 		});
 		index = 0;
-		if (raw.shader_type == 'vert') {
+		if (raw.shader_type == "vert") {
 			for (let i: i32 = 0; i < raw.outs.length; ++i) {
 				let a: string = raw.outs[i];
-				s += `${a} [[user(locn${index})]];\n`;
+				s += a + " [[user(locn" + index + ")]];\n";
 				index++;
 			}
-			s += 'float4 svpos [[position]];\n';
+			s += "float4 svpos [[position]];\n";
 		}
 		else {
 			let out: string = raw.outs[0];
 			// Multiple render targets
-			if (char_at(out, out.length - 1) == ']') {
+			if (char_at(out, out.length - 1) == "]") {
 				num = parse_int(char_at(out, out.length - 2));
 				for (let i: i32 = 0; i < num; ++i) {
-					s += `float4 fragColor_${i} [[color(${i})]];\n`;
+					s += "float4 fragColor_" + i + " [[color(" + i + ")]];\n";
 				}
 			}
 			else {
-				s += 'float4 fragColor [[color(0)]];\n';
+				s += "float4 fragColor [[color(0)]];\n";
 			}
 		}
-		s += '};\n';
+		s += "};\n";
 	}
 
 	let samplers: string[] = [];
 
 	if (raw.uniforms.length > 0) {
-		s += 'struct main_uniforms {\n';
+		s += "struct main_uniforms {\n";
 
 		for (let i: i32 = 0; i < raw.uniforms.length; ++i) {
 			let a: string = raw.uniforms[i];
-			if (starts_with(a, 'sampler')) {
+			if (starts_with(a, "sampler")) {
 				array_push(samplers, a);
 			}
 			else {
-				s += a + ';\n';
+				s += a + ";\n";
 			}
 		}
 
-		s += '};\n';
+		s += "};\n";
 	}
 
 	let values: string[] = map_to_array(raw.functions);
 	for (let i: i32 = 0; i < values.length; ++i) {
 		let f: string = values[i];
-		s += f + '\n';
+		s += f + "\n";
 	}
 
 	// Begin main declaration
-	s += '#undef texture\n';
+	s += "#undef texture\n";
 
-	s += raw.shader_type == 'vert' ? 'vertex ' : 'fragment ';
-	s += (raw.outs.length > 0 || raw.shader_type == 'vert') ? 'main_out ' : 'void ';
-	s += 'my_main(';
+	s += raw.shader_type == "vert" ? "vertex " : "fragment ";
+	s += (raw.outs.length > 0 || raw.shader_type == "vert") ? "main_out " : "void ";
+	s += "my_main(";
 	//if (ins.length > 0) {
-		s += 'main_in in [[stage_in]]';
+		s += "main_in in [[stage_in]]";
 	//}
 	if (raw.uniforms.length > 0) {
-		let bufi: i32 = raw.shader_type == 'vert' ? 1 : 0;
-		s += `, constant main_uniforms& uniforms [[buffer(${bufi})]]`;
+		let bufi: i32 = raw.shader_type == "vert" ? 1 : 0;
+		s += ", constant main_uniforms& uniforms [[buffer(" + bufi + ")]]";
 	}
 
 	if (samplers.length > 0) {
 		for (let i: i32 = 0; i < samplers.length; ++i) {
-			s += `, ${samplers[i]} [[texture(${i})]]`;
-			s += ', sampler ' + string_split(samplers[i], ' ')[1] + `_sampler [[sampler(${i})]]`;
+			s += ", " + samplers[i] + " [[texture(" + i + ")]]";
+			s += ", sampler " + string_split(samplers[i], " ")[1] + "_sampler [[sampler(" + i + ")]]";
 		}
 	}
 
 	if (raw.shared_samplers.length > 0) {
 		for (let i: i32 = 0; i < raw.shared_samplers.length; ++i) {
 			let index: i32 = samplers.length + i;
-			s += `, ${raw.shared_samplers[i]} [[texture(${index})]]`;
+			s += ", " + raw + "shared_samplers[i]} [[texture(" + index + ")]]";
 		}
-		s += `, sampler ${shared_sampler} [[sampler(${samplers.length})]]`;
+		s += ", sampler " + shared_sampler + " [[sampler(" + samplers + "length})]]";
 	}
 
 	// Built-ins
-	if (raw.shader_type == 'vert' && string_index_of(raw.main, "gl_VertexID") >= 0) {
-		s += ', uint gl_VertexID [[vertex_id]]';
+	if (raw.shader_type == "vert" && string_index_of(raw.main, "gl_VertexID") >= 0) {
+		s += ", uint gl_VertexID [[vertex_id]]";
 	}
-	if (raw.shader_type == 'vert' && string_index_of(raw.main, "gl_InstanceID") >= 0) {
-		s += ', uint gl_InstanceID [[instance_id]]';
+	if (raw.shader_type == "vert" && string_index_of(raw.main, "gl_InstanceID") >= 0) {
+		s += ", uint gl_InstanceID [[instance_id]]";
 	}
 
 	// End main declaration
-	s += ') {\n';
-	s += '#define texture(tex, coord) tex.sample(tex ## _sampler, coord)\n';
+	s += ") {\n";
+	s += "#define texture(tex, coord) tex.sample(tex ## _sampler, coord)\n";
 
 	// Declare inputs
 	for (let i: i32 = 0; i < raw.ins.length; ++i) {
 		let a: string = raw.ins[i];
-		let b: string = substring(a, 5, a.length); // Remove type 'vec4 '
-		s += `${a} = in.${b};\n`;
+		let b: string = substring(a, 5, a.length); // Remove type "vec4 "
+		s += a + " = in." + b + ";\n";
 	}
 
 	for (let i: i32 = 0; i < raw.uniforms.length; ++i) {
 		let a: string = raw.uniforms[i];
-		if (!starts_with(a, 'sampler')) {
-			let b: string = string_split(a, " ")[1]; // Remove type 'vec4 '
+		if (!starts_with(a, "sampler")) {
+			let b: string = string_split(a, " ")[1]; // Remove type "vec4 "
 			if (string_index_of(b, "[") >= 0) {
 				b = substring(b, 0, string_index_of(b, "["));
 				let type: string = string_split(a, " ")[0];
-				s += `constant ${type} *${b} = uniforms.${b};\n`;
+				s += "constant " + type + " *" + b + " = uniforms." + b + ";\n";
 			}
 			else {
-				s += `${a} = uniforms.${b};\n`;
+				s += a + " = uniforms." + b + ";\n";
 			}
 		}
 	}
 
-	if (raw.shader_type == 'vert') {
-		s += 'vec4 gl_Position;\n';
+	if (raw.shader_type == "vert") {
+		s += "vec4 gl_Position;\n";
 		for (let i: i32 = 0; i < raw.outs.length; ++i) {
 			let a: string = raw.outs[i];
-			s += `${a};\n`;
+			s += a + ";\n";
 		}
 	}
 	else {
 		if (raw.outs.length > 0) {
 			if (num > 0) {
-				s += `vec4 fragColor[${num}];\n`;
+				s += "vec4 fragColor[" + num + "];\n";
 			}
 			else {
-				s += 'vec4 fragColor;\n';
+				s += "vec4 fragColor;\n";
 			}
 		}
 	}
@@ -607,30 +607,30 @@ function node_shader_get_msl(raw: node_shader_t, shared_sampler: string): string
 	s += raw.main_end;
 
 	// Write output structure
-	if (raw.outs.length > 0 || raw.shader_type == 'vert') {
-		s += 'main_out out = {};\n';
-		if (raw.shader_type == 'vert') {
-			s += 'gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n';
-			s += 'out.svpos = gl_Position;\n';
+	if (raw.outs.length > 0 || raw.shader_type == "vert") {
+		s += "main_out out = {};\n";
+		if (raw.shader_type == "vert") {
+			s += "gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n";
+			s += "out.svpos = gl_Position;\n";
 			for (let i: i32 = 0; i < raw.outs.length; ++i) {
 				let a: string = raw.outs[i];
-				let b: string = string_split(a, " ")[1]; // Remove type 'vec4 '
-				s += `out.${b} = ${b};\n`;
+				let b: string = string_split(a, " ")[1]; // Remove type "vec4 "
+				s += "out." + b + " = " + b + ";\n";
 			}
 		}
 		else {
 			if (num > 0) {
 				for (let i: i32 = 0; i < num; ++i) {
-					s += `out.fragColor_${i} = fragColor[${i}];\n`;
+					s += "out.fragColor_" + i + " = fragColor[" + i + "];\n";
 				}
 			}
 			else {
-				s += 'out.fragColor = fragColor;\n';
+				s += "out.fragColor = fragColor;\n";
 			}
 		}
-		s += 'return out;\n';
+		s += "return out;\n";
 	}
-	s += '}\n';
+	s += "}\n";
 	return s;
 }
 ///end
@@ -638,63 +638,63 @@ function node_shader_get_msl(raw: node_shader_t, shared_sampler: string): string
 ///if (krom_opengl || krom_vulkan)
 function node_shader_get_glsl(raw: node_shader_t, shared_sampler: string, version_header: string): string {
 	let s: string = version_header;
-	s += '#define textureArg(tex) sampler2D tex\n';
-	s += '#define texturePass(tex) tex\n';
-	s += '#define mul(a, b) b * a\n';
-	s += '#define textureShared texture\n';
-	s += '#define textureLodShared textureLod\n';
-	s += '#define atan2(x, y) atan(y, x)\n';
+	s += "#define textureArg(tex) sampler2D tex\n";
+	s += "#define texturePass(tex) tex\n";
+	s += "#define mul(a, b) b * a\n";
+	s += "#define textureShared texture\n";
+	s += "#define textureLodShared textureLod\n";
+	s += "#define atan2(x, y) atan(y, x)\n";
 	s += raw.header;
 
-	let in_ext: string = '';
-	let out_ext: string = '';
+	let in_ext: string = "";
+	let out_ext: string = "";
 
 	for (let i: i32 = 0; i < raw.includes.length; ++i) {
 		let a: string = raw.includes[i];
-		s += '#include "' + a + '"\n';
+		s += "#include \"" + a + "\"\n";
 	}
 	for (let i: i32 = 0; i < raw.ins.length; ++i) {
 		let a: string = raw.ins[i];
-		s += `in ${a}${in_ext};\n`;
+		s += "in " + a + in_ext + ";\n";
 	}
 	for (let i: i32 = 0; i < raw.outs.length; ++i) {
 		let a: string = raw.outs[i];
-		s += `out ${a}${out_ext};\n`;
+		s += "out " + a + out_ext + ";\n";
 	}
 	for (let i: i32 = 0; i < raw.uniforms.length; ++i) {
 		let a: string = raw.uniforms[i];
-		s += 'uniform ' + a + ';\n';
+		s += "uniform " + a + ";\n";
 	}
 	for (let i: i32 = 0; i < raw.shared_samplers.length; ++i) {
 		let a: string = raw.shared_samplers[i];
-		s += 'uniform ' + a + ';\n';
+		s += "uniform " + a + ";\n";
 	}
 	let values: string[] = map_to_array(raw.functions);
 	for (let i: i32 = 0; i < values.length; ++i) {
 		let f: string = values[i];
-		s += f + '\n';
+		s += f + "\n";
 	}
-	s += 'void main() {\n';
+	s += "void main() {\n";
 	s += raw.main_attribs;
 	s += raw.main_textures;
 	s += raw.main_normal;
 	s += raw.main_init;
 	s += raw.main;
 	s += raw.main_end;
-	s += '}\n';
+	s += "}\n";
 	return s;
 }
 ///end
 
 function node_shader_get(raw: node_shader_t): string {
 
-	if (raw.shader_type == 'vert' && raw.vstruct_as_vsin) {
+	if (raw.shader_type == "vert" && raw.vstruct_as_vsin) {
 		node_shader_vstruct_to_vsin(raw);
 	}
 
-	let shared_sampler: string = 'shared_sampler';
+	let shared_sampler: string = "shared_sampler";
 	if (raw.shared_samplers.length > 0) {
-		shared_sampler = string_split(raw.shared_samplers[0], ' ')[1] + '_sampler';
+		shared_sampler = string_split(raw.shared_samplers[0], " ")[1] + "_sampler";
 	}
 
 	///if (krom_direct3d11 || krom_direct3d12)
@@ -702,17 +702,17 @@ function node_shader_get(raw: node_shader_t): string {
 	///elseif krom_metal
 	let s: string = node_shader_get_msl(raw, shared_sampler);
 	///elseif krom_vulkan
-	let version_header: string = '#version 450\n';
+	let version_header: string = "#version 450\n";
 	let s: string = node_shader_get_glsl(raw, shared_sampler, version_header);
 	///elseif krom_android
-	let version_header: string = '#version 300 es\n';
-	if (raw.shader_type == 'frag') {
-		version_header += 'precision highp float;\n';
-		version_header += 'precision mediump int;\n';
+	let version_header: string = "#version 300 es\n";
+	if (raw.shader_type == "frag") {
+		version_header += "precision highp float;\n";
+		version_header += "precision mediump int;\n";
 	}
 	let s: string = node_shader_get_glsl(raw, shared_sampler, version_header);
 	///elseif krom_opengl
-	let version_header: string = '#version 330\n';
+	let version_header: string = "#version 330\n";
 	let s: string = node_shader_get_glsl(raw, shared_sampler, version_header);
 	///end
 

+ 7 - 7
base/Sources/node_shader_context.ts

@@ -23,9 +23,9 @@ function node_shader_context_create(material: material_t, props: any): node_shad
 		alpha_blend_source: props.alpha_blend_source,
 		alpha_blend_destination: props.alpha_blend_destination,
 		alpha_blend_operation: props.alpha_blend_operation,
-		fragment_shader: '',
-		vertex_shader: '',
-		vertex_elements: 'vertex_elements' in props ? props.vertex_elements : [ {name: "pos", data: 'short4norm'}, {name: "nor", data: 'short2norm'}],
+		fragment_shader: "",
+		vertex_shader: "",
+		vertex_elements: props.vertex_elements != null ? props.vertex_elements : [ {name: "pos", data: "short4norm"}, {name: "nor", data: "short2norm"}],
 		color_attachments: props.color_attachments,
 		depth_attachment: props.depth_attachment
 	};
@@ -113,14 +113,14 @@ function node_shader_context_add_texture_unit(raw: node_shader_context_t, ctype:
 }
 
 function node_shader_context_make_vert(raw: node_shader_context_t): node_shader_t {
-	raw.data.vertex_shader = raw.material.name + '_' + raw.data.name + '.vert';
-	raw.vert = node_shader_create(raw, 'vert');
+	raw.data.vertex_shader = raw.material.name + "_" + raw.data.name + ".vert";
+	raw.vert = node_shader_create(raw, "vert");
 	return raw.vert;
 }
 
 function node_shader_context_make_frag(raw: node_shader_context_t): node_shader_t {
-	raw.data.fragment_shader = raw.material.name + '_' + raw.data.name + '.frag';
-	raw.frag = node_shader_create(raw, 'frag');
+	raw.data.fragment_shader = raw.material.name + "_" + raw.data.name + ".frag";
+	raw.frag = node_shader_create(raw, "frag");
 	return raw.frag;
 }
 

+ 3 - 2
base/Sources/operator.ts

@@ -13,7 +13,8 @@ function operator_run(name: string) {
 
 function operator_update() {
 	if (mouse_started_any() || keyboard_started_any()) {
-		for (let op in config_keymap) {
+		for (let i: i32 = 0; i < base_keymap_keys.length; ++i) {
+			let op: string = base_keymap_keys[i];
 			if (operator_shortcut(config_keymap[op])) {
 				operator_run(op);
 			}
@@ -21,7 +22,7 @@ function operator_update() {
 	}
 }
 
-function operator_shortcut(s: string, type = shortcut_type_t.STARTED): bool {
+function operator_shortcut(s: string, type: shortcut_type_t = shortcut_type_t.STARTED): bool {
 	if (s == "") {
 		return false;
 	}

+ 2 - 2
base/Sources/parser_blend.ts

@@ -126,7 +126,7 @@ function parser_blend_parse(raw: blend_t) {
 
 		// Memory address
 		let addr: any = parser_blend_read_pointer(raw);
-		if (!raw.map.has(addr)) {
+		if (map_get(raw.map, addr) == null) {
 			map_set(raw.map, addr, b);
 		}
 
@@ -426,7 +426,7 @@ function bl_handle_get(raw: bl_handle_t, name: string, index: i32 = 0, as_type:
 			if (is_pointer) {
 				raw.block.blend.pos = raw.block.pos + new_offset;
 				let addr: any = parser_blend_read_pointer(raw.block.blend);
-				if (raw.block.blend.map.has(addr)) {
+				if (map_get(raw.block.blend.map, addr) != null) {
 					h.block = map_get(raw.block.blend.map, addr);
 				}
 				else h.block = raw.block;

Fișier diff suprimat deoarece este prea mare
+ 230 - 230
base/Sources/parser_material.ts


+ 1 - 1
base/Sources/path.ts

@@ -72,7 +72,7 @@ function path_working_dir(): string {
 	if (path_working_dir_cache == null) {
 		let cmd: string = path_pwd;
 		let save: string = (path_is_protected() ? krom_save_path() : path_data() + path_sep) + "working_dir.txt";
-		krom_sys_command(cmd + ' > "' + save + '"');
+		krom_sys_command(cmd + " > \"" + save + "\"");
 		path_working_dir_cache = trim_end(sys_buffer_to_string(krom_load_blob(save)));
 	}
 	return path_working_dir_cache;

+ 2 - 2
base/Sources/physics_body.ts

@@ -397,7 +397,7 @@ function physics_body_fill_convex_hull(pb: physics_body_t, scale: vec4_t, margin
 	map_set(physics_body_convex_hull_cache, data, shape);
 	map_set(physics_body_users_cache, data, 1);
 
-	let positions: i16_array_t = mesh_data_get_vertex_array(data, 'pos').values;
+	let positions: i16_array_t = mesh_data_get_vertex_array(data, "pos").values;
 
 	let sx: f32 = scale.x * (1.0 - margin) * (1 / 32767);
 	let sy: f32 = scale.y * (1.0 - margin) * (1 / 32767);
@@ -429,7 +429,7 @@ function physics_body_fill_triangle_mesh(pb: physics_body_t, scale: vec4_t): Amm
 	map_set(physics_body_triangle_mesh_cache, data, triangle_mesh);
 	map_set(physics_body_users_cache, data, 1);
 
-	let positions: i16_array_t = mesh_data_get_vertex_array(data, 'pos').values;
+	let positions: i16_array_t = mesh_data_get_vertex_array(data, "pos").values;
 	let indices: any = data._indices;
 
 	let sx: f32 = scale.x * (1 / 32767);

+ 1 - 1
base/Sources/project.ts

@@ -46,7 +46,7 @@ function project_save(saveAndQuit: bool = false) {
 	if (project_filepath == "") {
 		///if krom_ios
 		let document_directory: string = krom_save_dialog("", "");
-		document_directory = substring(document_directory, 0, document_directory.length - 8); // Strip /'untitled'
+		document_directory = substring(document_directory, 0, document_directory.length - 8); // Strip /"untitled"
 		project_filepath = document_directory + "/" + sys_title() + ".arm";
 		///elseif krom_android
 		project_filepath = krom_save_path() + "/" + sys_title() + ".arm";

+ 479 - 479
base/Sources/strings.ts

@@ -37,520 +37,520 @@ function strings_graphics_api(): string {
 	///end
 }
 
-let str_tex_checker: string = `
-vec3 tex_checker(const vec3 co, const vec3 col1, const vec3 col2, const float scale) {
-	// Prevent precision issues on unit coordinates
-	vec3 p = (co + 0.000001 * 0.999999) * scale;
-	float xi = abs(floor(p.x));
-	float yi = abs(floor(p.y));
-	float zi = abs(floor(p.z));
-	bool check = ((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0)));
-	return check ? col1 : col2;
-}
-float tex_checker_f(const vec3 co, const float scale) {
-	vec3 p = (co + 0.000001 * 0.999999) * scale;
-	float xi = abs(floor(p.x));
-	float yi = abs(floor(p.y));
-	float zi = abs(floor(p.z));
-	return float((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0)));
-}
-`;
+let str_tex_checker: string = " \
+vec3 tex_checker(const vec3 co, const vec3 col1, const vec3 col2, const float scale) { \
+	// Prevent precision issues on unit coordinates \
+	vec3 p = (co + 0.000001 * 0.999999) * scale; \
+	float xi = abs(floor(p.x)); \
+	float yi = abs(floor(p.y)); \
+	float zi = abs(floor(p.z)); \
+	bool check = ((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0))); \
+	return check ? col1 : col2; \
+} \
+float tex_checker_f(const vec3 co, const float scale) { \
+	vec3 p = (co + 0.000001 * 0.999999) * scale; \
+	float xi = abs(floor(p.x)); \
+	float yi = abs(floor(p.y)); \
+	float zi = abs(floor(p.z)); \
+	return float((mod(xi, 2.0) == mod(yi, 2.0)) == bool(mod(zi, 2.0))); \
+} \
+";
 
 	// Created by inigo quilez - iq/2013
 	// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
-let str_tex_voronoi: string = `
-vec4 tex_voronoi(const vec3 x, textureArg(snoise256)) {
-	vec3 p = floor(x);
-	vec3 f = fract(x);
-	float id = 0.0;
-	float res = 100.0;
-	for (int k = -1; k <= 1; k++)
-	for (int j = -1; j <= 1; j++)
-	for (int i = -1; i <= 1; i++) {
-		vec3 b = vec3(float(i), float(j), float(k));
-		vec3 pb = p + b;
-		vec3 r = vec3(b) - f + texture(snoise256, (pb.xy + vec2(3.0, 1.0) * pb.z + 0.5) / 256.0).xyz;
-		float d = dot(r, r);
-		if (d < res) {
-			id = dot(p + b, vec3(1.0, 57.0, 113.0));
-			res = d;
-		}
-	}
-	vec3 col = 0.5 + 0.5 * cos(id * 0.35 + vec3(0.0, 1.0, 2.0));
-	return vec4(col, sqrt(res));
-}
-`;
+let str_tex_voronoi: string = " \
+vec4 tex_voronoi(const vec3 x, textureArg(snoise256)) { \
+	vec3 p = floor(x); \
+	vec3 f = fract(x); \
+	float id = 0.0; \
+	float res = 100.0; \
+	for (int k = -1; k <= 1; k++) \
+	for (int j = -1; j <= 1; j++) \
+	for (int i = -1; i <= 1; i++) { \
+		vec3 b = vec3(float(i), float(j), float(k)); \
+		vec3 pb = p + b; \
+		vec3 r = vec3(b) - f + texture(snoise256, (pb.xy + vec2(3.0, 1.0) * pb.z + 0.5) / 256.0).xyz; \
+		float d = dot(r, r); \
+		if (d < res) { \
+			id = dot(p + b, vec3(1.0, 57.0, 113.0)); \
+			res = d; \
+		} \
+	} \
+	vec3 col = 0.5 + 0.5 * cos(id * 0.35 + vec3(0.0, 1.0, 2.0)); \
+	return vec4(col, sqrt(res)); \
+} \
+";
 
 	// By Morgan McGuire @morgan3d, http://graphicscodex.com Reuse permitted under the BSD license.
 	// https://www.shadertoy.com/view/4dS3Wd
-let str_tex_noise: string = `
-float hash(float n) { return fract(sin(n) * 1e4); }
-float tex_noise_f(vec3 x) {
-    const vec3 step = vec3(110, 241, 171);
-    vec3 i = floor(x);
-    vec3 f = fract(x);
-    float n = dot(i, step);
-    vec3 u = f * f * (3.0 - 2.0 * f);
-    return mix(mix(mix(hash(n + dot(step, vec3(0, 0, 0))), hash(n + dot(step, vec3(1, 0, 0))), u.x),
-                   mix(hash(n + dot(step, vec3(0, 1, 0))), hash(n + dot(step, vec3(1, 1, 0))), u.x), u.y),
-               mix(mix(hash(n + dot(step, vec3(0, 0, 1))), hash(n + dot(step, vec3(1, 0, 1))), u.x),
-                   mix(hash(n + dot(step, vec3(0, 1, 1))), hash(n + dot(step, vec3(1, 1, 1))), u.x), u.y), u.z);
-}
-float tex_noise(vec3 p) {
-	p *= 1.25;
-	float f = 0.5 * tex_noise_f(p); p *= 2.01;
-	f += 0.25 * tex_noise_f(p); p *= 2.02;
-	f += 0.125 * tex_noise_f(p); p *= 2.03;
-	f += 0.0625 * tex_noise_f(p);
-	return 1.0 - f;
-}
-`;
+let str_tex_noise: string = " \
+float hash(float n) { return fract(sin(n) * 1e4); } \
+float tex_noise_f(vec3 x) { \
+    const vec3 step = vec3(110, 241, 171); \
+    vec3 i = floor(x); \
+    vec3 f = fract(x); \
+    float n = dot(i, step); \
+    vec3 u = f * f * (3.0 - 2.0 * f); \
+    return mix(mix(mix(hash(n + dot(step, vec3(0, 0, 0))), hash(n + dot(step, vec3(1, 0, 0))), u.x), \
+                   mix(hash(n + dot(step, vec3(0, 1, 0))), hash(n + dot(step, vec3(1, 1, 0))), u.x), u.y), \
+               mix(mix(hash(n + dot(step, vec3(0, 0, 1))), hash(n + dot(step, vec3(1, 0, 1))), u.x), \
+                   mix(hash(n + dot(step, vec3(0, 1, 1))), hash(n + dot(step, vec3(1, 1, 1))), u.x), u.y), u.z); \
+} \
+float tex_noise(vec3 p) { \
+	p *= 1.25; \
+	float f = 0.5 * tex_noise_f(p); p *= 2.01; \
+	f += 0.25 * tex_noise_f(p); p *= 2.02; \
+	f += 0.125 * tex_noise_f(p); p *= 2.03; \
+	f += 0.0625 * tex_noise_f(p); \
+	return 1.0 - f; \
+} \
+";
 
 	// Based on noise created by Nikita Miropolskiy, nikat/2013
 	// Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
-let str_tex_musgrave: string = `
-vec3 random3(const vec3 c) {
-	float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0)));
-	vec3 r;
-	r.z = fract(512.0 * j);
-	j *= 0.125;
-	r.x = fract(512.0 * j);
-	j *= 0.125;
-	r.y = fract(512.0 * j);
-	return r - 0.5;
-}
-float tex_musgrave_f(const vec3 p) {
-	const float F3 = 0.3333333;
-	const float G3 = 0.1666667;
-	vec3 s = floor(p + dot(p, vec3(F3, F3, F3)));
-	vec3 x = p - s + dot(s, vec3(G3, G3, G3));
-	vec3 e = step(vec3(0.0, 0.0, 0.0), x - x.yzx);
-	vec3 i1 = e*(1.0 - e.zxy);
-	vec3 i2 = 1.0 - e.zxy*(1.0 - e);
-	vec3 x1 = x - i1 + G3;
-	vec3 x2 = x - i2 + 2.0*G3;
-	vec3 x3 = x - 1.0 + 3.0*G3;
-	vec4 w, d;
-	w.x = dot(x, x);
-	w.y = dot(x1, x1);
-	w.z = dot(x2, x2);
-	w.w = dot(x3, x3);
-	w = max(0.6 - w, 0.0);
-	d.x = dot(random3(s), x);
-	d.y = dot(random3(s + i1), x1);
-	d.z = dot(random3(s + i2), x2);
-	d.w = dot(random3(s + 1.0), x3);
-	w *= w;
-	w *= w;
-	d *= w;
-	return clamp(dot(d, vec4(52.0, 52.0, 52.0, 52.0)), 0.0, 1.0);
-}
-`;
+let str_tex_musgrave: string = " \
+vec3 random3(const vec3 c) { \
+	float j = 4096.0 * sin(dot(c, vec3(17.0, 59.4, 15.0))); \
+	vec3 r; \
+	r.z = fract(512.0 * j); \
+	j *= 0.125; \
+	r.x = fract(512.0 * j); \
+	j *= 0.125; \
+	r.y = fract(512.0 * j); \
+	return r - 0.5; \
+} \
+float tex_musgrave_f(const vec3 p) { \
+	const float F3 = 0.3333333; \
+	const float G3 = 0.1666667; \
+	vec3 s = floor(p + dot(p, vec3(F3, F3, F3))); \
+	vec3 x = p - s + dot(s, vec3(G3, G3, G3)); \
+	vec3 e = step(vec3(0.0, 0.0, 0.0), x - x.yzx); \
+	vec3 i1 = e * (1.0 - e.zxy); \
+	vec3 i2 = 1.0 - e.zxy * (1.0 - e); \
+	vec3 x1 = x - i1 + G3; \
+	vec3 x2 = x - i2 + 2.0 * G3; \
+	vec3 x3 = x - 1.0 + 3.0 * G3; \
+	vec4 w, d; \
+	w.x = dot(x, x); \
+	w.y = dot(x1, x1); \
+	w.z = dot(x2, x2); \
+	w.w = dot(x3, x3); \
+	w = max(0.6 - w, 0.0); \
+	d.x = dot(random3(s), x); \
+	d.y = dot(random3(s + i1), x1); \
+	d.z = dot(random3(s + i2), x2); \
+	d.w = dot(random3(s + 1.0), x3); \
+	w *= w; \
+	w *= w; \
+	d *= w; \
+	return clamp(dot(d, vec4(52.0, 52.0, 52.0, 52.0)), 0.0, 1.0); \
+} \
+";
 
-let str_hue_sat: string = `
-vec3 hsv_to_rgb(const vec3 c) {
-	const vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
-	vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
-	return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
-}
-vec3 rgb_to_hsv(const vec3 c) {
-	const vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
-	vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
-	vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));
-	float d = q.x - min(q.w, q.y);
-	float e = 1.0e-10;
-	return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
-}
-vec3 hue_sat(const vec3 col, const vec4 shift) {
-	vec3 hsv = rgb_to_hsv(col);
-	hsv.x += shift.x;
-	hsv.y *= shift.y;
-	hsv.z *= shift.z;
-	return mix(hsv_to_rgb(hsv), col, shift.w);
-}
-`;
+let str_hue_sat: string = " \
+vec3 hsv_to_rgb(const vec3 c) { \
+	const vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); \
+	vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); \
+	return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); \
+} \
+vec3 rgb_to_hsv(const vec3 c) { \
+	const vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); \
+	vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); \
+	vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); \
+	float d = q.x - min(q.w, q.y); \
+	float e = 1.0e-10; \
+	return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); \
+} \
+vec3 hue_sat(const vec3 col, const vec4 shift) { \
+	vec3 hsv = rgb_to_hsv(col); \
+	hsv.x += shift.x; \
+	hsv.y *= shift.y; \
+	hsv.z *= shift.z; \
+	return mix(hsv_to_rgb(hsv), col, shift.w); \
+} \
+";
 
 // https://twitter.com/Donzanoid/status/903424376707657730
-let str_wavelength_to_rgb: string = `
-vec3 wavelength_to_rgb(const float t) {
-	vec3 r = t * 2.1 - vec3(1.8, 1.14, 0.3);
-	return 1.0 - r * r;
-}
-`;
+let str_wavelength_to_rgb: string = " \
+vec3 wavelength_to_rgb(const float t) { \
+	vec3 r = t * 2.1 - vec3(1.8, 1.14, 0.3); \
+	return 1.0 - r * r; \
+} \
+";
 
-let str_tex_magic: string = `
-vec3 tex_magic(const vec3 p) {
-	float a = 1.0 - (sin(p.x) + sin(p.y));
-	float b = 1.0 - sin(p.x - p.y);
-	float c = 1.0 - sin(p.x + p.y);
-	return vec3(a, b, c);
-}
-float tex_magic_f(const vec3 p) {
-	vec3 c = tex_magic(p);
-	return (c.x + c.y + c.z) / 3.0;
-}
-`;
+let str_tex_magic: string = " \
+vec3 tex_magic(const vec3 p) { \
+	float a = 1.0 - (sin(p.x) + sin(p.y)); \
+	float b = 1.0 - sin(p.x - p.y); \
+	float c = 1.0 - sin(p.x + p.y); \
+	return vec3(a, b, c); \
+} \
+float tex_magic_f(const vec3 p) { \
+	vec3 c = tex_magic(p); \
+	return (c.x + c.y + c.z) / 3.0; \
+} \
+";
 
-let str_tex_brick: string = `
-float tex_brick_noise(int n) {
-	int nn;
-	n = (n >> 13) ^ n;
-	nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff;
-	return 0.5f * float(nn) / 1073741824.0;
-}
-vec3 tex_brick(vec3 p, const vec3 c1, const vec3 c2, const vec3 c3) {
-	vec3 brickSize = vec3(0.9, 0.49, 0.49);
-	vec3 mortarSize = vec3(0.05, 0.1, 0.1);
-	p /= brickSize / 2;
-	if (fract(p.y * 0.5) > 0.5) p.x += 0.5;
-	float col = floor(p.x / (brickSize.x + (mortarSize.x * 2.0)));
-	float row = p.y;
-	p = fract(p);
-	vec3 b = step(p, 1.0 - mortarSize);
-	float tint = min(max(tex_brick_noise((int(col) << 16) + (int(row) & 0xFFFF)), 0.0), 1.0);
-	return mix(c3, mix(c1, c2, tint), b.x * b.y * b.z);
-}
-float tex_brick_f(vec3 p) {
-	p /= vec3(0.9, 0.49, 0.49) / 2;
-	if (fract(p.y * 0.5) > 0.5) p.x += 0.5;
-	p = fract(p);
-	vec3 b = step(p, vec3(0.95, 0.9, 0.9));
-	return mix(1.0, 0.0, b.x * b.y * b.z);
-}
-`;
+let str_tex_brick: string = " \
+float tex_brick_noise(int n) { \
+	int nn; \
+	n = (n >> 13) ^ n; \
+	nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; \
+	return 0.5f * float(nn) / 1073741824.0; \
+} \
+vec3 tex_brick(vec3 p, const vec3 c1, const vec3 c2, const vec3 c3) { \
+	vec3 brickSize = vec3(0.9, 0.49, 0.49); \
+	vec3 mortarSize = vec3(0.05, 0.1, 0.1); \
+	p /= brickSize / 2; \
+	if (fract(p.y * 0.5) > 0.5) p.x += 0.5; \
+	float col = floor(p.x / (brickSize.x + (mortarSize.x * 2.0))); \
+	float row = p.y; \
+	p = fract(p); \
+	vec3 b = step(p, 1.0 - mortarSize); \
+	float tint = min(max(tex_brick_noise((int(col) << 16) + (int(row) & 0xFFFF)), 0.0), 1.0); \
+	return mix(c3, mix(c1, c2, tint), b.x * b.y * b.z); \
+} \
+float tex_brick_f(vec3 p) { \
+	p /= vec3(0.9, 0.49, 0.49) / 2; \
+	if (fract(p.y * 0.5) > 0.5) p.x += 0.5; \
+	p = fract(p); \
+	vec3 b = step(p, vec3(0.95, 0.9, 0.9)); \
+	return mix(1.0, 0.0, b.x * b.y * b.z); \
+} \
+";
 
-let str_tex_wave: string = `
-float tex_wave_f(const vec3 p) {
-	return 1.0 - sin((p.x + p.y) * 10.0);
-}
-`;
+let str_tex_wave: string = " \
+float tex_wave_f(const vec3 p) { \
+	return 1.0 - sin((p.x + p.y) * 10.0); \
+} \
+";
 
-let str_brightcontrast: string = `
-vec3 brightcontrast(const vec3 col, const float bright, const float contr) {
-	float a = 1.0 + contr;
-	float b = bright - contr * 0.5;
-	return max(a * col + b, 0.0);
-}
-`;
+let str_brightcontrast: string = " \
+vec3 brightcontrast(const vec3 col, const float bright, const float contr) { \
+	float a = 1.0 + contr; \
+	float b = bright - contr * 0.5; \
+	return max(a * col + b, 0.0); \
+} \
+";
 
 ///if arm_voxels
-let str_trace_ao: string = `
-float traceConeAO(sampler3D voxels, const vec3 origin, vec3 dir, const float aperture, const float maxDist, const float offset) {
-	const ivec3 voxelgiResolution = ivec3(256, 256, 256);
-	const float voxelgiStep = 1.0;
-	const float VOXEL_SIZE = (2.0 / voxelgiResolution.x) * voxelgiStep;
-	dir = normalize(dir);
-	float sampleCol = 0.0;
-	float dist = offset;
-	float diam = dist * aperture;
-	vec3 samplePos;
-	while (sampleCol < 1.0 && dist < maxDist) {
-		samplePos = dir * dist + origin;
-		float mip = max(log2(diam * voxelgiResolution.x), 0);
-		float mipSample = textureLod(voxels, samplePos * 0.5 + vec3(0.5, 0.5, 0.5), mip).r;
-		sampleCol += (1 - sampleCol) * mipSample;
-		dist += max(diam / 2, VOXEL_SIZE);
-		diam = dist * aperture;
-	}
-	return sampleCol;
-}
-vec3 tangent(const vec3 n) {
-	vec3 t1 = cross(n, vec3(0, 0, 1));
-	vec3 t2 = cross(n, vec3(0, 1, 0));
-	if (length(t1) > length(t2)) return normalize(t1);
-	else return normalize(t2);
-}
-float traceAO(const vec3 origin, const vec3 normal, const float vrange, const float voffset) {
-	const float angleMix = 0.5f;
-	const float aperture = 0.55785173935;
-	vec3 o1 = normalize(tangent(normal));
-	vec3 o2 = normalize(cross(o1, normal));
-	vec3 c1 = 0.5f * (o1 + o2);
-	vec3 c2 = 0.5f * (o1 - o2);
-	float MAX_DISTANCE = 1.73205080757 * 2.0 * vrange;
-	const ivec3 voxelgiResolution = ivec3(256, 256, 256);
-	const float voxelgiStep = 1.0;
-	const float VOXEL_SIZE = (2.0 / voxelgiResolution.x) * voxelgiStep;
-	float offset = 1.5 * VOXEL_SIZE * 2.5 * voffset;
-	float col = traceConeAO(voxels, origin, normal, aperture, MAX_DISTANCE, offset);
-	col += traceConeAO(voxels, origin, mix(normal, o1, angleMix), aperture, MAX_DISTANCE, offset);
-	col += traceConeAO(voxels, origin, mix(normal, o2, angleMix), aperture, MAX_DISTANCE, offset);
-	col += traceConeAO(voxels, origin, mix(normal, -c1, angleMix), aperture, MAX_DISTANCE, offset);
-	col += traceConeAO(voxels, origin, mix(normal, -c2, angleMix), aperture, MAX_DISTANCE, offset);
-	col += traceConeAO(voxels, origin, mix(normal, -o1, angleMix), aperture, MAX_DISTANCE, offset);
-	col += traceConeAO(voxels, origin, mix(normal, -o2, angleMix), aperture, MAX_DISTANCE, offset);
-	col += traceConeAO(voxels, origin, mix(normal, c1, angleMix), aperture, MAX_DISTANCE, offset);
-	col += traceConeAO(voxels, origin, mix(normal, c2, angleMix), aperture, MAX_DISTANCE, offset);
-	return col / 9.0;
-}
-`;
+let str_trace_ao: string = " \
+float traceConeAO(sampler3D voxels, const vec3 origin, vec3 dir, const float aperture, const float maxDist, const float offset) { \
+	const ivec3 voxelgiResolution = ivec3(256, 256, 256); \
+	const float voxelgiStep = 1.0; \
+	const float VOXEL_SIZE = (2.0 / voxelgiResolution.x) * voxelgiStep; \
+	dir = normalize(dir); \
+	float sampleCol = 0.0; \
+	float dist = offset; \
+	float diam = dist * aperture; \
+	vec3 samplePos; \
+	while (sampleCol < 1.0 && dist < maxDist) { \
+		samplePos = dir * dist + origin; \
+		float mip = max(log2(diam * voxelgiResolution.x), 0); \
+		float mipSample = textureLod(voxels, samplePos * 0.5 + vec3(0.5, 0.5, 0.5), mip).r; \
+		sampleCol += (1 - sampleCol) * mipSample; \
+		dist += max(diam / 2, VOXEL_SIZE); \
+		diam = dist * aperture; \
+	} \
+	return sampleCol; \
+} \
+vec3 tangent(const vec3 n) { \
+	vec3 t1 = cross(n, vec3(0, 0, 1)); \
+	vec3 t2 = cross(n, vec3(0, 1, 0)); \
+	if (length(t1) > length(t2)) return normalize(t1); \
+	else return normalize(t2); \
+} \
+float traceAO(const vec3 origin, const vec3 normal, const float vrange, const float voffset) { \
+	const float angleMix = 0.5f; \
+	const float aperture = 0.55785173935; \
+	vec3 o1 = normalize(tangent(normal)); \
+	vec3 o2 = normalize(cross(o1, normal)); \
+	vec3 c1 = 0.5f * (o1 + o2); \
+	vec3 c2 = 0.5f * (o1 - o2); \
+	float MAX_DISTANCE = 1.73205080757 * 2.0 * vrange; \
+	const ivec3 voxelgiResolution = ivec3(256, 256, 256); \
+	const float voxelgiStep = 1.0; \
+	const float VOXEL_SIZE = (2.0 / voxelgiResolution.x) * voxelgiStep; \
+	float offset = 1.5 * VOXEL_SIZE * 2.5 * voffset; \
+	float col = traceConeAO(voxels, origin, normal, aperture, MAX_DISTANCE, offset); \
+	col += traceConeAO(voxels, origin, mix(normal, o1, angleMix), aperture, MAX_DISTANCE, offset); \
+	col += traceConeAO(voxels, origin, mix(normal, o2, angleMix), aperture, MAX_DISTANCE, offset); \
+	col += traceConeAO(voxels, origin, mix(normal, -c1, angleMix), aperture, MAX_DISTANCE, offset); \
+	col += traceConeAO(voxels, origin, mix(normal, -c2, angleMix), aperture, MAX_DISTANCE, offset); \
+	col += traceConeAO(voxels, origin, mix(normal, -o1, angleMix), aperture, MAX_DISTANCE, offset); \
+	col += traceConeAO(voxels, origin, mix(normal, -o2, angleMix), aperture, MAX_DISTANCE, offset); \
+	col += traceConeAO(voxels, origin, mix(normal, c1, angleMix), aperture, MAX_DISTANCE, offset); \
+	col += traceConeAO(voxels, origin, mix(normal, c2, angleMix), aperture, MAX_DISTANCE, offset); \
+	return col / 9.0; \
+} \
+";
 ///end
 
-let str_cotangent_frame: string = `
-mat3 cotangentFrame(const vec3 n, const vec3 p, const vec2 duv1, const vec2 duv2) {
-	vec3 dp1 = dFdx(p);
-	vec3 dp2 = dFdy(p);
-	vec3 dp2perp = cross(dp2, n);
-	vec3 dp1perp = cross(n, dp1);
-	vec3 t = dp2perp * duv1.x + dp1perp * duv2.x;
-	vec3 b = dp2perp * duv1.y + dp1perp * duv2.y;
-	float invmax = inversesqrt(max(dot(t, t), dot(b, b)));
-	return mat3(t * invmax, b * invmax, n);
-}
-mat3 cotangentFrame(const vec3 n, const vec3 p, const vec2 texCoord) {
-	return cotangentFrame(n, p, dFdx(texCoord), dFdy(texCoord));
-}
-`;
+let str_cotangent_frame: string = " \
+mat3 cotangentFrame(const vec3 n, const vec3 p, const vec2 duv1, const vec2 duv2) { \
+	vec3 dp1 = dFdx(p); \
+	vec3 dp2 = dFdy(p); \
+	vec3 dp2perp = cross(dp2, n); \
+	vec3 dp1perp = cross(n, dp1); \
+	vec3 t = dp2perp * duv1.x + dp1perp * duv2.x; \
+	vec3 b = dp2perp * duv1.y + dp1perp * duv2.y; \
+	float invmax = inversesqrt(max(dot(t, t), dot(b, b))); \
+	return mat3(t * invmax, b * invmax, n); \
+} \
+mat3 cotangentFrame(const vec3 n, const vec3 p, const vec2 texCoord) { \
+	return cotangentFrame(n, p, dFdx(texCoord), dFdy(texCoord)); \
+} \
+";
 
-let str_octahedron_wrap: string = `
-vec2 octahedronWrap(const vec2 v) {
-	return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0));
-}
-`;
+let str_octahedron_wrap: string = " \
+vec2 octahedronWrap(const vec2 v) { \
+	return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0)); \
+} \
+";
 
-let str_pack_float_int16: string = `
-float packFloatInt16(const float f, const uint i) {
-	const float prec = float(1 << 16);
-	const float maxi = float(1 << 4);
-	const float precMinusOne = prec - 1.0;
-	const float t1 = ((prec / maxi) - 1.0) / precMinusOne;
-	const float t2 = (prec / maxi) / precMinusOne;
-	return t1 * f + t2 * float(i);
-}
-`;
+let str_pack_float_int16: string = " \
+float packFloatInt16(const float f, const uint i) { \
+	const float prec = float(1 << 16); \
+	const float maxi = float(1 << 4); \
+	const float precMinusOne = prec - 1.0; \
+	const float t1 = ((prec / maxi) - 1.0) / precMinusOne; \
+	const float t2 = (prec / maxi) / precMinusOne; \
+	return t1 * f + t2 * float(i); \
+} \
+";
 
 ///if arm_skin
-let str_get_skinning_dual_quat: string = `
-void getSkinningDualQuat(const ivec4 bone, vec4 weight, out vec4 A, inout vec4 B) {
-	ivec4 bonei = bone * 2;
-	mat4 matA = mat4(
-		skinBones[bonei.x],
-		skinBones[bonei.y],
-		skinBones[bonei.z],
-		skinBones[bonei.w]);
-	mat4 matB = mat4(
-		skinBones[bonei.x + 1],
-		skinBones[bonei.y + 1],
-		skinBones[bonei.z + 1],
-		skinBones[bonei.w + 1]);
-	weight.xyz *= sign(mul(matA, matA[3])).xyz;
-	A = mul(weight, matA);
-	B = mul(weight, matB);
-	float invNormA = 1.0 / length(A);
-	A *= invNormA;
-	B *= invNormA;
-}
-`;
+let str_get_skinning_dual_quat: string = " \
+void getSkinningDualQuat(const ivec4 bone, vec4 weight, out vec4 A, inout vec4 B) { \
+	ivec4 bonei = bone * 2; \
+	mat4 matA = mat4( \
+		skinBones[bonei.x], \
+		skinBones[bonei.y], \
+		skinBones[bonei.z], \
+		skinBones[bonei.w]); \
+	mat4 matB = mat4( \
+		skinBones[bonei.x + 1], \
+		skinBones[bonei.y + 1], \
+		skinBones[bonei.z + 1], \
+		skinBones[bonei.w + 1]); \
+	weight.xyz *= sign(mul(matA, matA[3])).xyz; \
+	A = mul(weight, matA); \
+	B = mul(weight, matB); \
+	float invNormA = 1.0 / length(A); \
+	A *= invNormA; \
+	B *= invNormA; \
+} \
+";
 ///end
 
-let str_create_basis: string = `
-void createBasis(vec3 normal, out vec3 tangent, out vec3 binormal) {
-	tangent = normalize(cameraRight - normal * dot(cameraRight, normal));
-	binormal = cross(tangent, normal);
-}
-`;
+let str_create_basis: string = " \
+void createBasis(vec3 normal, out vec3 tangent, out vec3 binormal) { \
+	tangent = normalize(cameraRight - normal * dot(cameraRight, normal)); \
+	binormal = cross(tangent, normal); \
+} \
+";
 
 function str_sh_irradiance(): string {
 ///if krom_metal
-	return `vec3 shIrradiance(const vec3 nor, constant vec4 shirr[7]) {
-	const float c1 = 0.429043;
-	const float c2 = 0.511664;
-	const float c3 = 0.743125;
-	const float c4 = 0.886227;
-	const float c5 = 0.247708;
-	vec3 cl00 = vec3(shirr[0].x, shirr[0].y, shirr[0].z);
-	vec3 cl1m1 = vec3(shirr[0].w, shirr[1].x, shirr[1].y);
-	vec3 cl10 = vec3(shirr[1].z, shirr[1].w, shirr[2].x);
-	vec3 cl11 = vec3(shirr[2].y, shirr[2].z, shirr[2].w);
-	vec3 cl2m2 = vec3(shirr[3].x, shirr[3].y, shirr[3].z);
-	vec3 cl2m1 = vec3(shirr[3].w, shirr[4].x, shirr[4].y);
-	vec3 cl20 = vec3(shirr[4].z, shirr[4].w, shirr[5].x);
-	vec3 cl21 = vec3(shirr[5].y, shirr[5].z, shirr[5].w);
-	vec3 cl22 = vec3(shirr[6].x, shirr[6].y, shirr[6].z);
-	return (
-		c1 * cl22 * (nor.y * nor.y - (-nor.z) * (-nor.z)) +
-		c3 * cl20 * nor.x * nor.x +
-		c4 * cl00 -
-		c5 * cl20 +
-		2.0 * c1 * cl2m2 * nor.y * (-nor.z) +
-		2.0 * c1 * cl21  * nor.y * nor.x +
-		2.0 * c1 * cl2m1 * (-nor.z) * nor.x +
-		2.0 * c2 * cl11  * nor.y +
-		2.0 * c2 * cl1m1 * (-nor.z) +
-		2.0 * c2 * cl10  * nor.x
-	);
-}
-`;
+	return "vec3 shIrradiance(const vec3 nor, constant vec4 shirr[7]) { \
+	const float c1 = 0.429043; \
+	const float c2 = 0.511664; \
+	const float c3 = 0.743125; \
+	const float c4 = 0.886227; \
+	const float c5 = 0.247708; \
+	vec3 cl00 = vec3(shirr[0].x, shirr[0].y, shirr[0].z); \
+	vec3 cl1m1 = vec3(shirr[0].w, shirr[1].x, shirr[1].y); \
+	vec3 cl10 = vec3(shirr[1].z, shirr[1].w, shirr[2].x); \
+	vec3 cl11 = vec3(shirr[2].y, shirr[2].z, shirr[2].w); \
+	vec3 cl2m2 = vec3(shirr[3].x, shirr[3].y, shirr[3].z); \
+	vec3 cl2m1 = vec3(shirr[3].w, shirr[4].x, shirr[4].y); \
+	vec3 cl20 = vec3(shirr[4].z, shirr[4].w, shirr[5].x); \
+	vec3 cl21 = vec3(shirr[5].y, shirr[5].z, shirr[5].w); \
+	vec3 cl22 = vec3(shirr[6].x, shirr[6].y, shirr[6].z); \
+	return ( \
+		c1 * cl22 * (nor.y * nor.y - (-nor.z) * (-nor.z)) + \
+		c3 * cl20 * nor.x * nor.x + \
+		c4 * cl00 - \
+		c5 * cl20 + \
+		2.0 * c1 * cl2m2 * nor.y * (-nor.z) + \
+		2.0 * c1 * cl21  * nor.y * nor.x + \
+		2.0 * c1 * cl2m1 * (-nor.z) * nor.x + \
+		2.0 * c2 * cl11  * nor.y + \
+		2.0 * c2 * cl1m1 * (-nor.z) + \
+		2.0 * c2 * cl10  * nor.x \
+	); \
+} \
+";
 ///else
-	return `vec3 shIrradiance(const vec3 nor, const vec4 shirr[7]) {
-	const float c1 = 0.429043;
-	const float c2 = 0.511664;
-	const float c3 = 0.743125;
-	const float c4 = 0.886227;
-	const float c5 = 0.247708;
-	vec3 cl00 = vec3(shirr[0].x, shirr[0].y, shirr[0].z);
-	vec3 cl1m1 = vec3(shirr[0].w, shirr[1].x, shirr[1].y);
-	vec3 cl10 = vec3(shirr[1].z, shirr[1].w, shirr[2].x);
-	vec3 cl11 = vec3(shirr[2].y, shirr[2].z, shirr[2].w);
-	vec3 cl2m2 = vec3(shirr[3].x, shirr[3].y, shirr[3].z);
-	vec3 cl2m1 = vec3(shirr[3].w, shirr[4].x, shirr[4].y);
-	vec3 cl20 = vec3(shirr[4].z, shirr[4].w, shirr[5].x);
-	vec3 cl21 = vec3(shirr[5].y, shirr[5].z, shirr[5].w);
-	vec3 cl22 = vec3(shirr[6].x, shirr[6].y, shirr[6].z);
-	return (
-		c1 * cl22 * (nor.y * nor.y - (-nor.z) * (-nor.z)) +
-		c3 * cl20 * nor.x * nor.x +
-		c4 * cl00 -
-		c5 * cl20 +
-		2.0 * c1 * cl2m2 * nor.y * (-nor.z) +
-		2.0 * c1 * cl21  * nor.y * nor.x +
-		2.0 * c1 * cl2m1 * (-nor.z) * nor.x +
-		2.0 * c2 * cl11  * nor.y +
-		2.0 * c2 * cl1m1 * (-nor.z) +
-		2.0 * c2 * cl10  * nor.x
-	);
-}
-`;
+	return "vec3 shIrradiance(const vec3 nor, const vec4 shirr[7]) { \
+	const float c1 = 0.429043; \
+	const float c2 = 0.511664; \
+	const float c3 = 0.743125; \
+	const float c4 = 0.886227; \
+	const float c5 = 0.247708; \
+	vec3 cl00 = vec3(shirr[0].x, shirr[0].y, shirr[0].z); \
+	vec3 cl1m1 = vec3(shirr[0].w, shirr[1].x, shirr[1].y); \
+	vec3 cl10 = vec3(shirr[1].z, shirr[1].w, shirr[2].x); \
+	vec3 cl11 = vec3(shirr[2].y, shirr[2].z, shirr[2].w); \
+	vec3 cl2m2 = vec3(shirr[3].x, shirr[3].y, shirr[3].z); \
+	vec3 cl2m1 = vec3(shirr[3].w, shirr[4].x, shirr[4].y); \
+	vec3 cl20 = vec3(shirr[4].z, shirr[4].w, shirr[5].x); \
+	vec3 cl21 = vec3(shirr[5].y, shirr[5].z, shirr[5].w); \
+	vec3 cl22 = vec3(shirr[6].x, shirr[6].y, shirr[6].z); \
+	return ( \
+		c1 * cl22 * (nor.y * nor.y - (-nor.z) * (-nor.z)) + \
+		c3 * cl20 * nor.x * nor.x + \
+		c4 * cl00 - \
+		c5 * cl20 + \
+		2.0 * c1 * cl2m2 * nor.y * (-nor.z) + \
+		2.0 * c1 * cl21  * nor.y * nor.x + \
+		2.0 * c1 * cl2m1 * (-nor.z) * nor.x + \
+		2.0 * c2 * cl11  * nor.y + \
+		2.0 * c2 * cl1m1 * (-nor.z) + \
+		2.0 * c2 * cl10  * nor.x \
+	); \
+} \
+";
 ///end
 }
 
-let str_envmap_equirect: string = `
-vec2 envMapEquirect(const vec3 normal, const float angle) {
-	const float PI = 3.1415926535;
-	const float PI2 = PI * 2.0;
-	float phi = acos(normal.z);
-	float theta = atan2(-normal.y, normal.x) + PI + angle;
-	return vec2(theta / PI2, phi / PI);
-}
-`;
+let str_envmap_equirect: string = " \
+vec2 envMapEquirect(const vec3 normal, const float angle) { \
+	const float PI = 3.1415926535; \
+	const float PI2 = PI * 2.0; \
+	float phi = acos(normal.z); \
+	float theta = atan2(-normal.y, normal.x) + PI + angle; \
+	return vec2(theta / PI2, phi / PI); \
+} \
+";
 
 // Linearly Transformed Cosines
 // https://eheitzresearch.wordpress.com/415-2/
-let str_ltc_evaluate: string = `
-float integrateEdge(vec3 v1, vec3 v2) {
-	float cosTheta = dot(v1, v2);
-	float theta = acos(cosTheta);
-	float res = cross(v1, v2).z * ((theta > 0.001) ? theta / sin(theta) : 1.0);
-	return res;
-}
-float ltcEvaluate(vec3 N, vec3 V, float dotNV, vec3 P, mat3 Minv, vec3 points0, vec3 points1, vec3 points2, vec3 points3) {
-	vec3 T1 = normalize(V - N * dotNV);
-	vec3 T2 = cross(N, T1);
-	Minv = mul(transpose(mat3(T1, T2, N)), Minv);
-	vec3 L0 = mul((points0 - P), Minv);
-	vec3 L1 = mul((points1 - P), Minv);
-	vec3 L2 = mul((points2 - P), Minv);
-	vec3 L3 = mul((points3 - P), Minv);
-	vec3 L4 = vec3(0.0, 0.0, 0.0);
-	int n = 0;
-	int config = 0;
-	if (L0.z > 0.0) config += 1;
-	if (L1.z > 0.0) config += 2;
-	if (L2.z > 0.0) config += 4;
-	if (L3.z > 0.0) config += 8;
-	if (config == 0) {}
-	else if (config == 1) {
-		n = 3;
-		L1 = -L1.z * L0 + L0.z * L1;
-		L2 = -L3.z * L0 + L0.z * L3;
-	}
-	else if (config == 2) {
-		n = 3;
-		L0 = -L0.z * L1 + L1.z * L0;
-		L2 = -L2.z * L1 + L1.z * L2;
-	}
-	else if (config == 3) {
-		n = 4;
-		L2 = -L2.z * L1 + L1.z * L2;
-		L3 = -L3.z * L0 + L0.z * L3;
-	}
-	else if (config == 4) {
-		n = 3;
-		L0 = -L3.z * L2 + L2.z * L3;
-		L1 = -L1.z * L2 + L2.z * L1;
-	}
-	else if (config == 5) { n = 0; }
-	else if (config == 6) {
-		n = 4;
-		L0 = -L0.z * L1 + L1.z * L0;
-		L3 = -L3.z * L2 + L2.z * L3;
-	}
-	else if (config == 7) {
-		n = 5;
-		L4 = -L3.z * L0 + L0.z * L3;
-		L3 = -L3.z * L2 + L2.z * L3;
-	}
-	else if (config == 8) {
-		n = 3;
-		L0 = -L0.z * L3 + L3.z * L0;
-		L1 = -L2.z * L3 + L3.z * L2;
-		L2 =  L3;
-	}
-	else if (config == 9) {
-		n = 4;
-		L1 = -L1.z * L0 + L0.z * L1;
-		L2 = -L2.z * L3 + L3.z * L2;
-	}
-	else if (config == 10) { n = 0; }
-	else if (config == 11) {
-		n = 5;
-		L4 = L3;
-		L3 = -L2.z * L3 + L3.z * L2;
-		L2 = -L2.z * L1 + L1.z * L2;
-	}
-	else if (config == 12) {
-		n = 4;
-		L1 = -L1.z * L2 + L2.z * L1;
-		L0 = -L0.z * L3 + L3.z * L0;
-	}
-	else if (config == 13) {
-		n = 5;
-		L4 = L3;
-		L3 = L2;
-		L2 = -L1.z * L2 + L2.z * L1;
-		L1 = -L1.z * L0 + L0.z * L1;
-	}
-	else if (config == 14) {
-		n = 5;
-		L4 = -L0.z * L3 + L3.z * L0;
-		L0 = -L0.z * L1 + L1.z * L0;
-	}
-	else if (config == 15) { n = 4; }
-	if (n == 0) return 0.0;
-	if (n == 3) L3 = L0;
-	if (n == 4) L4 = L0;
-	L0 = normalize(L0);
-	L1 = normalize(L1);
-	L2 = normalize(L2);
-	L3 = normalize(L3);
-	L4 = normalize(L4);
-	float sum = 0.0;
-	sum += integrateEdge(L0, L1);
-	sum += integrateEdge(L1, L2);
-	sum += integrateEdge(L2, L3);
-	if (n >= 4) sum += integrateEdge(L3, L4);
-	if (n == 5) sum += integrateEdge(L4, L0);
-	return max(0.0, -sum);
-}
-`;
+let str_ltc_evaluate: string = " \
+float integrateEdge(vec3 v1, vec3 v2) { \
+	float cosTheta = dot(v1, v2); \
+	float theta = acos(cosTheta); \
+	float res = cross(v1, v2).z * ((theta > 0.001) ? theta / sin(theta) : 1.0); \
+	return res; \
+} \
+float ltcEvaluate(vec3 N, vec3 V, float dotNV, vec3 P, mat3 Minv, vec3 points0, vec3 points1, vec3 points2, vec3 points3) { \
+	vec3 T1 = normalize(V - N * dotNV); \
+	vec3 T2 = cross(N, T1); \
+	Minv = mul(transpose(mat3(T1, T2, N)), Minv); \
+	vec3 L0 = mul((points0 - P), Minv); \
+	vec3 L1 = mul((points1 - P), Minv); \
+	vec3 L2 = mul((points2 - P), Minv); \
+	vec3 L3 = mul((points3 - P), Minv); \
+	vec3 L4 = vec3(0.0, 0.0, 0.0); \
+	int n = 0; \
+	int config = 0; \
+	if (L0.z > 0.0) config += 1; \
+	if (L1.z > 0.0) config += 2; \
+	if (L2.z > 0.0) config += 4; \
+	if (L3.z > 0.0) config += 8; \
+	if (config == 0) {} \
+	else if (config == 1) { \
+		n = 3; \
+		L1 = -L1.z * L0 + L0.z * L1; \
+		L2 = -L3.z * L0 + L0.z * L3; \
+	} \
+	else if (config == 2) { \
+		n = 3; \
+		L0 = -L0.z * L1 + L1.z * L0; \
+		L2 = -L2.z * L1 + L1.z * L2; \
+	} \
+	else if (config == 3) { \
+		n = 4; \
+		L2 = -L2.z * L1 + L1.z * L2; \
+		L3 = -L3.z * L0 + L0.z * L3; \
+	} \
+	else if (config == 4) { \
+		n = 3; \
+		L0 = -L3.z * L2 + L2.z * L3; \
+		L1 = -L1.z * L2 + L2.z * L1; \
+	} \
+	else if (config == 5) { n = 0; } \
+	else if (config == 6) { \
+		n = 4; \
+		L0 = -L0.z * L1 + L1.z * L0; \
+		L3 = -L3.z * L2 + L2.z * L3; \
+	} \
+	else if (config == 7) { \
+		n = 5; \
+		L4 = -L3.z * L0 + L0.z * L3; \
+		L3 = -L3.z * L2 + L2.z * L3; \
+	} \
+	else if (config == 8) { \
+		n = 3; \
+		L0 = -L0.z * L3 + L3.z * L0; \
+		L1 = -L2.z * L3 + L3.z * L2; \
+		L2 =  L3; \
+	} \
+	else if (config == 9) { \
+		n = 4; \
+		L1 = -L1.z * L0 + L0.z * L1; \
+		L2 = -L2.z * L3 + L3.z * L2; \
+	} \
+	else if (config == 10) { n = 0; } \
+	else if (config == 11) { \
+		n = 5; \
+		L4 = L3; \
+		L3 = -L2.z * L3 + L3.z * L2; \
+		L2 = -L2.z * L1 + L1.z * L2; \
+	} \
+	else if (config == 12) { \
+		n = 4; \
+		L1 = -L1.z * L2 + L2.z * L1; \
+		L0 = -L0.z * L3 + L3.z * L0; \
+	} \
+	else if (config == 13) { \
+		n = 5; \
+		L4 = L3; \
+		L3 = L2; \
+		L2 = -L1.z * L2 + L2.z * L1; \
+		L1 = -L1.z * L0 + L0.z * L1; \
+	} \
+	else if (config == 14) { \
+		n = 5; \
+		L4 = -L0.z * L3 + L3.z * L0; \
+		L0 = -L0.z * L1 + L1.z * L0; \
+	} \
+	else if (config == 15) { n = 4; } \
+	if (n == 0) return 0.0; \
+	if (n == 3) L3 = L0; \
+	if (n == 4) L4 = L0; \
+	L0 = normalize(L0); \
+	L1 = normalize(L1); \
+	L2 = normalize(L2); \
+	L3 = normalize(L3); \
+	L4 = normalize(L4); \
+	float sum = 0.0; \
+	sum += integrateEdge(L0, L1); \
+	sum += integrateEdge(L1, L2); \
+	sum += integrateEdge(L2, L3); \
+	if (n >= 4) sum += integrateEdge(L3, L4); \
+	if (n == 5) sum += integrateEdge(L4, L0); \
+	return max(0.0, -sum); \
+} \
+";
 
-let str_get_pos_from_depth: string = `
-vec3 get_pos_from_depth(vec2 uv, mat4 invVP, textureArg(gbufferD)) {
-	#if defined(HLSL) || defined(METAL) || defined(SPIRV)
-	float depth = textureLod(gbufferD, vec2(uv.x, 1.0 - uv.y), 0.0).r;
-	#else
-	float depth = textureLod(gbufferD, uv, 0.0).r;
-	#endif
-	vec4 wpos = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
-	wpos = mul(wpos, invVP);
-	return wpos.xyz / wpos.w;
-}
-`;
+let str_get_pos_from_depth: string = " \
+vec3 get_pos_from_depth(vec2 uv, mat4 invVP, textureArg(gbufferD)) { \
+	#if defined(HLSL) || defined(METAL) || defined(SPIRV) \
+	float depth = textureLod(gbufferD, vec2(uv.x, 1.0 - uv.y), 0.0).r; \
+	#else \
+	float depth = textureLod(gbufferD, uv, 0.0).r; \
+	#endif \
+	vec4 wpos = vec4(uv * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0); \
+	wpos = mul(wpos, invVP); \
+	return wpos.xyz / wpos.w; \
+} \
+";
 
-let str_get_nor_from_depth: string = `
-vec3 get_nor_from_depth(vec3 p0, vec2 uv, mat4 invVP, vec2 texStep, textureArg(gbufferD)) {
-	vec3 p1 = get_pos_from_depth(uv + vec2(texStep.x * 4.0, 0.0), invVP, texturePass(gbufferD));
-	vec3 p2 = get_pos_from_depth(uv + vec2(0.0, texStep.y * 4.0), invVP, texturePass(gbufferD));
-	return normalize(cross(p2 - p0, p1 - p0));
-}
-`;
+let str_get_nor_from_depth: string = " \
+vec3 get_nor_from_depth(vec3 p0, vec2 uv, mat4 invVP, vec2 texStep, textureArg(gbufferD)) { \
+	vec3 p1 = get_pos_from_depth(uv + vec2(texStep.x * 4.0, 0.0), invVP, texturePass(gbufferD)); \
+	vec3 p2 = get_pos_from_depth(uv + vec2(0.0, texStep.y * 4.0), invVP, texturePass(gbufferD)); \
+	return normalize(cross(p2 - p0, p1 - p0)); \
+} \
+";

+ 1 - 1
base/Sources/tab_materials.ts

@@ -43,7 +43,7 @@ function tab_materials_button_nodes() {
 		ui_base_show_material_nodes();
 	}
 	else if (ui.is_hovered) {
-		zui_tooltip(tr("Show Node Editor") + ` (${config_keymap.toggle_node_editor})`);
+		zui_tooltip(tr("Show Node Editor") + " (" + config_keymap.toggle_node_editor + ")");
 	}
 }
 

+ 1 - 1
base/Sources/tab_meshes.ts

@@ -26,7 +26,7 @@ function tab_meshes_draw(htab: zui_handle_t) {
 
 		if (zui_button(tr("Import"))) {
 			ui_menu_draw(function (ui: zui_t) {
-				if (ui_menu_button(ui, tr("Replace Existing"), `${config_keymap.file_import_assets}`)) {
+				if (ui_menu_button(ui, tr("Replace Existing"), config_keymap.file_import_assets)) {
 					project_import_mesh(true);
 				}
 				if (ui_menu_button(ui, tr("Append"))) {

+ 1 - 1
base/Sources/tab_textures.ts

@@ -20,7 +20,7 @@ function tab_textures_draw(htab: zui_handle_t) {
 			});
 		}
 		if (ui.is_hovered) {
-			zui_tooltip(tr("Import texture file") + ` (${config_keymap.file_import_assets})`);
+			zui_tooltip(tr("Import texture file") + " (" + config_keymap.file_import_assets + ")");
 		}
 
 		if (zui_button(tr("2D View"))) {

+ 12 - 10
base/Sources/translator.ts

@@ -5,26 +5,28 @@ let translator_cjk_font_indices: map_t<string, i32> = null;
 
 let translator_last_locale: string = "en";
 
-// Mark strings as localizable in order to be parsed by the extract_locale script.
-// The string will not be translated to the currently selected locale though.
+// Mark strings as localizable in order to be parsed by the extract_locale script
+// The string will not be translated to the currently selected locale though
 function _tr(s: string) {
 	return s;
 }
 
-// Localizes a string with the given placeholders replaced (format is `{placeholderName}`).
-// If the string isn't available in the translation, this method will return the source English string.
+// Localizes a string with the given placeholders replaced (format is "{placeholder_name}")
+// If the string isn't available in the translation, this method will return the source English string
 function tr(id: string, vars: map_t<string, string> = null): string {
 	let translation: string = id;
 
 	// English is the source language
-	if (config_raw.locale != "en" && translator_translations.has(id)) {
+	if (config_raw.locale != "en" && map_get(translator_translations, id) != null) {
 		let atranslations: any = translator_translations as any;
 		translation = atranslations[id];
 	}
 
 	if (vars != null) {
-		for (let [key, value] of vars) {
-			translation = string_replace_all(translation, `{${key}}`, any_to_string(value));
+		let keys: string[] = map_keys_to_array(vars);
+		let values: string[] = map_to_array(vars);
+		for (let i: i32 = 0; i < keys.length; ++i) {
+			translation = string_replace_all(translation, "{" + keys[i] + "}", any_to_string(values[i]));
 		}
 	}
 
@@ -65,7 +67,7 @@ function translator_load_translations(new_locale: string) {
 
 	if (config_raw.locale != "en") {
 		// Load the translation file
-		let translation_json: string = sys_buffer_to_string(krom_load_blob(`data/locale/${config_raw.locale}.json`));
+		let translation_json: string = sys_buffer_to_string(krom_load_blob("data/locale/" + config_raw.locale + ".json"));
 
 		let data: any = json_parse(translation_json);
 		for (let field in data) {
@@ -129,7 +131,7 @@ function translator_init_font(cjk: bool, font_path: string, font_scale: f32) {
 		let f: g2_font_t = data_get_font(font_path);
 		if (cjk) {
 			let acjk_font_indices: any = translator_cjk_font_indices as any;
-			let font_index: i32 = translator_cjk_font_indices.has(config_raw.locale) ? acjk_font_indices[config_raw.locale] : 0;
+			let font_index: i32 = map_get(translator_cjk_font_indices, config_raw.locale) != null ? acjk_font_indices[config_raw.locale] : 0;
 			g2_font_set_font_index(f, font_index);
 		}
 		base_font = f;
@@ -162,7 +164,7 @@ function translator_extended_glyphs() {
 function translator_get_supported_locales(): string[] {
 	let locales: string[] = ["system", "en"];
 	for (let locale_filename of file_read_directory(path_data() + path_sep + "locale")) {
-		// Trim the `.json` file extension from file names
+		// Trim the ".json" file extension from file names
 		array_push(locales, substring(locale_filename, 0, locale_filename.length - 5));
 	}
 	return locales;

+ 2 - 1
base/Sources/ui_base.ts

@@ -883,7 +883,8 @@ function ui_base_operator_search() {
 		let count: i32 = 0;
 		let BUTTON_COL: i32 = ui.t.BUTTON_COL;
 
-		for (let n in config_keymap) {
+		for (let i: i32 = 0; i < base_keymap_keys.length; ++i) {
+			let n: string = base_keymap_keys[i];
 			if (string_index_of(n, search) >= 0) {
 				ui.t.BUTTON_COL = count == ui_base_operator_search_offset ? ui.t.HIGHLIGHT_COL : ui.t.SEPARATOR_COL;
 				if (zui_button(n, zui_align_t.LEFT, config_keymap[n]) || (enter && count == ui_base_operator_search_offset)) {

+ 2 - 2
base/Sources/ui_files.ts

@@ -79,7 +79,7 @@ function ui_files_file_browser(ui: zui_t, handle: zui_handle_t, folders_only: bo
 
 	///if krom_ios
 	let document_directory: string = krom_save_dialog("", "");
-	document_directory = substring(document_directory, 0, document_directory.length - 8); // Strip /'untitled'
+	document_directory = substring(document_directory, 0, document_directory.length - 8); // Strip /"untitled"
 	///end
 
 	if (handle.text == "") handle.text = ui_files_default_path;
@@ -231,7 +231,7 @@ function ui_files_file_browser(ui: zui_t, handle: zui_handle_t, folders_only: bo
 				}
 				let key: string = handle.text + path_sep + f;
 				icon = map_get(ui_files_icon_map, key);
-				if (!ui_files_icon_map.has(key)) {
+				if (map_get(ui_files_icon_map, key) == null) {
 					let blob_path: string = key;
 
 					///if krom_ios

+ 7 - 7
base/Sources/ui_header.ts

@@ -162,13 +162,13 @@ function ui_header_draw_tool_properties(ui: zui_t) {
 			zui_tooltip(tr("Add picked color to swatches"));
 		}
 
-		zui_text(tr("Base") + ` (${base_r_picked},${base_g_picked},${base_b_picked})`);
-		zui_text(tr("Normal") + ` (${normal_r_picked},${normal_g_picked},${normal_b_picked})`);
-		zui_text(tr("Occlusion") + ` (${occlusion_picked})`);
-		zui_text(tr("Roughness") + ` (${roughness_picked})`);
-		zui_text(tr("Metallic") + ` (${metallic_picked})`);
-		zui_text(tr("Height") + ` (${height_picked})`);
-		zui_text(tr("Opacity") + ` (${opacity_picked})`);
+		zui_text(tr("Base") + " (" + base_r_picked + "," + base_g_picked + "," + base_b_picked + ")");
+		zui_text(tr("Normal") + " (" + normal_r_picked + "," + normal_g_picked + "," + normal_b_picked + ")");
+		zui_text(tr("Occlusion") + " (" + occlusion_picked + ")");
+		zui_text(tr("Roughness") + " (" + roughness_picked + ")");
+		zui_text(tr("Metallic") + " (" + metallic_picked + ")");
+		zui_text(tr("Height") + " (" + height_picked + ")");
+		zui_text(tr("Opacity") + " (" + opacity_picked + ")");
 		context_raw.picker_select_material = zui_check(zui_handle("uiheader_1", { selected: context_raw.picker_select_material }), tr("Select Material"));
 		zui_combo(context_raw.picker_mask_handle, [tr("None"), tr("Material")], tr("Mask"), true);
 		if (context_raw.picker_mask_handle.changed) {

+ 3 - 3
base/Sources/ui_menu.ts

@@ -455,7 +455,7 @@ function ui_menu_render() {
 			ui_menu_align(ui);
 			context_raw.camera_type = zui_inline_radio(context_raw.cam_handle, [tr("Perspective"), tr("Orthographic")], zui_align_t.LEFT);
 			if (ui.is_hovered) {
-				zui_tooltip(tr("Camera Type") + ` (${config_keymap.view_camera_type})`);
+				zui_tooltip(tr("Camera Type") + " (" + config_keymap.view_camera_type + ")");
 			}
 			if (context_raw.cam_handle.changed) {
 				viewport_update_camera_type(context_raw.camera_type);
@@ -536,7 +536,7 @@ function ui_menu_render() {
 
 				///if krom_windows
 				let save: string = (path_is_protected() ? krom_save_path() : path_data()) + path_sep + "tmp.txt";
-				krom_sys_command('wmic path win32_VideoController get name > "' + save + '"');
+				krom_sys_command("wmic path win32_VideoController get name > \"" + save + "\"");
 				let blob: buffer_t = krom_load_blob(save);
 				let u8: u8_array_t = u8_array_create_from_buffer(blob);
 				let gpu_raw: string = "";
@@ -553,7 +553,7 @@ function ui_menu_render() {
 					gpu += trim_end(g) + ", ";
 				}
 				gpu = substring(gpu, 0, gpu.length - 2);
-				msg += `\n${gpu}`;
+				msg += "\n" + gpu;
 				///else
 				// { lshw -C display }
 				///end

+ 1 - 1
base/Sources/ui_nodes.ts

@@ -1090,7 +1090,7 @@ function ui_nodes_render() {
 			}
 		}
 		if (ui_nodes_ui.is_hovered) {
-			zui_tooltip(tr("Search for nodes") + ` (${config_keymap.node_search})`);
+			zui_tooltip(tr("Search for nodes") + " (" + config_keymap.node_search + ")");
 		}
 		ui_nodes_ui._x += ui_nodes_ui._w + 3;
 		ui_nodes_ui._y = 2 + start_y;

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff