luboslenco 1 năm trước cách đây
mục cha
commit
3132882acf
100 tập tin đã thay đổi với 5894 bổ sung15580 xóa
  1. 1 1
      armorforge/Sources/TabObjects.ts
  2. 1 1
      armorlab/Sources/MakeMaterial.ts
  3. 132 132
      armorlab/Sources/MakeMesh.ts
  4. 149 149
      armorlab/Sources/MakePaint.ts
  5. 2 2
      armorlab/Sources/RenderPathPaint.ts
  6. 2 2
      armorlab/Sources/UINodesExt.ts
  7. 1 1
      armorlab/Sources/nodes/RGBNode.ts
  8. 13 13
      armorpaint/Sources/ImportFolder.ts
  9. 77 77
      armorpaint/Sources/MakeBake.ts
  10. 59 59
      armorpaint/Sources/MakeBlur.ts
  11. 45 45
      armorpaint/Sources/MakeBrush.ts
  12. 15 15
      armorpaint/Sources/MakeClone.ts
  13. 26 26
      armorpaint/Sources/MakeColorIdPicker.ts
  14. 26 26
      armorpaint/Sources/MakeDiscard.ts
  15. 75 75
      armorpaint/Sources/MakeMaterial.ts
  16. 262 262
      armorpaint/Sources/MakeMesh.ts
  17. 79 79
      armorpaint/Sources/MakeMeshPreview.ts
  18. 33 33
      armorpaint/Sources/MakeNodePreview.ts
  19. 184 184
      armorpaint/Sources/MakePaint.ts
  20. 81 81
      armorpaint/Sources/MakeParticle.ts
  21. 45 45
      armorpaint/Sources/MakeTexcoord.ts
  22. 4 4
      armorpaint/Sources/NodesBrush.ts
  23. 145 145
      armorpaint/Sources/RenderPathPaint.ts
  24. 7 7
      armorpaint/Sources/RenderPathPreview.ts
  25. 5 5
      armorpaint/Sources/SlotBrush.ts
  26. 1 1
      armorpaint/Sources/SlotFont.ts
  27. 97 97
      armorpaint/Sources/SlotLayer.ts
  28. 8 8
      armorpaint/Sources/SlotMaterial.ts
  29. 173 173
      armorpaint/Sources/TabLayers.ts
  30. 3 3
      armorpaint/Sources/nodes/BrushOutputNode.ts
  31. 16 16
      armorsculpt/Sources/MakeBrush.ts
  32. 7 7
      armorsculpt/Sources/MakeMaterial.ts
  33. 167 167
      armorsculpt/Sources/MakeMesh.ts
  34. 70 70
      armorsculpt/Sources/MakeMeshPreview.ts
  35. 31 31
      armorsculpt/Sources/MakeSculpt.ts
  36. 42 42
      armorsculpt/Sources/TabLayers.ts
  37. 0 470
      base/Sources/BoxExport.ts
  38. 0 692
      base/Sources/BoxPreferences.ts
  39. 0 250
      base/Sources/BoxProjects.ts
  40. 0 464
      base/Sources/ExportArm.ts
  41. 0 17
      base/Sources/ExportGpl.ts
  42. 0 9
      base/Sources/ExportMesh.ts
  43. 0 173
      base/Sources/ExportObj.ts
  44. 0 434
      base/Sources/ExportTexture.ts
  45. 0 590
      base/Sources/ImportArm.ts
  46. 0 83
      base/Sources/ImportAsset.ts
  47. 0 294
      base/Sources/ImportBlendMaterial.ts
  48. 0 454
      base/Sources/ImportBlendMesh.ts
  49. 0 157
      base/Sources/ImportEnvmap.ts
  50. 0 39
      base/Sources/ImportFont.ts
  51. 0 45
      base/Sources/ImportGpl.ts
  52. 0 17
      base/Sources/ImportKeymap.ts
  53. 0 242
      base/Sources/ImportMesh.ts
  54. 0 117
      base/Sources/ImportObj.ts
  55. 0 16
      base/Sources/ImportPlugin.ts
  56. 0 57
      base/Sources/ImportTexture.ts
  57. 0 19
      base/Sources/ImportTheme.ts
  58. 0 651
      base/Sources/NodeShader.ts
  59. 0 126
      base/Sources/NodeShaderContext.ts
  60. 0 3039
      base/Sources/NodesMaterial.ts
  61. 0 370
      base/Sources/ParserBlend.ts
  62. 0 323
      base/Sources/ParserExr.ts
  63. 0 207
      base/Sources/ParserLogic.ts
  64. 0 1934
      base/Sources/ParserMaterial.ts
  65. 0 482
      base/Sources/PhysicsBody.ts
  66. 0 200
      base/Sources/PhysicsWorld.ts
  67. 0 587
      base/Sources/RenderPathBase.ts
  68. 0 201
      base/Sources/RenderPathDeferred.ts
  69. 0 30
      base/Sources/RenderPathForward.ts
  70. 0 196
      base/Sources/RenderPathRaytrace.ts
  71. 0 149
      base/Sources/RenderPathRaytraceBake.ts
  72. 43 43
      base/Sources/TabBrowser.ts
  73. 9 9
      base/Sources/TabBrushes.ts
  74. 1 1
      base/Sources/TabConsole.ts
  75. 4 4
      base/Sources/TabFonts.ts
  76. 1 1
      base/Sources/TabHistory.ts
  77. 30 30
      base/Sources/TabMaterials.ts
  78. 8 8
      base/Sources/TabMeshes.ts
  79. 1 1
      base/Sources/TabParticles.ts
  80. 3 3
      base/Sources/TabPlugins.ts
  81. 15 15
      base/Sources/TabScript.ts
  82. 23 23
      base/Sources/TabSwatches.ts
  83. 13 13
      base/Sources/TabTextures.ts
  84. 12 12
      base/Sources/args.ts
  85. 117 117
      base/Sources/base.ts
  86. 467 0
      base/Sources/box_export.ts
  87. 688 0
      base/Sources/box_preferences.ts
  88. 247 0
      base/Sources/box_projects.ts
  89. 1 1
      base/Sources/config.ts
  90. 18 18
      base/Sources/context.ts
  91. 461 0
      base/Sources/export_arm.ts
  92. 14 0
      base/Sources/export_gpl.ts
  93. 12 0
      base/Sources/export_mesh.ts
  94. 170 0
      base/Sources/export_obj.ts
  95. 431 0
      base/Sources/export_texture.ts
  96. 1 1
      base/Sources/gizmo.ts
  97. 62 62
      base/Sources/history.ts
  98. 587 0
      base/Sources/import_arm.ts
  99. 80 0
      base/Sources/import_asset.ts
  100. 291 0
      base/Sources/import_blend_material.ts

+ 1 - 1
armorforge/Sources/TabObjects.ts

@@ -98,7 +98,7 @@ class TabObjects {
 								let md: material_data_t = data_get_material("Scene", "TempMaterial" + TabObjects.materialId);
 								let mo: mesh_object_t = currentObject.ext;
 								mo.materials = [md];
-								MakeMaterial.parse_mesh_preview_material(md);
+								MakeMaterial.make_material_parse_mesh_preview_material(md);
 							}
 						}, 1);
 					}

+ 1 - 1
armorlab/Sources/MakeMaterial.ts

@@ -38,7 +38,7 @@ class MakeMaterial {
 		///end
 
 		///if (krom_direct3d12 || krom_vulkan)
-		RenderPathRaytrace.dirty = 1;
+		render_path_raytrace_dirty = 1;
 		///end
 	}
 

+ 132 - 132
armorlab/Sources/MakeMesh.ts

@@ -18,220 +18,220 @@ class MakeMesh {
 		let frag = NodeShadercontext_make_frag(con_mesh);
 		frag.ins = vert.outs;
 
-		NodeShader.add_out(vert, 'vec2 texCoord');
+		node_shader_add_out(vert, 'vec2 texCoord');
 		frag.wvpposition = true;
-		NodeShader.add_out(vert, 'vec4 prevwvpposition');
-		NodeShader.add_uniform(vert, 'mat4 VP', '_view_proj_matrix');
-		NodeShader.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 = MakeMaterial.getDisplaceStrength();
 		if (MakeMaterial.heightUsed && displaceStrength > 0.0) {
 			vert.n = true;
-			NodeShader.write(vert, 'float height = 0.0;');
+			node_shader_write(vert, 'float height = 0.0;');
 			let numLayers = 1;
-			NodeShader.write(vert, `wposition += wnormal * vec3(height, height, height) * vec3(${displaceStrength}, ${displaceStrength}, ${displaceStrength});`);
+			node_shader_write(vert, `wposition += wnormal * vec3(height, height, height) * vec3(${displaceStrength}, ${displaceStrength}, ${displaceStrength});`);
 		}
 
-		NodeShader.write(vert, 'gl_Position = mul(vec4(wposition.xyz, 1.0), VP);');
+		node_shader_write(vert, 'gl_Position = mul(vec4(wposition.xyz, 1.0), VP);');
 		let brushScale = context_raw.brushScale;
-		NodeShader.add_uniform(vert, 'float texScale', '_tex_unpack');
-		NodeShader.write(vert, `texCoord = tex * ${brushScale} * texScale;`);
+		node_shader_add_uniform(vert, 'float texScale', '_tex_unpack');
+		node_shader_write(vert, `texCoord = tex * ${brushScale} * texScale;`);
 		if (MakeMaterial.heightUsed && displaceStrength > 0) {
-			NodeShader.add_uniform(vert, 'mat4 invW', '_inv_world_matrix');
-			NodeShader.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 {
-			NodeShader.write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
+			node_shader_write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
 		}
 
-		NodeShader.add_out(frag, 'vec4 fragColor[3]');
+		node_shader_add_out(frag, 'vec4 fragColor[3]');
 		frag.n = true;
-		NodeShader.add_function(frag, str_packFloatInt16);
-		NodeShader.add_function(frag, str_octahedronWrap);
-		NodeShader.add_function(frag, str_cotangentFrame);
-
-		NodeShader.write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-		NodeShader.write(frag, 'float roughness = 0.0;');
-		NodeShader.write(frag, 'float metallic = 0.0;');
-		NodeShader.write(frag, 'float occlusion = 1.0;');
-		NodeShader.write(frag, 'float opacity = 1.0;');
-		NodeShader.write(frag, 'float matid = 0.0;');
-		NodeShader.write(frag, 'vec3 ntex = vec3(0.5, 0.5, 1.0);');
-		NodeShader.write(frag, 'float height = 0.0;');
-
-		NodeShader.write(frag, 'vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);');
-		NodeShader.write(frag, 'vec4 texpaint_nor_sample;');
-		NodeShader.write(frag, 'vec4 texpaint_pack_sample;');
-		NodeShader.write(frag, 'float texpaint_opac;');
+		node_shader_add_function(frag, str_packFloatInt16);
+		node_shader_add_function(frag, str_octahedronWrap);
+		node_shader_add_function(frag, str_cotangentFrame);
+
+		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;');
 
 		if (MakeMaterial.heightUsed) {
-			NodeShader.write(frag, 'float height0 = 0.0;');
-			NodeShader.write(frag, 'float height1 = 0.0;');
-			NodeShader.write(frag, 'float height2 = 0.0;');
-			NodeShader.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.viewportMode == ViewportMode.ViewLit && context_raw.renderMode == RenderMode.RenderForward) {
-			NodeShader.add_uniform(frag, 'sampler2D senvmapBrdf', "$brdf.k");
-			NodeShader.add_uniform(frag, 'sampler2D senvmapRadiance', '_envmap_radiance');
-			NodeShader.add_uniform(frag, 'sampler2D sltcMat', '_ltcMat');
-			NodeShader.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');
 		}
 
-		NodeShader.add_shared_sampler(frag, 'sampler2D texpaint');
-		NodeShader.write(frag, 'texpaint_sample = textureLodShared(texpaint' + ', texCoord, 0.0);');
-		NodeShader.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;');
 
-		NodeShader.write(frag, 'basecol = texpaint_sample.rgb * texpaint_opac;');
+		node_shader_write(frag, 'basecol = texpaint_sample.rgb * texpaint_opac;');
 
-		NodeShader.add_shared_sampler(frag, 'sampler2D texpaint_nor');
-		NodeShader.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);');
 
-		NodeShader.write(frag, 'ntex = mix(ntex, texpaint_nor_sample.rgb, texpaint_opac);');
+		node_shader_write(frag, 'ntex = mix(ntex, texpaint_nor_sample.rgb, texpaint_opac);');
 
-		NodeShader.add_shared_sampler(frag, 'sampler2D texpaint_pack');
-		NodeShader.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);');
 
-		NodeShader.write(frag, 'occlusion = mix(occlusion, texpaint_pack_sample.r, texpaint_opac);');
+		node_shader_write(frag, 'occlusion = mix(occlusion, texpaint_pack_sample.r, texpaint_opac);');
 
-		NodeShader.write(frag, 'roughness = mix(roughness, texpaint_pack_sample.g, texpaint_opac);');
+		node_shader_write(frag, 'roughness = mix(roughness, texpaint_pack_sample.g, texpaint_opac);');
 
-		NodeShader.write(frag, 'metallic = mix(metallic, texpaint_pack_sample.b, texpaint_opac);');
+		node_shader_write(frag, 'metallic = mix(metallic, texpaint_pack_sample.b, texpaint_opac);');
 
-		NodeShader.write(frag, 'height = texpaint_pack_sample.a * texpaint_opac;');
+		node_shader_write(frag, 'height = texpaint_pack_sample.a * texpaint_opac;');
 
 		// if (l.paintHeight && MakeMaterial.heightUsed) {
 		// 	let assign = l.paintHeightBlend ? "+=" : "=";
-		// 	NodeShader.write(frag, `height ${assign} texpaint_pack_sample.a * texpaint_opac;`);
-		// 	NodeShader.write(frag, '{');
-		// 	NodeShader.add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-		// 	NodeShader.write(frag, 'float tex_step = 1.0 / texpaintSize.x;');
-		// 	NodeShader.write(frag, `height0 ${assign} textureLodShared(texpaint_pack` + ', vec2(texCoord.x - tex_step, texCoord.y), 0.0).a * texpaint_opac;');
-		// 	NodeShader.write(frag, `height1 ${assign} textureLodShared(texpaint_pack` + ', vec2(texCoord.x + tex_step, texCoord.y), 0.0).a * texpaint_opac;');
-		// 	NodeShader.write(frag, `height2 ${assign} textureLodShared(texpaint_pack` + ', vec2(texCoord.x, texCoord.y - tex_step), 0.0).a * texpaint_opac;');
-		// 	NodeShader.write(frag, `height3 ${assign} textureLodShared(texpaint_pack` + ', vec2(texCoord.x, texCoord.y + tex_step), 0.0).a * texpaint_opac;');
-		// 	NodeShader.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 (MakeMaterial.heightUsed) {
-			NodeShader.write(frag, 'if (height > 0.0) {');
-			NodeShader.write(frag, 'float height_dx = height0 - height1;');
-			NodeShader.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
-			NodeShader.write(frag, 'vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-			NodeShader.write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-			NodeShader.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);');
-			NodeShader.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)
-		NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
 		///else
-		NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+		node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
 		///end
-		NodeShader.write(frag, 'n = ntex * 2.0 - 1.0;');
-		NodeShader.write(frag, 'n.y = -n.y;');
-		NodeShader.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.viewportMode == ViewportMode.ViewLit || context_raw.viewportMode == ViewportMode.ViewPathTrace) {
 
-			NodeShader.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.viewportShader != null) {
 				let color = context_raw.viewportShader(frag);
-				NodeShader.write(frag, `fragColor[1] = vec4(${color}, 1.0);`);
+				node_shader_write(frag, `fragColor[1] = vec4(${color}, 1.0);`);
 			}
 			else if (context_raw.renderMode == RenderMode.RenderForward && context_raw.viewportMode != ViewportMode.ViewPathTrace) {
 				frag.wposition = true;
-				NodeShader.write(frag, 'vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);');
-				NodeShader.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;
-				NodeShader.write(frag, 'float dotNV = max(0.0, dot(n, vVec));');
-				NodeShader.write(frag, 'vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;');
-				NodeShader.add_uniform(frag, 'int envmapNumMipmaps', '_envmap_num_mipmaps');
-				NodeShader.add_uniform(frag, 'vec4 envmapData', '_envmapData'); // angle, sin(angle), cos(angle), strength
-				NodeShader.write(frag, 'vec3 wreflect = reflect(-vVec, n);');
-				NodeShader.write(frag, 'float envlod = roughness * float(envmapNumMipmaps);');
-				NodeShader.add_function(frag, str_envMapEquirect);
-				NodeShader.write(frag, 'vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;');
-				NodeShader.add_uniform(frag, 'vec3 lightArea0', '_light_area0');
-				NodeShader.add_uniform(frag, 'vec3 lightArea1', '_light_area1');
-				NodeShader.add_uniform(frag, 'vec3 lightArea2', '_light_area2');
-				NodeShader.add_uniform(frag, 'vec3 lightArea3', '_light_area3');
-				NodeShader.add_function(frag, str_ltcEvaluate);
-				NodeShader.add_uniform(frag, 'vec3 lightPos', '_point_pos');
-				NodeShader.add_uniform(frag, 'vec3 lightColor', '_point_color');
-				NodeShader.write(frag, 'float ldist = distance(wposition, lightPos);');
-				NodeShader.write(frag, 'const float LUT_SIZE = 64.0;');
-				NodeShader.write(frag, 'const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;');
-				NodeShader.write(frag, 'const float LUT_BIAS = 0.5 / LUT_SIZE;');
-				NodeShader.write(frag, 'float theta = acos(dotNV);');
-				NodeShader.write(frag, 'vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));');
-				NodeShader.write(frag, 'tuv = tuv * LUT_SCALE + LUT_BIAS;');
-				NodeShader.write(frag, 'vec4 t = textureLod(sltcMat, tuv, 0.0);');
-				NodeShader.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));');
-				NodeShader.write(frag, 'float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);');
-				NodeShader.write(frag, 'ltcspec *= textureLod(sltcMag, tuv, 0.0).a;');
-				NodeShader.write(frag, 'mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);');
-				NodeShader.write(frag, 'float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);');
-				NodeShader.write(frag, 'vec3 direct = albedo * ltcdiff + ltcspec * 0.05;');
-				NodeShader.write(frag, 'direct *= lightColor * (1.0 / (ldist * ldist));');
-
-				NodeShader.add_uniform(frag, 'vec4 shirr[7]', '_envmap_irradiance');
-				NodeShader.add_function(frag, str_shIrradiance);
-				NodeShader.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);');
-				NodeShader.write(frag, 'indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;');
-				NodeShader.write(frag, 'indirect *= envmapData.w * occlusion;');
-				NodeShader.write(frag, 'fragColor[1] = vec4(direct + indirect, 1.0);');
+				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_envMapEquirect);
+				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_ltcEvaluate);
+				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_shIrradiance);
+				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
-				NodeShader.write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
+				node_shader_write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
 			}
 		}
 		else if (context_raw.viewportMode == ViewportMode.ViewBaseColor) {
-			NodeShader.write(frag, 'fragColor[1] = vec4(basecol, 1.0);');
+			node_shader_write(frag, 'fragColor[1] = vec4(basecol, 1.0);');
 		}
 		else if (context_raw.viewportMode == ViewportMode.ViewNormalMap) {
-			NodeShader.write(frag, 'fragColor[1] = vec4(ntex.rgb, 1.0);');
+			node_shader_write(frag, 'fragColor[1] = vec4(ntex.rgb, 1.0);');
 		}
 		else if (context_raw.viewportMode == ViewportMode.ViewOcclusion) {
-			NodeShader.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.viewportMode == ViewportMode.ViewRoughness) {
-			NodeShader.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.viewportMode == ViewportMode.ViewMetallic) {
-			NodeShader.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.viewportMode == ViewportMode.ViewOpacity) {
-			NodeShader.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.viewportMode == ViewportMode.ViewHeight) {
-			NodeShader.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 {
-			NodeShader.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.viewportMode != ViewportMode.ViewLit && context_raw.viewportMode != ViewportMode.ViewPathTrace) {
-			NodeShader.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));');
 		}
 
-		NodeShader.write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-		NodeShader.write(frag, 'n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);');
-		NodeShader.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)));');
 
-		NodeShader.write(frag, 'vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
-		NodeShader.write(frag, 'vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;');
-		NodeShader.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);');
 
-		ParserMaterial.finalize(con_mesh);
+		parser_material_finalize(con_mesh);
 		con_mesh.data.shader_from_source = true;
-		con_mesh.data.vertex_shader = NodeShader.get(vert);
-		con_mesh.data.fragment_shader = NodeShader.get(frag);
+		con_mesh.data.vertex_shader = node_shader_get(vert);
+		con_mesh.data.fragment_shader = node_shader_get(frag);
 		return con_mesh;
 	}
 }

+ 149 - 149
armorlab/Sources/MakePaint.ts

@@ -26,125 +26,125 @@ class MakePaint {
 
 		if (context_raw.tool == WorkspaceTool.ToolPicker) {
 			// Mangle vertices to form full screen triangle
-			NodeShader.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);');
 
-			NodeShader.add_uniform(frag, 'sampler2D gbuffer2');
-			NodeShader.add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
-			NodeShader.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)
-			NodeShader.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
-			NodeShader.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
 
-			NodeShader.add_out(frag, 'vec4 fragColor[4]');
-			NodeShader.add_uniform(frag, 'sampler2D texpaint');
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_nor');
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_pack');
-			NodeShader.write(frag, 'fragColor[0] = textureLod(texpaint, texCoordInp, 0.0);');
-			NodeShader.write(frag, 'fragColor[1] = textureLod(texpaint_nor, texCoordInp, 0.0);');
-			NodeShader.write(frag, 'fragColor[2] = textureLod(texpaint_pack, texCoordInp, 0.0);');
-			NodeShader.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 = NodeShader.get(vert);
-			con_paint.data.fragment_shader = NodeShader.get(frag);
+			con_paint.data.vertex_shader = node_shader_get(vert);
+			con_paint.data.fragment_shader = node_shader_get(frag);
 			return con_paint;
 		}
 
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		NodeShader.write(vert, 'vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);');
-		// NodeShader.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
-		NodeShader.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
 
-		NodeShader.write(vert, 'gl_Position = vec4(tpos, 0.0, 1.0);');
+		node_shader_write(vert, 'gl_Position = vec4(tpos, 0.0, 1.0);');
 
-		NodeShader.add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
+		node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
 
-		NodeShader.add_out(vert, 'vec4 ndc');
-		NodeShader.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);');
 
-		NodeShader.write_attrib(frag, 'vec3 sp = vec3((ndc.xyz / ndc.w) * 0.5 + 0.5);');
-		NodeShader.write_attrib(frag, 'sp.y = 1.0 - sp.y;');
-		NodeShader.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
 
-		NodeShader.add_uniform(frag, 'vec4 inp', '_inputBrush');
-		NodeShader.add_uniform(frag, 'vec4 inplast', '_inputBrushLast');
-		NodeShader.add_uniform(frag, 'float aspectRatio', '_aspect_ratio_window');
-		NodeShader.write(frag, 'vec2 bsp = sp.xy * 2.0 - 1.0;');
-		NodeShader.write(frag, 'bsp.x *= aspectRatio;');
-		NodeShader.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;');
 
-		NodeShader.add_uniform(frag, 'sampler2D gbufferD');
+		node_shader_add_uniform(frag, 'sampler2D gbufferD');
 
-		NodeShader.add_out(frag, 'vec4 fragColor[4]');
+		node_shader_add_out(frag, 'vec4 fragColor[4]');
 
-		NodeShader.add_uniform(frag, 'float brushRadius', '_brushRadius');
-		NodeShader.add_uniform(frag, 'float brushOpacity', '_brushOpacity');
-		NodeShader.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 == WorkspaceTool.ToolEraser ||
 			context_raw.tool == WorkspaceTool.ToolClone  ||
 			context_raw.tool == WorkspaceTool.ToolBlur   ||
 			context_raw.tool == WorkspaceTool.ToolSmudge) {
 
-			NodeShader.write(frag, 'float dist = 0.0;');
+			node_shader_write(frag, 'float dist = 0.0;');
 
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			NodeShader.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
-			NodeShader.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
 
-			NodeShader.add_uniform(frag, 'mat4 invVP', '_inv_view_proj_matrix');
-			NodeShader.write(frag, 'vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);');
-			NodeShader.write(frag, 'winp = mul(winp, invVP);');
-			NodeShader.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)
-			NodeShader.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
-			NodeShader.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
 
-			NodeShader.write(frag, 'vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);');
-			NodeShader.write(frag, 'winplast = mul(winplast, invVP);');
-			NodeShader.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;');
 
-			NodeShader.write(frag, 'vec3 pa = wposition - winp.xyz;');
-			NodeShader.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
-			NodeShader.write(frag, 'float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);');
-			NodeShader.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);');
 
-			NodeShader.write(frag, 'if (dist > brushRadius) discard;');
+			node_shader_write(frag, 'if (dist > brushRadius) discard;');
 		}
 
-		// NodeShader.add_uniform(vert, 'float brushScale', '_brushScale');
-		// NodeShader.add_uniform(vert, 'float texScale', '_tex_unpack');
-		// NodeShader.add_out(vert, 'vec2 texCoord');
-		// NodeShader.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 == WorkspaceTool.ToolClone || context_raw.tool == WorkspaceTool.ToolBlur || context_raw.tool == WorkspaceTool.ToolSmudge) {
-			NodeShader.add_uniform(frag, 'sampler2D gbuffer2');
-			NodeShader.add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
-			NodeShader.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 == WorkspaceTool.ToolClone) {
-				// NodeShader.add_uniform(frag, 'vec2 cloneDelta', '_cloneDelta');
+				// node_shader_add_uniform(frag, 'vec2 cloneDelta', '_cloneDelta');
 				// ///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-				// NodeShader.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
-				// NodeShader.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
 
-				// NodeShader.write(frag, 'vec3 texpaint_pack_sample = textureLod(texpaint_pack_undo, texCoordInp, 0.0).rgb;');
+				// 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';
@@ -152,125 +152,125 @@ class MakePaint {
 				// let nortan = 'textureLod(texpaint_nor_undo, texCoordInp, 0.0).rgb';
 				// let height = '0.0';
 				// let opac = '1.0';
-				// NodeShader.write(frag, `vec3 basecol = ${base};`);
-				// NodeShader.write(frag, `float roughness = ${rough};`);
-				// NodeShader.write(frag, `float metallic = ${met};`);
-				// NodeShader.write(frag, `float occlusion = ${occ};`);
-				// NodeShader.write(frag, `vec3 nortan = ${nortan};`);
-				// NodeShader.write(frag, `float height = ${height};`);
-				// NodeShader.write(frag, `float mat_opacity = ${opac};`);
-				// NodeShader.write(frag, 'float opacity = mat_opacity * brushOpacity;');
+				// 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)
-				// NodeShader.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
-				// NodeShader.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
 
-				// NodeShader.write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-				// NodeShader.write(frag, 'float roughness = 0.0;');
-				// NodeShader.write(frag, 'float metallic = 0.0;');
-				// NodeShader.write(frag, 'float occlusion = 0.0;');
-				// NodeShader.write(frag, 'vec3 nortan = vec3(0.0, 0.0, 0.0);');
-				// NodeShader.write(frag, 'float height = 0.0;');
-				// NodeShader.write(frag, 'float mat_opacity = 1.0;');
-				// NodeShader.write(frag, 'float opacity = 0.0;');
-
-				// NodeShader.add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-				// NodeShader.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)
-				// 	NodeShader.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
-				// 	NodeShader.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
-				// 	NodeShader.add_uniform(frag, 'vec3 brushDirection', '_brushDirection');
-				// 	NodeShader.write(frag, 'vec2 blur_direction = brushDirection.yx;');
-				// 	NodeShader.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)
-				// 	NodeShader.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
-				// 	NodeShader.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
-				// 	NodeShader.write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp2);');
-				// 	NodeShader.write(frag, 'opacity += texpaint_sample.a * blur_weight[i];');
-				// 	NodeShader.write(frag, 'basecol += texpaint_sample.rgb * blur_weight[i];');
-				// 	NodeShader.write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp2) * blur_weight[i];');
-				// 	NodeShader.write(frag, 'roughness += texpaint_pack_sample.g;');
-				// 	NodeShader.write(frag, 'metallic += texpaint_pack_sample.b;');
-				// 	NodeShader.write(frag, 'occlusion += texpaint_pack_sample.r;');
-				// 	NodeShader.write(frag, 'height += texpaint_pack_sample.a;');
-				// 	NodeShader.write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp2).rgb * blur_weight[i];');
-				// 	NodeShader.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)
-				// 	NodeShader.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
-				// 	NodeShader.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
-				// 	NodeShader.write(frag, 'for (int i = -7; i <= 7; ++i) {');
-				// 	NodeShader.write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(blur_step * float(i), 0.0));');
-				// 	NodeShader.write(frag, 'opacity += texpaint_sample.a * blur_weight[i + 7];');
-				// 	NodeShader.write(frag, 'basecol += texpaint_sample.rgb * blur_weight[i + 7];');
-				// 	NodeShader.write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(blur_step * float(i), 0.0)) * blur_weight[i + 7];');
-				// 	NodeShader.write(frag, 'roughness += texpaint_pack_sample.g;');
-				// 	NodeShader.write(frag, 'metallic += texpaint_pack_sample.b;');
-				// 	NodeShader.write(frag, 'occlusion += texpaint_pack_sample.r;');
-				// 	NodeShader.write(frag, 'height += texpaint_pack_sample.a;');
-				// 	NodeShader.write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp + vec2(blur_step * float(i), 0.0)).rgb * blur_weight[i + 7];');
-				// 	NodeShader.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
-				// 	NodeShader.write(frag, 'for (int j = -7; j <= 7; ++j) {');
-				// 	NodeShader.write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(0.0, blur_step * float(j)));');
-				// 	NodeShader.write(frag, 'opacity += texpaint_sample.a * blur_weight[j + 7];');
-				// 	NodeShader.write(frag, 'basecol += texpaint_sample.rgb * blur_weight[j + 7];');
-				// 	NodeShader.write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(0.0, blur_step * float(j))) * blur_weight[j + 7];');
-				// 	NodeShader.write(frag, 'roughness += texpaint_pack_sample.g;');
-				// 	NodeShader.write(frag, 'metallic += texpaint_pack_sample.b;');
-				// 	NodeShader.write(frag, 'occlusion += texpaint_pack_sample.r;');
-				// 	NodeShader.write(frag, 'height += texpaint_pack_sample.a;');
-				// 	NodeShader.write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp + vec2(0.0, blur_step * float(j))).rgb * blur_weight[j + 7];');
-				// 	NodeShader.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, '}');
 				// }
-				// NodeShader.write(frag, 'opacity *= brushOpacity;');
+				// node_shader_write(frag, 'opacity *= brushOpacity;');
 			}
 		}
 
-		NodeShader.write(frag, 'float opacity = 1.0;');
-		NodeShader.write(frag, 'if (opacity == 0.0) discard;');
+		node_shader_write(frag, 'float opacity = 1.0;');
+		node_shader_write(frag, 'if (opacity == 0.0) discard;');
 
-		NodeShader.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;
-		NodeShader.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)
-		NodeShader.write(frag, 'sample_tc.y = 1.0 - sample_tc.y;');
+		node_shader_write(frag, 'sample_tc.y = 1.0 - sample_tc.y;');
 		///end
-		NodeShader.add_uniform(frag, 'sampler2D paintmask');
-		NodeShader.write(frag, 'float sample_mask = textureLod(paintmask, sample_tc, 0.0).r;');
-		NodeShader.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);');
 
-		NodeShader.add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-		NodeShader.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 == WorkspaceTool.ToolEraser) {
-			// NodeShader.write(frag, 'fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);');
-			NodeShader.write(frag, 'fragColor[0] = vec4(0.0, 0.0, 0.0, 0.0);');
-			NodeShader.write(frag, 'fragColor[1] = vec4(0.5, 0.5, 1.0, 0.0);');
-			NodeShader.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);');
 		}
 
-		NodeShader.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);');
 
-		ParserMaterial.finalize(con_paint);
-		ParserMaterial.sample_keep_aspect = false;
+		parser_material_finalize(con_paint);
+		parser_material_sample_keep_aspect = false;
 		con_paint.data.shader_from_source = true;
-		con_paint.data.vertex_shader = NodeShader.get(vert);
-		con_paint.data.fragment_shader = NodeShader.get(frag);
+		con_paint.data.vertex_shader = node_shader_get(vert);
+		con_paint.data.fragment_shader = node_shader_get(frag);
 
 		return con_paint;
 	}

+ 2 - 2
armorlab/Sources/RenderPathPaint.ts

@@ -256,7 +256,7 @@ class RenderPathPaint {
 		let canvas = ui_nodes_getCanvas(true);
 		if (nodes.nodesSelectedId.length > 0) {
 			let node = zui_get_node(canvas.nodes, nodes.nodesSelectedId[0]);
-			let brushNode = ParserLogic.getLogicNode(node);
+			let brushNode = parser_logic_getLogicNode(node);
 			if (brushNode != null) {
 				image = brushNode.getCachedImage();
 			}
@@ -288,7 +288,7 @@ class RenderPathPaint {
 			let node = zui_get_node(canvas.nodes, nodes.nodesSelectedId[0]);
 			let inpaint = node.type == "InpaintNode";
 			if (inpaint) {
-				let brushNode = ParserLogic.getLogicNode(node);
+				let brushNode = parser_logic_getLogicNode(node);
 				render_path_render_targets.get("texpaint_node_target")._image = (brushNode as InpaintNode).getTarget();
 			}
 		}

+ 2 - 2
armorlab/Sources/UINodesExt.ts

@@ -23,14 +23,14 @@ class UINodesExt {
 					app_remove_render_2d(delayIdleSleep);
 
 					///if (krom_direct3d12 || krom_vulkan || krom_metal)
-					RenderPathRaytrace.ready = false;
+					render_path_raytrace_ready = false;
 					///end
 				}
 			}
 
 			base_notifyOnNextFrame(() => {
 				let timer = time_time();
-				ParserLogic.parse(project_canvas);
+				parser_logic_parse(project_canvas);
 
 				PhotoToPBRNode.cachedSource = null;
 				BrushOutputNode.inst.getAsImage(ChannelType.ChannelBaseColor, (texbase: image_t) => {

+ 1 - 1
armorlab/Sources/nodes/RGBNode.ts

@@ -15,7 +15,7 @@ class RGBNode extends LogicNode {
 		}
 
 		let f32a = new Float32Array(4);
-		let raw = ParserLogic.getRawNode(this);
+		let raw = parser_logic_getRawNode(this);
 		let default_value = raw.outputs[0].default_value;
 		f32a[0] = default_value[0];
 		f32a[1] = default_value[1];

+ 13 - 13
armorpaint/Sources/ImportFolder.ts

@@ -1,7 +1,7 @@
 
 class ImportFolder {
 
-	static run = (path: string) => {
+	static import_folder_run = (path: string) => {
 		let files: string[] = file_read_directory(path);
 		let mapbase: string = "";
 		let mapopac: string = "";
@@ -50,7 +50,7 @@ class ImportFolder {
 			}
 
 			if (valid) {
-				ImportTexture.run(path + path_sep + f, false);
+				import_texture_run(path + path_sep + f, false);
 				found_texture = true;
 			}
 		}
@@ -61,7 +61,7 @@ class ImportFolder {
 		}
 
 		// Create material
-		context_raw.material = SlotMaterial.create(project_materials[0].data);
+		context_raw.material = SlotMaterial.slot_material_create(project_materials[0].data);
 		project_materials.push(context_raw.material);
 		let nodes: zui_nodes_t = context_raw.material.nodes;
 		let canvas: zui_node_canvas_t = context_raw.material.canvas;
@@ -86,42 +86,42 @@ class ImportFolder {
 		let start_y: i32 = 100;
 		let node_h: i32 = 164;
 		if (mapbase != "") {
-			ImportFolder.place_image_node(nodes, canvas, mapbase, start_y + node_h * pos, nout.id, 0);
+			ImportFolder.import_folder_place_image_node(nodes, canvas, mapbase, start_y + node_h * pos, nout.id, 0);
 			pos++;
 		}
 		if (mapopac != "") {
-			ImportFolder.place_image_node(nodes, canvas, mapopac, start_y + node_h * pos, nout.id, 1);
+			ImportFolder.import_folder_place_image_node(nodes, canvas, mapopac, start_y + node_h * pos, nout.id, 1);
 			pos++;
 		}
 		if (mapocc != "") {
-			ImportFolder.place_image_node(nodes, canvas, mapocc, start_y + node_h * pos, nout.id, 2);
+			ImportFolder.import_folder_place_image_node(nodes, canvas, mapocc, start_y + node_h * pos, nout.id, 2);
 			pos++;
 		}
 		if (maprough != "") {
-			ImportFolder.place_image_node(nodes, canvas, maprough, start_y + node_h * pos, nout.id, 3);
+			ImportFolder.import_folder_place_image_node(nodes, canvas, maprough, start_y + node_h * pos, nout.id, 3);
 			pos++;
 		}
 		if (mapmet != "") {
-			ImportFolder.place_image_node(nodes, canvas, mapmet, start_y + node_h * pos, nout.id, 4);
+			ImportFolder.import_folder_place_image_node(nodes, canvas, mapmet, start_y + node_h * pos, nout.id, 4);
 			pos++;
 		}
 		if (mapnor != "") {
-			ImportFolder.place_image_node(nodes, canvas, mapnor, start_y + node_h * pos, nout.id, 5);
+			ImportFolder.import_folder_place_image_node(nodes, canvas, mapnor, start_y + node_h * pos, nout.id, 5);
 			pos++;
 		}
 		if (mapheight != "") {
-			ImportFolder.place_image_node(nodes, canvas, mapheight, start_y + node_h * pos, nout.id, 7);
+			ImportFolder.import_folder_place_image_node(nodes, canvas, mapheight, start_y + node_h * pos, nout.id, 7);
 			pos++;
 		}
 
-		MakeMaterial.parse_paint_material();
+		MakeMaterial.make_material_parse_paint_material();
 		util_render_make_material_preview();
 		ui_base_hwnds[1].redraws = 2;
 		history_new_material();
 	}
 
-	static place_image_node = (nodes: zui_nodes_t, canvas: zui_node_canvas_t, asset: string, ny: i32, to_id: i32, to_socket: i32) => {
-		let n: zui_node_t = NodesMaterial.create_node("TEX_IMAGE");
+	static import_folder_place_image_node = (nodes: zui_nodes_t, canvas: zui_node_canvas_t, asset: string, ny: i32, to_id: i32, to_socket: i32) => {
+		let n: zui_node_t = nodes_material_create_node("TEX_IMAGE");
 		n.buttons[0].default_value = base_get_asset_index(asset);
 		n.x = 72;
 		n.y = ny;

+ 77 - 77
armorpaint/Sources/MakeBake.ts

@@ -1,142 +1,142 @@
 
 class MakeBake {
 
-	static run = (con: NodeShaderContextRaw, vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+	static make_bake_run = (con: NodeShaderContextRaw, vert: NodeShaderRaw, frag: NodeShaderRaw) => {
 		if (context_raw.bake_type == bake_type_t.AO) { // Voxel
 			///if arm_voxels
 			// Apply normal channel
 			frag.wposition = true;
 			frag.n = true;
 			frag.vvec = true;
-			NodeShader.add_function(frag, str_cotangent_frame);
+			node_shader_add_function(frag, str_cotangent_frame);
 			///if krom_direct3d11
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
 			///else
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
 			///end
-			NodeShader.write(frag, 'n = nortan * 2.0 - 1.0;');
-			NodeShader.write(frag, 'n.y = -n.y;');
-			NodeShader.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));');
 
-			NodeShader.write(frag, MakeMaterial.voxelgi_half_extents());
-			NodeShader.write(frag, 'vec3 voxpos = wposition / voxelgiHalfExtents;');
-			NodeShader.add_uniform(frag, 'sampler3D voxels');
-			NodeShader.add_function(frag, str_trace_ao);
+			node_shader_write(frag, MakeMaterial.make_material_voxelgi_half_extents());
+			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;
-			NodeShader.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 = MakeBake.axis_string(context_raw.bake_axis);
-				NodeShader.write(frag, `ao *= dot(n, ${axis});`);
+				let axis: string = MakeBake.make_bake_axis_string(context_raw.bake_axis);
+				node_shader_write(frag, `ao *= dot(n, ${axis});`);
 			}
-			NodeShader.write(frag, 'ao = 1.0 - ao;');
-			NodeShader.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) {
-			let pass: bool = ParserMaterial.bake_passthrough;
-			let strength: string = pass ? ParserMaterial.bake_passthrough_strength : context_raw.bake_curv_strength + "";
-			let radius: string = pass ? ParserMaterial.bake_passthrough_radius : context_raw.bake_curv_radius + "";
-			let offset: string = pass ? ParserMaterial.bake_passthrough_offset : context_raw.bake_curv_offset + "";
+			let pass: bool = parser_material_bake_passthrough;
+			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})`;
 			frag.n = true;
-			NodeShader.write(frag, 'vec3 dx = dFdx(n);');
-			NodeShader.write(frag, 'vec3 dy = dFdy(n);');
-			NodeShader.write(frag, 'float curvature = max(dot(dx, dx), dot(dy, dy));');
-			NodeShader.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 = MakeBake.axis_string(context_raw.bake_axis);
-				NodeShader.write(frag, `curvature *= dot(n, ${axis});`);
+				let axis: string = MakeBake.make_bake_axis_string(context_raw.bake_axis);
+				node_shader_write(frag, `curvature *= dot(n, ${axis});`);
 			}
-			NodeShader.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;
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo'); // Baked high-poly normals
-			NodeShader.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);');
-			NodeShader.add_function(frag, str_cotangent_frame);
-			NodeShader.write(frag, 'mat3 invTBN = transpose(cotangentFrame(n, n, texCoord));');
-			NodeShader.write(frag, 'vec3 res = normalize(mul(n0, invTBN)) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5);');
-			NodeShader.write(frag, 'fragColor[0] = vec4(res, 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);');
 		}
 		else if (context_raw.bake_type == bake_type_t.NORMAL_OBJECT) {
 			frag.n = true;
-			NodeShader.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) {
-				NodeShader.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;
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo'); // Baked high-poly positions
-			NodeShader.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);');
-			NodeShader.write(frag, 'float res = distance(wpos0, wposition) * 10.0;');
-			NodeShader.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) {
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo'); // Baked height
-			NodeShader.write(frag, 'vec2 texDx = dFdx(texCoord);');
-			NodeShader.write(frag, 'vec2 texDy = dFdy(texCoord);');
-			NodeShader.write(frag, 'float h0 = textureLod(texpaint_undo, texCoord, 0.0).r * 100;');
-			NodeShader.write(frag, 'float h1 = textureLod(texpaint_undo, texCoord + texDx, 0.0).r * 100;');
-			NodeShader.write(frag, 'float h2 = textureLod(texpaint_undo, texCoord + texDy, 0.0).r * 100;');
-			NodeShader.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;
-			NodeShader.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) {
-				NodeShader.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) {
-			NodeShader.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) {
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
-			NodeShader.write(frag, 'float sample_matid = textureLod(texpaint_nor_undo, texCoord, 0.0).a + 1.0 / 255.0;');
-			NodeShader.write(frag, 'float matid_r = fract(sin(dot(vec2(sample_matid, sample_matid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			NodeShader.write(frag, 'float matid_g = fract(sin(dot(vec2(sample_matid * 20.0, sample_matid), vec2(12.9898, 78.233))) * 43758.5453);');
-			NodeShader.write(frag, 'float matid_b = fract(sin(dot(vec2(sample_matid, sample_matid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			NodeShader.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) {
-			NodeShader.add_uniform(frag, 'float objectId', '_objectId');
-			NodeShader.write(frag, 'float obid = objectId + 1.0 / 255.0;');
-			NodeShader.write(frag, 'float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			NodeShader.write(frag, 'float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);');
-			NodeShader.write(frag, 'float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-			NodeShader.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) {
-				NodeShaderContext.add_elem(con, "col", "short4norm");
-				NodeShader.write(frag, 'fragColor[0] = vec4(vcolor.r, vcolor.g, vcolor.b, 1.0);');
+				node_shader_context_add_elem(con, "col", "short4norm");
+				node_shader_write(frag, 'fragColor[0] = vec4(vcolor.r, vcolor.g, vcolor.b, 1.0);');
 			}
 			else {
-				NodeShader.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);');
 			}
 		}
 	}
 
-	static position_normal = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
-		NodeShader.add_out(vert, 'vec3 position');
-		NodeShader.add_out(vert, 'vec3 normal');
-		NodeShader.add_uniform(vert, 'mat4 W', '_world_matrix');
-		NodeShader.write(vert, 'position = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;');
-		NodeShader.write(vert, 'normal = vec3(nor.xy, pos.w);');
-		NodeShader.write(vert, 'vec2 tpos = vec2(tex.x * 2.0 - 1.0, (1.0 - tex.y) * 2.0 - 1.0);');
-		NodeShader.write(vert, 'gl_Position = vec4(tpos, 0.0, 1.0);');
-		NodeShader.add_out(frag, 'vec4 fragColor[2]');
-		NodeShader.write(frag, 'fragColor[0] = vec4(position, 1.0);');
-		NodeShader.write(frag, 'fragColor[1] = vec4(normal, 1.0);');
+	static make_bake_position_normal = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+		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);');
 	}
 
-	static set_color_writes = (con_paint: NodeShaderContextRaw) => {
+	static make_bake_set_color_writes = (con_paint: NodeShaderContextRaw) => {
 		// Bake into base color, disable other slots
 		con_paint.data.color_writes_red[1] = false;
 		con_paint.data.color_writes_green[1] = false;
@@ -148,7 +148,7 @@ class MakeBake {
 		con_paint.data.color_writes_alpha[2] = false;
 	}
 
-	static axis_string = (i: i32): string => {
+	static make_bake_axis_string = (i: i32): string => {
 		return i == bake_axis_t.X  ? "vec3(1,0,0)"  :
 			   i == bake_axis_t.Y  ? "vec3(0,1,0)"  :
 			   i == bake_axis_t.Z  ? "vec3(0,0,1)"  :

+ 59 - 59
armorpaint/Sources/MakeBlur.ts

@@ -1,92 +1,92 @@
 
 class MakeBlur {
 
-	static run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+	static make_blur_run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		NodeShader.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
-		NodeShader.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
 
-		NodeShader.write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-		NodeShader.write(frag, 'float roughness = 0.0;');
-		NodeShader.write(frag, 'float metallic = 0.0;');
-		NodeShader.write(frag, 'float occlusion = 0.0;');
-		NodeShader.write(frag, 'vec3 nortan = vec3(0.0, 0.0, 0.0);');
-		NodeShader.write(frag, 'float height = 0.0;');
-		NodeShader.write(frag, 'float mat_opacity = 1.0;');
-		let is_mask: bool = SlotLayer.is_mask(context_raw.layer);
+		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 = SlotLayer.slot_layer_is_mask(context_raw.layer);
 		if (is_mask) {
-			NodeShader.write(frag, 'float opacity = 1.0;');
+			node_shader_write(frag, 'float opacity = 1.0;');
 		}
 		else {
-			NodeShader.write(frag, 'float opacity = 0.0;');
+			node_shader_write(frag, 'float opacity = 0.0;');
 		}
 		if (context_raw.material.paint_emis) {
-			NodeShader.write(frag, 'float emis = 0.0;');
+			node_shader_write(frag, 'float emis = 0.0;');
 		}
 		if (context_raw.material.paint_subs) {
-			NodeShader.write(frag, 'float subs = 0.0;');
+			node_shader_write(frag, 'float subs = 0.0;');
 		}
 
-		NodeShader.add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-		NodeShader.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)
-			NodeShader.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
-			NodeShader.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
-			NodeShader.add_uniform(frag, 'vec3 brushDirection', '_brushDirection');
-			NodeShader.write(frag, 'vec2 blur_direction = brushDirection.yx;');
-			NodeShader.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)
-			NodeShader.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
-			NodeShader.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
-			NodeShader.write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp2);');
-			NodeShader.write(frag, 'opacity += texpaint_sample.a * blur_weight[i];');
-			NodeShader.write(frag, 'basecol += texpaint_sample.rgb * blur_weight[i];');
-			NodeShader.write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp2) * blur_weight[i];');
-			NodeShader.write(frag, 'roughness += texpaint_pack_sample.g;');
-			NodeShader.write(frag, 'metallic += texpaint_pack_sample.b;');
-			NodeShader.write(frag, 'occlusion += texpaint_pack_sample.r;');
-			NodeShader.write(frag, 'height += texpaint_pack_sample.a;');
-			NodeShader.write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp2).rgb * blur_weight[i];');
-			NodeShader.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)
-			NodeShader.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
-			NodeShader.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
-			NodeShader.write(frag, 'for (int i = -7; i <= 7; ++i) {');
-			NodeShader.write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(blur_step * float(i), 0.0));');
-			NodeShader.write(frag, 'opacity += texpaint_sample.a * blur_weight[i + 7];');
-			NodeShader.write(frag, 'basecol += texpaint_sample.rgb * blur_weight[i + 7];');
-			NodeShader.write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(blur_step * float(i), 0.0)) * blur_weight[i + 7];');
-			NodeShader.write(frag, 'roughness += texpaint_pack_sample.g;');
-			NodeShader.write(frag, 'metallic += texpaint_pack_sample.b;');
-			NodeShader.write(frag, 'occlusion += texpaint_pack_sample.r;');
-			NodeShader.write(frag, 'height += texpaint_pack_sample.a;');
-			NodeShader.write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp + vec2(blur_step * float(i), 0.0)).rgb * blur_weight[i + 7];');
-			NodeShader.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
-			NodeShader.write(frag, 'for (int j = -7; j <= 7; ++j) {');
-			NodeShader.write(frag, 'vec4 texpaint_sample = texture(texpaint_undo, texCoordInp + vec2(0.0, blur_step * float(j)));');
-			NodeShader.write(frag, 'opacity += texpaint_sample.a * blur_weight[j + 7];');
-			NodeShader.write(frag, 'basecol += texpaint_sample.rgb * blur_weight[j + 7];');
-			NodeShader.write(frag, 'vec4 texpaint_pack_sample = texture(texpaint_pack_undo, texCoordInp + vec2(0.0, blur_step * float(j))) * blur_weight[j + 7];');
-			NodeShader.write(frag, 'roughness += texpaint_pack_sample.g;');
-			NodeShader.write(frag, 'metallic += texpaint_pack_sample.b;');
-			NodeShader.write(frag, 'occlusion += texpaint_pack_sample.r;');
-			NodeShader.write(frag, 'height += texpaint_pack_sample.a;');
-			NodeShader.write(frag, 'nortan += texture(texpaint_nor_undo, texCoordInp + vec2(0.0, blur_step * float(j))).rgb * blur_weight[j + 7];');
-			NodeShader.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, '}');
 		}
-		NodeShader.write(frag, 'opacity *= brushOpacity;');
+		node_shader_write(frag, 'opacity *= brushOpacity;');
 	}
 }

+ 45 - 45
armorpaint/Sources/MakeBrush.ts

@@ -1,94 +1,94 @@
 
 class MakeBrush {
 
-	static run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+	static make_brush_run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
 
-		NodeShader.write(frag, 'float dist = 0.0;');
+		node_shader_write(frag, 'float dist = 0.0;');
 
 		if (context_raw.tool == workspace_tool_t.PARTICLE) return;
 
 		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) NodeShader.write(frag, 'if (decalMask.z > 0.0) {');
+		if (decal && !fill_layer) node_shader_write(frag, 'if (decalMask.z > 0.0) {');
 
 		if (config_raw.brush_3d) {
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			NodeShader.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
-			NodeShader.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
 
-			NodeShader.add_uniform(frag, 'mat4 invVP', '_inv_view_proj_matrix');
-			NodeShader.write(frag, 'vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);');
-			NodeShader.write(frag, 'winp = mul(winp, invVP);');
-			NodeShader.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) {
-				NodeShader.add_function(frag, str_octahedron_wrap);
-				NodeShader.add_uniform(frag, 'sampler2D gbuffer0');
+				node_shader_add_function(frag, str_octahedron_wrap);
+				node_shader_add_uniform(frag, 'sampler2D gbuffer0');
 				///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-				NodeShader.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
-				NodeShader.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
-				NodeShader.write(frag, 'vec3 wn;');
-				NodeShader.write(frag, 'wn.z = 1.0 - abs(g0.x) - abs(g0.y);');
-				NodeShader.write(frag, 'wn.xy = wn.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);');
-				NodeShader.write(frag, 'wn = normalize(wn);');
-				NodeShader.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) {
-					NodeShader.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;
-					NodeShader.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)
-			NodeShader.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
-			NodeShader.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
 
-			NodeShader.write(frag, 'vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);');
-			NodeShader.write(frag, 'winplast = mul(winplast, invVP);');
-			NodeShader.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;');
 
-			NodeShader.write(frag, 'vec3 pa = wposition - winp.xyz;');
+			node_shader_write(frag, 'vec3 pa = wposition - winp.xyz;');
 			if (context_raw.xray) {
-				NodeShader.write(frag, 'pa += wn * vec3(planeDist, planeDist, planeDist);');
+				node_shader_write(frag, 'pa += wn * vec3(planeDist, planeDist, planeDist);');
 			}
-			NodeShader.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
-				NodeShader.write(frag, 'dist = distance(wposition, winp.xyz);');
+				node_shader_write(frag, 'dist = distance(wposition, winp.xyz);');
 			}
 			else {
 				// Capsule
-				NodeShader.write(frag, 'float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);');
-				NodeShader.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
-			NodeShader.write(frag, 'vec2 binp = inp.xy * 2.0 - 1.0;');
-			NodeShader.write(frag, 'binp.x *= aspectRatio;');
-			NodeShader.write(frag, 'binp = binp * 0.5 + 0.5;');
-
-			NodeShader.write(frag, 'vec2 binplast = inplast.xy * 2.0 - 1.0;');
-			NodeShader.write(frag, 'binplast.x *= aspectRatio;');
-			NodeShader.write(frag, 'binplast = binplast * 0.5 + 0.5;');
-
-			NodeShader.write(frag, 'vec2 pa = bsp.xy - binp.xy;');
-			NodeShader.write(frag, 'vec2 ba = binplast.xy - binp.xy;');
-			NodeShader.write(frag, 'float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);');
-			NodeShader.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);');
 		}
 
-		NodeShader.write(frag, 'if (dist > brushRadius) discard;');
+		node_shader_write(frag, 'if (dist > brushRadius) discard;');
 
-		if (decal && !fill_layer) NodeShader.write(frag, '}');
+		if (decal && !fill_layer) node_shader_write(frag, '}');
 	}
 }

+ 15 - 15
armorpaint/Sources/MakeClone.ts

@@ -1,15 +1,15 @@
 
 class MakeClone {
 
-	static run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
-		NodeShader.add_uniform(frag, 'vec2 cloneDelta', '_cloneDelta');
+	static make_clone_run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+		node_shader_add_uniform(frag, 'vec2 cloneDelta', '_cloneDelta');
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		NodeShader.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
-		NodeShader.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
 
-		NodeShader.write(frag, 'vec3 texpaint_pack_sample = textureLod(texpaint_pack_undo, texCoordInp, 0.0).rgb;');
+		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';
@@ -17,19 +17,19 @@ class MakeClone {
 		let nortan: string = 'textureLod(texpaint_nor_undo, texCoordInp, 0.0).rgb';
 		let height: string = '0.0';
 		let opac: string = '1.0';
-		NodeShader.write(frag, `vec3 basecol = ${base};`);
-		NodeShader.write(frag, `float roughness = ${rough};`);
-		NodeShader.write(frag, `float metallic = ${met};`);
-		NodeShader.write(frag, `float occlusion = ${occ};`);
-		NodeShader.write(frag, `vec3 nortan = ${nortan};`);
-		NodeShader.write(frag, `float height = ${height};`);
-		NodeShader.write(frag, `float mat_opacity = ${opac};`);
-		NodeShader.write(frag, 'float opacity = mat_opacity * brushOpacity;');
+		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) {
-			NodeShader.write(frag, 'float emis = 0.0;');
+			node_shader_write(frag, 'float emis = 0.0;');
 		}
 		if (context_raw.material.paint_subs) {
-			NodeShader.write(frag, 'float subs = 0.0;');
+			node_shader_write(frag, 'float subs = 0.0;');
 		}
 	}
 }

+ 26 - 26
armorpaint/Sources/MakeColorIdPicker.ts

@@ -1,45 +1,45 @@
 
 class MakeColorIdPicker {
 
-	static run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+	static make_colorid_picker_run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
 		// Mangle vertices to form full screen triangle
-		NodeShader.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);');
 
-		NodeShader.add_uniform(frag, 'sampler2D gbuffer2');
-		NodeShader.add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
-		NodeShader.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)
-		NodeShader.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
-		NodeShader.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) {
-			NodeShader.add_out(frag, 'vec4 fragColor');
-			NodeShader.add_uniform(frag, 'sampler2D texcolorid', '_texcolorid');
-			NodeShader.write(frag, 'vec3 idcol = textureLod(texcolorid, texCoordInp, 0.0).rgb;');
-			NodeShader.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) {
-				NodeShader.add_out(frag, 'vec4 fragColor[2]');
-				NodeShader.add_uniform(frag, 'sampler2D gbufferD');
-				NodeShader.add_uniform(frag, 'mat4 invVP', '_inv_view_proj_matrix');
-				NodeShader.add_function(frag, str_get_pos_from_depth);
-				NodeShader.add_function(frag, str_get_nor_from_depth);
-				NodeShader.write(frag, 'fragColor[0] = vec4(get_pos_from_depth(vec2(inp.x, 1.0 - inp.y), invVP, texturePass(gbufferD)), texCoordInp.x);');
-				NodeShader.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_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);');
 			}
 			else {
-				NodeShader.add_out(frag, 'vec4 fragColor[4]');
-				NodeShader.add_uniform(frag, 'sampler2D texpaint');
-				NodeShader.add_uniform(frag, 'sampler2D texpaint_nor');
-				NodeShader.add_uniform(frag, 'sampler2D texpaint_pack');
-				NodeShader.write(frag, 'fragColor[0] = textureLod(texpaint, texCoordInp, 0.0);');
-				NodeShader.write(frag, 'fragColor[1] = textureLod(texpaint_nor, texCoordInp, 0.0);');
-				NodeShader.write(frag, 'fragColor[2] = textureLod(texpaint_pack, texCoordInp, 0.0);');
-				NodeShader.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;');
 			}
 		}
 	}

+ 26 - 26
armorpaint/Sources/MakeDiscard.ts

@@ -1,50 +1,50 @@
 
 class MakeDiscard {
 
-	static color_id = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
-		NodeShader.add_uniform(frag, 'sampler2D texpaint_colorid'); // 1x1 picker
-		NodeShader.add_uniform(frag, 'sampler2D texcolorid', '_texcolorid'); // color map
-		NodeShader.write(frag, 'vec3 colorid_c1 = texelFetch(texpaint_colorid, ivec2(0, 0), 0).rgb;');
-		NodeShader.write(frag, 'vec3 colorid_c2 = textureLod(texcolorid, texCoordPick, 0).rgb;');
+	static make_discard_color_id = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+		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)
-		NodeShader.write(frag, 'if (any(colorid_c1 != colorid_c2)) discard;');
+		node_shader_write(frag, 'if (any(colorid_c1 != colorid_c2)) discard;');
 		///else
-		NodeShader.write(frag, 'if (colorid_c1 != colorid_c2) discard;');
+		node_shader_write(frag, 'if (colorid_c1 != colorid_c2) discard;');
 		///end
 	}
 
-	static face = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
-		NodeShader.add_uniform(frag, 'sampler2D gbuffer2');
-		NodeShader.add_uniform(frag, 'sampler2D textrianglemap', '_textrianglemap');
-		NodeShader.add_uniform(frag, 'vec2 textrianglemapSize', '_texpaintSize');
-		NodeShader.add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
+	static make_discard_face = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+		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)
-		NodeShader.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
-		NodeShader.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
-		NodeShader.write(frag, 'vec4 face_c1 = texelFetch(textrianglemap, ivec2(texCoordInp * textrianglemapSize), 0);');
-		NodeShader.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)
-		NodeShader.write(frag, 'if (any(face_c1 != face_c2)) discard;');
+		node_shader_write(frag, 'if (any(face_c1 != face_c2)) discard;');
 		///else
-		NodeShader.write(frag, 'if (face_c1 != face_c2) discard;');
+		node_shader_write(frag, 'if (face_c1 != face_c2) discard;');
 		///end
 	}
 
-	static uv_island = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
-		NodeShader.add_uniform(frag, 'sampler2D texuvislandmap', '_texuvislandmap');
-		NodeShader.write(frag, 'if (textureLod(texuvislandmap, texCoordPick, 0).r == 0.0) discard;');
+	static make_discard_uv_island = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+		node_shader_add_uniform(frag, 'sampler2D texuvislandmap', '_texuvislandmap');
+		node_shader_write(frag, 'if (textureLod(texuvislandmap, texCoordPick, 0).r == 0.0) discard;');
 	}
 
-	static material_id = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+	static make_discard_material_id = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
 		frag.wvpposition = true;
-		NodeShader.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)
-		NodeShader.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
-		NodeShader.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;
-		NodeShader.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;`);
 	}
 }

+ 75 - 75
armorpaint/Sources/MakeMaterial.ts

@@ -1,39 +1,39 @@
 
 class MakeMaterial {
 
-	static default_scon: shader_context_t = null;
-	static default_mcon: material_context_t = null;
+	static make_material_default_scon: shader_context_t = null;
+	static make_material_default_mcon: material_context_t = null;
 
-	static height_used = false;
-	static emis_used = false;
-	static subs_used = false;
+	static make_material_height_used = false;
+	static make_material_emis_used = false;
+	static make_material_subs_used = false;
 
-	static get_mout = (): bool => {
+	static make_material_get_mout = (): bool => {
 		for (let n of ui_nodes_get_canvas_material().nodes) if (n.type == "OUTPUT_MATERIAL_PBR") return true;
 		return false;
 	}
 
-	static parse_mesh_material = () => {
+	static make_material_parse_mesh_material = () => {
 		let m: material_data_t = project_materials[0].data;
 
 		for (let c of m._.shader._.contexts) {
 			if (c.name == "mesh") {
 				array_remove(m._.shader.contexts, c);
 				array_remove(m._.shader._.contexts, c);
-				MakeMaterial.delete_context(c);
+				MakeMaterial.make_material_delete_context(c);
 				break;
 			}
 		}
 
-		if (MakeMesh.layer_pass_count > 1) {
+		if (MakeMesh.make_mesh_layer_pass_count > 1) {
 			let i: i32 = 0;
 			while (i < m._.shader._.contexts.length) {
 				let c: shader_context_t = m._.shader._.contexts[i];
-				for (let j: i32 = 1; j < MakeMesh.layer_pass_count; ++j) {
+				for (let j: i32 = 1; j < MakeMesh.make_mesh_layer_pass_count; ++j) {
 					if (c.name == "mesh" + j) {
 						array_remove(m._.shader.contexts, c);
 						array_remove(m._.shader._.contexts, c);
-						MakeMaterial.delete_context(c);
+						MakeMaterial.make_material_delete_context(c);
 						i--;
 						break;
 					}
@@ -44,7 +44,7 @@ class MakeMaterial {
 			i = 0;
 			while (i < m._.contexts.length) {
 				let c: material_context_t = m._.contexts[i];
-				for (let j: i32 = 1; j < MakeMesh.layer_pass_count; ++j) {
+				for (let j: i32 = 1; j < MakeMesh.make_mesh_layer_pass_count; ++j) {
 					if (c.name == "mesh" + j) {
 						array_remove(m.contexts, c);
 						array_remove(m._.contexts, c);
@@ -56,7 +56,7 @@ class MakeMaterial {
 			}
 		}
 
-		let con: NodeShaderContextRaw = MakeMesh.run({ name: "Material", canvas: null });
+		let con: NodeShaderContextRaw = MakeMesh.make_mesh_run({ name: "Material", canvas: null });
 		let scon: shader_context_t = shader_context_create(con.data);
 		scon._.override_context = {};
 		if (con.frag.shared_samplers.length > 0) {
@@ -69,8 +69,8 @@ class MakeMaterial {
 		m._.shader.contexts.push(scon);
 		m._.shader._.contexts.push(scon);
 
-		for (let i: i32 = 1; i < MakeMesh.layer_pass_count; ++i) {
-			let con: NodeShaderContextRaw = MakeMesh.run({ name: "Material", canvas: null }, i);
+		for (let i: i32 = 1; i < MakeMesh.make_mesh_layer_pass_count; ++i) {
+			let con: NodeShaderContextRaw = MakeMesh.make_mesh_run({ name: "Material", canvas: null }, i);
 			let scon: shader_context_t = shader_context_create(con.data);
 			scon._.override_context = {};
 			if (con.frag.shared_samplers.length > 0) {
@@ -92,15 +92,15 @@ class MakeMaterial {
 		context_raw.ddirty = 2;
 
 		///if arm_voxels
-		MakeMaterial.make_voxel(m);
+		MakeMaterial.make_material_make_voxel(m);
 		///end
 
 		///if (krom_direct3d12 || krom_vulkan || krom_metal)
-		RenderPathRaytrace.dirty = 1;
+		render_path_raytrace_dirty = 1;
 		///end
 	}
 
-	static parse_particle_material = () => {
+	static make_material_parse_particle_material = () => {
 		let m: material_data_t = context_raw.particle_material;
 		let sc: shader_context_t = null;
 		for (let c of m._.shader._.contexts) {
@@ -113,15 +113,15 @@ class MakeMaterial {
 			array_remove(m._.shader.contexts, sc);
 			array_remove(m._.shader._.contexts, sc);
 		}
-		let con: NodeShaderContextRaw = MakeParticle.run({ name: "MaterialParticle", canvas: null });
-		if (sc != null) MakeMaterial.delete_context(sc);
+		let con: NodeShaderContextRaw = MakeParticle.make_particle_run({ name: "MaterialParticle", canvas: null });
+		if (sc != null) MakeMaterial.make_material_delete_context(sc);
 		sc = shader_context_create(con.data);
 		m._.shader.contexts.push(sc);
 		m._.shader._.contexts.push(sc);
 	}
 
-	static parse_mesh_preview_material = (md: material_data_t = null) => {
-		if (!MakeMaterial.get_mout()) return;
+	static make_material_parse_mesh_preview_material = (md: material_data_t = null) => {
+		if (!MakeMaterial.make_material_get_mout()) return;
 
 		let m: material_data_t = md == null ? project_materials[0].data : md;
 		let scon: shader_context_t = null;
@@ -138,7 +138,7 @@ class MakeMaterial {
 		let mcon: material_context_t = { name: "mesh", bind_textures: [] };
 
 		let sd: material_t = { name: "Material", canvas: null };
-		let con: NodeShaderContextRaw = MakeMeshPreview.run(sd, mcon);
+		let con: NodeShaderContextRaw = MakeMeshPreview.make_mesh_preview_run(sd, mcon);
 
 		for (let i: i32 = 0; i < m._.contexts.length; ++i) {
 			if (m._.contexts[i].name == "mesh") {
@@ -147,7 +147,7 @@ class MakeMaterial {
 			}
 		}
 
-		if (scon != null) MakeMaterial.delete_context(scon);
+		if (scon != null) MakeMaterial.make_material_delete_context(scon);
 
 		let compile_error: bool = false;
 		let _scon: shader_context_t = shader_context_create(con.data);
@@ -160,8 +160,8 @@ class MakeMaterial {
 	}
 
 	///if arm_voxels
-	static make_voxel = (m: material_data_t) => {
-		let rebuild: bool = MakeMaterial.height_used;
+	static make_material_make_voxel = (m: material_data_t) => {
+		let rebuild: bool = MakeMaterial.make_material_height_used;
 		if (config_raw.rp_gi != false && rebuild) {
 			let scon: shader_context_t = null;
 			for (let c of m._.shader._.contexts) {
@@ -175,14 +175,14 @@ class MakeMaterial {
 	}
 	///end
 
-	static parse_paint_material = (bake_previews = true) => {
-		if (!MakeMaterial.get_mout()) return;
+	static make_material_parse_paint_material = (bake_previews = true) => {
+		if (!MakeMaterial.make_material_get_mout()) return;
 
 		if (bake_previews) {
 			let current: image_t = _g2_current;
 			let g2_in_use: bool = _g2_in_use;
 			if (g2_in_use) g2_end();
-			MakeMaterial.bake_node_previews();
+			MakeMaterial.make_material_bake_node_previews();
 			if (g2_in_use) g2_begin(current);
 		}
 
@@ -193,7 +193,7 @@ class MakeMaterial {
 			if (c.name == "paint") {
 				array_remove(m._.shader.contexts, c);
 				array_remove(m._.shader._.contexts, c);
-				if (c != MakeMaterial.default_scon) MakeMaterial.delete_context(c);
+				if (c != MakeMaterial.make_material_default_scon) MakeMaterial.make_material_delete_context(c);
 				break;
 			}
 		}
@@ -207,7 +207,7 @@ class MakeMaterial {
 
 		let sdata: material_t = { name: "Material", canvas: ui_nodes_get_canvas_material() };
 		let tmcon: material_context_t = { name: "paint", bind_textures: [] };
-		let con: NodeShaderContextRaw = MakePaint.run(sdata, tmcon);
+		let con: NodeShaderContextRaw = MakePaint.make_paint_run(sdata, tmcon);
 
 		let compile_error: bool = false;
 		let scon: shader_context_t;
@@ -224,14 +224,14 @@ class MakeMaterial {
 		m.contexts.push(mcon);
 		m._.contexts.push(mcon);
 
-		if (MakeMaterial.default_scon == null) MakeMaterial.default_scon = scon;
-		if (MakeMaterial.default_mcon == null) MakeMaterial.default_mcon = mcon;
+		if (MakeMaterial.make_material_default_scon == null) MakeMaterial.make_material_default_scon = scon;
+		if (MakeMaterial.make_material_default_mcon == null) MakeMaterial.make_material_default_mcon = mcon;
 	}
 
-	static bake_node_previews = () => {
+	static make_material_bake_node_previews = () => {
 		context_raw.node_previews_used = [];
 		if (context_raw.node_previews == null) context_raw.node_previews = map_create();
-		MakeMaterial.traverse_nodes(ui_nodes_get_canvas_material().nodes, null, []);
+		MakeMaterial.make_material_traverse_nodes(ui_nodes_get_canvas_material().nodes, null, []);
 		for (let key of context_raw.node_previews.keys()) {
 			if (context_raw.node_previews_used.indexOf(key) == -1) {
 				let image: image_t = context_raw.node_previews.get(key);
@@ -241,14 +241,14 @@ class MakeMaterial {
 		}
 	}
 
-	static traverse_nodes = (nodes: zui_node_t[], group: zui_node_canvas_t, parents: zui_node_t[]) => {
+	static make_material_traverse_nodes = (nodes: zui_node_t[], group: zui_node_canvas_t, parents: zui_node_t[]) => {
 		for (let node of nodes) {
-			MakeMaterial.bake_node_preview(node, group, parents);
+			MakeMaterial.make_material_bake_node_preview(node, group, parents);
 			if (node.type == "GROUP") {
 				for (let g of project_material_groups) {
 					if (g.canvas.name == node.name) {
 						parents.push(node);
-						MakeMaterial.traverse_nodes(g.canvas.nodes, g.canvas, parents);
+						MakeMaterial.make_material_traverse_nodes(g.canvas.nodes, g.canvas, parents);
 						parents.pop();
 						break;
 					}
@@ -257,9 +257,9 @@ class MakeMaterial {
 		}
 	}
 
-	static bake_node_preview = (node: zui_node_t, group: zui_node_canvas_t, parents: zui_node_t[]) => {
+	static make_material_bake_node_preview = (node: zui_node_t, group: zui_node_canvas_t, parents: zui_node_t[]) => {
 		if (node.type == "BLUR") {
-			let id: string = ParserMaterial.node_name(node, parents);
+			let id: string = parser_material_node_name(node, parents);
 			let image: image_t = context_raw.node_previews.get(id);
 			context_raw.node_previews_used.push(id);
 			let resX: i32 = math_floor(config_get_texture_res_x() / 4);
@@ -270,12 +270,12 @@ class MakeMaterial {
 				context_raw.node_previews.set(id, image);
 			}
 
-			ParserMaterial.blur_passthrough = true;
+			parser_material_blur_passthrough = true;
 			util_render_make_node_preview(ui_nodes_get_canvas_material(), node, image, group, parents);
-			ParserMaterial.blur_passthrough = false;
+			parser_material_blur_passthrough = false;
 		}
 		else if (node.type == "DIRECT_WARP") {
-			let id: string = ParserMaterial.node_name(node, parents);
+			let id: string = parser_material_node_name(node, parents);
 			let image: image_t = context_raw.node_previews.get(id);
 			context_raw.node_previews_used.push(id);
 			let resX: i32 = math_floor(config_get_texture_res_x());
@@ -286,12 +286,12 @@ class MakeMaterial {
 				context_raw.node_previews.set(id, image);
 			}
 
-			ParserMaterial.warp_passthrough = true;
+			parser_material_warp_passthrough = true;
 			util_render_make_node_preview(ui_nodes_get_canvas_material(), node, image, group, parents);
-			ParserMaterial.warp_passthrough = false;
+			parser_material_warp_passthrough = false;
 		}
 		else if (node.type == "BAKE_CURVATURE") {
-			let id: string = ParserMaterial.node_name(node, parents);
+			let id: string = parser_material_node_name(node, parents);
 			let image: image_t = context_raw.node_previews.get(id);
 			context_raw.node_previews_used.push(id);
 			let resX: i32 = math_floor(config_get_texture_res_x());
@@ -302,8 +302,8 @@ class MakeMaterial {
 				context_raw.node_previews.set(id, image);
 			}
 
-			if (RenderPathPaint.live_layer == null) {
-				RenderPathPaint.live_layer = SlotLayer.create("_live");
+			if (RenderPathPaint.render_path_paint_live_layer == null) {
+				RenderPathPaint.render_path_paint_live_layer = SlotLayer.slot_layer_create("_live");
 			}
 
 			let _space: i32 = ui_header_worktab.position;
@@ -313,26 +313,26 @@ class MakeMaterial {
 			context_raw.tool = workspace_tool_t.BAKE;
 			context_raw.bake_type = bake_type_t.CURVATURE;
 
-			ParserMaterial.bake_passthrough = true;
-			ParserMaterial.start_node = node;
-			ParserMaterial.start_group = group;
-			ParserMaterial.start_parents = parents;
-			MakeMaterial.parse_paint_material(false);
-			ParserMaterial.bake_passthrough = false;
-			ParserMaterial.start_node = null;
-			ParserMaterial.start_group = null;
-			ParserMaterial.start_parents = null;
+			parser_material_bake_passthrough = true;
+			parser_material_start_node = node;
+			parser_material_start_group = group;
+			parser_material_start_parents = parents;
+			MakeMaterial.make_material_parse_paint_material(false);
+			parser_material_bake_passthrough = false;
+			parser_material_start_node = null;
+			parser_material_start_group = null;
+			parser_material_start_parents = null;
 			context_raw.pdirty = 1;
-			RenderPathPaint.use_live_layer(true);
-			RenderPathPaint.commands_paint(false);
-			RenderPathPaint.dilate(true, false);
-			RenderPathPaint.use_live_layer(false);
+			RenderPathPaint.render_path_paint_use_live_layer(true);
+			RenderPathPaint.render_path_paint_commands_paint(false);
+			RenderPathPaint.render_path_paint_dilate(true, false);
+			RenderPathPaint.render_path_paint_use_live_layer(false);
 			context_raw.pdirty = 0;
 
 			ui_header_worktab.position = _space;
 			context_raw.tool = _tool;
 			context_raw.bake_type = _bake_type;
-			MakeMaterial.parse_paint_material(false);
+			MakeMaterial.make_material_parse_paint_material(false);
 
 			let rts: map_t<string, render_target_t> = render_path_render_targets;
 			let texpaint_live: render_target_t = rts.get("texpaint_live");
@@ -343,11 +343,11 @@ class MakeMaterial {
 		}
 	}
 
-	static parse_node_preview_material = (node: zui_node_t, group: zui_node_canvas_t = null, parents: zui_node_t[] = null): { scon: shader_context_t, mcon: material_context_t } => {
+	static make_material_parse_node_preview_material = (node: zui_node_t, group: zui_node_canvas_t = null, parents: zui_node_t[] = null): { scon: shader_context_t, mcon: material_context_t } => {
 		if (node.outputs.length == 0) return null;
 		let sdata: material_t = { name: "Material", canvas: ui_nodes_get_canvas_material() };
 		let mcon_raw: material_context_t = { name: "mesh", bind_textures: [] };
-		let con: NodeShaderContextRaw = MakeNodePreview.run(sdata, mcon_raw, node, group, parents);
+		let con: NodeShaderContextRaw = MakeNodePreview.make_node_preview_run(sdata, mcon_raw, node, group, parents);
 		let compile_error: bool = false;
 		let scon: shader_context_t;
 		let _scon: shader_context_t = shader_context_create(con.data);
@@ -358,11 +358,11 @@ class MakeMaterial {
 		return { scon: scon, mcon: mcon };
 	}
 
-	static parse_brush = () => {
-		ParserLogic.parse(context_raw.brush.canvas);
+	static make_material_parse_brush = () => {
+		parser_logic_parse(context_raw.brush.canvas);
 	}
 
-	static blend_mode = (frag: NodeShaderRaw, blending: i32, cola: string, colb: string, opac: string): string => {
+	static make_material_blend_mode = (frag: NodeShaderRaw, blending: i32, cola: string, colb: string, opac: string): string => {
 		if (blending == blend_type_t.MIX) {
 			return `mix(${cola}, ${colb}, ${opac})`;
 		}
@@ -410,24 +410,24 @@ class MakeMaterial {
 			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) {
-			NodeShader.add_function(frag, str_hue_sat);
+			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})`;
 		}
 		else if (blending == blend_type_t.SATURATION) {
-			NodeShader.add_function(frag, str_hue_sat);
+			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})`;
 		}
 		else if (blending == blend_type_t.COLOR) {
-			NodeShader.add_function(frag, str_hue_sat);
+			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})`;
 		}
 		else { // BlendValue
-			NodeShader.add_function(frag, str_hue_sat);
+			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})`;
 		}
 	}
 
-	static blend_mode_mask = (frag: NodeShaderRaw, blending: i32, cola: string, colb: string, opac: string): string => {
+	static make_material_blend_mode_mask = (frag: NodeShaderRaw, blending: i32, cola: string, colb: string, opac: string): string => {
 		if (blending == blend_type_t.MIX) {
 			return `mix(${cola}, ${colb}, ${opac})`;
 		}
@@ -475,17 +475,17 @@ class MakeMaterial {
 		}
 	}
 
-	static get_displace_strength = (): f32 => {
+	static make_material_get_displace_strength = (): f32 => {
 		let sc: f32 = context_main_object().base.transform.scale.x;
 		return config_raw.displace_strength * 0.02 * sc;
 	}
 
-	static voxelgi_half_extents = (): string => {
+	static make_material_voxelgi_half_extents = (): string => {
 		let ext: f32 = context_raw.vxao_ext;
 		return `const vec3 voxelgiHalfExtents = vec3(${ext}, ${ext}, ${ext});`;
 	}
 
-	static delete_context = (c: shader_context_t) => {
+	static make_material_delete_context = (c: shader_context_t) => {
 		base_notify_on_next_frame(() => { // Ensure pipeline is no longer in use
 			shader_context_delete(c);
 		});

+ 262 - 262
armorpaint/Sources/MakeMesh.ts

@@ -1,11 +1,11 @@
 
 class MakeMesh {
 
-	static layer_pass_count = 1;
+	static make_mesh_layer_pass_count = 1;
 
-	static run = (data: material_t, layerPass = 0): NodeShaderContextRaw => {
+	static make_mesh_run = (data: material_t, layerPass = 0): NodeShaderContextRaw => {
 		let context_id: string = layerPass == 0 ? "mesh" : "mesh" + layerPass;
-		let con_mesh: NodeShaderContextRaw = NodeShaderContext.create(data, {
+		let con_mesh: NodeShaderContextRaw = node_shader_context_create(data, {
 			name: context_id,
 			depth_write: layerPass == 0 ? true : false,
 			compare_mode: layerPass == 0 ? "less" : "equal",
@@ -15,470 +15,470 @@ class MakeMesh {
 			depth_attachment: "DEPTH32"
 		});
 
-		let vert: NodeShaderRaw = NodeShaderContext.make_vert(con_mesh);
-		let frag: NodeShaderRaw = NodeShaderContext.make_frag(con_mesh);
+		let vert: NodeShaderRaw = node_shader_context_make_vert(con_mesh);
+		let frag: NodeShaderRaw = node_shader_context_make_frag(con_mesh);
 		frag.ins = vert.outs;
 
-		NodeShader.add_out(vert, 'vec2 texCoord');
+		node_shader_add_out(vert, 'vec2 texCoord');
 		frag.wvpposition = true;
-		NodeShader.add_out(vert, 'vec4 prevwvpposition');
-		NodeShader.add_uniform(vert, 'mat4 VP', '_view_proj_matrix');
-		NodeShader.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 = MakeMaterial.get_displace_strength();
-		if (MakeMaterial.height_used && displace_strength > 0.0) {
+		let displace_strength: f32 = MakeMaterial.make_material_get_displace_strength();
+		if (MakeMaterial.make_material_height_used && displace_strength > 0.0) {
 			vert.n = true;
-			NodeShader.write(vert, 'float height = 0.0;');
+			node_shader_write(vert, 'float height = 0.0;');
 			let num_layers: i32 = 0;
 			for (let l of project_layers) {
-				if (!SlotLayer.is_visible(l) || !l.paint_height || !SlotLayer.is_layer(l)) continue;
+				if (!SlotLayer.slot_layer_is_visible(l) || !l.paint_height || !SlotLayer.slot_layer_is_layer(l)) continue;
 				if (num_layers > 16) break;
 				num_layers++;
 				texture_count++;
-				NodeShader.add_uniform(vert, 'sampler2D texpaint_pack_vert' + l.id, '_texpaint_pack_vert' + l.id);
-				NodeShader.write(vert, 'height += textureLod(texpaint_pack_vert' + l.id + ', tex, 0.0).a;');
-				let masks: SlotLayerRaw[] = SlotLayer.get_masks(l);
+				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: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l);
 				if (masks != null) {
 					for (let m of masks) {
-						if (!SlotLayer.is_visible(m)) continue;
+						if (!SlotLayer.slot_layer_is_visible(m)) continue;
 						texture_count++;
-						NodeShader.add_uniform(vert, 'sampler2D texpaint_vert' + m.id, '_texpaint_vert' + m.id);
-						NodeShader.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;');
 					}
 				}
 			}
-			NodeShader.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});`);
 		}
 
-		NodeShader.write(vert, 'gl_Position = mul(vec4(wposition.xyz, 1.0), VP);');
-		NodeShader.write(vert, 'texCoord = tex;');
-		if (MakeMaterial.height_used && displace_strength > 0) {
-			NodeShader.add_uniform(vert, 'mat4 invW', '_inv_world_matrix');
-			NodeShader.write(vert, 'prevwvpposition = mul(mul(vec4(wposition, 1.0), invW), prevWVP);');
+		node_shader_write(vert, 'gl_Position = mul(vec4(wposition.xyz, 1.0), VP);');
+		node_shader_write(vert, 'texCoord = tex;');
+		if (MakeMaterial.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 {
-			NodeShader.write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
+			node_shader_write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
 		}
 
-		NodeShader.add_out(frag, 'vec4 fragColor[3]');
+		node_shader_add_out(frag, 'vec4 fragColor[3]');
 		frag.n = true;
-		NodeShader.add_function(frag, str_pack_float_int16);
+		node_shader_add_function(frag, str_pack_float_int16);
 
 		if (context_raw.tool == workspace_tool_t.COLORID) {
 			texture_count++;
-			NodeShader.add_uniform(frag, 'sampler2D texcolorid', '_texcolorid');
-			NodeShader.write(frag, 'fragColor[0] = vec4(n.xy, 1.0, packFloatInt16(0.0, uint(0)));');
-			NodeShader.write(frag, 'vec3 idcol = pow(textureLod(texcolorid, texCoord, 0.0).rgb, vec3(2.2, 2.2, 2.2));');
-			NodeShader.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 {
-			NodeShader.add_function(frag, str_octahedron_wrap);
-			NodeShader.add_function(frag, str_cotangent_frame);
+			node_shader_add_function(frag, str_octahedron_wrap);
+			node_shader_add_function(frag, str_cotangent_frame);
 			if (layerPass > 0) {
-				NodeShader.add_uniform(frag, 'sampler2D gbuffer0');
-				NodeShader.add_uniform(frag, 'sampler2D gbuffer1');
-				NodeShader.add_uniform(frag, 'sampler2D gbuffer2');
-				NodeShader.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)
-				NodeShader.write(frag, 'fragcoord.y = 1.0 - fragcoord.y;');
+				node_shader_write(frag, 'fragcoord.y = 1.0 - fragcoord.y;');
 				///end
-				NodeShader.write(frag, 'vec4 gbuffer0_sample = textureLod(gbuffer0, fragcoord, 0.0);');
-				NodeShader.write(frag, 'vec4 gbuffer1_sample = textureLod(gbuffer1, fragcoord, 0.0);');
-				NodeShader.write(frag, 'vec4 gbuffer2_sample = textureLod(gbuffer2, fragcoord, 0.0);');
-				NodeShader.write(frag, 'vec3 basecol = gbuffer0_sample.rgb;');
-				NodeShader.write(frag, 'float roughness = gbuffer2_sample.g;');
-				NodeShader.write(frag, 'float metallic = gbuffer2_sample.b;');
-				NodeShader.write(frag, 'float occlusion = gbuffer2_sample.r;');
-				NodeShader.write(frag, 'float opacity = 1.0;//gbuffer0_sample.a;');
-				NodeShader.write(frag, 'float matid = gbuffer1_sample.a;');
-				NodeShader.write(frag, 'vec3 ntex = gbuffer1_sample.rgb;');
-				NodeShader.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 {
-				NodeShader.write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-				NodeShader.write(frag, 'float roughness = 0.0;');
-				NodeShader.write(frag, 'float metallic = 0.0;');
-				NodeShader.write(frag, 'float occlusion = 1.0;');
-				NodeShader.write(frag, 'float opacity = 1.0;');
-				NodeShader.write(frag, 'float matid = 0.0;');
-				NodeShader.write(frag, 'vec3 ntex = vec3(0.5, 0.5, 1.0);');
-				NodeShader.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;');
 			}
-			NodeShader.write(frag, 'vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);');
-			NodeShader.write(frag, 'vec4 texpaint_nor_sample;');
-			NodeShader.write(frag, 'vec4 texpaint_pack_sample;');
-			NodeShader.write(frag, 'float texpaint_opac;');
-
-			if (MakeMaterial.height_used) {
-				NodeShader.write(frag, 'float height0 = 0.0;');
-				NodeShader.write(frag, 'float height1 = 0.0;');
-				NodeShader.write(frag, 'float height2 = 0.0;');
-				NodeShader.write(frag, 'float height3 = 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;');
+
+			if (MakeMaterial.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;');
 			}
 
 			if (context_raw.draw_wireframe) {
 				texture_count++;
-				NodeShader.add_uniform(frag, 'sampler2D texuvmap', '_texuvmap');
+				node_shader_add_uniform(frag, 'sampler2D texuvmap', '_texuvmap');
 			}
 
-			if (context_raw.viewport_mode == viewport_mode_t.MASK && SlotLayer.get_masks(context_raw.layer) != null) {
-				for (let m of SlotLayer.get_masks(context_raw.layer)) {
-					if (!SlotLayer.is_visible(m)) continue;
+			if (context_raw.viewport_mode == viewport_mode_t.MASK && SlotLayer.slot_layer_get_masks(context_raw.layer) != null) {
+				for (let m of SlotLayer.slot_layer_get_masks(context_raw.layer)) {
+					if (!SlotLayer.slot_layer_is_visible(m)) continue;
 					texture_count++;
-					NodeShader.add_uniform(frag, 'sampler2D texpaint_view_mask' + m.id, '_texpaint' + project_layers.indexOf(m));
+					node_shader_add_uniform(frag, 'sampler2D texpaint_view_mask' + m.id, '_texpaint' + project_layers.indexOf(m));
 				}
 			}
 
 			if (context_raw.viewport_mode == viewport_mode_t.LIT && context_raw.render_mode == render_mode_t.FORWARD) {
 				texture_count += 4;
-				NodeShader.add_uniform(frag, 'sampler2D senvmapBrdf', "$brdf.k");
-				NodeShader.add_uniform(frag, 'sampler2D senvmapRadiance', '_envmap_radiance');
-				NodeShader.add_uniform(frag, 'sampler2D sltcMat', '_ltcMat');
-				NodeShader.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
-			MakeMesh.layer_pass_count = 1;
+			MakeMesh.make_mesh_layer_pass_count = 1;
 			let layers: SlotLayerRaw[] = [];
 			let start_count: i32 = texture_count;
 			let is_material_tool: bool = context_raw.tool == workspace_tool_t.MATERIAL;
 			for (let l of project_layers) {
 				if (is_material_tool && l != context_raw.layer) continue;
-				if (!SlotLayer.is_layer(l) || !SlotLayer.is_visible(l)) continue;
+				if (!SlotLayer.slot_layer_is_layer(l) || !SlotLayer.slot_layer_is_visible(l)) continue;
 
 				let count: i32 = 3;
-				let masks: SlotLayerRaw[] = SlotLayer.get_masks(l);
+				let masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l);
 				if (masks != null) count += masks.length;
 				texture_count += count;
-				if (texture_count >= MakeMesh.get_max_textures()) {
+				if (texture_count >= MakeMesh.make_mesh_get_max_textures()) {
 					texture_count = start_count + count + 3; // gbuffer0_copy, gbuffer1_copy, gbuffer2_copy
-					MakeMesh.layer_pass_count++;
+					MakeMesh.make_mesh_layer_pass_count++;
 				}
-				if (layerPass == MakeMesh.layer_pass_count - 1) {
+				if (layerPass == MakeMesh.make_mesh_layer_pass_count - 1) {
 					layers.push(l);
 				}
 			}
 
-			let last_pass: bool = layerPass == MakeMesh.layer_pass_count - 1;
+			let last_pass: bool = layerPass == MakeMesh.make_mesh_layer_pass_count - 1;
 
 			for (let l of layers) {
-				if (SlotLayer.get_object_mask(l) > 0) {
-					NodeShader.add_uniform(frag, 'int uid', '_uid');
-					if (SlotLayer.get_object_mask(l) > project_paint_objects.length) { // Atlas
-						let visibles: mesh_object_t[] = project_get_atlas_objects(SlotLayer.get_object_mask(l));
-						NodeShader.write(frag, 'if (');
+				if (SlotLayer.slot_layer_get_object_mask(l) > 0) {
+					node_shader_add_uniform(frag, 'int uid', '_uid');
+					if (SlotLayer.slot_layer_get_object_mask(l) > project_paint_objects.length) { // Atlas
+						let visibles: mesh_object_t[] = project_get_atlas_objects(SlotLayer.slot_layer_get_object_mask(l));
+						node_shader_write(frag, 'if (');
 						for (let i: i32 = 0; i < visibles.length; ++i) {
-							if (i > 0) NodeShader.write(frag, ' || ');
-							NodeShader.write(frag, `${visibles[i].base.uid} == uid`);
+							if (i > 0) node_shader_write(frag, ' || ');
+							node_shader_write(frag, `${visibles[i].base.uid} == uid`);
 						}
-						NodeShader.write(frag, ') {');
+						node_shader_write(frag, ') {');
 					}
 					else { // Object mask
-						let uid: i32 = project_paint_objects[SlotLayer.get_object_mask(l) - 1].base.uid;
-						NodeShader.write(frag, `if (${uid} == uid) {`);
+						let uid: i32 = project_paint_objects[SlotLayer.slot_layer_get_object_mask(l) - 1].base.uid;
+						node_shader_write(frag, `if (${uid} == uid) {`);
 					}
 				}
 
-				NodeShader.add_shared_sampler(frag, 'sampler2D texpaint' + l.id);
-				NodeShader.write(frag, 'texpaint_sample = textureLodShared(texpaint' + l.id + ', texCoord, 0.0);');
-				NodeShader.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) {
-				// 	NodeShader.write(frag, 'if (texpaint_opac < 0.1) discard;');
+				// 	write(frag, 'if (texpaint_opac < 0.1) discard;');
 				// }
 				// ///end
 
-				let masks: SlotLayerRaw[] = SlotLayer.get_masks(l);
+				let masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l);
 				if (masks != null) {
 					let has_visible: bool = false;
 					for (let m of masks) {
-						if (SlotLayer.is_visible(m)) {
+						if (SlotLayer.slot_layer_is_visible(m)) {
 							has_visible = true;
 							break;
 						}
 					}
 					if (has_visible) {
 						let texpaint_mask: string = 'texpaint_mask' + l.id;
-						NodeShader.write(frag, `float ${texpaint_mask} = 0.0;`);
+						node_shader_write(frag, `float ${texpaint_mask} = 0.0;`);
 						for (let m of masks) {
-							if (!SlotLayer.is_visible(m)) continue;
-							NodeShader.add_shared_sampler(frag, 'sampler2D texpaint' + m.id);
-							NodeShader.write(frag, '{'); // Group mask is sampled across multiple layers
-							NodeShader.write(frag, 'float texpaint_mask_sample' + m.id + ' = textureLodShared(texpaint' + m.id + ', texCoord, 0.0).r;');
-							NodeShader.write(frag, `${texpaint_mask} = ` + MakeMaterial.blend_mode_mask(frag, m.blending, `${texpaint_mask}`, 'texpaint_mask_sample' + m.id, 'float(' + SlotLayer.get_opacity(m) + ')') + ';');
-							NodeShader.write(frag, '}');
+							if (!SlotLayer.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} = ` + MakeMaterial.make_material_blend_mode_mask(frag, m.blending, `${texpaint_mask}`, 'texpaint_mask_sample' + m.id, 'float(' + SlotLayer.slot_layer_get_opacity(m) + ')') + ';');
+							node_shader_write(frag, '}');
 						}
-						NodeShader.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 (SlotLayer.get_opacity(l) < 1) {
-					NodeShader.write(frag, `texpaint_opac *= ${SlotLayer.get_opacity(l)};`);
+				if (SlotLayer.slot_layer_get_opacity(l) < 1) {
+					node_shader_write(frag, `texpaint_opac *= ${SlotLayer.slot_layer_get_opacity(l)};`);
 				}
 
 				if (l.paint_base) {
 					if (l == project_layers[0]) {
-						NodeShader.write(frag, 'basecol = texpaint_sample.rgb * texpaint_opac;');
+						node_shader_write(frag, 'basecol = texpaint_sample.rgb * texpaint_opac;');
 					}
 					else {
-						NodeShader.write(frag, 'basecol = ' + MakeMaterial.blend_mode(frag, l.blending, 'basecol', 'texpaint_sample.rgb', 'texpaint_opac') + ';');
+						node_shader_write(frag, 'basecol = ' + MakeMaterial.make_material_blend_mode(frag, l.blending, 'basecol', 'texpaint_sample.rgb', 'texpaint_opac') + ';');
 					}
 				}
 
-				if (l.paint_nor || MakeMaterial.emis_used) {
-					NodeShader.add_shared_sampler(frag, 'sampler2D texpaint_nor' + l.id);
-					NodeShader.write(frag, 'texpaint_nor_sample = textureLodShared(texpaint_nor' + l.id + ', texCoord, 0.0);');
+				if (l.paint_nor || MakeMaterial.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);');
 
-					if (MakeMaterial.emis_used) {
-						NodeShader.write(frag, 'if (texpaint_opac > 0.0) matid = texpaint_nor_sample.a;');
+					if (MakeMaterial.make_material_emis_used) {
+						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
-							NodeShader.write(frag, '{');
-							NodeShader.write(frag, 'vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-							NodeShader.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);');
-							NodeShader.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);');
-							NodeShader.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 {
-							NodeShader.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 && MakeMaterial.height_used)) {
-					NodeShader.add_shared_sampler(frag, 'sampler2D texpaint_pack' + l.id);
-					NodeShader.write(frag, 'texpaint_pack_sample = textureLodShared(texpaint_pack' + l.id + ', texCoord, 0.0);');
+				if (l.paint_occ || l.paint_rough || l.paint_met || (l.paint_height && MakeMaterial.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);');
 
 					if (l.paint_occ) {
-						NodeShader.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) {
-						NodeShader.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) {
-						NodeShader.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 && MakeMaterial.height_used) {
+					if (l.paint_height && MakeMaterial.make_material_height_used) {
 						let assign: string = l.paint_height_blend ? "+=" : "=";
-						NodeShader.write(frag, `height ${assign} texpaint_pack_sample.a * texpaint_opac;`);
-						NodeShader.write(frag, '{');
-						NodeShader.add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-						NodeShader.write(frag, 'float tex_step = 1.0 / texpaintSize.x;');
-						NodeShader.write(frag, `height0 ${assign} textureLodShared(texpaint_pack` + l.id + ', vec2(texCoord.x - tex_step, texCoord.y), 0.0).a * texpaint_opac;');
-						NodeShader.write(frag, `height1 ${assign} textureLodShared(texpaint_pack` + l.id + ', vec2(texCoord.x + tex_step, texCoord.y), 0.0).a * texpaint_opac;');
-						NodeShader.write(frag, `height2 ${assign} textureLodShared(texpaint_pack` + l.id + ', vec2(texCoord.x, texCoord.y - tex_step), 0.0).a * texpaint_opac;');
-						NodeShader.write(frag, `height3 ${assign} textureLodShared(texpaint_pack` + l.id + ', vec2(texCoord.x, texCoord.y + tex_step), 0.0).a * texpaint_opac;');
-						NodeShader.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 (SlotLayer.get_object_mask(l) > 0) {
-					NodeShader.write(frag, '}');
+				if (SlotLayer.slot_layer_get_object_mask(l) > 0) {
+					node_shader_write(frag, '}');
 				}
 			}
 
 			if (last_pass && context_raw.draw_texels) {
-				NodeShader.add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-				NodeShader.write(frag, 'vec2 texel0 = texCoord * texpaintSize * 0.01;');
-				NodeShader.write(frag, 'vec2 texel1 = texCoord * texpaintSize * 0.1;');
-				NodeShader.write(frag, 'vec2 texel2 = texCoord * texpaintSize;');
-				NodeShader.write(frag, 'basecol *= max(float(mod(int(texel0.x), 2.0) == mod(int(texel0.y), 2.0)), 0.9);');
-				NodeShader.write(frag, 'basecol *= max(float(mod(int(texel1.x), 2.0) == mod(int(texel1.y), 2.0)), 0.9);');
-				NodeShader.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) {
-				NodeShader.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 (MakeMaterial.height_used) {
-				NodeShader.write(frag, 'if (height > 0.0) {');
-				// NodeShader.write(frag, 'float height_dx = dFdx(height * 16.0);');
-				// NodeShader.write(frag, 'float height_dy = dFdy(height * 16.0);');
-				NodeShader.write(frag, 'float height_dx = height0 - height1;');
-				NodeShader.write(frag, 'float height_dy = height2 - height3;');
+			if (MakeMaterial.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;');
 				// Whiteout blend
-				NodeShader.write(frag, 'vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-				NodeShader.write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-				NodeShader.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);');
-				NodeShader.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) {
-				NodeShader.write(frag, 'fragColor[0] = vec4(basecol, opacity);');
-				NodeShader.write(frag, 'fragColor[1] = vec4(ntex, matid);');
-				NodeShader.write(frag, 'fragColor[2] = vec4(occlusion, roughness, metallic, height);');
-				ParserMaterial.finalize(con_mesh);
+				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 = NodeShader.get(vert);
-				con_mesh.data.fragment_shader = NodeShader.get(frag);
+				con_mesh.data.vertex_shader = node_shader_get(vert);
+				con_mesh.data.fragment_shader = node_shader_get(frag);
 				return con_mesh;
 			}
 
 			frag.vvec = true;
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
 			///else
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
 			///end
-			NodeShader.write(frag, 'n = ntex * 2.0 - 1.0;');
-			NodeShader.write(frag, 'n.y = -n.y;');
-			NodeShader.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) {
-				NodeShader.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);
-					NodeShader.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;
-					NodeShader.write(frag, 'vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);');
-					NodeShader.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;
-					NodeShader.write(frag, 'float dotNV = max(0.0, dot(n, vVec));');
-					NodeShader.write(frag, 'vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;');
-					NodeShader.add_uniform(frag, 'int envmapNumMipmaps', '_envmap_num_mipmaps');
-					NodeShader.add_uniform(frag, 'vec4 envmapData', '_envmapData'); // angle, sin(angle), cos(angle), strength
-					NodeShader.write(frag, 'vec3 wreflect = reflect(-vVec, n);');
-					NodeShader.write(frag, 'float envlod = roughness * float(envmapNumMipmaps);');
-					NodeShader.add_function(frag, str_envmap_equirect);
-					NodeShader.write(frag, 'vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;');
-					NodeShader.add_uniform(frag, 'vec3 lightArea0', '_light_area0');
-					NodeShader.add_uniform(frag, 'vec3 lightArea1', '_light_area1');
-					NodeShader.add_uniform(frag, 'vec3 lightArea2', '_light_area2');
-					NodeShader.add_uniform(frag, 'vec3 lightArea3', '_light_area3');
-					NodeShader.add_function(frag, str_ltc_evaluate);
-					NodeShader.add_uniform(frag, 'vec3 lightPos', '_point_pos');
-					NodeShader.add_uniform(frag, 'vec3 lightColor', '_point_color');
-					// NodeShader.write(frag, 'float dotNL = max(dot(n, normalize(lightPos - wposition)), 0.0);');
-					// NodeShader.write(frag, 'vec3 direct = albedo * dotNL;');
-					NodeShader.write(frag, 'float ldist = distance(wposition, lightPos);');
-					NodeShader.write(frag, 'const float LUT_SIZE = 64.0;');
-					NodeShader.write(frag, 'const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;');
-					NodeShader.write(frag, 'const float LUT_BIAS = 0.5 / LUT_SIZE;');
-					NodeShader.write(frag, 'float theta = acos(dotNV);');
-					NodeShader.write(frag, 'vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));');
-					NodeShader.write(frag, 'tuv = tuv * LUT_SCALE + LUT_BIAS;');
-					NodeShader.write(frag, 'vec4 t = textureLod(sltcMat, tuv, 0.0);');
-					NodeShader.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));');
-					NodeShader.write(frag, 'float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);');
-					NodeShader.write(frag, 'ltcspec *= textureLod(sltcMag, tuv, 0.0).a;');
-					NodeShader.write(frag, 'mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);');
-					NodeShader.write(frag, 'float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);');
-					NodeShader.write(frag, 'vec3 direct = albedo * ltcdiff + ltcspec * 0.05;');
-					NodeShader.write(frag, 'direct *= lightColor * (1.0 / (ldist * ldist));');
-
-					NodeShader.add_uniform(frag, 'vec4 shirr[7]', '_envmap_irradiance');
-					NodeShader.add_function(frag, str_sh_irradiance());
-					NodeShader.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);');
-					NodeShader.write(frag, 'indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;');
-					NodeShader.write(frag, 'indirect *= envmapData.w * occlusion;');
-					NodeShader.write(frag, 'fragColor[1] = vec4(direct + indirect, 1.0);');
+					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_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_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);');
 				}
 				else { // Deferred, Pathtraced
-					if (MakeMaterial.emis_used) NodeShader.write(frag, 'if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;'); // Boost for bloom
-					NodeShader.write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
+					if (MakeMaterial.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, 'fragColor[1] = vec4(basecol, occlusion);');
 				}
 			}
 			else if (context_raw.viewport_mode == viewport_mode_t.BASE_COLOR && context_raw.layer.paint_base) {
-				NodeShader.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) {
-				NodeShader.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) {
-				NodeShader.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) {
-				NodeShader.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) {
-				NodeShader.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) {
-				NodeShader.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) {
-				NodeShader.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) {
-				NodeShader.write(frag, 'float emis = int(matid * 255.0) % 3 == 1 ? 1.0 : 0.0;');
-				NodeShader.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) {
-				NodeShader.write(frag, 'float subs = int(matid * 255.0) % 3 == 2 ? 1.0 : 0.0;');
-				NodeShader.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) {
-				NodeShader.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;
-				NodeShader.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) {
-				NodeShader.add_shared_sampler(frag, 'sampler2D texpaint_nor' + context_raw.layer.id);
-				NodeShader.add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-				NodeShader.write(frag, 'float sample_matid = texelFetch(texpaint_nor' + context_raw.layer.id + ', ivec2(texCoord * texpaintSize), 0).a + 1.0 / 255.0;');
-				NodeShader.write(frag, 'float matid_r = fract(sin(dot(vec2(sample_matid, sample_matid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.write(frag, 'float matid_g = fract(sin(dot(vec2(sample_matid * 20.0, sample_matid), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.write(frag, 'float matid_b = fract(sin(dot(vec2(sample_matid, sample_matid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.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) {
-				NodeShader.add_uniform(frag, 'float objectId', '_objectId');
-				NodeShader.write(frag, 'float obid = objectId + 1.0 / 255.0;');
-				NodeShader.write(frag, 'float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.write(frag, 'float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.write(frag, 'float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.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 && (SlotLayer.get_masks(context_raw.layer) != null || SlotLayer.is_mask(context_raw.layer))) {
-				if (SlotLayer.is_mask(context_raw.layer)) {
-					NodeShader.write(frag, 'float mask_view = textureLodShared(texpaint' + context_raw.layer.id + ', texCoord, 0.0).r;');
+			else if (context_raw.viewport_mode == viewport_mode_t.MASK && (SlotLayer.slot_layer_get_masks(context_raw.layer) != null || SlotLayer.slot_layer_is_mask(context_raw.layer))) {
+				if (SlotLayer.slot_layer_is_mask(context_raw.layer)) {
+					node_shader_write(frag, 'float mask_view = textureLodShared(texpaint' + context_raw.layer.id + ', texCoord, 0.0).r;');
 				}
 				else {
-					NodeShader.write(frag, 'float mask_view = 0.0;');
-					for (let m of SlotLayer.get_masks(context_raw.layer)) {
-						if (!SlotLayer.is_visible(m)) continue;
-						NodeShader.write(frag, 'float mask_sample' + m.id + ' = textureLodShared(texpaint_view_mask' + m.id + ', texCoord, 0.0).r;');
-						NodeShader.write(frag, 'mask_view = ' + MakeMaterial.blend_mode_mask(frag, m.blending, 'mask_view', 'mask_sample' + m.id, 'float(' + SlotLayer.get_opacity(m) + ')') + ';');
+					node_shader_write(frag, 'float mask_view = 0.0;');
+					for (let m of SlotLayer.slot_layer_get_masks(context_raw.layer)) {
+						if (!SlotLayer.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 = ' + MakeMaterial.make_material_blend_mode_mask(frag, m.blending, 'mask_view', 'mask_sample' + m.id, 'float(' + SlotLayer.slot_layer_get_opacity(m) + ')') + ';');
 					}
 				}
-				NodeShader.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 {
-				NodeShader.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) {
-				NodeShader.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));');
 			}
 
-			NodeShader.write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-			NodeShader.write(frag, 'n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);');
-			NodeShader.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)));');
 		}
 
-		NodeShader.write(frag, 'vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
-		NodeShader.write(frag, 'vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;');
-		NodeShader.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);');
 
-		ParserMaterial.finalize(con_mesh);
+		parser_material_finalize(con_mesh);
 		con_mesh.data.shader_from_source = true;
-		con_mesh.data.vertex_shader = NodeShader.get(vert);
-		con_mesh.data.fragment_shader = NodeShader.get(frag);
+		con_mesh.data.vertex_shader = node_shader_get(vert);
+		con_mesh.data.fragment_shader = node_shader_get(frag);
 		return con_mesh;
 	}
 
-	static get_max_textures = (): i32 => {
+	static make_mesh_get_max_textures = (): i32 => {
 		///if krom_direct3d11
 		return 128 - 66;
 		///else

+ 79 - 79
armorpaint/Sources/MakeMeshPreview.ts

@@ -1,11 +1,11 @@
 
 class MakeMeshPreview {
 
-	static opacity_discard_decal: f32 = 0.05;
+	static make_mesh_preview_opacity_discard_decal: f32 = 0.05;
 
-	static run = (data: material_t, matcon: material_context_t): NodeShaderContextRaw => {
+	static make_mesh_preview_run = (data: material_t, matcon: material_context_t): NodeShaderContextRaw => {
 		let context_id: string = "mesh";
-		let con_mesh: NodeShaderContextRaw = NodeShaderContext.create(data, {
+		let con_mesh: NodeShaderContextRaw = node_shader_context_create(data, {
 			name: context_id,
 			depth_write: true,
 			compare_mode: "less",
@@ -15,8 +15,8 @@ class MakeMeshPreview {
 			depth_attachment: "DEPTH32"
 		});
 
-		let vert: NodeShaderRaw = NodeShaderContext.make_vert(con_mesh);
-		let frag: NodeShaderRaw = NodeShaderContext.make_frag(con_mesh);
+		let vert: NodeShaderRaw = node_shader_context_make_vert(con_mesh);
+		let frag: NodeShaderRaw = node_shader_context_make_frag(con_mesh);
 		frag.ins = vert.outs;
 		let pos: string = "pos";
 
@@ -24,92 +24,92 @@ class MakeMeshPreview {
 		let skin: bool = mesh_data_get_vertex_array(context_raw.paint_object.data, "bone") != null;
 		if (skin) {
 			pos = "spos";
-			NodeShaderContext.add_elem(con_mesh, "bone", 'short4norm');
-			NodeShaderContext.add_elem(con_mesh, "weight", 'short4norm');
-			NodeShader.add_function(vert, str_get_skinning_dual_quat);
-			NodeShader.add_uniform(vert, 'vec4 skinBones[128 * 2]', '_skin_bones');
-			NodeShader.add_uniform(vert, 'float posUnpack', '_pos_unpack');
-			NodeShader.write_attrib(vert, 'vec4 skinA;');
-			NodeShader.write_attrib(vert, 'vec4 skinB;');
-			NodeShader.write_attrib(vert, 'getSkinningDualQuat(ivec4(bone * 32767), weight, skinA, skinB);');
-			NodeShader.write_attrib(vert, 'vec3 spos = pos.xyz;');
-			NodeShader.write_attrib(vert, 'spos.xyz *= posUnpack;');
-			NodeShader.write_attrib(vert, 'spos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, spos.xyz) + skinA.w * spos.xyz);');
-			NodeShader.write_attrib(vert, 'spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz));');
-			NodeShader.write_attrib(vert, 'spos.xyz /= posUnpack;');
+			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;');
 		}
 		///end
 
-		NodeShader.add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
-		NodeShader.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) + "";
-		NodeShader.add_out(vert, 'vec2 texCoord');
-		NodeShader.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;
-		ParserMaterial.sample_keep_aspect = decal;
-		ParserMaterial.sample_uv_scale = brush_scale;
-		ParserMaterial.parse_height = MakeMaterial.height_used;
-		ParserMaterial.parse_height_as_channel = true;
-		let sout: shader_out_t = ParserMaterial.parse(ui_nodes_get_canvas_material(), con_mesh, vert, frag, matcon);
-		ParserMaterial.parse_height = false;
-		ParserMaterial.parse_height_as_channel = false;
-		ParserMaterial.sample_keep_aspect = false;
+		parser_material_sample_keep_aspect = decal;
+		parser_material_sample_uv_scale = brush_scale;
+		parser_material_parse_height = MakeMaterial.make_material_height_used;
+		parser_material_parse_height_as_channel = true;
+		let sout: shader_out_t = parser_material_parse(ui_nodes_get_canvas_material(), con_mesh, vert, frag, matcon);
+		parser_material_parse_height = false;
+		parser_material_parse_height_as_channel = false;
+		parser_material_sample_keep_aspect = false;
 		let base: string = sout.out_basecol;
 		let rough: string = sout.out_roughness;
 		let met: string = sout.out_metallic;
 		let occ: string = sout.out_occlusion;
 		let opac: string = sout.out_opacity;
 		let height: string = sout.out_height;
-		let nortan: string = ParserMaterial.out_normaltan;
-		NodeShader.write(frag, `vec3 basecol = pow(${base}, vec3(2.2, 2.2, 2.2));`);
-		NodeShader.write(frag, `float roughness = ${rough};`);
-		NodeShader.write(frag, `float metallic = ${met};`);
-		NodeShader.write(frag, `float occlusion = ${occ};`);
-		NodeShader.write(frag, `float opacity = ${opac};`);
-		NodeShader.write(frag, `vec3 nortan = ${nortan};`);
-		NodeShader.write(frag, `float height = ${height};`);
-
-		// ParserMaterial.parse_height_as_channel = false;
-		// NodeShader.write(vert, `float vheight = ${height};`);
-		// NodeShader.add_out(vert, 'float height');
-		// NodeShader.write(vert, 'height = vheight;');
+		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};`);
+
+		// parse_height_as_channel = false;
+		// write(vert, `float vheight = ${height};`);
+		// add_out(vert, 'float height');
+		// write(vert, 'height = vheight;');
 		// let displaceStrength: f32 = 0.1;
 		// if (MakeMaterial.heightUsed && displaceStrength > 0.0) {
-		// 	NodeShader.write(vert, `vec3 pos2 = ${pos}.xyz + vec3(nor.xy, pos.w) * vec3(${height}, ${height}, ${height}) * vec3(${displaceStrength}, ${displaceStrength}, ${displaceStrength});`);
-		// 	NodeShader.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) {
-				NodeShader.add_uniform(frag, 'sampler2D textexttool', '_textexttool');
-				NodeShader.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 = MakeMeshPreview.opacity_discard_decal;
-			NodeShader.write(frag, `if (opacity < ${opac}) discard;`);
+			let opac: f32 = MakeMeshPreview.make_mesh_preview_opacity_discard_decal;
+			node_shader_write(frag, `if (opacity < ${opac}) discard;`);
 		}
 
-		NodeShader.add_out(frag, 'vec4 fragColor[3]');
+		node_shader_add_out(frag, 'vec4 fragColor[3]');
 		frag.n = true;
 
-		NodeShader.add_function(frag, str_pack_float_int16);
-		NodeShader.add_function(frag, str_cotangent_frame);
-		NodeShader.add_function(frag, str_octahedron_wrap);
+		node_shader_add_function(frag, str_pack_float_int16);
+		node_shader_add_function(frag, str_cotangent_frame);
+		node_shader_add_function(frag, str_octahedron_wrap);
 
-		if (MakeMaterial.height_used) {
-			NodeShader.write(frag, 'if (height > 0.0) {');
-			NodeShader.write(frag, 'float height_dx = dFdx(height * 2.0);');
-			NodeShader.write(frag, 'float height_dy = dFdy(height * 2.0);');
-			// NodeShader.write(frag, 'float height_dx = height0 - height1;');
-			// NodeShader.write(frag, 'float height_dy = height2 - height3;');
+		if (MakeMaterial.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;');
 			// Whiteout blend
-			NodeShader.write(frag, 'vec3 n1 = nortan * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-			NodeShader.write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-			NodeShader.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);');
-			NodeShader.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
@@ -119,40 +119,40 @@ class MakeMeshPreview {
 		else {
 			frag.vvec = true;
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
 			///else
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
 			///end
-			NodeShader.write(frag, 'n = nortan * 2.0 - 1.0;');
-			NodeShader.write(frag, 'n.y = -n.y;');
-			NodeShader.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));');
 		}
 
-		NodeShader.write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-		NodeShader.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) {
-			NodeShader.write(frag, 'fragColor[0] = vec4(n.x, n.y, roughness, packFloatInt16(metallic, uint(0)));'); // metallic/matid
-			NodeShader.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 {
-			NodeShader.write(frag, 'fragColor[0] = vec4(n.x, n.y, mix(1.0, roughness, opacity), packFloatInt16(mix(1.0, metallic, opacity), uint(0)));'); // metallic/matid
-			NodeShader.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);');
 		}
-		NodeShader.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
 
-		ParserMaterial.finalize(con_mesh);
+		parser_material_finalize(con_mesh);
 
 		///if arm_skin
 		if (skin) {
-			NodeShader.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
 
 		con_mesh.data.shader_from_source = true;
-		con_mesh.data.vertex_shader = NodeShader.get(vert);
-		con_mesh.data.fragment_shader = NodeShader.get(frag);
+		con_mesh.data.vertex_shader = node_shader_get(vert);
+		con_mesh.data.fragment_shader = node_shader_get(frag);
 
 		return con_mesh;
 	}

+ 33 - 33
armorpaint/Sources/MakeNodePreview.ts

@@ -1,9 +1,9 @@
 
 class MakeNodePreview {
 
-	static run = (data: material_t, matcon: material_context_t, node: zui_node_t, group: zui_node_canvas_t, parents: zui_node_t[]): NodeShaderContextRaw => {
+	static make_node_preview_run = (data: material_t, matcon: material_context_t, node: zui_node_t, group: zui_node_canvas_t, parents: zui_node_t[]): NodeShaderContextRaw => {
 		let context_id: string = "mesh";
-		let con_mesh: NodeShaderContextRaw = NodeShaderContext.create(data, {
+		let con_mesh: NodeShaderContextRaw = node_shader_context_create(data, {
 			name: context_id,
 			depth_write: false,
 			compare_mode: "always",
@@ -13,58 +13,58 @@ class MakeNodePreview {
 		});
 
 		con_mesh.allow_vcols = true;
-		let vert: NodeShaderRaw = NodeShaderContext.make_vert(con_mesh);
-		let frag: NodeShaderRaw = NodeShaderContext.make_frag(con_mesh);
+		let vert: NodeShaderRaw = node_shader_context_make_vert(con_mesh);
+		let frag: NodeShaderRaw = node_shader_context_make_frag(con_mesh);
 		frag.ins = vert.outs;
 
-		NodeShader.write_attrib(vert, 'gl_Position = vec4(pos.xy * 3.0, 0.0, 1.0);'); // Pos unpack
-		NodeShader.write_attrib(vert, 'const vec2 madd = vec2(0.5, 0.5);');
-		NodeShader.add_out(vert, 'vec2 texCoord');
-		NodeShader.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)
-		NodeShader.write_attrib(vert, 'texCoord.y = 1.0 - texCoord.y;');
+		node_shader_write_attrib(vert, 'texCoord.y = 1.0 - texCoord.y;');
 		///end
 
-		ParserMaterial.init();
-		ParserMaterial.canvases = [context_raw.material.canvas];
-		ParserMaterial.nodes = context_raw.material.canvas.nodes;
-		ParserMaterial.links = context_raw.material.canvas.links;
+		parser_material_init();
+		parser_material_canvases = [context_raw.material.canvas];
+		parser_material_nodes = context_raw.material.canvas.nodes;
+		parser_material_links = context_raw.material.canvas.links;
 		if (group != null) {
-			ParserMaterial.push_group(group);
-			ParserMaterial.parents = parents;
+			parser_material_push_group(group);
+			parser_material_parents = parents;
 		}
-		let links: zui_node_link_t[] = ParserMaterial.links;
+		let links: zui_node_link_t[] = parser_material_links;
 		let link: zui_node_link_t = { id: zui_get_link_id(links), from_id: node.id, from_socket: context_raw.node_preview_socket, to_id: -1, to_socket: -1 };
 		links.push(link);
 
-		ParserMaterial.con = con_mesh;
-		ParserMaterial.vert = vert;
-		ParserMaterial.frag = frag;
-		ParserMaterial.curshader = frag;
-		ParserMaterial.matcon = matcon;
+		parser_material_con = con_mesh;
+		parser_material_vert = vert;
+		parser_material_frag = frag;
+		parser_material_curshader = frag;
+		parser_material_matcon = matcon;
 
-		ParserMaterial.transform_color_space = false;
-		let res: string = ParserMaterial.write_result(link);
-		ParserMaterial.transform_color_space = true;
+		parser_material_transform_color_space = false;
+		let res: string = parser_material_write_result(link);
+		parser_material_transform_color_space = true;
 		let st: string = node.outputs[link.from_socket].type;
 		if (st != "RGB" && st != "RGBA" && st != "VECTOR") {
-			res = ParserMaterial.to_vec3(res);
+			res = parser_material_to_vec3(res);
 		}
 		array_remove(links, link);
 
-		NodeShader.add_out(frag, 'vec4 fragColor');
-		NodeShader.write(frag, `vec3 basecol = ${res};`);
-		NodeShader.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;
-		// NodeShader.add_out(vert, 'vec4 ndc');
-		// NodeShader.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);');
 
-		ParserMaterial.finalize(con_mesh);
+		parser_material_finalize(con_mesh);
 
 		con_mesh.data.shader_from_source = true;
-		con_mesh.data.vertex_shader = NodeShader.get(vert);
-		con_mesh.data.fragment_shader = NodeShader.get(frag);
+		con_mesh.data.vertex_shader = node_shader_get(vert);
+		con_mesh.data.fragment_shader = node_shader_get(frag);
 
 		return con_mesh;
 	}

+ 184 - 184
armorpaint/Sources/MakePaint.ts

@@ -3,7 +3,7 @@
 
 class MakePaint {
 
-	static get is_raytraced_bake(): bool {
+	static get make_paint_is_raytraced_bake(): bool {
 		///if (krom_direct3d12 || krom_vulkan || krom_metal)
 		return context_raw.bake_type == bake_type_t.INIT;
 		///else
@@ -11,10 +11,10 @@ class MakePaint {
 		///end
 	}
 
-	static run = (data: material_t, matcon: material_context_t): NodeShaderContextRaw => {
+	static make_paint_run = (data: material_t, matcon: material_context_t): NodeShaderContextRaw => {
 		let context_id: string = "paint";
 
-		let con_paint: NodeShaderContextRaw = NodeShaderContext.create(data, {
+		let con_paint: NodeShaderContextRaw = node_shader_context_create(data, {
 			name: context_id,
 			depth_write: false,
 			compare_mode: "always", // TODO: align texcoords winding order
@@ -25,7 +25,7 @@ class MakePaint {
 				context_raw.tool == workspace_tool_t.COLORID ? ["RGBA32"] :
 				(context_raw.tool == workspace_tool_t.PICKER && context_raw.pick_pos_nor_tex) ? ["RGBA128", "RGBA128"] :
 				(context_raw.tool == workspace_tool_t.PICKER || context_raw.tool == workspace_tool_t.MATERIAL) ? ["RGBA32", "RGBA32", "RGBA32", "RGBA32"] :
-				(context_raw.tool == workspace_tool_t.BAKE && MakePaint.is_raytraced_bake) ? ["RGBA64", "RGBA64"] :
+				(context_raw.tool == workspace_tool_t.BAKE && MakePaint.make_paint_is_raytraced_bake) ? ["RGBA64", "RGBA64"] :
 					["RGBA32", "RGBA32", "RGBA32", "R8"]
 		});
 
@@ -35,30 +35,30 @@ class MakePaint {
 		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;
 
-		let vert: NodeShaderRaw = NodeShaderContext.make_vert(con_paint);
-		let frag: NodeShaderRaw = NodeShaderContext.make_frag(con_paint);
+		let vert: NodeShaderRaw = node_shader_context_make_vert(con_paint);
+		let frag: NodeShaderRaw = node_shader_context_make_frag(con_paint);
 		frag.ins = vert.outs;
 
 		///if (krom_direct3d12 || krom_vulkan || krom_metal)
 		if (context_raw.tool == workspace_tool_t.BAKE && context_raw.bake_type == bake_type_t.INIT) {
 			// Init raytraced bake
-			MakeBake.position_normal(vert, frag);
+			MakeBake.make_bake_position_normal(vert, frag);
 			con_paint.data.shader_from_source = true;
-			con_paint.data.vertex_shader = NodeShader.get(vert);
-			con_paint.data.fragment_shader = NodeShader.get(frag);
+			con_paint.data.vertex_shader = node_shader_get(vert);
+			con_paint.data.fragment_shader = node_shader_get(frag);
 			return con_paint;
 		}
 		///end
 
 		if (context_raw.tool == workspace_tool_t.BAKE) {
-			MakeBake.set_color_writes(con_paint);
+			MakeBake.make_bake_set_color_writes(con_paint);
 		}
 
 		if (context_raw.tool == workspace_tool_t.COLORID || context_raw.tool == workspace_tool_t.PICKER || context_raw.tool == workspace_tool_t.MATERIAL) {
-			MakeColorIdPicker.run(vert, frag);
+			MakeColorIdPicker.make_colorid_picker_run(vert, frag);
 			con_paint.data.shader_from_source = true;
-			con_paint.data.vertex_shader = NodeShader.get(vert);
-			con_paint.data.fragment_shader = NodeShader.get(frag);
+			con_paint.data.vertex_shader = node_shader_get(vert);
+			con_paint.data.fragment_shader = node_shader_get(frag);
 			return con_paint;
 		}
 
@@ -67,45 +67,45 @@ class MakePaint {
 		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)
-		NodeShader.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
-		NodeShader.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
 
-		NodeShader.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) {
-			NodeShader.add_uniform(vert, 'mat4 WVP', '_decalLayerMatrix');
+			node_shader_add_uniform(vert, 'mat4 WVP', '_decalLayerMatrix');
 		}
 		else {
-			NodeShader.add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
+			node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
 		}
 
-		NodeShader.add_out(vert, 'vec4 ndc');
-		NodeShader.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);');
 
-		NodeShader.write_attrib(frag, 'vec3 sp = vec3((ndc.xyz / ndc.w) * 0.5 + 0.5);');
-		NodeShader.write_attrib(frag, 'sp.y = 1.0 - sp.y;');
-		NodeShader.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;
 
-		NodeShader.add_uniform(frag, 'vec4 inp', '_inputBrush');
-		NodeShader.add_uniform(frag, 'vec4 inplast', '_inputBrushLast');
-		NodeShader.add_uniform(frag, 'float aspectRatio', '_aspect_ratio_window');
-		NodeShader.write(frag, 'vec2 bsp = sp.xy * 2.0 - 1.0;');
-		NodeShader.write(frag, 'bsp.x *= aspectRatio;');
-		NodeShader.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;');
 
-		NodeShader.add_uniform(frag, 'sampler2D gbufferD');
+		node_shader_add_uniform(frag, 'sampler2D gbufferD');
 
-		NodeShader.add_out(frag, 'vec4 fragColor[4]');
+		node_shader_add_out(frag, 'vec4 fragColor[4]');
 
-		NodeShader.add_uniform(frag, 'float brushRadius', '_brushRadius');
-		NodeShader.add_uniform(frag, 'float brushOpacity', '_brushOpacity');
-		NodeShader.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 ||
@@ -121,140 +121,140 @@ class MakePaint {
 			// TODO: sp.z needs to take height channel into account
 			let particle: bool = context_raw.tool == workspace_tool_t.PARTICLE;
 			if (config_raw.brush_3d && !decal && !particle) {
-				if (MakeMaterial.height_used || context_raw.sym_x || context_raw.sym_y || context_raw.sym_z) depth_reject = false;
+				if (MakeMaterial.make_material_height_used || context_raw.sym_x || context_raw.sym_y || context_raw.sym_z) depth_reject = false;
 			}
 
 			if (depth_reject) {
 				///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-				NodeShader.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
-				NodeShader.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
 			}
 
-			MakeBrush.run(vert, frag);
+			MakeBrush.make_brush_run(vert, frag);
 		}
 		else { // Fill, Bake
-			NodeShader.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) {
-				NodeShader.add_function(frag, str_octahedron_wrap);
-				NodeShader.add_uniform(frag, 'sampler2D gbuffer0');
-				NodeShader.write(frag, 'vec2 g0 = textureLod(gbuffer0, inp.xy, 0.0).rg;');
-				NodeShader.write(frag, 'vec3 wn;');
-				NodeShader.write(frag, 'wn.z = 1.0 - abs(g0.x) - abs(g0.y);');
-				NodeShader.write(frag, 'wn.xy = wn.z >= 0.0 ? g0.xy : octahedronWrap(g0.xy);');
-				NodeShader.write(frag, 'wn = normalize(wn);');
+				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);');
 				frag.n = true;
 				let angle: f32 = context_raw.brush_angle_reject_dot;
-				NodeShader.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)
-				NodeShader.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
-				NodeShader.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) {
-			NodeShader.add_out(vert, 'vec2 texCoordPick');
-			NodeShader.write(vert, 'texCoordPick = tex;');
+			node_shader_add_out(vert, 'vec2 texCoordPick');
+			node_shader_write(vert, 'texCoordPick = tex;');
 			if (context_raw.colorid_picked) {
-				MakeDiscard.color_id(vert, frag);
+				MakeDiscard.make_discard_color_id(vert, frag);
 			}
 			if (face_fill) {
-				MakeDiscard.face(vert, frag);
+				MakeDiscard.make_discard_face(vert, frag);
 			}
 			else if (uv_island_fill) {
-				MakeDiscard.uv_island(vert, frag);
+				MakeDiscard.make_discard_uv_island(vert, frag);
 			}
 		}
 
 		if (context_raw.picker_mask_handle.position == picker_mask_t.MATERIAL) {
-			MakeDiscard.material_id(vert, frag);
+			MakeDiscard.make_discard_material_id(vert, frag);
 		}
 
-		MakeTexcoord.run(vert, frag);
+		MakeTexcoord.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) {
-			NodeShader.add_uniform(frag, 'sampler2D gbuffer2');
-			NodeShader.add_uniform(frag, 'vec2 gbufferSize', '_gbufferSize');
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-			NodeShader.add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
-			NodeShader.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) {
-				MakeClone.run(vert, frag);
+				MakeClone.make_clone_run(vert, frag);
 			}
 			else { // Blur, Smudge
-				MakeBlur.run(vert, frag);
+				MakeBlur.make_blur_run(vert, frag);
 			}
 		}
 		else {
-			ParserMaterial.parse_emission = context_raw.material.paint_emis;
-			ParserMaterial.parse_subsurface = context_raw.material.paint_subs;
-			ParserMaterial.parse_height = context_raw.material.paint_height;
-			ParserMaterial.parse_height_as_channel = true;
+			parser_material_parse_emission = context_raw.material.paint_emis;
+			parser_material_parse_subsurface = context_raw.material.paint_subs;
+			parser_material_parse_height = context_raw.material.paint_height;
+			parser_material_parse_height_as_channel = true;
 			let uv_type: uv_type_t = context_raw.layer.fill_layer != null ? context_raw.layer.uv_type : context_raw.brush_paint;
-			ParserMaterial.triplanar = uv_type == uv_type_t.TRIPLANAR && !decal;
-			ParserMaterial.sample_keep_aspect = decal;
-			ParserMaterial.sample_uv_scale = 'brushScale';
-			let sout: shader_out_t = ParserMaterial.parse(ui_nodes_get_canvas_material(), con_paint, vert, frag, matcon);
-			ParserMaterial.parse_emission = false;
-			ParserMaterial.parse_subsurface = false;
-			ParserMaterial.parse_height_as_channel = false;
-			ParserMaterial.parse_height = false;
+			parser_material_triplanar = uv_type == uv_type_t.TRIPLANAR && !decal;
+			parser_material_sample_keep_aspect = decal;
+			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;
+			parser_material_parse_height_as_channel = false;
+			parser_material_parse_height = false;
 			let base: string = sout.out_basecol;
 			let rough: string = sout.out_roughness;
 			let met: string = sout.out_metallic;
 			let occ: string = sout.out_occlusion;
-			let nortan: string = ParserMaterial.out_normaltan;
+			let nortan: string = parser_material_out_normaltan;
 			let height: string = sout.out_height;
 			let opac: string = sout.out_opacity;
 			let emis: string = sout.out_emission;
 			let subs: string = sout.out_subsurface;
-			NodeShader.write(frag, `vec3 basecol = ${base};`);
-			NodeShader.write(frag, `float roughness = ${rough};`);
-			NodeShader.write(frag, `float metallic = ${met};`);
-			NodeShader.write(frag, `float occlusion = ${occ};`);
-			NodeShader.write(frag, `vec3 nortan = ${nortan};`);
-			NodeShader.write(frag, `float height = ${height};`);
-			NodeShader.write(frag, `float mat_opacity = ${opac};`);
-			NodeShader.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) {
-				NodeShader.write(frag, 'opacity *= brushOpacity;');
+				node_shader_write(frag, 'opacity *= brushOpacity;');
 			}
 			if (context_raw.material.paint_emis) {
-				NodeShader.write(frag, `float emis = ${emis};`);
+				node_shader_write(frag, `float emis = ${emis};`);
 			}
 			if (context_raw.material.paint_subs) {
-				NodeShader.write(frag, `float subs = ${subs};`);
+				node_shader_write(frag, `float subs = ${subs};`);
 			}
-			if (parseFloat(height) != 0.0 && !MakeMaterial.height_used) {
-				MakeMaterial.height_used = true;
+			if (parseFloat(height) != 0.0 && !MakeMaterial.make_material_height_used) {
+				MakeMaterial.make_material_height_used = true;
 				// Height used for the first time, also rebuild vertex shader
-				return MakePaint.run(data, matcon);
+				return MakePaint.make_paint_run(data, matcon);
 			}
-			if (parseFloat(emis) != 0.0) MakeMaterial.emis_used = true;
-			if (parseFloat(subs) != 0.0) MakeMaterial.subs_used = true;
+			if (parseFloat(emis) != 0.0) MakeMaterial.make_material_emis_used = true;
+			if (parseFloat(subs) != 0.0) MakeMaterial.make_material_subs_used = true;
 		}
 
 		if (context_raw.brush_mask_image != null && context_raw.tool == workspace_tool_t.DECAL) {
-			NodeShader.add_uniform(frag, 'sampler2D texbrushmask', '_texbrushmask');
-			NodeShader.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) {
-				NodeShader.write(frag, 'opacity *= mask_sample.a;');
+				node_shader_write(frag, 'opacity *= mask_sample.a;');
 			}
 			else {
-				NodeShader.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) {
-			NodeShader.add_uniform(frag, 'sampler2D textexttool', '_textexttool');
-			NodeShader.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 && (
@@ -266,161 +266,161 @@ class MakePaint {
 			context_raw.tool == workspace_tool_t.SMUDGE   ||
 			context_raw.tool == workspace_tool_t.PARTICLE ||
 			decal)) {
-			NodeShader.add_uniform(frag, 'sampler2D texbrushstencil', '_texbrushstencil');
-			NodeShader.add_uniform(frag, 'vec4 stencilTransform', '_stencilTransform');
-			NodeShader.write(frag, 'vec2 stencil_uv = vec2((sp.xy - stencilTransform.xy) / stencilTransform.z * vec2(aspectRatio, 1.0));');
-			NodeShader.write(frag, 'vec2 stencil_size = vec2(textureSize(texbrushstencil, 0));');
-			NodeShader.write(frag, 'float stencil_ratio = stencil_size.y / stencil_size.x;');
-			NodeShader.write(frag, 'stencil_uv -= vec2(0.5 / stencil_ratio, 0.5);');
-			NodeShader.write(frag, `stencil_uv = vec2(stencil_uv.x * cos(stencilTransform.w) - stencil_uv.y * sin(stencilTransform.w),
+			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));`);
-			NodeShader.write(frag, 'stencil_uv += vec2(0.5 / stencil_ratio, 0.5);');
-			NodeShader.write(frag, 'stencil_uv.x *= stencil_ratio;');
-			NodeShader.write(frag, 'if (stencil_uv.x < 0 || stencil_uv.x > 1 || stencil_uv.y < 0 || stencil_uv.y > 1) discard;');
-			NodeShader.write(frag, 'vec4 texbrushstencil_sample = textureLod(texbrushstencil, stencil_uv, 0.0);');
+			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) {
-				NodeShader.write(frag, 'opacity *= texbrushstencil_sample.a;');
+				node_shader_write(frag, 'opacity *= texbrushstencil_sample.a;');
 			}
 			else {
-				NodeShader.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)) {
-			NodeShader.add_uniform(frag, 'sampler2D texbrushmask', '_texbrushmask');
-			NodeShader.write(frag, 'vec2 binp_mask = inp.xy * 2.0 - 1.0;');
-			NodeShader.write(frag, 'binp_mask.x *= aspectRatio;');
-			NodeShader.write(frag, 'binp_mask = binp_mask * 0.5 + 0.5;');
-			NodeShader.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) {
-				NodeShader.add_uniform(frag, 'vec3 brushDirection', '_brushDirection');
-				NodeShader.write(frag, 'if (brushDirection.z == 0.0) discard;');
-				NodeShader.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) {
-				NodeShader.add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-				NodeShader.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);');
 			}
-			NodeShader.write(frag, 'pa_mask /= brushRadius;');
+			node_shader_write(frag, 'pa_mask /= brushRadius;');
 			if (config_raw.brush_3d) {
-				NodeShader.add_uniform(frag, 'vec3 eye', '_camera_pos');
-				NodeShader.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;');
 			}
-			NodeShader.write(frag, 'pa_mask = pa_mask.xy * 0.5 + 0.5;');
-			NodeShader.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) {
-				NodeShader.write(frag, 'opacity *= mask_sample.a;');
+				node_shader_write(frag, 'opacity *= mask_sample.a;');
 			}
 			else {
-				NodeShader.write(frag, 'opacity *= mask_sample.r * mask_sample.a;');
+				node_shader_write(frag, 'opacity *= mask_sample.r * mask_sample.a;');
 			}
 		}
 
-		NodeShader.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
 			MakeParticle.mask(vert, frag);
 		}
 		else { // Brush cursor mask
-			NodeShader.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;
-		NodeShader.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)
-		NodeShader.write(frag, 'sample_tc.y = 1.0 - sample_tc.y;');
+		node_shader_write(frag, 'sample_tc.y = 1.0 - sample_tc.y;');
 		///end
-		NodeShader.add_uniform(frag, 'sampler2D paintmask');
-		NodeShader.write(frag, 'float sample_mask = textureLod(paintmask, sample_tc, 0.0).r;');
-		NodeShader.write(frag, 'str = max(str, sample_mask);');
-		// NodeShader.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);');
 
-		NodeShader.add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-		NodeShader.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 = ParserMaterial.vec1(matid * 3.0);
-		NodeShader.write(frag, `float matid = ${matid_string};`);
+		let matid_string: string = parser_material_vec1(matid * 3.0);
+		node_shader_write(frag, `float matid = ${matid_string};`);
 
 		// matid % 3 == 0 - normal, 1 - emission, 2 - subsurface
 		if (context_raw.material.paint_emis) {
-			NodeShader.write(frag, 'if (emis > 0.0) {');
-			NodeShader.write(frag, '	matid += 1.0 / 255.0;');
-			NodeShader.write(frag, '	if (str == 0.0) discard;');
-			NodeShader.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) {
-			NodeShader.write(frag, 'if (subs > 0.0) {');
-			NodeShader.write(frag, '    matid += 2.0 / 255.0;');
-			NodeShader.write(frag, '	if (str == 0.0) discard;');
-			NodeShader.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 = SlotLayer.is_mask(context_raw.layer);
+		let is_mask: bool = SlotLayer.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) {
-				NodeShader.write(frag, 'fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);');
-				NodeShader.write(frag, 'nortan = vec3(0.5, 0.5, 1.0);');
-				NodeShader.write(frag, 'occlusion = 1.0;');
-				NodeShader.write(frag, 'roughness = 0.0;');
-				NodeShader.write(frag, 'metallic = 0.0;');
-				NodeShader.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) {
-				NodeShader.write(frag, 'fragColor[0] = vec4(' + MakeMaterial.blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'str') + ', max(str, sample_undo.a));');
+				node_shader_write(frag, 'fragColor[0] = vec4(' + MakeMaterial.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) {
-					NodeShader.write(frag, 'fragColor[0] = vec4(' + MakeMaterial.blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'opacity') + ', mat_opacity);');
+					node_shader_write(frag, 'fragColor[0] = vec4(' + MakeMaterial.make_material_blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'opacity') + ', mat_opacity);');
 				}
 				else {
-					NodeShader.write(frag, 'fragColor[0] = vec4(' + MakeMaterial.blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'opacity') + ', max(str, sample_undo.a));');
+					node_shader_write(frag, 'fragColor[0] = vec4(' + MakeMaterial.make_material_blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'opacity') + ', max(str, sample_undo.a));');
 				}
 			}
-			NodeShader.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 && MakeMaterial.height_used) {
+			if (context_raw.material.paint_height && MakeMaterial.make_material_height_used) {
 				height = "height";
 			}
 
 			if (decal) {
-				NodeShader.add_uniform(frag, 'sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
-				NodeShader.write(frag, 'vec4 sample_pack_undo = textureLod(texpaint_pack_undo, sample_tc, 0.0);');
-				NodeShader.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 {
-				NodeShader.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) {
-				NodeShader.write(frag, 'fragColor[0] = vec4(mix(sample_undo.rgb, vec3(0.0, 0.0, 0.0), str), sample_undo.a - str);');
-				NodeShader.write(frag, 'fragColor[1] = vec4(0.5, 0.5, 1.0, 0.0);');
-				NodeShader.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 {
-				NodeShader.add_uniform(frag, 'sampler2D texpaint_nor_undo', '_texpaint_nor_undo');
-				NodeShader.add_uniform(frag, 'sampler2D texpaint_pack_undo', '_texpaint_pack_undo');
-				NodeShader.write(frag, 'vec4 sample_nor_undo = textureLod(texpaint_nor_undo, sample_tc, 0.0);');
-				NodeShader.write(frag, 'vec4 sample_pack_undo = textureLod(texpaint_pack_undo, sample_tc, 0.0);');
-				NodeShader.write(frag, 'fragColor[0] = vec4(' + MakeMaterial.blend_mode(frag, context_raw.brush_blending, 'sample_undo.rgb', 'basecol', 'str') + ', max(str, sample_undo.a));');
-				NodeShader.write(frag, 'fragColor[1] = vec4(mix(sample_nor_undo.rgb, nortan, str), matid);');
-				if (context_raw.material.paint_height && MakeMaterial.height_used) {
-					NodeShader.write(frag, 'fragColor[2] = mix(sample_pack_undo, vec4(occlusion, roughness, metallic, height), str);');
+				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(' + MakeMaterial.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 && MakeMaterial.make_material_height_used) {
+					node_shader_write(frag, 'fragColor[2] = mix(sample_pack_undo, vec4(occlusion, roughness, metallic, height), str);');
 				}
 				else {
-					NodeShader.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);');
 				}
 			}
 		}
-		NodeShader.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;
@@ -451,7 +451,7 @@ class MakePaint {
 		// Base color only as mask
 		if (is_mask) {
 			// TODO: Apply opacity into base
-			// NodeShader.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;
@@ -466,15 +466,15 @@ class MakePaint {
 		}
 
 		if (context_raw.tool == workspace_tool_t.BAKE) {
-			MakeBake.run(con_paint, vert, frag);
+			MakeBake.make_bake_run(con_paint, vert, frag);
 		}
 
-		ParserMaterial.finalize(con_paint);
-		ParserMaterial.triplanar = false;
-		ParserMaterial.sample_keep_aspect = false;
+		parser_material_finalize(con_paint);
+		parser_material_triplanar = false;
+		parser_material_sample_keep_aspect = false;
 		con_paint.data.shader_from_source = true;
-		con_paint.data.vertex_shader = NodeShader.get(vert);
-		con_paint.data.fragment_shader = NodeShader.get(frag);
+		con_paint.data.vertex_shader = node_shader_get(vert);
+		con_paint.data.fragment_shader = node_shader_get(frag);
 
 		return con_paint;
 	}

+ 81 - 81
armorpaint/Sources/MakeParticle.ts

@@ -1,9 +1,9 @@
 
 class MakeParticle {
 
-	static run = (data: material_t): NodeShaderContextRaw => {
+	static make_particle_run = (data: material_t): NodeShaderContextRaw => {
 		let context_id: string = "mesh";
-		let con_part: NodeShaderContextRaw = NodeShaderContext.create(data, {
+		let con_part: NodeShaderContextRaw = node_shader_context_create(data, {
 			name: context_id,
 			depth_write: false,
 			compare_mode: "always",
@@ -12,75 +12,75 @@ class MakeParticle {
 			color_attachments: ["R8"]
 		});
 
-		let vert: NodeShaderRaw = NodeShaderContext.make_vert(con_part);
-		let frag: NodeShaderRaw = NodeShaderContext.make_frag(con_part);
+		let vert: NodeShaderRaw = node_shader_context_make_vert(con_part);
+		let frag: NodeShaderRaw = node_shader_context_make_frag(con_part);
 		frag.ins = vert.outs;
 
-		NodeShader.write_attrib(vert, 'vec4 spos = vec4(pos.xyz, 1.0);');
+		node_shader_write_attrib(vert, 'vec4 spos = vec4(pos.xyz, 1.0);');
 
-		NodeShader.add_uniform(vert, 'float brushRadius', '_brushRadius');
-		NodeShader.write_attrib(vert, 'vec3 emitFrom = vec3(fhash(gl_InstanceID), fhash(gl_InstanceID * 2), fhash(gl_InstanceID * 3));');
-		NodeShader.write_attrib(vert, 'emitFrom = emitFrom * brushRadius - brushRadius / 2.0;');
-		NodeShader.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);');
 
-		NodeShader.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";
-		NodeShader.add_function(vert, str_tex_hash);
-		NodeShader.add_out(vert, 'float p_age');
-		NodeShader.write(vert, 'p_age = pd[3][3] - float(gl_InstanceID) * pd[0][1];');
-		NodeShader.write(vert, 'p_age -= p_age * fhash(gl_InstanceID) * pd[2][3];');
-
-		NodeShader.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];');
-
-		NodeShader.add_out(vert, 'float p_lifetime');
-		NodeShader.write(vert, 'p_lifetime = pd[0][2];');
-		NodeShader.write(vert, 'if (p_age < 0.0 || p_age > p_lifetime) {');
-		// NodeShader.write(vert, 'SPIRV_Cross_Output stage_output;');
-		// NodeShader.write(vert, 'stage_output.svpos /= 0.0;');
-		// NodeShader.write(vert, 'return stage_output;');
-		NodeShader.write(vert, 'spos /= 0.0;');
-		NodeShader.write(vert, '}');
-
-		NodeShader.add_out(vert, 'vec3 p_velocity');
-		NodeShader.write(vert, 'p_velocity = vec3(pd[1][0], pd[1][1], pd[1][2]);');
-		NodeShader.write(vert, 'p_velocity.x += fhash(gl_InstanceID)                     * pd[1][3] - pd[1][3] / 2.0;');
-		NodeShader.write(vert, 'p_velocity.y += fhash(gl_InstanceID +     int(pd[0][3])) * pd[1][3] - pd[1][3] / 2.0;');
-		NodeShader.write(vert, 'p_velocity.z += fhash(gl_InstanceID + 2 * int(pd[0][3])) * pd[1][3] - pd[1][3] / 2.0;');
-		NodeShader.write(vert, 'p_velocity.x += (pd[2][0] * p_age) / 5.0;');
-		NodeShader.write(vert, 'p_velocity.y += (pd[2][1] * p_age) / 5.0;');
-		NodeShader.write(vert, 'p_velocity.z += (pd[2][2] * p_age) / 5.0;');
-
-		NodeShader.add_out(vert, 'vec3 p_location');
-		NodeShader.write(vert, 'p_location = p_velocity * p_age;');
-		NodeShader.write(vert, 'spos.xyz += p_location;');
-		NodeShader.write(vert, 'spos.xyz *= vec3(0.01, 0.01, 0.01);');
-
-		NodeShader.add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
-		NodeShader.write(vert, 'gl_Position = mul(spos, WVP);');
-
-		NodeShader.add_uniform(vert, 'vec4 inp', '_inputBrush');
-		NodeShader.write(vert, 'vec2 binp = vec2(inp.x, 1.0 - inp.y);');
-		NodeShader.write(vert, 'binp = binp * 2.0 - 1.0;');
-		NodeShader.write(vert, 'binp *= gl_Position.w;');
-		NodeShader.write(vert, 'gl_Position.xy += binp;');
-
-		NodeShader.add_out(vert, 'float p_fade');
-		NodeShader.write(vert, 'p_fade = sin(min((p_age / 8.0) * 3.141592, 3.141592));');
-
-		NodeShader.add_out(frag, 'float fragColor');
-		NodeShader.write(frag, 'fragColor = p_fade;');
-
-		// NodeShader.add_out(vert, 'vec4 wvpposition');
-		// NodeShader.write(vert, 'wvpposition = gl_Position;');
-		// NodeShader.write(frag, 'vec2 texCoord = wvpposition.xy / wvpposition.w;');
-		// NodeShader.add_uniform(frag, 'sampler2D gbufferD');
-		// NodeShader.write(frag, 'fragColor *= 1.0 - clamp(distance(textureLod(gbufferD, texCoord, 0.0).r, wvpposition.z), 0.0, 1.0);');
+		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);');
 
 		// Material.finalize(con_part);
 		con_part.data.shader_from_source = true;
-		con_part.data.vertex_shader = NodeShader.get(vert);
-		con_part.data.fragment_shader = NodeShader.get(frag);
+		con_part.data.vertex_shader = node_shader_get(vert);
+		con_part.data.fragment_shader = node_shader_get(frag);
 
 		return con_part;
 	}
@@ -88,31 +88,31 @@ class MakeParticle {
 	static mask = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
 		///if arm_physics
 		if (context_raw.particle_physics) {
-			NodeShader.add_out(vert, 'vec4 wpos');
-			NodeShader.add_uniform(vert, 'mat4 W', '_world_matrix');
-			NodeShader.write_attrib(vert, 'wpos = mul(vec4(pos.xyz, 1.0), W);');
-			NodeShader.add_uniform(frag, 'vec3 particleHit', '_particleHit');
-			NodeShader.add_uniform(frag, 'vec3 particleHitLast', '_particleHitLast');
-
-			NodeShader.write(frag, 'vec3 pa = wpos.xyz - particleHit;');
-			NodeShader.write(frag, 'vec3 ba = particleHitLast - particleHit;');
-			NodeShader.write(frag, 'float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);');
-			NodeShader.write(frag, 'dist = length(pa - ba * h) * 10.0;');
-			// NodeShader.write(frag, 'dist = distance(particleHit, wpos.xyz) * 10.0;');
-
-			NodeShader.write(frag, 'if (dist > 1.0) discard;');
-			NodeShader.write(frag, 'float str = clamp(pow(1.0 / dist * brushHardness * 0.2, 4.0), 0.0, 1.0) * opacity;');
-			NodeShader.write(frag, 'if (particleHit.x == 0.0 && particleHit.y == 0.0 && particleHit.z == 0.0) str = 0.0;');
-			NodeShader.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
 
-		NodeShader.add_uniform(frag, 'sampler2D texparticle', '_texparticle');
+		node_shader_add_uniform(frag, 'sampler2D texparticle', '_texparticle');
 		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		NodeShader.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
-		NodeShader.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
 	}
 }

+ 45 - 45
armorpaint/Sources/MakeTexcoord.ts

@@ -1,7 +1,7 @@
 
 class MakeTexcoord {
 
-	static run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
+	static make_texcoord_run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
 
 		let fill_layer: bool = context_raw.layer.fill_layer != null;
 		let uv_type: uv_type_t = fill_layer ? context_raw.layer.uv_type : context_raw.brush_paint;
@@ -10,89 +10,89 @@ class MakeTexcoord {
 		let uvAngle: f32 = fill_layer ? context_raw.layer.angle : angle;
 
 		if (uv_type == uv_type_t.PROJECT || decal) { // TexCoords - project
-			NodeShader.add_uniform(frag, 'float brushScale', '_brushScale');
-			NodeShader.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
-				NodeShader.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 (uvAngle != 0.0) {
-					NodeShader.add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-					NodeShader.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;
-				NodeShader.add_uniform(frag, 'vec3 decalLayerNor', '_decalLayerNor');
+				node_shader_add_uniform(frag, 'vec3 decalLayerNor', '_decalLayerNor');
 				let dot_angle: f32 = context_raw.brush_angle_reject_dot;
-				NodeShader.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;
-				NodeShader.add_uniform(frag, 'vec3 decalLayerLoc', '_decalLayerLoc');
-				NodeShader.add_uniform(frag, 'float decalLayerDim', '_decalLayerDim');
-				NodeShader.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) {
-				NodeShader.add_uniform(frag, 'vec4 decalMask', '_decalMask');
-				NodeShader.write_attrib(frag, 'uvsp -= decalMask.xy;');
-				NodeShader.write_attrib(frag, 'uvsp.x *= aspectRatio;');
-				NodeShader.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) {
-					NodeShader.add_uniform(frag, 'vec3 brushDirection', '_brushDirection');
-					NodeShader.write_attrib(frag, 'if (brushDirection.z == 0.0) discard;');
-					NodeShader.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 (uvAngle != 0.0) {
-					NodeShader.add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-					NodeShader.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);');
 				}
 
-				NodeShader.add_uniform(frag, 'float brushScaleX', '_brushScaleX');
-				NodeShader.write_attrib(frag, 'uvsp.x *= brushScaleX;');
+				node_shader_add_uniform(frag, 'float brushScaleX', '_brushScaleX');
+				node_shader_write_attrib(frag, 'uvsp.x *= brushScaleX;');
 
-				NodeShader.write_attrib(frag, 'uvsp += vec2(0.5, 0.5);');
+				node_shader_write_attrib(frag, 'uvsp += vec2(0.5, 0.5);');
 
-				NodeShader.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 {
-				NodeShader.write_attrib(frag, 'uvsp.x *= aspectRatio;');
+				node_shader_write_attrib(frag, 'uvsp.x *= aspectRatio;');
 
 				if (uvAngle != 0.0) {
-					NodeShader.add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-					NodeShader.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);');
 				}
 			}
 
-			NodeShader.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
-			NodeShader.add_uniform(vert, 'float brushScale', '_brushScale');
-			NodeShader.add_out(vert, 'vec2 texCoord');
-			NodeShader.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 (uvAngle > 0.0) {
-				NodeShader.add_uniform(vert, 'vec2 brushAngle', '_brushAngle');
-				NodeShader.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;
-			NodeShader.add_uniform(frag, 'float brushScale', '_brushScale');
-			NodeShader.write_attrib(frag, 'vec3 triWeight = wnormal * wnormal;'); // n * n
-			NodeShader.write_attrib(frag, 'float triMax = max(triWeight.x, max(triWeight.y, triWeight.z));');
-			NodeShader.write_attrib(frag, 'triWeight = max(triWeight - triMax * 0.75, 0.0);');
-			NodeShader.write_attrib(frag, 'vec3 texCoordBlend = triWeight * (1.0 / (triWeight.x + triWeight.y + triWeight.z));');
-			NodeShader.write_attrib(frag, 'vec2 texCoord = wposition.yz * brushScale * 0.5;');
-			NodeShader.write_attrib(frag, 'vec2 texCoord1 = wposition.xz * brushScale * 0.5;');
-			NodeShader.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 (uvAngle != 0.0) {
-				NodeShader.add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
-				NodeShader.write_attrib(frag, 'texCoord = vec2(texCoord.x * brushAngle.x - texCoord.y * brushAngle.y, texCoord.x * brushAngle.y + texCoord.y * brushAngle.x);');
-				NodeShader.write_attrib(frag, 'texCoord1 = vec2(texCoord1.x * brushAngle.x - texCoord1.y * brushAngle.y, texCoord1.x * brushAngle.y + texCoord1.y * brushAngle.x);');
-				NodeShader.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);');
 			}
 		}
 	}

+ 4 - 4
armorpaint/Sources/NodesBrush.ts

@@ -10,9 +10,9 @@
 
 class NodesBrush {
 
-	static categories = [_tr("Nodes")];
+	static nodes_brush_categories = [_tr("Nodes")];
 
-	static list: zui_node_t[][] = [
+	static nodes_brush_list: zui_node_t[][] = [
 		[ // Category 0
 			TEX_IMAGE.def,
 			InputNode.def,
@@ -26,8 +26,8 @@ class NodesBrush {
 		]
 	];
 
-	static create_node = (nodeType: string): zui_node_t => {
-		for (let c of NodesBrush.list) {
+	static nodes_brush_create_node = (nodeType: string): zui_node_t => {
+		for (let c of NodesBrush.nodes_brush_list) {
 			for (let n of c) {
 				if (n.type == nodeType) {
 					let canvas: zui_node_canvas_t = context_raw.brush.canvas;

+ 145 - 145
armorpaint/Sources/RenderPathPaint.ts

@@ -1,28 +1,28 @@
 
 class RenderPathPaint {
 
-	static live_layer: SlotLayerRaw = null;
-	static live_layer_drawn: i32 = 0;
-	static live_layer_locked: bool = false;
-	static dilated: bool = true;
-	static init_voxels: bool = true; // Bake AO
-	static push_undo_last: bool;
-	static painto: mesh_object_t = null;
-	static planeo: mesh_object_t = null;
-	static visibles: bool[] = null;
-	static merged_object_visible: bool = false;
-	static saved_fov: f32 = 0.0;
-	static baking: bool = false;
-	static _texpaint: render_target_t;
-	static _texpaint_nor: render_target_t;
-	static _texpaint_pack: render_target_t;
-	static _texpaint_undo: render_target_t;
-	static _texpaint_nor_undo: render_target_t;
-	static _texpaint_pack_undo: render_target_t;
-	static last_x: f32 = -1.0;
-	static last_y: f32 = -1.0;
-
-	static init = () => {
+	static render_path_paint_live_layer: SlotLayerRaw = null;
+	static render_path_paint_live_layer_drawn: i32 = 0;
+	static render_path_paint_live_layer_locked: bool = false;
+	static render_path_paint_dilated: bool = true;
+	static render_path_paint_init_voxels: bool = true; // Bake AO
+	static render_path_paint_push_undo_last: bool;
+	static render_path_paint_painto: mesh_object_t = null;
+	static render_path_paint_planeo: mesh_object_t = null;
+	static render_path_paint_visibles: bool[] = null;
+	static render_path_paint_merged_object_visible: bool = false;
+	static render_path_paint_saved_fov: f32 = 0.0;
+	static render_path_paint_baking: bool = false;
+	static _render_path_paint_texpaint: render_target_t;
+	static _render_path_paint_texpaint_nor: render_target_t;
+	static _render_path_paint_texpaint_pack: render_target_t;
+	static _render_path_paint_texpaint_undo: render_target_t;
+	static _render_path_paint_texpaint_nor_undo: render_target_t;
+	static _render_path_paint_texpaint_pack_undo: render_target_t;
+	static render_path_paint_last_x: f32 = -1.0;
+	static render_path_paint_last_y: f32 = -1.0;
+
+	static render_path_paint_init = () => {
 
 		{
 			let t: render_target_t = render_target_create();
@@ -104,7 +104,7 @@ class RenderPathPaint {
 		///end
 	}
 
-	static commands_paint = (dilation = true) => {
+	static render_path_paint_commands_paint = (dilation = true) => {
 		let tid: i32 = context_raw.layer.id;
 
 		if (context_raw.pdirty > 0) {
@@ -169,12 +169,12 @@ class RenderPathPaint {
 					render_path_bind_target("gbuffer2", "gbuffer2");
 					tid = context_raw.layer.id;
 					let use_live_layer: bool = context_raw.tool == workspace_tool_t.MATERIAL;
-					if (use_live_layer) RenderPathPaint.use_live_layer(true);
+					if (use_live_layer) RenderPathPaint.render_path_paint_use_live_layer(true);
 					render_path_bind_target("texpaint" + tid, "texpaint");
 					render_path_bind_target("texpaint_nor" + tid, "texpaint_nor");
 					render_path_bind_target("texpaint_pack" + tid, "texpaint_pack");
 					render_path_draw_meshes("paint");
-					if (use_live_layer) RenderPathPaint.use_live_layer(false);
+					if (use_live_layer) RenderPathPaint.render_path_paint_use_live_layer(false);
 					ui_header_handle.redraws = 2;
 					ui_base_hwnds[2].redraws = 2;
 
@@ -232,11 +232,11 @@ class RenderPathPaint {
 			else {
 				///if arm_voxels
 				if (context_raw.tool == workspace_tool_t.BAKE && context_raw.bake_type == bake_type_t.AO) {
-					if (RenderPathPaint.init_voxels) {
-						RenderPathPaint.init_voxels = false;
+					if (RenderPathPaint.render_path_paint_init_voxels) {
+						RenderPathPaint.render_path_paint_init_voxels = false;
 						let _rp_gi: bool = config_raw.rp_gi;
 						config_raw.rp_gi = true;
-						RenderPathBase.init_voxels();
+						render_path_base_init_voxels();
 						config_raw.rp_gi = _rp_gi;
 					}
 					render_path_clear_image("voxels", 0x00000000);
@@ -258,11 +258,11 @@ class RenderPathPaint {
 				render_path_set_target("texpaint_blend1");
 				render_path_bind_target("texpaint_blend0", "tex");
 				render_path_draw_shader("shader_datas/copy_pass/copyR8_pass");
-				let is_mask: bool = SlotLayer.is_mask(context_raw.layer);
+				let is_mask: bool = SlotLayer.slot_layer_is_mask(context_raw.layer);
 				if (is_mask) {
 					let ptid: i32 = context_raw.layer.parent.id;
-					if (SlotLayer.is_group(context_raw.layer.parent)) { // Group mask
-						for (let c of SlotLayer.get_children(context_raw.layer.parent)) {
+					if (SlotLayer.slot_layer_is_group(context_raw.layer.parent)) { // Group mask
+						for (let c of SlotLayer.slot_layer_get_children(context_raw.layer.parent)) {
 							ptid = c.id;
 							break;
 						}
@@ -318,7 +318,7 @@ class RenderPathPaint {
 				}
 
 				if (dilation && config_raw.dilate == dilate_type_t.INSTANT) {
-					RenderPathPaint.dilate(true, false);
+					RenderPathPaint.render_path_paint_dilate(true, false);
 				}
 			}
 			///end
@@ -364,19 +364,19 @@ class RenderPathPaint {
 		}
 	}
 
-	static use_live_layer = (use: bool) => {
+	static render_path_paint_use_live_layer = (use: bool) => {
 		let tid: i32 = context_raw.layer.id;
 		let hid: i32 = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 		if (use) {
-			RenderPathPaint._texpaint = render_path_render_targets.get("texpaint" + tid);
-			RenderPathPaint._texpaint_undo = render_path_render_targets.get("texpaint_undo" + hid);
-			RenderPathPaint._texpaint_nor_undo = render_path_render_targets.get("texpaint_nor_undo" + hid);
-			RenderPathPaint._texpaint_pack_undo = render_path_render_targets.get("texpaint_pack_undo" + hid);
-			RenderPathPaint._texpaint_nor = render_path_render_targets.get("texpaint_nor" + tid);
-			RenderPathPaint._texpaint_pack = render_path_render_targets.get("texpaint_pack" + tid);
+			RenderPathPaint._render_path_paint_texpaint = render_path_render_targets.get("texpaint" + tid);
+			RenderPathPaint._render_path_paint_texpaint_undo = render_path_render_targets.get("texpaint_undo" + hid);
+			RenderPathPaint._render_path_paint_texpaint_nor_undo = render_path_render_targets.get("texpaint_nor_undo" + hid);
+			RenderPathPaint._render_path_paint_texpaint_pack_undo = render_path_render_targets.get("texpaint_pack_undo" + hid);
+			RenderPathPaint._render_path_paint_texpaint_nor = render_path_render_targets.get("texpaint_nor" + tid);
+			RenderPathPaint._render_path_paint_texpaint_pack = render_path_render_targets.get("texpaint_pack" + tid);
 			render_path_render_targets.set("texpaint_undo" + hid,render_path_render_targets.get("texpaint" + tid));
 			render_path_render_targets.set("texpaint" + tid,render_path_render_targets.get("texpaint_live"));
-			if (SlotLayer.is_layer(context_raw.layer)) {
+			if (SlotLayer.slot_layer_is_layer(context_raw.layer)) {
 				render_path_render_targets.set("texpaint_nor_undo" + hid,render_path_render_targets.get("texpaint_nor" + tid));
 				render_path_render_targets.set("texpaint_pack_undo" + hid,render_path_render_targets.get("texpaint_pack" + tid));
 				render_path_render_targets.set("texpaint_nor" + tid,render_path_render_targets.get("texpaint_nor_live"));
@@ -384,19 +384,19 @@ class RenderPathPaint {
 			}
 		}
 		else {
-			render_path_render_targets.set("texpaint" + tid, RenderPathPaint._texpaint);
-			render_path_render_targets.set("texpaint_undo" + hid, RenderPathPaint._texpaint_undo);
-			if (SlotLayer.is_layer(context_raw.layer)) {
-				render_path_render_targets.set("texpaint_nor_undo" + hid, RenderPathPaint._texpaint_nor_undo);
-				render_path_render_targets.set("texpaint_pack_undo" + hid, RenderPathPaint._texpaint_pack_undo);
-				render_path_render_targets.set("texpaint_nor" + tid, RenderPathPaint._texpaint_nor);
-				render_path_render_targets.set("texpaint_pack" + tid, RenderPathPaint._texpaint_pack);
+			render_path_render_targets.set("texpaint" + tid, RenderPathPaint._render_path_paint_texpaint);
+			render_path_render_targets.set("texpaint_undo" + hid, RenderPathPaint._render_path_paint_texpaint_undo);
+			if (SlotLayer.slot_layer_is_layer(context_raw.layer)) {
+				render_path_render_targets.set("texpaint_nor_undo" + hid, RenderPathPaint._render_path_paint_texpaint_nor_undo);
+				render_path_render_targets.set("texpaint_pack_undo" + hid, RenderPathPaint._render_path_paint_texpaint_pack_undo);
+				render_path_render_targets.set("texpaint_nor" + tid, RenderPathPaint._render_path_paint_texpaint_nor);
+				render_path_render_targets.set("texpaint_pack" + tid, RenderPathPaint._render_path_paint_texpaint_pack);
 			}
 		}
-		RenderPathPaint.live_layer_locked = use;
+		RenderPathPaint.render_path_paint_live_layer_locked = use;
 	}
 
-	static commands_live_brush = () => {
+	static render_path_paint_commands_live_brush = () => {
 		let tool: workspace_tool_t = context_raw.tool;
 		if (tool != workspace_tool_t.BRUSH &&
 			tool != workspace_tool_t.ERASER &&
@@ -408,14 +408,14 @@ class RenderPathPaint {
 				return;
 		}
 
-		if (RenderPathPaint.live_layer_locked) return;
+		if (RenderPathPaint.render_path_paint_live_layer_locked) return;
 
-		if (RenderPathPaint.live_layer == null) {
-			RenderPathPaint.live_layer = SlotLayer.create("_live");
+		if (RenderPathPaint.render_path_paint_live_layer == null) {
+			RenderPathPaint.render_path_paint_live_layer = SlotLayer.slot_layer_create("_live");
 		}
 
 		let tid: i32 = context_raw.layer.id;
-		if (SlotLayer.is_mask(context_raw.layer)) {
+		if (SlotLayer.slot_layer_is_mask(context_raw.layer)) {
 			render_path_set_target("texpaint_live");
 			render_path_bind_target("texpaint" + tid, "tex");
 			render_path_draw_shader("shader_datas/copy_pass/copy_pass");
@@ -428,9 +428,9 @@ class RenderPathPaint {
 			render_path_draw_shader("shader_datas/copy_mrt3_pass/copy_mrt3_pass");
 		}
 
-		RenderPathPaint.use_live_layer(true);
+		RenderPathPaint.render_path_paint_use_live_layer(true);
 
-		RenderPathPaint.live_layer_drawn = 2;
+		RenderPathPaint.render_path_paint_live_layer_drawn = 2;
 
 		ui_view2d_hwnd.redraws = 2;
 		let _x: f32 = context_raw.paint_vec.x;
@@ -450,10 +450,10 @@ class RenderPathPaint {
 		}
 		context_raw.pdirty = 2;
 
-		RenderPathPaint.commands_symmetry();
-		RenderPathPaint.commands_paint();
+		RenderPathPaint.render_path_paint_commands_symmetry();
+		RenderPathPaint.render_path_paint_commands_paint();
 
-		RenderPathPaint.use_live_layer(false);
+		RenderPathPaint.render_path_paint_use_live_layer(false);
 
 		context_raw.paint_vec.x = _x;
 		context_raw.paint_vec.y = _y;
@@ -463,7 +463,7 @@ class RenderPathPaint {
 		context_raw.brush_blend_dirty = true;
 	}
 
-	static commands_cursor = () => {
+	static render_path_paint_commands_cursor = () => {
 		if (!config_raw.brush_3d) return;
 		let decal: bool = context_raw.tool == workspace_tool_t.DECAL || context_raw.tool == workspace_tool_t.TEXT;
 		let decal_mask: bool = decal && operator_shortcut(config_keymap.decal_mask, shortcut_type_t.DOWN);
@@ -479,7 +479,7 @@ class RenderPathPaint {
 		}
 
 		let fill_layer: bool = context_raw.layer.fill_layer != null;
-		let group_layer: bool = SlotLayer.is_group(context_raw.layer);
+		let group_layer: bool = SlotLayer.slot_layer_is_group(context_raw.layer);
 		if (!base_ui_enabled || base_is_dragging || fill_layer || group_layer) {
 			return;
 		}
@@ -491,10 +491,10 @@ class RenderPathPaint {
 			my = 1.0 - (context_raw.lock_started_y - app_y()) / app_h();
 		}
 		let radius: f32 = decal_mask ? context_raw.brush_decal_mask_radius : context_raw.brush_radius;
-		RenderPathPaint.draw_cursor(mx, my, context_raw.brush_nodes_radius * radius / 3.4);
+		RenderPathPaint.render_path_paint_draw_cursor(mx, my, context_raw.brush_nodes_radius * radius / 3.4);
 	}
 
-	static draw_cursor = (mx: f32, my: f32, radius: f32, tintR = 1.0, tintG = 1.0, tintB = 1.0) => {
+	static render_path_paint_draw_cursor = (mx: f32, my: f32, radius: f32, tint_r: f32 = 1.0, tint_g: f32 = 1.0, tint_b: f32 = 1.0) => {
 		let plane: mesh_object_t = scene_get_child(".Plane").ext;
 		let geom: mesh_data_t = plane.data;
 
@@ -513,7 +513,7 @@ class RenderPathPaint {
 		g4_set_float(base_cursor_radius, radius);
 		let right: vec4_t = vec4_normalize(camera_object_right_world(scene_camera));
 		g4_set_float3(base_cursor_camera_right, right.x, right.y, right.z);
-		g4_set_float3(base_cursor_tint, tintR, tintG, tintB);
+		g4_set_float3(base_cursor_tint, tint_r, tint_g, tint_b);
 		g4_set_mat(base_cursor_vp, scene_camera.vp);
 		let help_mat: mat4_t = mat4_identity();
 		mat4_get_inv(help_mat, scene_camera.vp);
@@ -530,7 +530,7 @@ class RenderPathPaint {
 		render_path_end();
 	}
 
-	static commands_symmetry = () => {
+	static render_path_paint_commands_symmetry = () => {
 		if (context_raw.sym_x || context_raw.sym_y || context_raw.sym_z) {
 			context_raw.ddirty = 2;
 			let t: transform_t = context_raw.paint_object.base.transform;
@@ -540,44 +540,44 @@ class RenderPathPaint {
 			if (context_raw.sym_x) {
 				vec4_set(t.scale, -sx, sy, sz);
 				transform_build_matrix(t);
-				RenderPathPaint.commands_paint(false);
+				RenderPathPaint.render_path_paint_commands_paint(false);
 			}
 			if (context_raw.sym_y) {
 				vec4_set(t.scale, sx, -sy, sz);
 				transform_build_matrix(t);
-				RenderPathPaint.commands_paint(false);
+				RenderPathPaint.render_path_paint_commands_paint(false);
 			}
 			if (context_raw.sym_z) {
 				vec4_set(t.scale, sx, sy, -sz);
 				transform_build_matrix(t);
-				RenderPathPaint.commands_paint(false);
+				RenderPathPaint.render_path_paint_commands_paint(false);
 			}
 			if (context_raw.sym_x && context_raw.sym_y) {
 				vec4_set(t.scale, -sx, -sy, sz);
 				transform_build_matrix(t);
-				RenderPathPaint.commands_paint(false);
+				RenderPathPaint.render_path_paint_commands_paint(false);
 			}
 			if (context_raw.sym_x && context_raw.sym_z) {
 				vec4_set(t.scale, -sx, sy, -sz);
 				transform_build_matrix(t);
-				RenderPathPaint.commands_paint(false);
+				RenderPathPaint.render_path_paint_commands_paint(false);
 			}
 			if (context_raw.sym_y && context_raw.sym_z) {
 				vec4_set(t.scale, sx, -sy, -sz);
 				transform_build_matrix(t);
-				RenderPathPaint.commands_paint(false);
+				RenderPathPaint.render_path_paint_commands_paint(false);
 			}
 			if (context_raw.sym_x && context_raw.sym_y && context_raw.sym_z) {
 				vec4_set(t.scale, -sx, -sy, -sz);
 				transform_build_matrix(t);
-				RenderPathPaint.commands_paint(false);
+				RenderPathPaint.render_path_paint_commands_paint(false);
 			}
 			vec4_set(t.scale, sx, sy, sz);
 			transform_build_matrix(t);
 		}
 	}
 
-	static paint_enabled = (): bool => {
+	static render_path_paint_paint_enabled = (): bool => {
 		///if is_paint
 		let fill_layer: bool = context_raw.layer.fill_layer != null && context_raw.tool != workspace_tool_t.PICKER && context_raw.tool != workspace_tool_t.MATERIAL && context_raw.tool != workspace_tool_t.COLORID;
 		///end
@@ -586,36 +586,36 @@ class RenderPathPaint {
 		let fill_layer: bool = context_raw.layer.fill_layer != null && context_raw.tool != workspace_tool_t.PICKER && context_raw.tool != workspace_tool_t.MATERIAL;
 		///end
 
-		let group_layer: bool = SlotLayer.is_group(context_raw.layer);
+		let group_layer: bool = SlotLayer.slot_layer_is_group(context_raw.layer);
 		return !fill_layer && !group_layer && !context_raw.foreground_event;
 	}
 
-	static live_brush_dirty = () => {
-		let mx: f32 = RenderPathPaint.last_x;
-		let my: f32 = RenderPathPaint.last_y;
-		RenderPathPaint.last_x = mouse_view_x();
-		RenderPathPaint.last_y = mouse_view_y();
+	static render_path_paint_live_brush_dirty = () => {
+		let mx: f32 = RenderPathPaint.render_path_paint_last_x;
+		let my: f32 = RenderPathPaint.render_path_paint_last_y;
+		RenderPathPaint.render_path_paint_last_x = mouse_view_x();
+		RenderPathPaint.render_path_paint_last_y = mouse_view_y();
 		if (config_raw.brush_live && context_raw.pdirty <= 0) {
-			let moved: bool = (mx != RenderPathPaint.last_x || my != RenderPathPaint.last_y) && (context_in_viewport() || context_in_2d_view());
+			let moved: bool = (mx != RenderPathPaint.render_path_paint_last_x || my != RenderPathPaint.render_path_paint_last_y) && (context_in_viewport() || context_in_2d_view());
 			if (moved || context_raw.brush_locked) {
 				context_raw.rdirty = 2;
 			}
 		}
 	}
 
-	static begin = () => {
+	static render_path_paint_begin = () => {
 
 		///if is_paint
-		if (!RenderPathPaint.dilated) {
-			RenderPathPaint.dilate(config_raw.dilate == dilate_type_t.DELAYED, true);
-			RenderPathPaint.dilated = true;
+		if (!RenderPathPaint.render_path_paint_dilated) {
+			RenderPathPaint.render_path_paint_dilate(config_raw.dilate == dilate_type_t.DELAYED, true);
+			RenderPathPaint.render_path_paint_dilated = true;
 		}
 		///end
 
-		if (!RenderPathPaint.paint_enabled()) return;
+		if (!RenderPathPaint.render_path_paint_paint_enabled()) return;
 
 		///if is_paint
-		RenderPathPaint.push_undo_last = history_push_undo;
+		RenderPathPaint.render_path_paint_push_undo_last = history_push_undo;
 		///end
 
 		if (history_push_undo && history_undo_layers != null) {
@@ -639,40 +639,40 @@ class RenderPathPaint {
 		///end
 
 		if (context_raw.paint2d) {
-			RenderPathPaint.set_plane_mesh();
+			RenderPathPaint.render_path_paint_set_plane_mesh();
 		}
 
-		if (RenderPathPaint.live_layer_drawn > 0) RenderPathPaint.live_layer_drawn--;
+		if (RenderPathPaint.render_path_paint_live_layer_drawn > 0) RenderPathPaint.render_path_paint_live_layer_drawn--;
 
 		if (config_raw.brush_live && context_raw.pdirty <= 0 && context_raw.ddirty <= 0 && context_raw.brush_time == 0) {
 			// Depth is unchanged, draw before gbuffer gets updated
-			RenderPathPaint.commands_live_brush();
+			RenderPathPaint.render_path_paint_commands_live_brush();
 		}
 	}
 
-	static end = () => {
-		RenderPathPaint.commands_cursor();
+	static render_path_paint_end = () => {
+		RenderPathPaint.render_path_paint_commands_cursor();
 		context_raw.ddirty--;
 		context_raw.rdirty--;
 
-		if (!RenderPathPaint.paint_enabled()) return;
+		if (!RenderPathPaint.render_path_paint_paint_enabled()) return;
 		context_raw.pdirty--;
 	}
 
-	static draw = () => {
-		if (!RenderPathPaint.paint_enabled()) return;
+	static render_path_paint_draw = () => {
+		if (!RenderPathPaint.render_path_paint_paint_enabled()) return;
 
 		///if (!krom_ios) // No hover on iPad, decals are painted by pen release
 		if (config_raw.brush_live && context_raw.pdirty <= 0 && context_raw.ddirty > 0 && context_raw.brush_time == 0) {
 			// gbuffer has been updated now but brush will lag 1 frame
-			RenderPathPaint.commands_live_brush();
+			RenderPathPaint.render_path_paint_commands_live_brush();
 		}
 		///end
 
 		if (history_undo_layers != null) {
-			RenderPathPaint.commands_symmetry();
+			RenderPathPaint.render_path_paint_commands_symmetry();
 
-			if (context_raw.pdirty > 0) RenderPathPaint.dilated = false;
+			if (context_raw.pdirty > 0) RenderPathPaint.render_path_paint_dilated = false;
 
 			///if is_paint
 			if (context_raw.tool == workspace_tool_t.BAKE) {
@@ -685,36 +685,36 @@ class RenderPathPaint {
 				///end
 
 				if (context_raw.bake_type == bake_type_t.NORMAL || context_raw.bake_type == bake_type_t.HEIGHT || context_raw.bake_type == bake_type_t.DERIVATIVE) {
-					if (!RenderPathPaint.baking && context_raw.pdirty > 0) {
-						RenderPathPaint.baking = true;
+					if (!RenderPathPaint.render_path_paint_baking && context_raw.pdirty > 0) {
+						RenderPathPaint.render_path_paint_baking = true;
 						let _bake_type: bake_type_t = context_raw.bake_type;
 						context_raw.bake_type = context_raw.bake_type == bake_type_t.NORMAL ? bake_type_t.NORMAL_OBJECT : bake_type_t.POSITION; // Bake high poly data
-						MakeMaterial.parse_paint_material();
+						MakeMaterial.make_material_parse_paint_material();
 						let _paint_object: mesh_object_t = context_raw.paint_object;
 						let high_poly: mesh_object_t = project_paint_objects[context_raw.bake_high_poly];
 						let _visible: bool = high_poly.base.visible;
 						high_poly.base.visible = true;
 						context_select_paint_object(high_poly);
-						RenderPathPaint.commands_paint();
+						RenderPathPaint.render_path_paint_commands_paint();
 						high_poly.base.visible = _visible;
-						if (RenderPathPaint.push_undo_last) history_paint();
+						if (RenderPathPaint.render_path_paint_push_undo_last) history_paint();
 						context_select_paint_object(_paint_object);
 
 						let _render_final = () => {
 							context_raw.bake_type = _bake_type;
-							MakeMaterial.parse_paint_material();
+							MakeMaterial.make_material_parse_paint_material();
 							context_raw.pdirty = 1;
-							RenderPathPaint.commands_paint();
+							RenderPathPaint.render_path_paint_commands_paint();
 							context_raw.pdirty = 0;
-							RenderPathPaint.baking = false;
+							RenderPathPaint.render_path_paint_baking = false;
 						}
 						let _render_deriv = () => {
 							context_raw.bake_type = bake_type_t.HEIGHT;
-							MakeMaterial.parse_paint_material();
+							MakeMaterial.make_material_parse_paint_material();
 							context_raw.pdirty = 1;
-							RenderPathPaint.commands_paint();
+							RenderPathPaint.render_path_paint_commands_paint();
 							context_raw.pdirty = 0;
-							if (RenderPathPaint.push_undo_last) history_paint();
+							if (RenderPathPaint.render_path_paint_push_undo_last) history_paint();
 							app_notify_on_init(_render_final);
 						}
 						let bake_type: bake_type_t = context_raw.bake_type as bake_type_t;
@@ -731,7 +731,7 @@ class RenderPathPaint {
 
 					for (let p of project_paint_objects) {
 						context_select_paint_object(p);
-						RenderPathPaint.commands_paint();
+						RenderPathPaint.render_path_paint_commands_paint();
 					}
 
 					context_raw.layer_filter = _layer_filter;
@@ -740,24 +740,24 @@ class RenderPathPaint {
 				}
 				///if (krom_direct3d12 || krom_vulkan || krom_metal)
 				else if (is_raytraced_bake) {
-					let dirty: bool = RenderPathRaytraceBake.commands(MakeMaterial.parse_paint_material);
+					let dirty: bool = render_path_raytrace_bake_commands(MakeMaterial.make_material_parse_paint_material);
 					if (dirty) ui_header_handle.redraws = 2;
 					if (config_raw.dilate == dilate_type_t.INSTANT) { // && raw.pdirty == 1
-						RenderPathPaint.dilate(true, false);
+						RenderPathPaint.render_path_paint_dilate(true, false);
 					}
 				}
 				///end
 				else {
-					RenderPathPaint.commands_paint();
+					RenderPathPaint.render_path_paint_commands_paint();
 				}
 			}
 			else { // Paint
-				RenderPathPaint.commands_paint();
+				RenderPathPaint.render_path_paint_commands_paint();
 			}
 			///end
 
 			///if is_sculpt
-			RenderPathPaint.commands_paint();
+			RenderPathPaint.render_path_paint_commands_paint();
 			///end
 		}
 
@@ -775,26 +775,26 @@ class RenderPathPaint {
 		}
 
 		if (context_raw.paint2d) {
-			RenderPathPaint.restore_plane_mesh();
+			RenderPathPaint.render_path_paint_restore_plane_mesh();
 		}
 	}
 
-	static set_plane_mesh = () => {
+	static render_path_paint_set_plane_mesh = () => {
 		context_raw.paint2d_view = true;
-		RenderPathPaint.painto = context_raw.paint_object;
-		RenderPathPaint.visibles = [];
+		RenderPathPaint.render_path_paint_painto = context_raw.paint_object;
+		RenderPathPaint.render_path_paint_visibles = [];
 		for (let p of project_paint_objects) {
-			RenderPathPaint.visibles.push(p.base.visible);
+			RenderPathPaint.render_path_paint_visibles.push(p.base.visible);
 			p.base.visible = false;
 		}
 		if (context_raw.merged_object != null) {
-			RenderPathPaint.merged_object_visible = context_raw.merged_object.base.visible;
+			RenderPathPaint.render_path_paint_merged_object_visible = context_raw.merged_object.base.visible;
 			context_raw.merged_object.base.visible = false;
 		}
 
 		let cam: camera_object_t = scene_camera;
 		mat4_set_from(context_raw.saved_camera, cam.base.transform.local);
-		RenderPathPaint.saved_fov = cam.data.fov;
+		RenderPathPaint.render_path_paint_saved_fov = cam.data.fov;
 		viewport_update_camera_type(camera_type_t.PERSPECTIVE);
 		let m: mat4_t = mat4_identity();
 		mat4_translate(m, 0, 0, 0.5);
@@ -839,44 +839,44 @@ class RenderPathPaint {
 			o.base.name = ".PlaneTiled";
 		}
 
-		RenderPathPaint.planeo = scene_get_child(tiled ? ".PlaneTiled" : ".Plane").ext;
-		RenderPathPaint.planeo.base.visible = true;
-		context_raw.paint_object = RenderPathPaint.planeo;
+		RenderPathPaint.render_path_paint_planeo = scene_get_child(tiled ? ".PlaneTiled" : ".Plane").ext;
+		RenderPathPaint.render_path_paint_planeo.base.visible = true;
+		context_raw.paint_object = RenderPathPaint.render_path_paint_planeo;
 
 		let v: vec4_t = vec4_create();
 		let sx: f32 = vec4_len(vec4_set(v, m.m[0], m.m[1], m.m[2]));
-		quat_from_euler(RenderPathPaint.planeo.base.transform.rot, -math_pi() / 2, 0, 0);
-		vec4_set(RenderPathPaint.planeo.base.transform.scale, sx, 1.0, sx);
-		RenderPathPaint.planeo.base.transform.scale.z *= config_get_texture_res_y() / config_get_texture_res_x();
-		vec4_set(RenderPathPaint.planeo.base.transform.loc, m.m[12], -m.m[13], 0.0);
-		transform_build_matrix(RenderPathPaint.planeo.base.transform);
+		quat_from_euler(RenderPathPaint.render_path_paint_planeo.base.transform.rot, -math_pi() / 2, 0, 0);
+		vec4_set(RenderPathPaint.render_path_paint_planeo.base.transform.scale, sx, 1.0, sx);
+		RenderPathPaint.render_path_paint_planeo.base.transform.scale.z *= config_get_texture_res_y() / config_get_texture_res_x();
+		vec4_set(RenderPathPaint.render_path_paint_planeo.base.transform.loc, m.m[12], -m.m[13], 0.0);
+		transform_build_matrix(RenderPathPaint.render_path_paint_planeo.base.transform);
 	}
 
-	static restore_plane_mesh = () => {
+	static render_path_paint_restore_plane_mesh = () => {
 		context_raw.paint2d_view = false;
-		RenderPathPaint.planeo.base.visible = false;
-		vec4_set(RenderPathPaint.planeo.base.transform.loc, 0.0, 0.0, 0.0);
+		RenderPathPaint.render_path_paint_planeo.base.visible = false;
+		vec4_set(RenderPathPaint.render_path_paint_planeo.base.transform.loc, 0.0, 0.0, 0.0);
 		for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
-			project_paint_objects[i].base.visible = RenderPathPaint.visibles[i];
+			project_paint_objects[i].base.visible = RenderPathPaint.render_path_paint_visibles[i];
 		}
 		if (context_raw.merged_object != null) {
-			context_raw.merged_object.base.visible = RenderPathPaint.merged_object_visible;
+			context_raw.merged_object.base.visible = RenderPathPaint.render_path_paint_merged_object_visible;
 		}
-		context_raw.paint_object = RenderPathPaint.painto;
+		context_raw.paint_object = RenderPathPaint.render_path_paint_painto;
 		transform_set_matrix(scene_camera.base.transform, context_raw.saved_camera);
-		scene_camera.data.fov = RenderPathPaint.saved_fov;
+		scene_camera.data.fov = RenderPathPaint.render_path_paint_saved_fov;
 		viewport_update_camera_type(context_raw.camera_type);
 		camera_object_build_proj(scene_camera);
 		camera_object_build_mat(scene_camera);
 
-		RenderPathBase.draw_gbuffer();
+		render_path_base_draw_gbuffer();
 	}
 
-	static bind_layers = () => {
+	static render_path_paint_bind_layers = () => {
 		///if is_paint
-		let is_live: bool = config_raw.brush_live && RenderPathPaint.live_layer_drawn > 0;
+		let is_live: bool = config_raw.brush_live && RenderPathPaint.render_path_paint_live_layer_drawn > 0;
 		let is_material_tool: bool = context_raw.tool == workspace_tool_t.MATERIAL;
-		if (is_live || is_material_tool) RenderPathPaint.use_live_layer(true);
+		if (is_live || is_material_tool) RenderPathPaint.render_path_paint_use_live_layer(true);
 		///end
 
 		for (let i: i32 = 0; i < project_layers.length; ++i) {
@@ -884,7 +884,7 @@ class RenderPathPaint {
 			render_path_bind_target("texpaint" + l.id, "texpaint" + l.id);
 
 			///if is_paint
-			if (SlotLayer.is_layer(l)) {
+			if (SlotLayer.slot_layer_is_layer(l)) {
 				render_path_bind_target("texpaint_nor" + l.id, "texpaint_nor" + l.id);
 				render_path_bind_target("texpaint_pack" + l.id, "texpaint_pack" + l.id);
 			}
@@ -892,15 +892,15 @@ class RenderPathPaint {
 		}
 	}
 
-	static unbind_layers = () => {
+	static render_path_paint_unbind_layers = () => {
 		///if is_paint
-		let is_live: bool = config_raw.brush_live && RenderPathPaint.live_layer_drawn > 0;
+		let is_live: bool = config_raw.brush_live && RenderPathPaint.render_path_paint_live_layer_drawn > 0;
 		let is_material_tool: bool = context_raw.tool == workspace_tool_t.MATERIAL;
-		if (is_live || is_material_tool) RenderPathPaint.use_live_layer(false);
+		if (is_live || is_material_tool) RenderPathPaint.render_path_paint_use_live_layer(false);
 		///end
 	}
 
-	static dilate = (base: bool, nor_pack: bool) => {
+	static render_path_paint_dilate = (base: bool, nor_pack: bool) => {
 		///if is_paint
 		if (config_raw.dilate_radius > 0 && !context_raw.paint2d) {
 			util_uv_cache_dilate_map();
@@ -915,7 +915,7 @@ class RenderPathPaint {
 				render_path_bind_target("temptex0", "tex");
 				render_path_draw_shader("shader_datas/dilate_pass/dilate_pass");
 			}
-			if (nor_pack && !SlotLayer.is_mask(context_raw.layer)) {
+			if (nor_pack && !SlotLayer.slot_layer_is_mask(context_raw.layer)) {
 				render_path_set_target("temptex0");
 				render_path_bind_target("texpaint_nor" + tid, "tex");
 				render_path_draw_shader("shader_datas/copy_pass/copy_pass");

+ 7 - 7
armorpaint/Sources/RenderPathPreview.ts

@@ -1,7 +1,7 @@
 
 class RenderPathPreview {
 
-	static init = () => {
+	static render_path_preview_init = () => {
 
 		{
 			let t: render_target_t = render_target_create();
@@ -28,7 +28,7 @@ class RenderPathPreview {
 			t.width = math_floor(util_render_material_preview_size * 2.0);
 			t.height = math_floor(util_render_material_preview_size * 2.0);
 			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
+			t.scale = render_path_base_get_super_sampling();
 			///if krom_opengl
 			t.depth_buffer = "mmain";
 			///end
@@ -41,7 +41,7 @@ class RenderPathPreview {
 			t.width = math_floor(util_render_material_preview_size * 2.0);
 			t.height = math_floor(util_render_material_preview_size * 2.0);
 			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
+			t.scale = render_path_base_get_super_sampling();
 			t.depth_buffer = "mmain";
 			render_path_create_render_target(t);
 		}
@@ -52,7 +52,7 @@ class RenderPathPreview {
 			t.width = math_floor(util_render_material_preview_size * 2.0);
 			t.height = math_floor(util_render_material_preview_size * 2.0);
 			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
+			t.scale = render_path_base_get_super_sampling();
 			render_path_create_render_target(t);
 		}
 
@@ -62,12 +62,12 @@ class RenderPathPreview {
 			t.width = math_floor(util_render_material_preview_size * 2.0);
 			t.height = math_floor(util_render_material_preview_size * 2.0);
 			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
+			t.scale = render_path_base_get_super_sampling();
 			render_path_create_render_target(t);
 		}
 	}
 
-	static commands_preview = () => {
+	static render_path_preview_commands_preview = () => {
 		render_path_set_target("mgbuffer2");
 		render_path_clear_target(0xff000000);
 
@@ -111,7 +111,7 @@ class RenderPathPreview {
 		render_path_draw_shader("shader_datas/supersample_resolve/supersample_resolve");
 	}
 
-	static commands_decal = () => {
+	static render_path_preview_commands_decal = () => {
 		render_path_set_target("gbuffer2");
 		render_path_clear_target(0xff000000);
 

+ 5 - 5
armorpaint/Sources/SlotBrush.ts

@@ -9,18 +9,18 @@ class SlotBrushRaw {
 }
 
 class SlotBrush {
-	static default_canvas: ArrayBuffer = null;
+	static slot_brush_default_canvas: ArrayBuffer = null;
 
-	static create(c: zui_node_canvas_t = null): SlotBrushRaw {
+	static slot_brush_create(c: zui_node_canvas_t = null): SlotBrushRaw {
 		let raw: SlotBrushRaw = new SlotBrushRaw();
 		for (let brush of project_brushes) if (brush.id >= raw.id) raw.id = brush.id + 1;
 
 		if (c == null) {
-			if (SlotBrush.default_canvas == null) { // Synchronous
+			if (SlotBrush.slot_brush_default_canvas == null) { // Synchronous
 				let b: ArrayBuffer = data_get_blob("default_brush.arm")
-				SlotBrush.default_canvas = b;
+				SlotBrush.slot_brush_default_canvas = b;
 			}
-			raw.canvas = armpack_decode(SlotBrush.default_canvas);
+			raw.canvas = armpack_decode(SlotBrush.slot_brush_default_canvas);
 			raw.canvas.name = "Brush " + (raw.id + 1);
 		}
 		else {

+ 1 - 1
armorpaint/Sources/SlotFont.ts

@@ -10,7 +10,7 @@ class SlotFontRaw {
 
 class SlotFont {
 
-	static create(name: string, font: g2_font_t, file = ""): SlotFontRaw {
+	static slot_font_create(name: string, font: g2_font_t, file = ""): SlotFontRaw {
 		let raw: SlotFontRaw = new SlotFontRaw();
 		for (let slot of project_fonts) if (slot.id >= raw.id) raw.id = slot.id + 1;
 		raw.name = name;

+ 97 - 97
armorpaint/Sources/SlotLayer.ts

@@ -37,7 +37,7 @@ class SlotLayerRaw {
 
 class SlotLayer {
 
-	static create(ext = "", type = layer_slot_type_t.LAYER, parent: SlotLayerRaw = null): SlotLayerRaw {
+	static slot_layer_create(ext = "", type = layer_slot_type_t.LAYER, parent: SlotLayerRaw = null): SlotLayerRaw {
 		let raw: SlotLayerRaw = new SlotLayerRaw();
 		if (ext == "") {
 			raw.id = 0;
@@ -115,18 +115,18 @@ class SlotLayer {
 		return raw;
 	}
 
-	static delete = (raw: SlotLayerRaw) => {
-		SlotLayer.unload(raw);
+	static slot_layer_delete = (raw: SlotLayerRaw) => {
+		SlotLayer.slot_layer_unload(raw);
 
-		if (SlotLayer.is_layer(raw)) {
-			let masks: SlotLayerRaw[] = SlotLayer.get_masks(raw, false); // Prevents deleting group masks
-			if (masks != null) for (let m of masks) SlotLayer.delete(m);
+		if (SlotLayer.slot_layer_is_layer(raw)) {
+			let masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(raw, false); // Prevents deleting group masks
+			if (masks != null) for (let m of masks) SlotLayer.slot_layer_delete(m);
 		}
-		else if (SlotLayer.is_group(raw)) {
-			let children: SlotLayerRaw[] = SlotLayer.get_children(raw);
-			if (children != null) for (let c of children) SlotLayer.delete(c);
-			let masks: SlotLayerRaw[] = SlotLayer.get_masks(raw);
-			if (masks != null) for (let m of masks) SlotLayer.delete(m);
+		else if (SlotLayer.slot_layer_is_group(raw)) {
+			let children: SlotLayerRaw[] = SlotLayer.slot_layer_get_children(raw);
+			if (children != null) for (let c of children) SlotLayer.slot_layer_delete(c);
+			let masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(raw);
+			if (masks != null) for (let m of masks) SlotLayer.slot_layer_delete(m);
 		}
 
 		let lpos: i32 = project_layers.indexOf(raw);
@@ -139,8 +139,8 @@ class SlotLayer {
 		// Do not remove empty groups if the last layer is deleted as this prevents redo from working properly
 	}
 
-	static unload = (raw: SlotLayerRaw) => {
-		if (SlotLayer.is_group(raw)) return;
+	static slot_layer_unload = (raw: SlotLayerRaw) => {
+		if (SlotLayer.slot_layer_is_group(raw)) return;
 
 		let _texpaint: image_t = raw.texpaint;
 		///if is_paint
@@ -161,15 +161,15 @@ class SlotLayer {
 
 		render_path_render_targets.delete("texpaint" + raw.ext);
 		///if is_paint
-		if (SlotLayer.is_layer(raw)) {
+		if (SlotLayer.slot_layer_is_layer(raw)) {
 			render_path_render_targets.delete("texpaint_nor" + raw.ext);
 			render_path_render_targets.delete("texpaint_pack" + raw.ext);
 		}
 		///end
 	}
 
-	static swap = (raw: SlotLayerRaw, other: SlotLayerRaw) => {
-		if ((SlotLayer.is_layer(raw) || SlotLayer.is_mask(raw)) && (SlotLayer.is_layer(other) || SlotLayer.is_mask(other))) {
+	static slot_layer_swap = (raw: SlotLayerRaw, other: SlotLayerRaw) => {
+		if ((SlotLayer.slot_layer_is_layer(raw) || SlotLayer.slot_layer_is_mask(raw)) && (SlotLayer.slot_layer_is_layer(other) || SlotLayer.slot_layer_is_mask(other))) {
 			render_path_render_targets.get("texpaint" + raw.ext)._image = other.texpaint;
 			render_path_render_targets.get("texpaint" + other.ext)._image = raw.texpaint;
 			let _texpaint: image_t = raw.texpaint;
@@ -184,7 +184,7 @@ class SlotLayer {
 		}
 
 		///if is_paint
-		if (SlotLayer.is_layer(raw) && SlotLayer.is_layer(other)) {
+		if (SlotLayer.slot_layer_is_layer(raw) && SlotLayer.slot_layer_is_layer(other)) {
 			render_path_render_targets.get("texpaint_nor" + raw.ext)._image = other.texpaint_nor;
 			render_path_render_targets.get("texpaint_pack" + raw.ext)._image = other.texpaint_pack;
 			render_path_render_targets.get("texpaint_nor" + other.ext)._image = raw.texpaint_nor;
@@ -199,7 +199,7 @@ class SlotLayer {
 		///end
 	}
 
-	static clear = (raw: SlotLayerRaw, baseColor = 0x00000000, baseImage: image_t = null, occlusion = 1.0, roughness = base_default_rough, metallic = 0.0) => {
+	static slot_layer_clear = (raw: SlotLayerRaw, baseColor = 0x00000000, baseImage: image_t = null, occlusion = 1.0, roughness = base_default_rough, metallic = 0.0) => {
 		g4_begin(raw.texpaint);
 		g4_clear(baseColor); // Base
 		g4_end();
@@ -210,7 +210,7 @@ class SlotLayer {
 		}
 
 		///if is_paint
-		if (SlotLayer.is_layer(raw)) {
+		if (SlotLayer.slot_layer_is_layer(raw)) {
 			g4_begin(raw.texpaint_nor);
 			g4_clear(color_from_floats(0.5, 0.5, 1.0, 0.0)); // Nor
 			g4_end();
@@ -224,7 +224,7 @@ class SlotLayer {
 		context_raw.ddirty = 3;
 	}
 
-	static invert_mask = (raw: SlotLayerRaw) => {
+	static slot_layer_invert_mask = (raw: SlotLayerRaw) => {
 		if (base_pipe_invert8 == null) base_make_pipe();
 		let inverted: image_t = image_create_render_target(raw.texpaint.width, raw.texpaint.height, tex_format_t.RGBA32);
 		g2_begin(inverted);
@@ -242,29 +242,29 @@ class SlotLayer {
 		context_raw.ddirty = 3;
 	}
 
-	static apply_mask = (raw: SlotLayerRaw) => {
+	static slot_layer_apply_mask = (raw: SlotLayerRaw) => {
 		if (raw.parent.fill_layer != null) {
-			SlotLayer.to_paint_layer(raw.parent);
+			SlotLayer.slot_layer_to_paint_layer(raw.parent);
 		}
-		if (SlotLayer.is_group(raw.parent)) {
-			for (let c of SlotLayer.get_children(raw.parent)) {
+		if (SlotLayer.slot_layer_is_group(raw.parent)) {
+			for (let c of SlotLayer.slot_layer_get_children(raw.parent)) {
 				base_apply_mask(c, raw);
 			}
 		}
 		else {
 			base_apply_mask(raw.parent, raw);
 		}
-		SlotLayer.delete(raw);
+		SlotLayer.slot_layer_delete(raw);
 	}
 
-	static duplicate = (raw: SlotLayerRaw): SlotLayerRaw => {
+	static slot_layer_duplicate = (raw: SlotLayerRaw): SlotLayerRaw => {
 		let layers: SlotLayerRaw[] = project_layers;
 		let i: i32 = layers.indexOf(raw) + 1;
-		let l: SlotLayerRaw = SlotLayer.create("", SlotLayer.is_layer(raw) ? layer_slot_type_t.LAYER : SlotLayer.is_mask(raw) ? layer_slot_type_t.MASK : layer_slot_type_t.GROUP, raw.parent);
+		let l: SlotLayerRaw = SlotLayer.slot_layer_create("", SlotLayer.slot_layer_is_layer(raw) ? layer_slot_type_t.LAYER : SlotLayer.slot_layer_is_mask(raw) ? layer_slot_type_t.MASK : layer_slot_type_t.GROUP, raw.parent);
 		layers.splice(i, 0, l);
 
 		if (base_pipe_merge == null) base_make_pipe();
-		if (SlotLayer.is_layer(raw)) {
+		if (SlotLayer.slot_layer_is_layer(raw)) {
 			g2_begin(l.texpaint);
 			g2_set_pipeline(base_pipe_copy);
 			g2_draw_image(raw.texpaint, 0, 0);
@@ -283,7 +283,7 @@ class SlotLayer {
 			g2_end();
 			///end
 		}
-		else if (SlotLayer.is_mask(raw)) {
+		else if (SlotLayer.slot_layer_is_mask(raw)) {
 			g2_begin(l.texpaint);
 			g2_set_pipeline(base_pipe_copy8);
 			g2_draw_image(raw.texpaint, 0, 0);
@@ -323,13 +323,13 @@ class SlotLayer {
 		return l;
 	}
 
-	static resize_and_set_bits = (raw: SlotLayerRaw) => {
+	static slot_layer_resize_and_set_bits = (raw: SlotLayerRaw) => {
 		let res_x: i32 = config_get_texture_res_x();
 		let res_y: i32 = config_get_texture_res_y();
 		let rts: map_t<string, render_target_t> = render_path_render_targets;
 		if (base_pipe_merge == null) base_make_pipe();
 
-		if (SlotLayer.is_layer(raw)) {
+		if (SlotLayer.slot_layer_is_layer(raw)) {
 			///if is_paint
 			let format: tex_format_t = base_bits_handle.position == texture_bits_t.BITS8  ? tex_format_t.RGBA32 :
 				base_bits_handle.position == texture_bits_t.BITS16 ? tex_format_t.RGBA64 :
@@ -382,7 +382,7 @@ class SlotLayer {
 			rts.get("texpaint_pack" + raw.ext)._image = raw.texpaint_pack;
 			///end
 		}
-		else if (SlotLayer.is_mask(raw)) {
+		else if (SlotLayer.slot_layer_is_mask(raw)) {
 			let _texpaint: image_t = raw.texpaint;
 			raw.texpaint = image_create_render_target(res_x, res_y, tex_format_t.RGBA32);
 
@@ -401,34 +401,34 @@ class SlotLayer {
 		}
 	}
 
-	static to_fill_layer = (raw: SlotLayerRaw) => {
+	static slot_layer_to_fill_layer = (raw: SlotLayerRaw) => {
 		context_set_layer(raw);
 		raw.fill_layer = context_raw.material;
 		base_update_fill_layer();
 		let _next = () => {
-			MakeMaterial.parse_paint_material();
+			MakeMaterial.make_material_parse_paint_material();
 			context_raw.layer_preview_dirty = true;
 			ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
 		}
 		base_notify_on_next_frame(_next);
 	}
 
-	static to_paint_layer = (raw: SlotLayerRaw) => {
+	static slot_layer_to_paint_layer = (raw: SlotLayerRaw) => {
 		context_set_layer(raw);
 		raw.fill_layer = null;
-		MakeMaterial.parse_paint_material();
+		MakeMaterial.make_material_parse_paint_material();
 		context_raw.layer_preview_dirty = true;
 		ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
 	}
 
-	static is_visible = (raw: SlotLayerRaw): bool => {
+	static slot_layer_is_visible = (raw: SlotLayerRaw): bool => {
 		return raw.visible && (raw.parent == null || raw.parent.visible);
 	}
 
-	static get_children = (raw: SlotLayerRaw): SlotLayerRaw[] => {
+	static slot_layer_get_children = (raw: SlotLayerRaw): SlotLayerRaw[] => {
 		let children: SlotLayerRaw[] = null; // Child layers of a group
 		for (let l of project_layers) {
-			if (l.parent == raw && SlotLayer.is_layer(l)) {
+			if (l.parent == raw && SlotLayer.slot_layer_is_layer(l)) {
 				if (children == null) children = [];
 				children.push(l);
 			}
@@ -436,7 +436,7 @@ class SlotLayer {
 		return children;
 	}
 
-	static get_recursive_children = (raw: SlotLayerRaw): SlotLayerRaw[] => {
+	static slot_layer_get_recursive_children = (raw: SlotLayerRaw): SlotLayerRaw[] => {
 		let children: SlotLayerRaw[] = null;
 		for (let l of project_layers) {
 			if (l.parent == raw) { // Child layers and group masks
@@ -451,22 +451,22 @@ class SlotLayer {
 		return children;
 	}
 
-	static get_masks = (raw: SlotLayerRaw, includeGroupMasks = true): SlotLayerRaw[] => {
-		if (SlotLayer.is_mask(raw)) return null;
+	static slot_layer_get_masks = (raw: SlotLayerRaw, includeGroupMasks = true): SlotLayerRaw[] => {
+		if (SlotLayer.slot_layer_is_mask(raw)) return null;
 
 		let children: SlotLayerRaw[] = null;
 		// Child masks of a layer
 		for (let l of project_layers) {
-			if (l.parent == raw && SlotLayer.is_mask(l)) {
+			if (l.parent == raw && SlotLayer.slot_layer_is_mask(l)) {
 				if (children == null) children = [];
 				children.push(l);
 			}
 		}
 		// Child masks of a parent group
 		if (includeGroupMasks) {
-			if (raw.parent != null && SlotLayer.is_group(raw.parent)) {
+			if (raw.parent != null && SlotLayer.slot_layer_is_group(raw.parent)) {
 				for (let l of project_layers) {
-					if (l.parent == raw.parent && SlotLayer.is_mask(l)) {
+					if (l.parent == raw.parent && SlotLayer.slot_layer_is_mask(l)) {
 						if (children == null) children = [];
 						children.push(l);
 					}
@@ -476,17 +476,17 @@ class SlotLayer {
 		return children;
 	}
 
-	static has_masks = (raw: SlotLayerRaw, includeGroupMasks = true): bool => {
+	static slot_layer_has_masks = (raw: SlotLayerRaw, includeGroupMasks = true): bool => {
 		// Layer mask
 		for (let l of project_layers) {
-			if (l.parent == raw && SlotLayer.is_mask(l)) {
+			if (l.parent == raw && SlotLayer.slot_layer_is_mask(l)) {
 				return true;
 			}
 		}
 		// Group mask
-		if (includeGroupMasks && raw.parent != null && SlotLayer.is_group(raw.parent)) {
+		if (includeGroupMasks && raw.parent != null && SlotLayer.slot_layer_is_group(raw.parent)) {
 			for (let l of project_layers) {
-				if (l.parent == raw.parent && SlotLayer.is_mask(l)) {
+				if (l.parent == raw.parent && SlotLayer.slot_layer_is_mask(l)) {
 					return true;
 				}
 			}
@@ -494,17 +494,17 @@ class SlotLayer {
 		return false;
 	}
 
-	static get_opacity = (raw: SlotLayerRaw): f32 => {
+	static slot_layer_get_opacity = (raw: SlotLayerRaw): f32 => {
 		let f: f32 = raw.mask_opacity;
-		if (SlotLayer.is_layer(raw) && raw.parent != null) f *= raw.parent.mask_opacity;
+		if (SlotLayer.slot_layer_is_layer(raw) && raw.parent != null) f *= raw.parent.mask_opacity;
 		return f;
 	}
 
-	static get_object_mask = (raw: SlotLayerRaw): i32 => {
-		return SlotLayer.is_mask(raw) ? raw.parent.object_mask : raw.object_mask;
+	static slot_layer_get_object_mask = (raw: SlotLayerRaw): i32 => {
+		return SlotLayer.slot_layer_is_mask(raw) ? raw.parent.object_mask : raw.object_mask;
 	}
 
-	static is_layer = (raw: SlotLayerRaw): bool => {
+	static slot_layer_is_layer = (raw: SlotLayerRaw): bool => {
 		///if is_paint
 		return raw.texpaint != null && raw.texpaint_nor != null;
 		///end
@@ -513,19 +513,19 @@ class SlotLayer {
 		///end
 	}
 
-	static is_group = (raw: SlotLayerRaw): bool => {
+	static slot_layer_is_group = (raw: SlotLayerRaw): bool => {
 		return raw.texpaint == null;
 	}
 
-	static get_containing_group = (raw: SlotLayerRaw): SlotLayerRaw => {
-		if (raw.parent != null && SlotLayer.is_group(raw.parent))
+	static slot_layer_get_containing_group = (raw: SlotLayerRaw): SlotLayerRaw => {
+		if (raw.parent != null && SlotLayer.slot_layer_is_group(raw.parent))
 			return raw.parent;
-		else if (raw.parent != null && raw.parent.parent != null && SlotLayer.is_group(raw.parent.parent))
+		else if (raw.parent != null && raw.parent.parent != null && SlotLayer.slot_layer_is_group(raw.parent.parent))
 			return raw.parent.parent;
 		else return null;
 	}
 
-	static is_mask = (raw: SlotLayerRaw): bool => {
+	static slot_layer_is_mask = (raw: SlotLayerRaw): bool => {
 		///if is_paint
 		return raw.texpaint != null && raw.texpaint_nor == null;
 		///end
@@ -534,29 +534,29 @@ class SlotLayer {
 		///end
 	}
 
-	static is_group_mask = (raw: SlotLayerRaw): bool => {
+	static slot_layer_is_group_mask = (raw: SlotLayerRaw): bool => {
 		///if is_paint
-		return raw.texpaint != null && raw.texpaint_nor == null && SlotLayer.is_group(raw.parent);
+		return raw.texpaint != null && raw.texpaint_nor == null && SlotLayer.slot_layer_is_group(raw.parent);
 		///end
 		///if is_sculpt
 		return false;
 		///end
 	}
 
-	static is_layer_mask = (raw: SlotLayerRaw): bool => {
+	static slot_layer_is_layer_mask = (raw: SlotLayerRaw): bool => {
 		///if is_paint
-		return raw.texpaint != null && raw.texpaint_nor == null && SlotLayer.is_layer(raw.parent);
+		return raw.texpaint != null && raw.texpaint_nor == null && SlotLayer.slot_layer_is_layer(raw.parent);
 		///end
 		///if is_sculpt
 		return false;
 		///end
 	}
 
-	static is_in_group = (raw: SlotLayerRaw): bool => {
-		return raw.parent != null && (SlotLayer.is_group(raw.parent) || (raw.parent.parent != null && SlotLayer.is_group(raw.parent.parent)));
+	static slot_layer_is_in_group = (raw: SlotLayerRaw): bool => {
+		return raw.parent != null && (SlotLayer.slot_layer_is_group(raw.parent) || (raw.parent.parent != null && SlotLayer.slot_layer_is_group(raw.parent.parent)));
 	}
 
-	static can_move = (raw: SlotLayerRaw, to: i32): bool => {
+	static slot_layer_can_move = (raw: SlotLayerRaw, to: i32): bool => {
 		let old_index: i32 = project_layers.indexOf(raw);
 
 		let delta: i32 = to - old_index; // If delta > 0 the layer is moved up, otherwise down
@@ -569,7 +569,7 @@ class SlotLayer {
 
 		// Group or layer is collapsed so we check below and update the upper layer.
 		if (new_upper_layer != null && !new_upper_layer.show_panel) {
-			let children: SlotLayerRaw[] = SlotLayer.get_recursive_children(new_upper_layer);
+			let children: SlotLayerRaw[] = SlotLayer.slot_layer_get_recursive_children(new_upper_layer);
 			to -= children != null ? children.length : 0;
 			delta = to - old_index;
 			new_upper_layer = delta > 0 ? (to < project_layers.length - 1 ? project_layers[to + 1] : null) : project_layers[to];
@@ -577,53 +577,53 @@ class SlotLayer {
 
 		let new_lower_layer: SlotLayerRaw = delta > 0 ? project_layers[to] : (to > 0 ? project_layers[to - 1] : null);
 
-		if (SlotLayer.is_mask(raw)) {
+		if (SlotLayer.slot_layer_is_mask(raw)) {
 			// Masks can not be on top.
 			if (new_upper_layer == null) return false;
 			// Masks should not be placed below a collapsed group. This condition can be savely removed.
-			if (SlotLayer.is_in_group(new_upper_layer) && !SlotLayer.get_containing_group(new_upper_layer).show_panel) return false;
+			if (SlotLayer.slot_layer_is_in_group(new_upper_layer) && !SlotLayer.slot_layer_get_containing_group(new_upper_layer).show_panel) return false;
 			// Masks should not be placed below a collapsed layer. This condition can be savely removed.
-			if (SlotLayer.is_mask(new_upper_layer) && !new_upper_layer.parent.show_panel) return false;
+			if (SlotLayer.slot_layer_is_mask(new_upper_layer) && !new_upper_layer.parent.show_panel) return false;
 		}
 
-		if (SlotLayer.is_layer(raw)) {
+		if (SlotLayer.slot_layer_is_layer(raw)) {
 			// Layers can not be moved directly below its own mask(s).
-			if (new_upper_layer != null && SlotLayer.is_mask(new_upper_layer) && new_upper_layer.parent == raw) return false;
+			if (new_upper_layer != null && SlotLayer.slot_layer_is_mask(new_upper_layer) && new_upper_layer.parent == raw) return false;
 			// Layers can not be placed above a mask as the mask would be reparented.
-			if (new_lower_layer != null && SlotLayer.is_mask(new_lower_layer)) return false;
+			if (new_lower_layer != null && SlotLayer.slot_layer_is_mask(new_lower_layer)) return false;
 		}
 
 		// Currently groups can not be nested. Thus valid positions for groups are:
-		if (SlotLayer.is_group(raw)) {
+		if (SlotLayer.slot_layer_is_group(raw)) {
 			// At the top.
 			if (new_upper_layer == null) return true;
 			// NOT below its own children.
-			if (SlotLayer.get_containing_group(new_upper_layer) == raw) return false;
+			if (SlotLayer.slot_layer_get_containing_group(new_upper_layer) == raw) return false;
 			// At the bottom.
 			if (new_lower_layer == null) return true;
 			// Above a group.
-			if (SlotLayer.is_group(new_lower_layer)) return true;
+			if (SlotLayer.slot_layer_is_group(new_lower_layer)) return true;
 			// Above a non-grouped layer.
-			if (SlotLayer.is_layer(new_lower_layer) && !SlotLayer.is_in_group(new_lower_layer)) return true;
+			if (SlotLayer.slot_layer_is_layer(new_lower_layer) && !SlotLayer.slot_layer_is_in_group(new_lower_layer)) return true;
 			else return false;
 		}
 
 		return true;
 	}
 
-	static move = (raw: SlotLayerRaw, to: i32) => {
-		if (!SlotLayer.can_move(raw, to)) {
+	static slot_layer_move = (raw: SlotLayerRaw, to: i32) => {
+		if (!SlotLayer.slot_layer_can_move(raw, to)) {
 			return;
 		}
 
-		let pointers: map_t<SlotLayerRaw, i32> = TabLayers.init_layer_map();
+		let pointers: map_t<SlotLayerRaw, i32> = TabLayers.tab_layers_init_layer_map();
 		let old_index: i32 = project_layers.indexOf(raw);
 		let delta: i32 = to - old_index;
 		let new_upper_layer: SlotLayerRaw = delta > 0 ? (to < project_layers.length - 1 ? project_layers[to + 1] : null) : project_layers[to];
 
 		// Group or layer is collapsed so we check below and update the upper layer.
 		if (new_upper_layer != null && !new_upper_layer.show_panel) {
-			let children: SlotLayerRaw[] = SlotLayer.get_recursive_children(new_upper_layer);
+			let children: SlotLayerRaw[] = SlotLayer.slot_layer_get_recursive_children(new_upper_layer);
 			to -= children != null ? children.length : 0;
 			delta = to - old_index;
 			new_upper_layer = delta > 0 ? (to < project_layers.length - 1 ? project_layers[to + 1] : null) : project_layers[to];
@@ -636,24 +636,24 @@ class SlotLayer {
 		array_remove(project_layers, raw);
 		project_layers.splice(to, 0, raw);
 
-		if (SlotLayer.is_layer(raw)) {
+		if (SlotLayer.slot_layer_is_layer(raw)) {
 			let old_parent: SlotLayerRaw = raw.parent;
 
 			if (new_upper_layer == null)
 				raw.parent = null; // Placed on top.
-			else if (SlotLayer.is_in_group(new_upper_layer) && !SlotLayer.get_containing_group(new_upper_layer).show_panel)
+			else if (SlotLayer.slot_layer_is_in_group(new_upper_layer) && !SlotLayer.slot_layer_get_containing_group(new_upper_layer).show_panel)
 				raw.parent = null; // Placed below a collapsed group.
-			else if (SlotLayer.is_layer(new_upper_layer))
+			else if (SlotLayer.slot_layer_is_layer(new_upper_layer))
 				raw.parent = new_upper_layer.parent; // Placed below a layer, use the same parent.
-			else if (SlotLayer.is_group(new_upper_layer))
+			else if (SlotLayer.slot_layer_is_group(new_upper_layer))
 				raw.parent = new_upper_layer; // Placed as top layer in a group.
-			else if (SlotLayer.is_group_mask(new_upper_layer))
+			else if (SlotLayer.slot_layer_is_group_mask(new_upper_layer))
 				raw.parent = new_upper_layer.parent; // Placed in a group below the lowest group mask.
-			else if (SlotLayer.is_layer_mask(new_upper_layer))
-				raw.parent = SlotLayer.get_containing_group(new_upper_layer); // Either the group the mask belongs to or null.
+			else if (SlotLayer.slot_layer_is_layer_mask(new_upper_layer))
+				raw.parent = SlotLayer.slot_layer_get_containing_group(new_upper_layer); // Either the group the mask belongs to or null.
 
 			// Layers can have masks as children. These have to be moved, too.
-			let layer_masks: SlotLayerRaw[] = SlotLayer.get_masks(raw, false);
+			let layer_masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(raw, false);
 			if (layer_masks != null) {
 				for (let idx: i32 = 0; idx < layer_masks.length; ++idx) {
 					let mask: SlotLayerRaw = layer_masks[idx];
@@ -664,19 +664,19 @@ class SlotLayer {
 			}
 
 			// The layer is the last layer in the group, remove it. Notice that this might remove group masks.
-			if (old_parent != null && SlotLayer.get_children(old_parent) == null)
-				SlotLayer.delete(old_parent);
+			if (old_parent != null && SlotLayer.slot_layer_get_children(old_parent) == null)
+				SlotLayer.slot_layer_delete(old_parent);
 		}
-		else if (SlotLayer.is_mask(raw)) {
+		else if (SlotLayer.slot_layer_is_mask(raw)) {
 			// Precondition newUpperLayer != null, ensured in canMove.
-			if (SlotLayer.is_layer(new_upper_layer) || SlotLayer.is_group(new_upper_layer))
+			if (SlotLayer.slot_layer_is_layer(new_upper_layer) || SlotLayer.slot_layer_is_group(new_upper_layer))
 				raw.parent = new_upper_layer;
-			else if (SlotLayer.is_mask(new_upper_layer)) { // Group mask or layer mask.
+			else if (SlotLayer.slot_layer_is_mask(new_upper_layer)) { // Group mask or layer mask.
 				raw.parent = new_upper_layer.parent;
 			}
 		}
-		else if (SlotLayer.is_group(raw)) {
-			let children: SlotLayerRaw[] = SlotLayer.get_recursive_children(raw);
+		else if (SlotLayer.slot_layer_is_group(raw)) {
+			let children: SlotLayerRaw[] = SlotLayer.slot_layer_get_recursive_children(raw);
 			if (children != null) {
 				for (let idx: i32 = 0; idx < children.length; ++idx) {
 					let child: SlotLayerRaw = children[idx];
@@ -687,6 +687,6 @@ class SlotLayer {
 			}
 		}
 
-		for (let m of project_materials) TabLayers.remap_layer_pointers(m.canvas.nodes, TabLayers.fill_layer_map(pointers));
+		for (let m of project_materials) TabLayers.tab_layers_remap_layer_pointers(m.canvas.nodes, TabLayers.tab_layers_fill_layer_map(pointers));
 	}
 }

+ 8 - 8
armorpaint/Sources/SlotMaterial.ts

@@ -20,9 +20,9 @@ class SlotMaterialRaw {
 }
 
 class SlotMaterial {
-	static default_canvas: ArrayBuffer = null;
+	static slot_material_default_canvas: ArrayBuffer = null;
 
-	static create(m: material_data_t = null, c: zui_node_canvas_t = null): SlotMaterialRaw {
+	static slot_material_create(m: material_data_t = null, c: zui_node_canvas_t = null): SlotMaterialRaw {
 		let raw: SlotMaterialRaw = new SlotMaterialRaw();
 		for (let mat of project_materials) if (mat.id >= raw.id) raw.id = mat.id + 1;
 		raw.data = m;
@@ -33,11 +33,11 @@ class SlotMaterial {
 		raw.image_icon = image_create_render_target(w_icon, w_icon);
 
 		if (c == null) {
-			if (SlotMaterial.default_canvas == null) { // Synchronous
+			if (SlotMaterial.slot_material_default_canvas == null) { // Synchronous
 				let b: ArrayBuffer = data_get_blob("default_material.arm");
-				SlotMaterial.default_canvas = b;
+				SlotMaterial.slot_material_default_canvas = b;
 			}
-			raw.canvas = armpack_decode(SlotMaterial.default_canvas);
+			raw.canvas = armpack_decode(SlotMaterial.slot_material_default_canvas);
 			raw.canvas.name = "Material " + (raw.id + 1);
 		}
 		else {
@@ -51,7 +51,7 @@ class SlotMaterial {
 		return raw;
 	}
 
-	static unload = (raw: SlotMaterialRaw) => {
+	static slot_material_unload = (raw: SlotMaterialRaw) => {
 		let _next = () => {
 			image_unload(raw.image);
 			image_unload(raw.image_icon);
@@ -59,8 +59,8 @@ class SlotMaterial {
 		base_notify_on_next_frame(_next);
 	}
 
-	static delete = (raw: SlotMaterialRaw) => {
-		SlotMaterial.unload(raw);
+	static slot_material_delete = (raw: SlotMaterialRaw) => {
+		SlotMaterial.slot_material_unload(raw);
 		let mpos: i32 = project_materials.indexOf(raw);
 		array_remove(project_materials, this);
 		if (project_materials.length > 0) {

+ 173 - 173
armorpaint/Sources/TabLayers.ts

@@ -1,16 +1,16 @@
 
 class TabLayers {
 
-	static layer_name_edit: i32 = -1;
-	static layer_name_handle: zui_handle_t = zui_handle_create();
-	static show_context_menu: bool = false;
+	static tab_layers_layer_name_edit: i32 = -1;
+	static tab_layers_layer_name_handle: zui_handle_t = zui_handle_create();
+	static tab_layers_show_context_menu: bool = false;
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_layers_draw = (htab: zui_handle_t) => {
 		let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_base_sidebar_mini_w;
-		mini ? TabLayers.draw_mini(htab) : TabLayers.draw_full(htab);
+		mini ? TabLayers.tab_layers_draw_mini(htab) : TabLayers.tab_layers_draw_full(htab);
 	}
 
-	static draw_mini = (htab: zui_handle_t) => {
+	static tab_layers_draw_mini = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		zui_set_hovered_tab_name(tr("Layers"));
 
@@ -20,38 +20,38 @@ class TabLayers {
 		zui_begin_sticky();
 		zui_separator(5);
 
-		TabLayers.combo_filter();
-		TabLayers.button_2d_view();
-		TabLayers.button_new("+");
+		TabLayers.tab_layers_combo_filter();
+		TabLayers.tab_layers_button_2d_view();
+		TabLayers.tab_layers_button_new("+");
 
 		zui_end_sticky();
 		ui._y += 2;
 
-		TabLayers.highlight_odd_lines();
-		TabLayers.draw_slots(true);
+		TabLayers.tab_layers_highlight_odd_lines();
+		TabLayers.tab_layers_draw_slots(true);
 
 		ui.t.ELEMENT_H = _ELEMENT_H;
 	}
 
-	static draw_full = (htab: zui_handle_t) => {
+	static tab_layers_draw_full = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		if (zui_tab(htab, tr("Layers"))) {
 			zui_begin_sticky();
 			zui_row([1 / 4, 1 / 4, 1 / 2]);
 
-			TabLayers.button_new(tr("New"));
-			TabLayers.button_2d_view();
-			TabLayers.combo_filter();
+			TabLayers.tab_layers_button_new(tr("New"));
+			TabLayers.tab_layers_button_2d_view();
+			TabLayers.tab_layers_combo_filter();
 
 			zui_end_sticky();
 			ui._y += 2;
 
-			TabLayers.highlight_odd_lines();
-			TabLayers.draw_slots(false);
+			TabLayers.tab_layers_highlight_odd_lines();
+			TabLayers.tab_layers_draw_slots(false);
 		}
 	}
 
-	static button_2d_view = () => {
+	static tab_layers_button_2d_view = () => {
 		let ui: zui_t = ui_base_ui;
 		if (zui_button(tr("2D View"))) {
 			ui_base_show_2d_view(view_2d_type_t.LAYER);
@@ -59,16 +59,16 @@ class TabLayers {
 		else if (ui.is_hovered) zui_tooltip(tr("Show 2D View") + ` (${config_keymap.toggle_2d_view})`);
 	}
 
-	static draw_slots = (mini: bool) => {
+	static tab_layers_draw_slots = (mini: bool) => {
 		for (let i: i32 = 0; i < project_layers.length; ++i) {
 			if (i >= project_layers.length) break; // Layer was deleted
 			let j: i32 = project_layers.length - 1 - i;
 			let l: SlotLayerRaw = project_layers[j];
-			TabLayers.draw_layer_slot(l, j, mini);
+			TabLayers.tab_layers_draw_layer_slot(l, j, mini);
 		}
 	}
 
-	static highlight_odd_lines = () => {
+	static tab_layers_highlight_odd_lines = () => {
 		let ui: zui_t = ui_base_ui;
 		let step: i32 = ui.t.ELEMENT_H * 2;
 		let full_h: i32 = ui._window_h - ui_base_hwnds[0].scroll_offset;
@@ -79,7 +79,7 @@ class TabLayers {
 		}
 	}
 
-	static button_new = (text: string) => {
+	static tab_layers_button_new = (text: string) => {
 		if (zui_button(text)) {
 			ui_menu_draw((ui: zui_t) => {
 				let l: SlotLayerRaw = context_raw.layer;
@@ -94,12 +94,12 @@ class TabLayers {
 					base_create_fill_layer(uv_type_t.PROJECT);
 				}
 				if (ui_menu_button(ui, tr("Black Mask"))) {
-					if (SlotLayer.is_mask(l)) context_set_layer(l.parent);
+					if (SlotLayer.slot_layer_is_mask(l)) context_set_layer(l.parent);
 					// let l: SlotLayerRaw = raw.layer;
 
 					let m: SlotLayerRaw = base_new_mask(false, l);
 					let _next = () => {
-						SlotLayer.clear(m, 0x00000000);
+						SlotLayer.slot_layer_clear(m, 0x00000000);
 					}
 					base_notify_on_next_frame(_next);
 					context_raw.layer_preview_dirty = true;
@@ -107,12 +107,12 @@ class TabLayers {
 					base_update_fill_layers();
 				}
 				if (ui_menu_button(ui, tr("White Mask"))) {
-					if (SlotLayer.is_mask(l)) context_set_layer(l.parent);
+					if (SlotLayer.slot_layer_is_mask(l)) context_set_layer(l.parent);
 					// let l: SlotLayerRaw = raw.layer;
 
 					let m: SlotLayerRaw = base_new_mask(false, l);
 					let _next = () => {
-						SlotLayer.clear(m, 0xffffffff);
+						SlotLayer.slot_layer_clear(m, 0xffffffff);
 					}
 					base_notify_on_next_frame(_next);
 					context_raw.layer_preview_dirty = true;
@@ -120,31 +120,31 @@ class TabLayers {
 					base_update_fill_layers();
 				}
 				if (ui_menu_button(ui, tr("Fill Mask"))) {
-					if (SlotLayer.is_mask(l)) context_set_layer(l.parent);
+					if (SlotLayer.slot_layer_is_mask(l)) context_set_layer(l.parent);
 					// let l: SlotLayerRaw = raw.layer;
 
 					let m: SlotLayerRaw = base_new_mask(false, l);
 					let _init = () => {
-						SlotLayer.to_fill_layer(m);
+						SlotLayer.slot_layer_to_fill_layer(m);
 					}
 					app_notify_on_init(_init);
 					context_raw.layer_preview_dirty = true;
 					history_new_fill_mask();
 					base_update_fill_layers();
 				}
-				ui.enabled = !SlotLayer.is_group(context_raw.layer) && !SlotLayer.is_in_group(context_raw.layer);
+				ui.enabled = !SlotLayer.slot_layer_is_group(context_raw.layer) && !SlotLayer.slot_layer_is_in_group(context_raw.layer);
 				if (ui_menu_button(ui, tr("Group"))) {
-					if (SlotLayer.is_group(l) || SlotLayer.is_in_group(l)) return;
+					if (SlotLayer.slot_layer_is_group(l) || SlotLayer.slot_layer_is_in_group(l)) return;
 
-					if (SlotLayer.is_layer_mask(l)) l = l.parent;
+					if (SlotLayer.slot_layer_is_layer_mask(l)) l = l.parent;
 
-					let pointers: map_t<SlotLayerRaw, i32> = TabLayers.init_layer_map();
+					let pointers: map_t<SlotLayerRaw, i32> = TabLayers.tab_layers_init_layer_map();
 					let group = base_new_group();
 					context_set_layer(l);
 					array_remove(project_layers, group);
 					project_layers.splice(project_layers.indexOf(l) + 1, 0, group);
 					l.parent = group;
-					for (let m of project_materials) TabLayers.remap_layer_pointers(m.canvas.nodes, TabLayers.fill_layer_map(pointers));
+					for (let m of project_materials) TabLayers.tab_layers_remap_layer_pointers(m.canvas.nodes, TabLayers.tab_layers_fill_layer_map(pointers));
 					context_set_layer(group);
 					history_new_group();
 				}
@@ -153,7 +153,7 @@ class TabLayers {
 		}
 	}
 
-	static combo_filter = () => {
+	static tab_layers_combo_filter = () => {
 		let ar: string[] = [tr("All")];
 		for (let p of project_paint_objects) ar.push(p.base.name);
 		let atlases: string[] = project_get_used_atlases();
@@ -177,47 +177,47 @@ class TabLayers {
 			util_uv_uvmap_cached = false;
 			context_raw.ddirty = 2;
 			///if (krom_direct3d12 || krom_vulkan || krom_metal)
-			RenderPathRaytrace.ready = false;
+			render_path_raytrace_ready = false;
 			///end
 		}
 	}
 
-	static remap_layer_pointers = (nodes: zui_node_t[], pointerMap: map_t<i32, i32>) => {
+	static tab_layers_remap_layer_pointers = (nodes: zui_node_t[], pointer_map: map_t<i32, i32>) => {
 		for (let n of nodes) {
 			if (n.type == "LAYER" || n.type == "LAYER_MASK") {
 				let i: any = n.buttons[0].default_value;
-				if (pointerMap.has(i)) {
-					n.buttons[0].default_value = pointerMap.get(i);
+				if (pointer_map.has(i)) {
+					n.buttons[0].default_value = pointer_map.get(i);
 				}
 			}
 		}
 	}
 
-	static init_layer_map = (): map_t<SlotLayerRaw, i32> => {
+	static tab_layers_init_layer_map = (): map_t<SlotLayerRaw, i32> => {
 		let res: map_t<SlotLayerRaw, i32> = map_create();
 		for (let i: i32 = 0; i < project_layers.length; ++i) res.set(project_layers[i], i);
 		return res;
 	}
 
-	static fill_layer_map = (map: map_t<SlotLayerRaw, i32>): map_t<i32, i32> => {
+	static tab_layers_fill_layer_map = (map: map_t<SlotLayerRaw, i32>): map_t<i32, i32> => {
 		let res: map_t<i32, i32> = map_create();
 		for (let l of map.keys()) res.set(map.get(l), project_layers.indexOf(l) > -1 ? project_layers.indexOf(l) : 9999);
 		return res;
 	}
 
-	static set_drag_layer = (layer: SlotLayerRaw, offX: f32, offY: f32) => {
-		base_drag_off_x = offX;
-		base_drag_off_y = offY;
+	static tab_layers_set_drag_layer = (layer: SlotLayerRaw, off_x: f32, off_y: f32) => {
+		base_drag_off_x = off_x;
+		base_drag_off_y = off_y;
 		base_drag_layer = layer;
 		context_raw.drag_dest = project_layers.indexOf(layer);
 	}
 
-	static draw_layer_slot = (l: SlotLayerRaw, i: i32, mini: bool) => {
+	static tab_layers_draw_layer_slot = (l: SlotLayerRaw, i: i32, mini: bool) => {
 		let ui: zui_t = ui_base_ui;
 
 		if (context_raw.layer_filter > 0 &&
-			SlotLayer.get_object_mask(l) > 0 &&
-			SlotLayer.get_object_mask(l) != context_raw.layer_filter) {
+			SlotLayer.slot_layer_get_object_mask(l) > 0 &&
+			SlotLayer.slot_layer_get_object_mask(l) != context_raw.layer_filter) {
 			return;
 		}
 
@@ -241,16 +241,16 @@ class TabLayers {
 				let ls: SlotLayerRaw[] = project_layers;
 				let dest: i32 = context_raw.drag_dest;
 				let to_group: bool = down ? dest > 0 && ls[dest - 1].parent != null && ls[dest - 1].parent.show_panel : dest < ls.length && ls[dest].parent != null && ls[dest].parent.show_panel;
-				let nested_group: bool = SlotLayer.is_group(base_drag_layer) && to_group;
+				let nested_group: bool = SlotLayer.slot_layer_is_group(base_drag_layer) && to_group;
 				if (!nested_group) {
-					if (SlotLayer.can_move(context_raw.layer, context_raw.drag_dest)) {
+					if (SlotLayer.slot_layer_can_move(context_raw.layer, context_raw.drag_dest)) {
 						zui_fill(checkw, step * 2, (ui._window_w / zui_SCALE(ui) - 2) - checkw, 2 * zui_SCALE(ui), ui.t.HIGHLIGHT_COL);
 					}
 				}
 			}
 			else if (i == project_layers.length - 1 && mouse_y < absy + step) {
 				context_raw.drag_dest = project_layers.length - 1;
-				if (SlotLayer.can_move(context_raw.layer, context_raw.drag_dest)) {
+				if (SlotLayer.slot_layer_can_move(context_raw.layer, context_raw.drag_dest)) {
 					zui_fill(checkw, 0, (ui._window_w / zui_SCALE(ui) - 2) - checkw, 2 * zui_SCALE(ui), ui.t.HIGHLIGHT_COL);
 				}
 			}
@@ -258,45 +258,45 @@ class TabLayers {
 		if (base_is_dragging && (base_drag_material != null || base_drag_swatch != null) && context_in_layers()) {
 			if (mouse_y > absy + step && mouse_y < absy + step * 3) {
 				context_raw.drag_dest = i;
-				if (TabLayers.can_drop_new_layer(i))
+				if (TabLayers.tab_layers_can_drop_new_layer(i))
 					zui_fill(checkw, 2 * step, (ui._window_w / zui_SCALE(ui) - 2) - checkw, 2 * zui_SCALE(ui), ui.t.HIGHLIGHT_COL);
 			}
 			else if (i == project_layers.length - 1 && mouse_y < absy + step) {
 				context_raw.drag_dest = project_layers.length;
-				if (TabLayers.can_drop_new_layer(project_layers.length))
+				if (TabLayers.tab_layers_can_drop_new_layer(project_layers.length))
 					zui_fill(checkw, 0, (ui._window_w / zui_SCALE(ui) - 2) - checkw, 2 * zui_SCALE(ui), ui.t.HIGHLIGHT_COL);
 			}
 		}
 
-		mini ? TabLayers.draw_layer_slot_mini(l, i) : TabLayers.draw_layer_slot_full(l, i);
+		mini ? TabLayers.tab_layers_draw_layer_slot_mini(l, i) : TabLayers.tab_layers_draw_layer_slot_full(l, i);
 
-		TabLayers.draw_layer_highlight(l, mini);
+		TabLayers.tab_layers_draw_layer_highlight(l, mini);
 
-		if (TabLayers.show_context_menu) {
-			TabLayers.draw_layer_context_menu(l, mini);
+		if (TabLayers.tab_layers_show_context_menu) {
+			TabLayers.tab_layers_draw_layer_context_menu(l, mini);
 		}
 	}
 
-	static draw_layer_slot_mini = (l: SlotLayerRaw, i: i32) => {
+	static tab_layers_draw_layer_slot_mini = (l: SlotLayerRaw, i: i32) => {
 		let ui = ui_base_ui;
 
 		zui_row([1, 1]);
 		let uix: f32 = ui._x;
 		let uiy: f32 = ui._y;
-		let state: zui_state_t = TabLayers.draw_layer_icon(l, i, uix, uiy, true);
-		TabLayers.handle_layer_icon_state(l, i, state, uix, uiy);
+		let state: zui_state_t = TabLayers.tab_layers_draw_layer_icon(l, i, uix, uiy, true);
+		TabLayers.tab_layers_handle_layer_icon_state(l, i, state, uix, uiy);
 		zui_end_element();
 
 		ui._y += zui_ELEMENT_H(ui);
 		ui._y -= zui_ELEMENT_OFFSET(ui);
 	}
 
-	static draw_layer_slot_full = (l: SlotLayerRaw, i: i32) => {
+	static tab_layers_draw_layer_slot_full = (l: SlotLayerRaw, i: i32) => {
 		let ui: zui_t = ui_base_ui;
 
 		let step: i32 = ui.t.ELEMENT_H;
 
-		let has_panel: bool = SlotLayer.is_group(l) || (SlotLayer.is_layer(l) && SlotLayer.get_masks(l, false) != null);
+		let has_panel: bool = SlotLayer.slot_layer_is_group(l) || (SlotLayer.slot_layer_is_layer(l) && SlotLayer.slot_layer_get_masks(l, false) != null);
 		if (has_panel) {
 			zui_row([8 / 100, 16 / 100, 36 / 100, 30 / 100, 10 / 100]);
 		}
@@ -316,7 +316,7 @@ class TabLayers {
 		if (parent_hidden) col -= 0x99000000;
 
 		if (zui_image(icons, col, -1.0, r.x, r.y, r.w, r.h) == zui_state_t.RELEASED) {
-			TabLayers.layer_toggle_visible(l);
+			TabLayers.tab_layers_layer_toggle_visible(l);
 		}
 		ui._x -= 2;
 		ui._y -= 3;
@@ -335,7 +335,7 @@ class TabLayers {
 			if (l.parent.parent != null) ui._x += 10 * zui_SCALE(ui);
 		}
 
-		let state: zui_state_t = TabLayers.draw_layer_icon(l, i, uix, uiy, false);
+		let state: zui_state_t = TabLayers.tab_layers_draw_layer_icon(l, i, uix, uiy, false);
 
 		ui._x -= 2;
 		ui._y -= 3;
@@ -348,14 +348,14 @@ class TabLayers {
 		ui.image_invert_y = false;
 		///end
 
-		TabLayers.handle_layer_icon_state(l, i, state, uix, uiy);
+		TabLayers.tab_layers_handle_layer_icon_state(l, i, state, uix, uiy);
 
 		// Draw layer name
 		ui._y += center;
-		if (TabLayers.layer_name_edit == l.id) {
-			TabLayers.layer_name_handle.text = l.name;
-			l.name = zui_text_input(TabLayers.layer_name_handle);
-			if (ui.text_selected_handle_ptr != TabLayers.layer_name_handle.ptr) TabLayers.layer_name_edit = -1;
+		if (TabLayers.tab_layers_layer_name_edit == l.id) {
+			TabLayers.tab_layers_layer_name_handle.text = l.name;
+			l.name = zui_text_input(TabLayers.tab_layers_layer_name_handle);
+			if (ui.text_selected_handle_ptr != TabLayers.tab_layers_layer_name_handle.ptr) TabLayers.tab_layers_layer_name_edit = -1;
 		}
 		else {
 			if (ui.enabled && ui.input_enabled && ui.combo_selected_handle_ptr == 0 &&
@@ -363,30 +363,30 @@ class TabLayers {
 				ui.input_y > ui._window_y + ui._y - center && ui.input_y < ui._window_y + ui._y - center + (step * zui_SCALE(ui)) * 2) {
 				if (ui.input_started) {
 					context_set_layer(l);
-					TabLayers.set_drag_layer(context_raw.layer, -(mouse_x - uix - ui._window_x - 3), -(mouse_y - uiy - ui._window_y + 1));
+					TabLayers.tab_layers_set_drag_layer(context_raw.layer, -(mouse_x - uix - ui._window_x - 3), -(mouse_y - uiy - ui._window_y + 1));
 				}
 				else if (ui.input_released_r) {
 					context_set_layer(l);
-					TabLayers.show_context_menu = true;
+					TabLayers.tab_layers_show_context_menu = true;
 				}
 			}
 
 			let state: zui_state_t = zui_text(l.name);
 			if (state == zui_state_t.RELEASED) {
 				if (time_time() - context_raw.select_time < 0.25) {
-					TabLayers.layer_name_edit = l.id;
-					TabLayers.layer_name_handle.text = l.name;
-					zui_start_text_edit(TabLayers.layer_name_handle);
+					TabLayers.tab_layers_layer_name_edit = l.id;
+					TabLayers.tab_layers_layer_name_handle.text = l.name;
+					zui_start_text_edit(TabLayers.tab_layers_layer_name_handle);
 				}
 				context_raw.select_time = time_time();
 			}
 
 			let in_focus: bool = ui.input_x > ui._window_x && ui.input_x < ui._window_x + ui._window_w &&
 						  		 ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
-			if (in_focus && ui.is_delete_down && TabLayers.can_delete(context_raw.layer)) {
+			if (in_focus && ui.is_delete_down && TabLayers.tab_layers_can_delete(context_raw.layer)) {
 				ui.is_delete_down = false;
 				let _init = () => {
-					TabLayers.delete_layer(context_raw.layer);
+					TabLayers.tab_layers_delete_layer(context_raw.layer);
 				}
 				app_notify_on_init(_init);
 			}
@@ -398,17 +398,17 @@ class TabLayers {
 			if (l.parent.parent != null) ui._x -= 10 * zui_SCALE(ui);
 		}
 
-		if (SlotLayer.is_group(l)) {
+		if (SlotLayer.slot_layer_is_group(l)) {
 			zui_end_element();
 		}
 		else {
-			if (SlotLayer.is_mask(l)) {
+			if (SlotLayer.slot_layer_is_mask(l)) {
 				ui._y += center;
 			}
 
-			TabLayers.combo_blending(ui, l);
+			TabLayers.tab_layers_combo_blending(ui, l);
 
-			if (SlotLayer.is_mask(l)) {
+			if (SlotLayer.slot_layer_is_mask(l)) {
 				ui._y -= center;
 			}
 		}
@@ -421,7 +421,7 @@ class TabLayers {
 			ui._y -= center;
 		}
 
-		if (SlotLayer.is_group(l) || SlotLayer.is_mask(l)) {
+		if (SlotLayer.slot_layer_is_group(l) || SlotLayer.slot_layer_is_mask(l)) {
 			ui._y -= zui_ELEMENT_OFFSET(ui);
 			zui_end_element();
 		}
@@ -437,14 +437,14 @@ class TabLayers {
 				ui._x += 12 * zui_SCALE(ui);
 			}
 
-			TabLayers.combo_object(ui, l);
+			TabLayers.tab_layers_combo_object(ui, l);
 			zui_end_element();
 		}
 
 		ui._y -= zui_ELEMENT_OFFSET(ui);
 	}
 
-	static combo_object = (ui: zui_t, l: SlotLayerRaw, label = false): zui_handle_t => {
+	static tab_layers_combo_object = (ui: zui_t, l: SlotLayerRaw, label = false): zui_handle_t => {
 		let ar: string[] = [tr("Shared")];
 		for (let p of project_paint_objects) ar.push(p.base.name);
 		let atlases: string[] = project_get_used_atlases();
@@ -454,11 +454,11 @@ class TabLayers {
 		l.object_mask = zui_combo(object_handle, ar, tr("Object"), label, zui_align_t.LEFT);
 		if (object_handle.changed) {
 			context_set_layer(l);
-			MakeMaterial.parse_mesh_material();
+			MakeMaterial.make_material_parse_mesh_material();
 			if (l.fill_layer != null) { // Fill layer
 				let _init = () => {
 					context_raw.material = l.fill_layer;
-					SlotLayer.clear(l);
+					SlotLayer.slot_layer_clear(l);
 					base_update_fill_layers();
 				}
 				app_notify_on_init(_init);
@@ -470,7 +470,7 @@ class TabLayers {
 		return object_handle;
 	}
 
-	static combo_blending = (ui: zui_t, l: SlotLayerRaw, label = false): zui_handle_t => {
+	static tab_layers_combo_blending = (ui: zui_t, l: SlotLayerRaw, label = false): zui_handle_t => {
 		let blending_handle: zui_handle_t = zui_nest(zui_handle("tablayers_3"), l.id);
 		blending_handle.position = l.blending;
 		zui_combo(blending_handle, [
@@ -497,18 +497,18 @@ class TabLayers {
 			context_set_layer(l);
 			history_layer_blending();
 			l.blending = blending_handle.position;
-			MakeMaterial.parse_mesh_material();
+			MakeMaterial.make_material_parse_mesh_material();
 		}
 		return blending_handle;
 	}
 
-	static layer_toggle_visible = (l: SlotLayerRaw) => {
+	static tab_layers_layer_toggle_visible = (l: SlotLayerRaw) => {
 		l.visible = !l.visible;
 		ui_view2d_hwnd.redraws = 2;
-		MakeMaterial.parse_mesh_material();
+		MakeMaterial.make_material_parse_mesh_material();
 	}
 
-	static draw_layer_highlight = (l: SlotLayerRaw, mini: bool) => {
+	static tab_layers_draw_layer_highlight = (l: SlotLayerRaw, mini: bool) => {
 		let ui: zui_t = ui_base_ui;
 		let step: i32 = ui.t.ELEMENT_H;
 
@@ -526,7 +526,7 @@ class TabLayers {
 		}
 	}
 
-	static handle_layer_icon_state = (l: SlotLayerRaw, i: i32, state: zui_state_t, uix: f32, uiy: f32) => {
+	static tab_layers_handle_layer_icon_state = (l: SlotLayerRaw, i: i32, state: zui_state_t, uix: f32, uiy: f32) => {
 		let ui: zui_t = ui_base_ui;
 
 		///if is_paint
@@ -536,12 +536,12 @@ class TabLayers {
 		let texpaint_preview: image_t = l.texpaint;
 		///end
 
-		TabLayers.show_context_menu = false;
+		TabLayers.tab_layers_show_context_menu = false;
 
 		// Layer preview tooltip
 		if (ui.is_hovered && texpaint_preview != null) {
-			if (SlotLayer.is_mask(l)) {
-				TabLayers.make_mask_preview_rgba32(l);
+			if (SlotLayer.slot_layer_is_mask(l)) {
+				TabLayers.tab_layers_make_mask_preview_rgba32(l);
 				zui_tooltip_image(context_raw.mask_preview_rgba32);
 			}
 			else {
@@ -554,12 +554,12 @@ class TabLayers {
 		// Show context menu
 		if (ui.is_hovered && ui.input_released_r) {
 			context_set_layer(l);
-			TabLayers.show_context_menu = true;
+			TabLayers.tab_layers_show_context_menu = true;
 		}
 
 		if (state == zui_state_t.STARTED) {
 			context_set_layer(l);
-			TabLayers.set_drag_layer(context_raw.layer, -(mouse_x - uix - ui._window_x - 3), -(mouse_y - uiy - ui._window_y + 1));
+			TabLayers.tab_layers_set_drag_layer(context_raw.layer, -(mouse_x - uix - ui._window_x - 3), -(mouse_y - uiy - ui._window_y + 1));
 		}
 		else if (state == zui_state_t.RELEASED) {
 			if (time_time() - context_raw.select_time < 0.2) {
@@ -572,7 +572,7 @@ class TabLayers {
 		}
 	}
 
-	static draw_layer_icon = (l: SlotLayerRaw, i: i32, uix: f32, uiy: f32, mini: bool) => {
+	static tab_layers_draw_layer_icon = (l: SlotLayerRaw, i: i32, uix: f32, uiy: f32, mini: bool) => {
 		let ui: zui_t = ui_base_ui;
 		let icons: image_t = resource_get("icons.k");
 		let icon_h: i32 = (zui_ELEMENT_H(ui) - (mini ? 2 : 3)) * 2;
@@ -590,7 +590,7 @@ class TabLayers {
 			}
 		}
 
-		if (!SlotLayer.is_group(l)) {
+		if (!SlotLayer.slot_layer_is_group(l)) {
 			///if is_paint
 			let texpaint_preview: image_t = l.texpaint_preview;
 			///end
@@ -611,7 +611,7 @@ class TabLayers {
 				ui._y = _y;
 				ui._w = _w;
 			}
-			if (l.fill_layer == null && SlotLayer.is_mask(l)) {
+			if (l.fill_layer == null && SlotLayer.slot_layer_is_mask(l)) {
 				g2_set_pipeline(ui_view2d_pipe);
 				///if krom_opengl
 				krom_g4_set_pipeline(ui_view2d_pipe.pipeline_);
@@ -621,7 +621,7 @@ class TabLayers {
 
 			let state: zui_state_t = zui_image(icon, 0xffffffff, icon_h);
 
-			if (l.fill_layer == null && SlotLayer.is_mask(l)) {
+			if (l.fill_layer == null && SlotLayer.slot_layer_is_mask(l)) {
 				g2_set_pipeline(null);
 			}
 
@@ -649,32 +649,32 @@ class TabLayers {
 		}
 	}
 
-	static can_merge_down = (l: SlotLayerRaw) : bool => {
+	static tab_layers_can_merge_down = (l: SlotLayerRaw) : bool => {
 		let index: i32 = project_layers.indexOf(l);
 		// Lowest layer
 		if (index == 0) return false;
 		// Lowest layer that has masks
-		if (SlotLayer.is_layer(l) && SlotLayer.is_mask(project_layers[0]) && project_layers[0].parent == l) return false;
+		if (SlotLayer.slot_layer_is_layer(l) && SlotLayer.slot_layer_is_mask(project_layers[0]) && project_layers[0].parent == l) return false;
 		// The lowest toplevel layer is a group
-		if (SlotLayer.is_group(l) && SlotLayer.is_in_group(project_layers[0]) && SlotLayer.get_containing_group(project_layers[0]) == l) return false;
+		if (SlotLayer.slot_layer_is_group(l) && SlotLayer.slot_layer_is_in_group(project_layers[0]) && SlotLayer.slot_layer_get_containing_group(project_layers[0]) == l) return false;
 		// Masks must be merged down to masks
-		if (SlotLayer.is_mask(l) && !SlotLayer.is_mask(project_layers[index - 1])) return false;
+		if (SlotLayer.slot_layer_is_mask(l) && !SlotLayer.slot_layer_is_mask(project_layers[index - 1])) return false;
 		return true;
 	}
 
-	static draw_layer_context_menu = (l: SlotLayerRaw, mini: bool) => {
+	static tab_layers_draw_layer_context_menu = (l: SlotLayerRaw, mini: bool) => {
 		let add: i32 = 0;
 
 		if (l.fill_layer == null) add += 1; // Clear
-		if (l.fill_layer != null && !SlotLayer.is_mask(l)) add += 3;
-		if (l.fill_layer != null && SlotLayer.is_mask(l)) add += 2;
-		if (SlotLayer.is_mask(l)) add += 2;
+		if (l.fill_layer != null && !SlotLayer.slot_layer_is_mask(l)) add += 3;
+		if (l.fill_layer != null && SlotLayer.slot_layer_is_mask(l)) add += 2;
+		if (SlotLayer.slot_layer_is_mask(l)) add += 2;
 		if (mini) {
 			add += 1;
-			if (!SlotLayer.is_group(l)) add += 1;
-			if (SlotLayer.is_layer(l)) add += 1;
+			if (!SlotLayer.slot_layer_is_group(l)) add += 1;
+			if (SlotLayer.slot_layer_is_layer(l)) add += 1;
 		}
-		let menu_elements: i32 = SlotLayer.is_group(l) ? 7 : (19 + add);
+		let menu_elements: i32 = SlotLayer.slot_layer_is_group(l) ? 7 : (19 + add);
 
 		ui_menu_draw((ui: zui_t) => {
 
@@ -684,26 +684,26 @@ class TabLayers {
 				ui_menu_fill(ui);
 				zui_check(visible_handle, tr("Visible"));
 				if (visible_handle.changed) {
-					TabLayers.layer_toggle_visible(l);
+					TabLayers.tab_layers_layer_toggle_visible(l);
 					ui_menu_keep_open = true;
 				}
 
-				if (!SlotLayer.is_group(l)) {
+				if (!SlotLayer.slot_layer_is_group(l)) {
 					ui_menu_fill(ui);
-					if (TabLayers.combo_blending(ui, l, true).changed) {
+					if (TabLayers.tab_layers_combo_blending(ui, l, true).changed) {
 						ui_menu_keep_open = true;
 					}
 				}
-				if (SlotLayer.is_layer(l)) {
+				if (SlotLayer.slot_layer_is_layer(l)) {
 					ui_menu_fill(ui);
-					if (TabLayers.combo_object(ui, l, true).changed) {
+					if (TabLayers.tab_layers_combo_object(ui, l, true).changed) {
 						ui_menu_keep_open = true;
 					}
 				}
 			}
 
 			if (ui_menu_button(ui, tr("Export"))) {
-				if (SlotLayer.is_mask(l)) {
+				if (SlotLayer.slot_layer_is_mask(l)) {
 					ui_files_show("png", true, false, (path: string) => {
 						let f: string = ui_files_filename;
 						if (f == "") f = tr("untitled");
@@ -714,35 +714,35 @@ class TabLayers {
 				else {
 					///if is_paint
 					context_raw.layers_export = export_mode_t.SELECTED;
-					BoxExport.show_textures();
+					box_export_show_textures();
 					///end
 				}
 			}
 
-			if (!SlotLayer.is_group(l)) {
-				let to_fill_string: string = SlotLayer.is_layer(l) ? tr("To Fill Layer") : tr("To Fill Mask");
-				let to_paint_string: string = SlotLayer.is_layer(l) ? tr("To Paint Layer") : tr("To Paint Mask");
+			if (!SlotLayer.slot_layer_is_group(l)) {
+				let to_fill_string: string = SlotLayer.slot_layer_is_layer(l) ? tr("To Fill Layer") : tr("To Fill Mask");
+				let to_paint_string: string = SlotLayer.slot_layer_is_layer(l) ? tr("To Paint Layer") : tr("To Paint Mask");
 
 				if (l.fill_layer == null && ui_menu_button(ui, to_fill_string)) {
 					let _init = () => {
-						SlotLayer.is_layer(l) ? history_to_fill_layer() : history_to_fill_mask();
-						SlotLayer.to_fill_layer(l);
+						SlotLayer.slot_layer_is_layer(l) ? history_to_fill_layer() : history_to_fill_mask();
+						SlotLayer.slot_layer_to_fill_layer(l);
 					}
 					app_notify_on_init(_init);
 				}
 				if (l.fill_layer != null && ui_menu_button(ui, to_paint_string)) {
 					let _init = () => {
-						SlotLayer.is_layer(l) ? history_to_paint_layer() : history_to_paint_mask();
-						SlotLayer.to_paint_layer(l);
+						SlotLayer.slot_layer_is_layer(l) ? history_to_paint_layer() : history_to_paint_mask();
+						SlotLayer.slot_layer_to_paint_layer(l);
 					}
 					app_notify_on_init(_init);
 				}
 			}
 
-			ui.enabled = TabLayers.can_delete(l);
+			ui.enabled = TabLayers.tab_layers_can_delete(l);
 			if (ui_menu_button(ui, tr("Delete"), "delete")) {
 				let _init = () => {
-					TabLayers.delete_layer(context_raw.layer);
+					TabLayers.tab_layers_delete_layer(context_raw.layer);
 				}
 				app_notify_on_init(_init);
 			}
@@ -751,15 +751,15 @@ class TabLayers {
 			if (l.fill_layer == null && ui_menu_button(ui, tr("Clear"))) {
 				context_set_layer(l);
 				let _init = () => {
-					if (!SlotLayer.is_group(l)) {
+					if (!SlotLayer.slot_layer_is_group(l)) {
 						history_clear_layer();
-						SlotLayer.clear(l);
+						SlotLayer.slot_layer_clear(l);
 					}
 					else {
-						for (let c of SlotLayer.get_children(l)) {
+						for (let c of SlotLayer.slot_layer_get_children(l)) {
 							context_raw.layer = c;
 							history_clear_layer();
-							SlotLayer.clear(c);
+							SlotLayer.slot_layer_clear(c);
 						}
 						context_raw.layers_preview_dirty = true;
 						context_raw.layer = l;
@@ -767,38 +767,38 @@ class TabLayers {
 				}
 				app_notify_on_init(_init);
 			}
-			if (SlotLayer.is_mask(l) && l.fill_layer == null && ui_menu_button(ui, tr("Invert"))) {
+			if (SlotLayer.slot_layer_is_mask(l) && l.fill_layer == null && ui_menu_button(ui, tr("Invert"))) {
 				let _init = () => {
 					context_set_layer(l);
 					history_invert_mask();
-					SlotLayer.invert_mask(l);
+					SlotLayer.slot_layer_invert_mask(l);
 				}
 				app_notify_on_init(_init);
 			}
-			if (SlotLayer.is_mask(l) && ui_menu_button(ui, tr("Apply"))) {
+			if (SlotLayer.slot_layer_is_mask(l) && ui_menu_button(ui, tr("Apply"))) {
 				let _init = () => {
 					context_raw.layer = l;
 					history_apply_mask();
-					SlotLayer.apply_mask(l);
+					SlotLayer.slot_layer_apply_mask(l);
 					context_set_layer(l.parent);
-					MakeMaterial.parse_mesh_material();
+					MakeMaterial.make_material_parse_mesh_material();
 					context_raw.layers_preview_dirty = true;
 				}
 				app_notify_on_init(_init);
 			}
-			if (SlotLayer.is_group(l) && ui_menu_button(ui, tr("Merge Group"))) {
+			if (SlotLayer.slot_layer_is_group(l) && ui_menu_button(ui, tr("Merge Group"))) {
 				let _init = () => {
 					base_merge_group(l);
 				}
 				app_notify_on_init(_init);
 			}
-			ui.enabled = TabLayers.can_merge_down(l);
+			ui.enabled = TabLayers.tab_layers_can_merge_down(l);
 			if (ui_menu_button(ui, tr("Merge Down"))) {
 				let _init = () => {
 					context_set_layer(l);
 					history_merge_layers();
 					base_merge_down();
-					if (context_raw.layer.fill_layer != null) SlotLayer.to_paint_layer(context_raw.layer);
+					if (context_raw.layer.fill_layer != null) SlotLayer.slot_layer_to_paint_layer(context_raw.layer);
 				}
 				app_notify_on_init(_init);
 			}
@@ -820,11 +820,11 @@ class TabLayers {
 			if (layer_opac_handle.changed) {
 				if (ui.input_started) history_layer_opacity();
 				l.mask_opacity = layer_opac_handle.value;
-				MakeMaterial.parse_mesh_material();
+				MakeMaterial.make_material_parse_mesh_material();
 				ui_menu_keep_open = true;
 			}
 
-			if (!SlotLayer.is_group(l)) {
+			if (!SlotLayer.slot_layer_is_group(l)) {
 				ui_menu_fill(ui);
 				ui_menu_align(ui);
 				let res_handle_changed_last: bool = base_res_handle.changed;
@@ -883,7 +883,7 @@ class TabLayers {
 				if (angle_handle.changed) {
 					context_set_material(l.fill_layer);
 					context_set_layer(l);
-					MakeMaterial.parse_paint_material();
+					MakeMaterial.make_material_parse_paint_material();
 					let _init = () => {
 						base_update_fill_layers();
 					}
@@ -899,7 +899,7 @@ class TabLayers {
 				if (uv_type_handle.changed) {
 					context_set_material(l.fill_layer);
 					context_set_layer(l);
-					MakeMaterial.parse_paint_material();
+					MakeMaterial.make_material_parse_paint_material();
 					let _init = () => {
 						base_update_fill_layers();
 					}
@@ -908,7 +908,7 @@ class TabLayers {
 				}
 			}
 
-			if (!SlotLayer.is_group(l)) {
+			if (!SlotLayer.slot_layer_is_group(l)) {
 				let base_handle: zui_handle_t = zui_nest(zui_handle("tablayers_9"), l.id);
 				let opac_handle: zui_handle_t = zui_nest(zui_handle("tablayers_10"), l.id);
 				let nor_handle: zui_handle_t = zui_nest(zui_handle("tablayers_11"), l.id);
@@ -964,14 +964,14 @@ class TabLayers {
 					height_blend_handle.changed ||
 					emis_handle.changed ||
 					subs_handle.changed) {
-					MakeMaterial.parse_mesh_material();
+					MakeMaterial.make_material_parse_mesh_material();
 					ui_menu_keep_open = true;
 				}
 			}
 		}, menu_elements);
 	}
 
-	static make_mask_preview_rgba32 = (l: SlotLayerRaw) => {
+	static tab_layers_make_mask_preview_rgba32 = (l: SlotLayerRaw) => {
 		///if is_paint
 		if (context_raw.mask_preview_rgba32 == null) {
 			context_raw.mask_preview_rgba32 = image_create_render_target(util_render_layer_preview_size, util_render_layer_preview_size);
@@ -991,84 +991,84 @@ class TabLayers {
 		///end
 	}
 
-	static delete_layer = (l: SlotLayerRaw) => {
-		let pointers: map_t<SlotLayerRaw, i32> = TabLayers.init_layer_map();
+	static tab_layers_delete_layer = (l: SlotLayerRaw) => {
+		let pointers: map_t<SlotLayerRaw, i32> = TabLayers.tab_layers_init_layer_map();
 
-		if (SlotLayer.is_layer(l) && SlotLayer.has_masks(l, false)) {
-			for (let m of SlotLayer.get_masks(l, false)) {
+		if (SlotLayer.slot_layer_is_layer(l) && SlotLayer.slot_layer_has_masks(l, false)) {
+			for (let m of SlotLayer.slot_layer_get_masks(l, false)) {
 				context_raw.layer = m;
 				history_delete_layer();
-				SlotLayer.delete(m);
+				SlotLayer.slot_layer_delete(m);
 			}
 		}
-		if (SlotLayer.is_group(l)) {
-			for (let c of SlotLayer.get_children(l)) {
-				if (SlotLayer.has_masks(c, false)) {
-					for (let m of SlotLayer.get_masks(c, false)) {
+		if (SlotLayer.slot_layer_is_group(l)) {
+			for (let c of SlotLayer.slot_layer_get_children(l)) {
+				if (SlotLayer.slot_layer_has_masks(c, false)) {
+					for (let m of SlotLayer.slot_layer_get_masks(c, false)) {
 						context_raw.layer = m;
 						history_delete_layer();
-						SlotLayer.delete(m);
+						SlotLayer.slot_layer_delete(m);
 					}
 				}
 				context_raw.layer = c;
 				history_delete_layer();
-				SlotLayer.delete(c);
+				SlotLayer.slot_layer_delete(c);
 			}
-			if (SlotLayer.has_masks(l)) {
-				for (let m of SlotLayer.get_masks(l)) {
+			if (SlotLayer.slot_layer_has_masks(l)) {
+				for (let m of SlotLayer.slot_layer_get_masks(l)) {
 					context_raw.layer = m;
 					history_delete_layer();
-					SlotLayer.delete(m);
+					SlotLayer.slot_layer_delete(m);
 				}
 			}
 		}
 
 		context_raw.layer = l;
 		history_delete_layer();
-		SlotLayer.delete(l);
+		SlotLayer.slot_layer_delete(l);
 
-		if (SlotLayer.is_mask(l)) {
+		if (SlotLayer.slot_layer_is_mask(l)) {
 			context_raw.layer = l.parent;
 			base_update_fill_layers();
 		}
 
 		// Remove empty group
-		if (SlotLayer.is_in_group(l) && SlotLayer.get_children(SlotLayer.get_containing_group(l)) == null) {
-			let g: SlotLayerRaw = SlotLayer.get_containing_group(l);
+		if (SlotLayer.slot_layer_is_in_group(l) && SlotLayer.slot_layer_get_children(SlotLayer.slot_layer_get_containing_group(l)) == null) {
+			let g: SlotLayerRaw = SlotLayer.slot_layer_get_containing_group(l);
 			// Maybe some group masks are left
-			if (SlotLayer.has_masks(g)) {
-				for (let m of SlotLayer.get_masks(g)) {
+			if (SlotLayer.slot_layer_has_masks(g)) {
+				for (let m of SlotLayer.slot_layer_get_masks(g)) {
 					context_raw.layer = m;
 					history_delete_layer();
-					SlotLayer.delete(m);
+					SlotLayer.slot_layer_delete(m);
 				}
 			}
 			context_raw.layer = l.parent;
 			history_delete_layer();
-			SlotLayer.delete(l.parent);
+			SlotLayer.slot_layer_delete(l.parent);
 		}
 		context_raw.ddirty = 2;
-		for (let m of project_materials) TabLayers.remap_layer_pointers(m.canvas.nodes, TabLayers.fill_layer_map(pointers));
+		for (let m of project_materials) TabLayers.tab_layers_remap_layer_pointers(m.canvas.nodes, TabLayers.tab_layers_fill_layer_map(pointers));
 	}
 
-	static can_delete = (l: SlotLayerRaw) => {
+	static tab_layers_can_delete = (l: SlotLayerRaw) => {
 		let num_layers: i32 = 0;
 
-		if (SlotLayer.is_mask(l)) return true;
+		if (SlotLayer.slot_layer_is_mask(l)) return true;
 
 		for (let slot of project_layers) {
-			if (SlotLayer.is_layer(slot)) ++num_layers;
+			if (SlotLayer.slot_layer_is_layer(slot)) ++num_layers;
 		}
 
 		// All layers are in one group
-		if (SlotLayer.is_group(l) && SlotLayer.get_children(l).length == num_layers) return false;
+		if (SlotLayer.slot_layer_is_group(l) && SlotLayer.slot_layer_get_children(l).length == num_layers) return false;
 
 		// Do not delete last layer
 		return num_layers > 1;
 	}
 
-	static can_drop_new_layer = (position: i32) => {
-		if (position > 0 && position < project_layers.length && SlotLayer.is_mask(project_layers[position - 1])) {
+	static tab_layers_can_drop_new_layer = (position: i32) => {
+		if (position > 0 && position < project_layers.length && SlotLayer.slot_layer_is_mask(project_layers[position - 1])) {
 			// 1. The layer to insert is inserted in the middle
 			// 2. The layer below is a mask, i.e. the layer would have to be a (group) mask, too.
 			return false;

+ 3 - 3
armorpaint/Sources/nodes/BrushOutputNode.ts

@@ -70,7 +70,7 @@ class BrushOutputNode extends LogicNode {
 
 		if (last_mask != context_raw.brush_mask_image ||
 			last_stencil != context_raw.brush_stencil_image) {
-			MakeMaterial.parse_paint_material();
+			MakeMaterial.make_material_parse_paint_material();
 		}
 
 		context_raw.brush_directional = this.Directional;
@@ -94,7 +94,7 @@ class BrushOutputNode extends LogicNode {
 		let fill_layer: bool = context_raw.layer.fill_layer != null && context_raw.tool != workspace_tool_t.PICKER && context_raw.tool != workspace_tool_t.MATERIAL && context_raw.tool != workspace_tool_t.COLORID;
 
 		// Do not paint over groups
-		let group_layer: bool = SlotLayer.is_group(context_raw.layer);
+		let group_layer: bool = SlotLayer.slot_layer_is_group(context_raw.layer);
 
 		// Paint bounds
 		if (context_raw.paint_vec.x > left &&
@@ -103,7 +103,7 @@ class BrushOutputNode extends LogicNode {
 			context_raw.paint_vec.y < 1 &&
 			!fill_layer &&
 			!group_layer &&
-			(SlotLayer.is_visible(context_raw.layer) || context_raw.paint2d) &&
+			(SlotLayer.slot_layer_is_visible(context_raw.layer) || context_raw.paint2d) &&
 			!ui_base_ui.is_hovered &&
 			!base_is_dragging &&
 			!base_is_resizing &&

+ 16 - 16
armorsculpt/Sources/MakeBrush.ts

@@ -3,37 +3,37 @@ class MakeBrush {
 
 	static run = (vert: NodeShaderRaw, frag: NodeShaderRaw) => {
 
-		NodeShader.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)
-			NodeShader.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
-			NodeShader.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
 
-			NodeShader.add_uniform(frag, 'mat4 invVP', '_inv_view_proj_matrix');
-			NodeShader.write(frag, 'vec4 winp = vec4(vec2(inp.x, 1.0 - inp.y) * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);');
-			NodeShader.write(frag, 'winp = mul(winp, invVP);');
-			NodeShader.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;');
 
-			NodeShader.add_uniform(frag, 'mat4 W', '_world_matrix');
+			node_shader_add_uniform(frag, 'mat4 W', '_world_matrix');
 
-			NodeShader.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)
-			NodeShader.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
-			NodeShader.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
 
-			NodeShader.write(frag, 'vec4 winplast = vec4(vec2(inplast.x, 1.0 - inplast.y) * 2.0 - 1.0, depthlast * 2.0 - 1.0, 1.0);');
-			NodeShader.write(frag, 'winplast = mul(winplast, invVP);');
-			NodeShader.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;');
 
-			NodeShader.write(frag, 'dist = distance(wposition, winp.xyz);');
+			node_shader_write(frag, 'dist = distance(wposition, winp.xyz);');
 		}
 
-		NodeShader.write(frag, 'if (dist > brushRadius) discard;');
+		node_shader_write(frag, 'if (dist > brushRadius) discard;');
 	}
 }

+ 7 - 7
armorsculpt/Sources/MakeMaterial.ts

@@ -254,7 +254,7 @@ class MakeMaterial {
 
 	static bakeNodePreview = (node: zui_node_t, group: zui_node_canvas_t, parents: zui_node_t[]) => {
 		if (node.type == "BLUR") {
-			let id = ParserMaterial.node_name(node, parents);
+			let id = parser_material_node_name(node, parents);
 			let image = context_raw.nodePreviews.get(id);
 			context_raw.nodePreviewsUsed.push(id);
 			let resX = math_floor(config_getTextureResX() / 4);
@@ -265,12 +265,12 @@ class MakeMaterial {
 				context_raw.nodePreviews.set(id, image);
 			}
 
-			ParserMaterial.blur_passthrough = true;
+			parser_material_blur_passthrough = true;
 			UtilRender.makeNodePreview(ui_nodes_getCanvasMaterial(), node, image, group, parents);
-			ParserMaterial.blur_passthrough = false;
+			parser_material_blur_passthrough = false;
 		}
 		else if (node.type == "DIRECT_WARP") {
-			let id = ParserMaterial.node_name(node, parents);
+			let id = parser_material_node_name(node, parents);
 			let image = context_raw.nodePreviews.get(id);
 			context_raw.nodePreviewsUsed.push(id);
 			let resX = math_floor(config_getTextureResX());
@@ -281,9 +281,9 @@ class MakeMaterial {
 				context_raw.nodePreviews.set(id, image);
 			}
 
-			ParserMaterial.warp_passthrough = true;
+			parser_material_warp_passthrough = true;
 			UtilRender.makeNodePreview(ui_nodes_getCanvasMaterial(), node, image, group, parents);
-			ParserMaterial.warp_passthrough = false;
+			parser_material_warp_passthrough = false;
 		}
 	}
 
@@ -304,7 +304,7 @@ class MakeMaterial {
 	}
 
 	static parseBrush = () => {
-		ParserLogic.parse(context_raw.brush.canvas);
+		parser_logic_parse(context_raw.brush.canvas);
 	}
 
 	static getDisplaceStrength = (): f32 => {

+ 167 - 167
armorsculpt/Sources/MakeMesh.ts

@@ -19,96 +19,96 @@ class MakeMesh {
 		let frag = NodeShadercontext_make_frag(con_mesh);
 		frag.ins = vert.outs;
 
-		NodeShader.add_out(vert, 'vec2 texCoord');
+		node_shader_add_out(vert, 'vec2 texCoord');
 		frag.wvpposition = true;
-		NodeShader.add_out(vert, 'vec4 prevwvpposition');
-		NodeShader.add_uniform(vert, 'mat4 VP', '_view_proj_matrix');
-		NodeShader.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;
 
-		NodeShader.add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
-		NodeShader.add_uniform(vert, 'sampler2D texpaint_vert', '_texpaint_vert' + project_layers[0].id);
-		NodeShader.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
-		NodeShader.write(vert, 'gl_Position = mul(vec4(meshpos.xyz, 1.0), WVP);');
+		node_shader_write(vert, 'gl_Position = mul(vec4(meshpos.xyz, 1.0), WVP);');
 
-		NodeShader.write(vert, 'texCoord = vec2(0.0, 0.0);');
+		node_shader_write(vert, 'texCoord = vec2(0.0, 0.0);');
 
-		NodeShader.write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
+		node_shader_write(vert, 'prevwvpposition = mul(vec4(pos.xyz, 1.0), prevWVP);');
 
-		NodeShader.add_out(frag, 'vec4 fragColor[3]');
+		node_shader_add_out(frag, 'vec4 fragColor[3]');
 
-		NodeShader.add_uniform(vert, "mat3 N", "_normal_matrix");
-		NodeShader.add_out(vert, "vec3 wnormal");
+		node_shader_add_uniform(vert, "mat3 N", "_normal_matrix");
+		node_shader_add_out(vert, "vec3 wnormal");
 
-		NodeShader.write_attrib(vert, 'int baseVertex0 = gl_VertexID - (gl_VertexID % 3);');
-		NodeShader.write_attrib(vert, 'int baseVertex1 = baseVertex0 + 1;');
-		NodeShader.write_attrib(vert, 'int baseVertex2 = baseVertex0 + 2;');
-		NodeShader.write_attrib(vert, 'vec3 meshpos0 = texelFetch(texpaint_vert, ivec2(baseVertex0 % textureSize(texpaint_vert, 0).x, baseVertex0 / textureSize(texpaint_vert, 0).y), 0).xyz;');
-		NodeShader.write_attrib(vert, 'vec3 meshpos1 = texelFetch(texpaint_vert, ivec2(baseVertex1 % textureSize(texpaint_vert, 0).x, baseVertex1 / textureSize(texpaint_vert, 0).y), 0).xyz;');
-		NodeShader.write_attrib(vert, 'vec3 meshpos2 = texelFetch(texpaint_vert, ivec2(baseVertex2 % textureSize(texpaint_vert, 0).x, baseVertex2 / textureSize(texpaint_vert, 0).y), 0).xyz;');
-		NodeShader.write_attrib(vert, 'vec3 meshnor = normalize(cross(meshpos2 - meshpos1, meshpos0 - meshpos1));');
-		NodeShader.write_attrib(vert, 'wnormal = mul(meshnor, N);');
-		NodeShader.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);');
 
-		NodeShader.add_function(frag, str_packFloatInt16);
-		NodeShader.add_function(frag, str_octahedronWrap);
-		NodeShader.add_function(frag, str_cotangentFrame);
+		node_shader_add_function(frag, str_packFloatInt16);
+		node_shader_add_function(frag, str_octahedronWrap);
+		node_shader_add_function(frag, str_cotangentFrame);
 		if (layerPass > 0) {
-			NodeShader.add_uniform(frag, 'sampler2D gbuffer0');
-			NodeShader.add_uniform(frag, 'sampler2D gbuffer1');
-			NodeShader.add_uniform(frag, 'sampler2D gbuffer2');
-			NodeShader.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)
-			NodeShader.write(frag, 'fragcoord.y = 1.0 - fragcoord.y;');
+			node_shader_write(frag, 'fragcoord.y = 1.0 - fragcoord.y;');
 			///end
-			NodeShader.write(frag, 'vec4 gbuffer0_sample = textureLod(gbuffer0, fragcoord, 0.0);');
-			NodeShader.write(frag, 'vec4 gbuffer1_sample = textureLod(gbuffer1, fragcoord, 0.0);');
-			NodeShader.write(frag, 'vec4 gbuffer2_sample = textureLod(gbuffer2, fragcoord, 0.0);');
-			NodeShader.write(frag, 'vec3 basecol = gbuffer0_sample.rgb;');
-			NodeShader.write(frag, 'float roughness = gbuffer2_sample.g;');
-			NodeShader.write(frag, 'float metallic = gbuffer2_sample.b;');
-			NodeShader.write(frag, 'float occlusion = gbuffer2_sample.r;');
-			NodeShader.write(frag, 'float opacity = 1.0;//gbuffer0_sample.a;');
-			NodeShader.write(frag, 'float matid = gbuffer1_sample.a;');
-			NodeShader.write(frag, 'vec3 ntex = gbuffer1_sample.rgb;');
-			NodeShader.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 {
-			NodeShader.write(frag, 'vec3 basecol = vec3(0.0, 0.0, 0.0);');
-			NodeShader.write(frag, 'float roughness = 0.3;');
-			NodeShader.write(frag, 'float metallic = 0.0;');
-			NodeShader.write(frag, 'float occlusion = 1.0;');
-			NodeShader.write(frag, 'float opacity = 1.0;');
-			NodeShader.write(frag, 'float matid = 0.0;');
-			NodeShader.write(frag, 'vec3 ntex = vec3(0.5, 0.5, 1.0);');
-			NodeShader.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;');
 		}
-		NodeShader.write(frag, 'vec4 texpaint_sample = vec4(0.0, 0.0, 0.0, 1.0);');
-		NodeShader.write(frag, 'vec4 texpaint_nor_sample;');
-		NodeShader.write(frag, 'vec4 texpaint_pack_sample;');
-		NodeShader.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 (MakeMaterial.heightUsed) {
-			NodeShader.write(frag, 'float height0 = 0.0;');
-			NodeShader.write(frag, 'float height1 = 0.0;');
-			NodeShader.write(frag, 'float height2 = 0.0;');
-			NodeShader.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.drawWireframe) {
 			textureCount++;
-			NodeShader.add_uniform(frag, 'sampler2D texuvmap', '_texuvmap');
+			node_shader_add_uniform(frag, 'sampler2D texuvmap', '_texuvmap');
 		}
 
 		if (context_raw.viewportMode == ViewportMode.ViewLit && context_raw.renderMode == RenderMode.RenderForward) {
 			textureCount += 4;
-			NodeShader.add_uniform(frag, 'sampler2D senvmapBrdf', "$brdf.k");
-			NodeShader.add_uniform(frag, 'sampler2D senvmapRadiance', '_envmap_radiance');
-			NodeShader.add_uniform(frag, 'sampler2D sltcMat', '_ltcMat');
-			NodeShader.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
@@ -135,25 +135,25 @@ class MakeMesh {
 
 		for (let l of layers) {
 			if (SlotLayer.getObjectMask(l) > 0) {
-				NodeShader.add_uniform(frag, 'int uid', '_uid');
+				node_shader_add_uniform(frag, 'int uid', '_uid');
 				if (SlotLayer.getObjectMask(l) > project_paintObjects.length) { // Atlas
 					let visibles = project_getAtlasObjects(SlotLayer.getObjectMask(l));
-					NodeShader.write(frag, 'if (');
+					node_shader_write(frag, 'if (');
 					for (let i = 0; i < visibles.length; ++i) {
-						if (i > 0) NodeShader.write(frag, ' || ');
-						NodeShader.write(frag, `${visibles[i].base.uid} == uid`);
+						if (i > 0) node_shader_write(frag, ' || ');
+						node_shader_write(frag, `${visibles[i].base.uid} == uid`);
 					}
-					NodeShader.write(frag, ') {');
+					node_shader_write(frag, ') {');
 				}
 				else { // Object mask
 					let uid = project_paintObjects[SlotLayer.getObjectMask(l) - 1].base.uid;
-					NodeShader.write(frag, `if (${uid} == uid) {`);
+					node_shader_write(frag, `if (${uid} == uid) {`);
 				}
 			}
 
-			NodeShader.add_shared_sampler(frag, 'sampler2D texpaint' + l.id);
-			NodeShader.write(frag, 'texpaint_sample = vec4(0.8, 0.8, 0.8, 1.0);');
-			NodeShader.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 = SlotLayer.getMasks(l);
 			if (masks != null) {
@@ -166,165 +166,165 @@ class MakeMesh {
 				}
 				if (hasVisible) {
 					let texpaint_mask = 'texpaint_mask' + l.id;
-					NodeShader.write(frag, `float ${texpaint_mask} = 0.0;`);
+					node_shader_write(frag, `float ${texpaint_mask} = 0.0;`);
 					for (let m of masks) {
 						if (!SlotLayer.isVisible(m)) continue;
-						NodeShader.add_shared_sampler(frag, 'sampler2D texpaint' + m.id);
-						NodeShader.write(frag, '{'); // Group mask is sampled across multiple layers
-						NodeShader.write(frag, 'float texpaint_mask_sample' + m.id + ' = textureLodShared(texpaint' + m.id + ', texCoord, 0.0).r;');
-						NodeShader.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, '}');
 					}
-					NodeShader.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 (SlotLayer.getOpacity(l) < 1) {
-				NodeShader.write(frag, `texpaint_opac *= ${SlotLayer.getOpacity(l)};`);
+				node_shader_write(frag, `texpaint_opac *= ${SlotLayer.getOpacity(l)};`);
 			}
 
 			if (l == project_layers[0]) {
-				NodeShader.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 (SlotLayer.getObjectMask(l) > 0) {
-				NodeShader.write(frag, '}');
+				node_shader_write(frag, '}');
 			}
 
 			if (lastPass && context_raw.drawTexels) {
-				NodeShader.add_uniform(frag, 'vec2 texpaintSize', '_texpaintSize');
-				NodeShader.write(frag, 'vec2 texel0 = texCoord * texpaintSize * 0.01;');
-				NodeShader.write(frag, 'vec2 texel1 = texCoord * texpaintSize * 0.1;');
-				NodeShader.write(frag, 'vec2 texel2 = texCoord * texpaintSize;');
-				NodeShader.write(frag, 'basecol *= max(float(mod(int(texel0.x), 2.0) == mod(int(texel0.y), 2.0)), 0.9);');
-				NodeShader.write(frag, 'basecol *= max(float(mod(int(texel1.x), 2.0) == mod(int(texel1.y), 2.0)), 0.9);');
-				NodeShader.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 (lastPass && context_raw.drawWireframe) {
-				NodeShader.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 (MakeMaterial.heightUsed) {
-				NodeShader.write(frag, 'if (height > 0.0) {');
-				NodeShader.write(frag, 'float height_dx = height0 - height1;');
-				NodeShader.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
-				NodeShader.write(frag, 'vec3 n1 = ntex * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-				NodeShader.write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-				NodeShader.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);');
-				NodeShader.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 (!lastPass) {
-				NodeShader.write(frag, 'fragColor[0] = vec4(basecol, opacity);');
-				NodeShader.write(frag, 'fragColor[1] = vec4(ntex, matid);');
-				NodeShader.write(frag, 'fragColor[2] = vec4(occlusion, roughness, metallic, height);');
-				ParserMaterial.finalize(con_mesh);
+				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 = NodeShader.get(vert);
-				con_mesh.data.fragment_shader = NodeShader.get(frag);
+				con_mesh.data.vertex_shader = node_shader_get(vert);
+				con_mesh.data.fragment_shader = node_shader_get(frag);
 				return con_mesh;
 			}
 
 			frag.vVec = true;
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
 			///else
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
 			///end
-			NodeShader.write(frag, 'n = ntex * 2.0 - 1.0;');
-			NodeShader.write(frag, 'n.y = -n.y;');
-			NodeShader.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.viewportMode == ViewportMode.ViewLit) {
 
-				NodeShader.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.viewportShader != null) {
 					let color = context_raw.viewportShader(frag);
-					NodeShader.write(frag, `fragColor[1] = vec4(${color}, 1.0);`);
+					node_shader_write(frag, `fragColor[1] = vec4(${color}, 1.0);`);
 				}
 				else if (context_raw.renderMode == RenderMode.RenderForward) {
 					frag.wposition = true;
-					NodeShader.write(frag, 'vec3 albedo = mix(basecol, vec3(0.0, 0.0, 0.0), metallic);');
-					NodeShader.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;
-					NodeShader.write(frag, 'float dotNV = max(0.0, dot(n, vVec));');
-					NodeShader.write(frag, 'vec2 envBRDF = texelFetch(senvmapBrdf, ivec2(vec2(roughness, 1.0 - dotNV) * 256.0), 0).xy;');
-					NodeShader.add_uniform(frag, 'int envmapNumMipmaps', '_envmap_num_mipmaps');
-					NodeShader.add_uniform(frag, 'vec4 envmapData', '_envmapData'); // angle, sin(angle), cos(angle), strength
-					NodeShader.write(frag, 'vec3 wreflect = reflect(-vVec, n);');
-					NodeShader.write(frag, 'float envlod = roughness * float(envmapNumMipmaps);');
-					NodeShader.add_function(frag, str_envMapEquirect);
-					NodeShader.write(frag, 'vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(wreflect, envmapData.x), envlod).rgb;');
-					NodeShader.add_uniform(frag, 'vec3 lightArea0', '_light_area0');
-					NodeShader.add_uniform(frag, 'vec3 lightArea1', '_light_area1');
-					NodeShader.add_uniform(frag, 'vec3 lightArea2', '_light_area2');
-					NodeShader.add_uniform(frag, 'vec3 lightArea3', '_light_area3');
-					NodeShader.add_function(frag, str_ltcEvaluate);
-					NodeShader.add_uniform(frag, 'vec3 lightPos', '_point_pos');
-					NodeShader.add_uniform(frag, 'vec3 lightColor', '_point_color');
-					NodeShader.write(frag, 'float ldist = distance(wposition, lightPos);');
-					NodeShader.write(frag, 'const float LUT_SIZE = 64.0;');
-					NodeShader.write(frag, 'const float LUT_SCALE = (LUT_SIZE - 1.0) / LUT_SIZE;');
-					NodeShader.write(frag, 'const float LUT_BIAS = 0.5 / LUT_SIZE;');
-					NodeShader.write(frag, 'float theta = acos(dotNV);');
-					NodeShader.write(frag, 'vec2 tuv = vec2(roughness, theta / (0.5 * 3.14159265));');
-					NodeShader.write(frag, 'tuv = tuv * LUT_SCALE + LUT_BIAS;');
-					NodeShader.write(frag, 'vec4 t = textureLod(sltcMat, tuv, 0.0);');
-					NodeShader.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));');
-					NodeShader.write(frag, 'float ltcspec = ltcEvaluate(n, vVec, dotNV, wposition, minv, lightArea0, lightArea1, lightArea2, lightArea3);');
-					NodeShader.write(frag, 'ltcspec *= textureLod(sltcMag, tuv, 0.0).a;');
-					NodeShader.write(frag, 'mat3 mident = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);');
-					NodeShader.write(frag, 'float ltcdiff = ltcEvaluate(n, vVec, dotNV, wposition, mident, lightArea0, lightArea1, lightArea2, lightArea3);');
-					NodeShader.write(frag, 'vec3 direct = albedo * ltcdiff + ltcspec * 0.05;');
-					NodeShader.write(frag, 'direct *= lightColor * (1.0 / (ldist * ldist));');
-
-					NodeShader.add_uniform(frag, 'vec4 shirr[7]', '_envmap_irradiance');
-					NodeShader.add_function(frag, str_shIrradiance);
-					NodeShader.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);');
-					NodeShader.write(frag, 'indirect += prefilteredColor * (f0 * envBRDF.x + envBRDF.y) * 1.5;');
-					NodeShader.write(frag, 'indirect *= envmapData.w * occlusion;');
-					NodeShader.write(frag, 'fragColor[1] = vec4(direct + indirect, 1.0);');
+					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_envMapEquirect);
+					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_ltcEvaluate);
+					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_shIrradiance);
+					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 (MakeMaterial.emisUsed) NodeShader.write(frag, 'if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;'); // Boost for bloom
-					NodeShader.write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
+					if (MakeMaterial.emisUsed) 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);');
 				}
 			}
 			else if (context_raw.viewportMode == ViewportMode.ViewObjectNormal) {
 				frag.nAttr = true;
-				NodeShader.write(frag, 'fragColor[1] = vec4(nAttr, 1.0);');
+				node_shader_write(frag, 'fragColor[1] = vec4(nAttr, 1.0);');
 			}
 			else if (context_raw.viewportMode == ViewportMode.ViewObjectID) {
-				NodeShader.add_uniform(frag, 'float objectId', '_objectId');
-				NodeShader.write(frag, 'float obid = objectId + 1.0 / 255.0;');
-				NodeShader.write(frag, 'float id_r = fract(sin(dot(vec2(obid, obid * 20.0), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.write(frag, 'float id_g = fract(sin(dot(vec2(obid * 20.0, obid), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.write(frag, 'float id_b = fract(sin(dot(vec2(obid, obid * 40.0), vec2(12.9898, 78.233))) * 43758.5453);');
-				NodeShader.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 {
-				NodeShader.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.viewportMode != ViewportMode.ViewLit && context_raw.viewportMode != ViewportMode.ViewPathTrace) {
-				NodeShader.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));');
 			}
 
-			NodeShader.write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-			NodeShader.write(frag, 'n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);');
-			NodeShader.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)));');
 		}
 
-		NodeShader.write(frag, 'vec2 posa = (wvpposition.xy / wvpposition.w) * 0.5 + 0.5;');
-		NodeShader.write(frag, 'vec2 posb = (prevwvpposition.xy / prevwvpposition.w) * 0.5 + 0.5;');
-		NodeShader.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);');
 
-		ParserMaterial.finalize(con_mesh);
+		parser_material_finalize(con_mesh);
 		con_mesh.data.shader_from_source = true;
-		con_mesh.data.vertex_shader = NodeShader.get(vert);
-		con_mesh.data.fragment_shader = NodeShader.get(frag);
+		con_mesh.data.vertex_shader = node_shader_get(vert);
+		con_mesh.data.fragment_shader = node_shader_get(frag);
 		return con_mesh;
 	}
 

+ 70 - 70
armorsculpt/Sources/MakeMeshPreview.ts

@@ -26,90 +26,90 @@ class MakeMeshPreview {
 			pos = "spos";
 			NodeShadercontext_add_elem(con_mesh, "bone", 'short4norm');
 			NodeShadercontext_add_elem(con_mesh, "weight", 'short4norm');
-			NodeShader.add_function(vert, str_getSkinningDualQuat);
-			NodeShader.add_uniform(vert, 'vec4 skinBones[128 * 2]', '_skin_bones');
-			NodeShader.add_uniform(vert, 'float posUnpack', '_pos_unpack');
-			NodeShader.write_attrib(vert, 'vec4 skinA;');
-			NodeShader.write_attrib(vert, 'vec4 skinB;');
-			NodeShader.write_attrib(vert, 'getSkinningDualQuat(ivec4(bone * 32767), weight, skinA, skinB);');
-			NodeShader.write_attrib(vert, 'vec3 spos = pos.xyz;');
-			NodeShader.write_attrib(vert, 'spos.xyz *= posUnpack;');
-			NodeShader.write_attrib(vert, 'spos.xyz += 2.0 * cross(skinA.xyz, cross(skinA.xyz, spos.xyz) + skinA.w * spos.xyz);');
-			NodeShader.write_attrib(vert, 'spos.xyz += 2.0 * (skinA.w * skinB.xyz - skinB.w * skinA.xyz + cross(skinA.xyz, skinB.xyz));');
-			NodeShader.write_attrib(vert, 'spos.xyz /= posUnpack;');
+			node_shader_add_function(vert, str_getSkinningDualQuat);
+			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
 
-		NodeShader.add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
-		NodeShader.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 brushScale = (context_raw.brushScale * context_raw.brushNodesScale) + "";
-		NodeShader.add_out(vert, 'vec2 texCoord');
-		NodeShader.write_attrib(vert, `texCoord = tex * float(${brushScale});`);
+		node_shader_add_out(vert, 'vec2 texCoord');
+		node_shader_write_attrib(vert, `texCoord = tex * float(${brushScale});`);
 
 		let decal = context_raw.decalPreview;
-		ParserMaterial.sample_keep_aspect = decal;
-		ParserMaterial.sample_uv_scale = brushScale;
-		ParserMaterial.parse_height = MakeMaterial.heightUsed;
-		ParserMaterial.parse_height_as_channel = true;
-		// let sout = ParserMaterial.parse(ui_nodes_getCanvasMaterial(), con_mesh, vert, frag, matcon);
-		ParserMaterial.parse_height = false;
-		ParserMaterial.parse_height_as_channel = false;
-		ParserMaterial.sample_keep_aspect = false;
+		parser_material_sample_keep_aspect = decal;
+		parser_material_sample_uv_scale = brushScale;
+		parser_material_parse_height = MakeMaterial.heightUsed;
+		parser_material_parse_height_as_channel = true;
+		// let sout = parser_material_parse(ui_nodes_getCanvasMaterial(), con_mesh, vert, frag, matcon);
+		parser_material_parse_height = false;
+		parser_material_parse_height_as_channel = false;
+		parser_material_sample_keep_aspect = false;
 		let base = "vec3(1.0, 1.0, 1.0)";//sout.out_basecol;
 		let rough = "0.0";//sout.out_roughness;
 		let met = "0.0";//sout.out_metallic;
 		let occ = "0.0";//sout.out_occlusion;
 		let opac = "0.0";//sout.out_opacity;
 		let height = "0.0";//sout.out_height;
-		let nortan = "vec3(1.0, 1.0, 1.0)";//ParserMaterial.out_normaltan;
-		NodeShader.write(frag, `vec3 basecol = pow(${base}, vec3(2.2, 2.2, 2.2));`);
-		NodeShader.write(frag, `float roughness = ${rough};`);
-		NodeShader.write(frag, `float metallic = ${met};`);
-		NodeShader.write(frag, `float occlusion = ${occ};`);
-		NodeShader.write(frag, `float opacity = ${opac};`);
-		NodeShader.write(frag, `vec3 nortan = ${nortan};`);
-		NodeShader.write(frag, `float height = ${height};`);
-
-		// ParserMaterial.parse_height_as_channel = false;
-		// NodeShader.write(vert, `float vheight = ${height};`);
-		// NodeShader.add_out(vert, 'float height');
-		// NodeShader.write(vert, 'height = vheight;');
+		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};`);
+
+		// 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 (MakeMaterial.heightUsed && displaceStrength > 0.0) {
-		// 	NodeShader.write(vert, `vec3 pos2 = ${pos}.xyz + vec3(nor.xy, pos.w) * vec3(${height}, ${height}, ${height}) * vec3(${displaceStrength}, ${displaceStrength}, ${displaceStrength});`);
-		// 	NodeShader.write(vert, 'gl_Position = mul(vec4(pos2.xyz, 1.0), WVP);');
+		// 	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);');
 		// }
 
 		if (decal) {
 			if (context_raw.tool == WorkspaceTool.ToolText) {
-				NodeShader.add_uniform(frag, 'sampler2D textexttool', '_textexttool');
-				NodeShader.write(frag, `opacity *= textureLod(textexttool, texCoord / float(${brushScale}), 0.0).r;`);
+				node_shader_add_uniform(frag, 'sampler2D textexttool', '_textexttool');
+				node_shader_write(frag, `opacity *= textureLod(textexttool, texCoord / float(${brushScale}), 0.0).r;`);
 			}
 		}
 		if (decal) {
 			let opac = MakeMeshPreview.opacityDiscardDecal;
-			NodeShader.write(frag, `if (opacity < ${opac}) discard;`);
+			node_shader_write(frag, `if (opacity < ${opac}) discard;`);
 		}
 
-		NodeShader.add_out(frag, 'vec4 fragColor[3]');
+		node_shader_add_out(frag, 'vec4 fragColor[3]');
 		frag.n = true;
 
-		NodeShader.add_function(frag, str_packFloatInt16);
-		NodeShader.add_function(frag, str_cotangentFrame);
-		NodeShader.add_function(frag, str_octahedronWrap);
+		node_shader_add_function(frag, str_packFloatInt16);
+		node_shader_add_function(frag, str_cotangentFrame);
+		node_shader_add_function(frag, str_octahedronWrap);
 
 		if (MakeMaterial.heightUsed) {
-			NodeShader.write(frag, 'if (height > 0.0) {');
-			NodeShader.write(frag, 'float height_dx = dFdx(height * 2.0);');
-			NodeShader.write(frag, 'float height_dy = dFdy(height * 2.0);');
-			// NodeShader.write(frag, 'float height_dx = height0 - height1;');
-			// NodeShader.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
-			NodeShader.write(frag, 'vec3 n1 = nortan * vec3(2.0, 2.0, 2.0) - vec3(1.0, 1.0, 1.0);');
-			NodeShader.write(frag, 'vec3 n2 = normalize(vec3(height_dx * 16.0, height_dy * 16.0, 1.0));');
-			NodeShader.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);');
-			NodeShader.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
@@ -119,40 +119,40 @@ class MakeMeshPreview {
 		else {
 			frag.vVec = true;
 			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, vVec, texCoord);');
 			///else
-			NodeShader.write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
+			node_shader_write(frag, 'mat3 TBN = cotangentFrame(n, -vVec, texCoord);');
 			///end
-			NodeShader.write(frag, 'n = nortan * 2.0 - 1.0;');
-			NodeShader.write(frag, 'n.y = -n.y;');
-			NodeShader.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));');
 		}
 
-		NodeShader.write(frag, 'n /= (abs(n.x) + abs(n.y) + abs(n.z));');
-		NodeShader.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) {
-			NodeShader.write(frag, 'fragColor[0] = vec4(n.x, n.y, roughness, packFloatInt16(metallic, uint(0)));'); // metallic/matid
-			NodeShader.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 {
-			NodeShader.write(frag, 'fragColor[0] = vec4(n.x, n.y, mix(1.0, roughness, opacity), packFloatInt16(mix(1.0, metallic, opacity), uint(0)));'); // metallic/matid
-			NodeShader.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);');
 		}
-		NodeShader.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
 
-		ParserMaterial.finalize(con_mesh);
+		parser_material_finalize(con_mesh);
 
 		///if arm_skin
 		if (skin) {
-			NodeShader.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
 
 		con_mesh.data.shader_from_source = true;
-		con_mesh.data.vertex_shader = NodeShader.get(vert);
-		con_mesh.data.fragment_shader = NodeShader.get(frag);
+		con_mesh.data.vertex_shader = node_shader_get(vert);
+		con_mesh.data.fragment_shader = node_shader_get(frag);
 
 		return con_mesh;
 	}

+ 31 - 31
armorsculpt/Sources/MakeSculpt.ts

@@ -26,24 +26,24 @@ class MakeSculpt {
 		let faceFill = context_raw.tool == WorkspaceTool.ToolFill && context_raw.fillTypeHandle.position == FillType.FillFace;
 		let decal = context_raw.tool == WorkspaceTool.ToolDecal || context_raw.tool == WorkspaceTool.ToolText;
 
-		NodeShader.add_out(vert, 'vec2 texCoord');
-		NodeShader.write(vert, 'const vec2 madd = vec2(0.5, 0.5);');
-		NodeShader.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)
-		NodeShader.write(vert, 'texCoord.y = 1.0 - texCoord.y;');
+		node_shader_write(vert, 'texCoord.y = 1.0 - texCoord.y;');
 		///end
-		NodeShader.write(vert, 'gl_Position = vec4(pos.xy, 0.0, 1.0);');
+		node_shader_write(vert, 'gl_Position = vec4(pos.xy, 0.0, 1.0);');
 
-		NodeShader.add_uniform(frag, 'vec4 inp', '_inputBrush');
-		NodeShader.add_uniform(frag, 'vec4 inplast', '_inputBrushLast');
+		node_shader_add_uniform(frag, 'vec4 inp', '_inputBrush');
+		node_shader_add_uniform(frag, 'vec4 inplast', '_inputBrushLast');
 
-		NodeShader.add_uniform(frag, 'sampler2D gbufferD');
+		node_shader_add_uniform(frag, 'sampler2D gbufferD');
 
-		NodeShader.add_out(frag, 'vec4 fragColor[2]');
+		node_shader_add_out(frag, 'vec4 fragColor[2]');
 
-		NodeShader.add_uniform(frag, 'float brushRadius', '_brushRadius');
-		NodeShader.add_uniform(frag, 'float brushOpacity', '_brushOpacity');
-		NodeShader.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 == WorkspaceTool.ToolBrush  ||
 			context_raw.tool == WorkspaceTool.ToolEraser ||
@@ -58,33 +58,33 @@ class MakeSculpt {
 			MakeBrush.run(vert, frag);
 		}
 
-		NodeShader.write(frag, 'vec3 basecol = vec3(1.0, 1.0, 1.0);');
-		NodeShader.write(frag, 'float opacity = 1.0;');
-		NodeShader.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;');
 
-		NodeShader.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;');
 
-		NodeShader.add_uniform(frag, 'sampler2D texpaint_undo', '_texpaint_undo');
-		NodeShader.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);');
 
-		NodeShader.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;');
 
-		NodeShader.add_function(frag, str_octahedronWrap);
-		NodeShader.add_uniform(frag, 'sampler2D gbuffer0_undo');
-		NodeShader.write(frag, 'vec2 g0_undo = textureLod(gbuffer0_undo, inp.xy, 0.0).rg;');
-		NodeShader.write(frag, 'vec3 wn;');
-		NodeShader.write(frag, 'wn.z = 1.0 - abs(g0_undo.x) - abs(g0_undo.y);');
-		NodeShader.write(frag, 'wn.xy = wn.z >= 0.0 ? g0_undo.xy : octahedronWrap(g0_undo.xy);');
-		NodeShader.write(frag, 'vec3 n = normalize(wn);');
+		node_shader_add_function(frag, str_octahedronWrap);
+		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);');
 
-		NodeShader.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);');
 
-		NodeShader.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);');
 
-		ParserMaterial.finalize(con_paint);
+		parser_material_finalize(con_paint);
 		con_paint.data.shader_from_source = true;
-		con_paint.data.vertex_shader = NodeShader.get(vert);
-		con_paint.data.fragment_shader = NodeShader.get(frag);
+		con_paint.data.vertex_shader = node_shader_get(vert);
+		con_paint.data.fragment_shader = node_shader_get(frag);
 
 		return con_paint;
 	}

+ 42 - 42
armorsculpt/Sources/TabLayers.ts

@@ -7,7 +7,7 @@ class TabLayers {
 
 	static draw = (htab: zui_handle_t) => {
 		let mini = config_config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_base_ui_base_sidebar_mini_w;
-		mini ? TabLayers.draw_mini(htab) : TabLayers.draw_full(htab);
+		mini ? TabLayers.tab_layers_draw_mini(htab) : TabLayers.tab_layers_draw_full(htab);
 	}
 
 	static drawMini = (htab: zui_handle_t) => {
@@ -20,14 +20,14 @@ class TabLayers {
 		zui_begin_sticky();
 		zui_separator(5);
 
-		TabLayers.combo_filter();
-		TabLayers.button_new("+");
+		TabLayers.tab_layers_combo_filter();
+		TabLayers.tab_layers_button_new("+");
 
 		zui_end_sticky();
 		ui._y += 2;
 
-		TabLayers.highlight_odd_lines();
-		TabLayers.draw_slots(true);
+		TabLayers.tab_layers_highlight_odd_lines();
+		TabLayers.tab_layers_draw_slots(true);
 
 		ui.t.ELEMENT_H = _ELEMENT_H;
 	}
@@ -38,14 +38,14 @@ class TabLayers {
 			zui_begin_sticky();
 			zui_row([1 / 4, 3 / 4]);
 
-			TabLayers.button_new(tr("New"));
-			TabLayers.combo_filter();
+			TabLayers.tab_layers_button_new(tr("New"));
+			TabLayers.tab_layers_combo_filter();
 
 			zui_end_sticky();
 			ui._y += 2;
 
-			TabLayers.highlight_odd_lines();
-			TabLayers.draw_slots(false);
+			TabLayers.tab_layers_highlight_odd_lines();
+			TabLayers.tab_layers_draw_slots(false);
 		}
 	}
 
@@ -54,7 +54,7 @@ class TabLayers {
 			if (i >= project_project_layers.length) break; // Layer was deleted
 			let j = project_project_layers.length - 1 - i;
 			let l = project_project_layers[j];
-			TabLayers.draw_layer_slot(l, j, mini);
+			TabLayers.tab_layers_draw_layer_slot(l, j, mini);
 		}
 	}
 
@@ -124,8 +124,8 @@ class TabLayers {
 		let ui = ui_base_ui_base_ui;
 
 		if (context_context_raw.layer_filter > 0 &&
-			SlotLayer.get_object_mask(l) > 0 &&
-			SlotLayer.get_object_mask(l) != context_context_raw.layer_filter) {
+			SlotLayer.slot_layer_get_object_mask(l) > 0 &&
+			SlotLayer.slot_layer_get_object_mask(l) != context_context_raw.layer_filter) {
 			return;
 		}
 
@@ -149,16 +149,16 @@ class TabLayers {
 				let ls = project_project_layers;
 				let dest = context_context_raw.drag_dest;
 				let toGroup = down ? dest > 0 && ls[dest - 1].parent != null && ls[dest - 1].parent.show_panel : dest < ls.length && ls[dest].parent != null && ls[dest].parent.show_panel;
-				let nestedGroup = SlotLayer.is_group(base_base_drag_layer) && toGroup;
+				let nestedGroup = SlotLayer.slot_layer_is_group(base_base_drag_layer) && toGroup;
 				if (!nestedGroup) {
-					if (SlotLayer.can_move(context_context_raw.layer, context_context_raw.drag_dest)) {
+					if (SlotLayer.slot_layer_can_move(context_context_raw.layer, context_context_raw.drag_dest)) {
 						zui_fill(checkw, step * 2, (ui._window_w / zui_SCALE(ui) - 2) - checkw, 2 * zui_SCALE(ui), ui.t.HIGHLIGHT_COL);
 					}
 				}
 			}
 			else if (i == project_project_layers.length - 1 && mouse_y < absy + step) {
 				context_context_raw.drag_dest = project_project_layers.length - 1;
-				if (SlotLayer.can_move(context_context_raw.layer, context_context_raw.drag_dest)) {
+				if (SlotLayer.slot_layer_can_move(context_context_raw.layer, context_context_raw.drag_dest)) {
 					zui_fill(checkw, 0, (ui._window_w / zui_SCALE(ui) - 2) - checkw, 2 * zui_SCALE(ui), ui.t.HIGHLIGHT_COL);
 				}
 			}
@@ -166,22 +166,22 @@ class TabLayers {
 		if (base_base_is_dragging && (base_base_drag_material != null || base_base_drag_swatch != null) && context_context_in_layers()) {
 			if (mouse_y > absy + step && mouse_y < absy + step * 3) {
 				context_context_raw.drag_dest = i;
-				if (TabLayers.can_drop_new_layer(i))
+				if (TabLayers.tab_layers_can_drop_new_layer(i))
 					zui_fill(checkw, 2 * step, (ui._window_w / zui_SCALE(ui) - 2) - checkw, 2 * zui_SCALE(ui), ui.t.HIGHLIGHT_COL);
 			}
 			else if (i == project_project_layers.length - 1 && mouse_y < absy + step) {
 				context_context_raw.drag_dest = project_project_layers.length;
-				if (TabLayers.can_drop_new_layer(project_project_layers.length))
+				if (TabLayers.tab_layers_can_drop_new_layer(project_project_layers.length))
 					zui_fill(checkw, 0, (ui._window_w / zui_SCALE(ui) - 2) - checkw, 2 * zui_SCALE(ui), ui.t.HIGHLIGHT_COL);
 			}
 		}
 
-		mini ? TabLayers.draw_layer_slot_mini(l, i) : TabLayers.draw_layer_slot_full(l, i);
+		mini ? TabLayers.tab_layers_draw_layer_slot_mini(l, i) : TabLayers.tab_layers_draw_layer_slot_full(l, i);
 
-		TabLayers.draw_layer_highlight(l, mini);
+		TabLayers.tab_layers_draw_layer_highlight(l, mini);
 
-		if (TabLayers.show_context_menu) {
-			TabLayers.draw_layer_context_menu(l, mini);
+		if (TabLayers.tab_layers_show_context_menu) {
+			TabLayers.tab_layers_draw_layer_context_menu(l, mini);
 		}
 	}
 
@@ -203,7 +203,7 @@ class TabLayers {
 
 		let step = ui.t.ELEMENT_H;
 
-		let hasPanel = SlotLayer.is_group(l) || (SlotLayer.is_layer(l) && SlotLayer.get_masks(l, false) != null);
+		let hasPanel = SlotLayer.slot_layer_is_group(l) || (SlotLayer.slot_layer_is_layer(l) && SlotLayer.slot_layer_get_masks(l, false) != null);
 		if (hasPanel) {
 			zui_row([8 / 100, 52 / 100, 30 / 100, 10 / 100]);
 		}
@@ -223,7 +223,7 @@ class TabLayers {
 		if (parentHidden) col -= 0x99000000;
 
 		if (zui_image(icons, col, -1.0, r.x, r.y, r.w, r.h) == zui_state_t.RELEASED) {
-			TabLayers.layer_toggle_visible(l);
+			TabLayers.tab_layers_layer_toggle_visible(l);
 		}
 		ui._x -= 2;
 		ui._y -= 3;
@@ -234,10 +234,10 @@ class TabLayers {
 
 		// Draw layer name
 		ui._y += center;
-		if (TabLayers.layer_name_edit == l.id) {
-			TabLayers.layer_name_handle.text = l.name;
-			l.name = zui_text_input(TabLayers.layer_name_handle);
-			if (ui.text_selected_handle_ptr != TabLayers.layer_name_handle.ptr) TabLayers.layer_name_edit = -1;
+		if (TabLayers.tab_layers_layer_name_edit == l.id) {
+			TabLayers.tab_layers_layer_name_handle.text = l.name;
+			l.name = zui_text_input(TabLayers.tab_layers_layer_name_handle);
+			if (ui.text_selected_handle_ptr != TabLayers.tab_layers_layer_name_handle.ptr) TabLayers.tab_layers_layer_name_edit = -1;
 		}
 		else {
 			if (ui.enabled && ui.input_enabled && ui.combo_selected_handle_ptr == 0 &&
@@ -245,7 +245,7 @@ class TabLayers {
 				ui.input_y > ui._window_y + ui._y - center && ui.input_y < ui._window_y + ui._y - center + (step * zui_SCALE(ui)) * 2) {
 				if (ui.input_started) {
 					context_context_set_layer(l);
-					TabLayers.set_drag_layer(context_context_raw.layer, -(mouse_x - uix - ui._window_x - 3), -(mouse_y - uiy - ui._window_y + 1));
+					TabLayers.tab_layers_set_drag_layer(context_context_raw.layer, -(mouse_x - uix - ui._window_x - 3), -(mouse_y - uiy - ui._window_y + 1));
 				}
 				else if (ui.input_released) {
 					if (time_time() - context_context_raw.select_time > 0.2) {
@@ -254,7 +254,7 @@ class TabLayers {
 				}
 				else if (ui.input_released_r) {
 					context_context_set_layer(l);
-					TabLayers.show_context_menu = true;
+					TabLayers.tab_layers_show_context_menu = true;
 				}
 			}
 
@@ -262,9 +262,9 @@ class TabLayers {
 			if (state == zui_state_t.RELEASED) {
 				let td = time_time() - context_context_raw.select_time;
 				if (td < 0.2 && td > 0.0) {
-					TabLayers.layer_name_edit = l.id;
-					TabLayers.layer_name_handle.text = l.name;
-					zui_start_text_edit(TabLayers.layer_name_handle);
+					TabLayers.tab_layers_layer_name_edit = l.id;
+					TabLayers.tab_layers_layer_name_handle.text = l.name;
+					zui_start_text_edit(TabLayers.tab_layers_layer_name_handle);
 				}
 			}
 
@@ -285,18 +285,18 @@ class TabLayers {
 			if (l.parent.parent != null) ui._x -= 10 * zui_SCALE(ui);
 		}
 
-		if (SlotLayer.is_group(l)) {
+		if (SlotLayer.slot_layer_is_group(l)) {
 			zui_end_element();
 		}
 		else {
-			if (SlotLayer.is_mask(l)) {
+			if (SlotLayer.slot_layer_is_mask(l)) {
 				ui._y += center;
 			}
 
 			// comboBlending(ui, l);
 			zui_end_element();
 
-			if (SlotLayer.is_mask(l)) {
+			if (SlotLayer.slot_layer_is_mask(l)) {
 				ui._y -= center;
 			}
 		}
@@ -309,7 +309,7 @@ class TabLayers {
 			ui._y -= center;
 		}
 
-		if (SlotLayer.is_group(l) || SlotLayer.is_mask(l)) {
+		if (SlotLayer.slot_layer_is_group(l) || SlotLayer.slot_layer_is_mask(l)) {
 			ui._y -= zui_ELEMENT_OFFSET(ui);
 			zui_end_element();
 		}
@@ -326,7 +326,7 @@ class TabLayers {
 			}
 
 			ui._y -= center;
-			TabLayers.combo_object(ui, l);
+			TabLayers.tab_layers_combo_object(ui, l);
 			ui._y += center;
 
 			zui_end_element();
@@ -346,7 +346,7 @@ class TabLayers {
 	static layerToggleVisible = (l: SlotLayerRaw) => {
 		l.visible = !l.visible;
 		ui_view2d_ui_view2d_hwnd.redraws = 2;
-		MakeMaterial.parse_mesh_material();
+		MakeMaterial.make_material_parse_mesh_material();
 	}
 
 	static drawLayerHighlight = (l: SlotLayerRaw, mini: bool) => {
@@ -372,11 +372,11 @@ class TabLayers {
 		// Lowest layer
 		if (index == 0) return false;
 		// Lowest layer that has masks
-		if (SlotLayer.is_layer(l) && SlotLayer.is_mask(project_project_layers[0]) && project_project_layers[0].parent == l) return false;
+		if (SlotLayer.slot_layer_is_layer(l) && SlotLayer.slot_layer_is_mask(project_project_layers[0]) && project_project_layers[0].parent == l) return false;
 		// The lowest toplevel layer is a group
-		if (SlotLayer.is_group(l) && SlotLayer.is_in_group(project_project_layers[0]) && SlotLayer.get_containing_group(project_project_layers[0]) == l) return false;
+		if (SlotLayer.slot_layer_is_group(l) && SlotLayer.slot_layer_is_in_group(project_project_layers[0]) && SlotLayer.slot_layer_get_containing_group(project_project_layers[0]) == l) return false;
 		// Masks must be merged down to masks
-		if (SlotLayer.is_mask(l) && !SlotLayer.is_mask(project_project_layers[index - 1])) return false;
+		if (SlotLayer.slot_layer_is_mask(l) && !SlotLayer.slot_layer_is_mask(project_project_layers[index - 1])) return false;
 		return true;
 	}
 
@@ -385,7 +385,7 @@ class TabLayers {
 	}
 
 	static canDropNewLayer = (position: i32) => {
-		if (position > 0 && position < project_project_layers.length && SlotLayer.is_mask(project_project_layers[position - 1])) {
+		if (position > 0 && position < project_project_layers.length && SlotLayer.slot_layer_is_mask(project_project_layers[position - 1])) {
 			// 1. The layer to insert is inserted in the middle
 			// 2. The layer below is a mask, i.e. the layer would have to be a (group) mask, too.
 			return false;

+ 0 - 470
base/Sources/BoxExport.ts

@@ -1,470 +0,0 @@
-
-class BoxExport {
-
-	static htab: zui_handle_t = zui_handle_create();
-	static files: string[] = null;
-	static export_mesh_handle: zui_handle_t = zui_handle_create();
-
-	///if (is_paint || is_lab)
-	static hpreset: zui_handle_t = zui_handle_create();
-	static preset: export_preset_t = null;
-	static channels: string[] = ["base_r", "base_g", "base_b", "height", "metal", "nor_r", "nor_g", "nor_g_directx", "nor_b", "occ", "opac", "rough", "smooth", "emis", "subs", "0.0", "1.0"];
-	static color_spaces: string[] = ["linear", "srgb"];
-	///end
-
-	///if (is_paint || is_lab)
-	static show_textures = () => {
-		ui_box_show_custom((ui: zui_t) => {
-
-			if (BoxExport.files == null) {
-				BoxExport.fetch_presets();
-				BoxExport.hpreset.position = BoxExport.files.indexOf("generic");
-			}
-			if (BoxExport.preset == null) {
-				BoxExport.parse_preset();
-				BoxExport.hpreset.children = null;
-			}
-
-			BoxExport.tab_export_textures(ui, tr("Export Textures"));
-			BoxExport.tab_presets(ui);
-
-			///if is_paint
-			BoxExport.tab_atlases(ui);
-			///if (krom_android || krom_ios)
-			BoxExport.tab_export_mesh(ui, BoxExport.htab);
-			///end
-			///end
-
-		}, 540, 310);
-	}
-	///end
-
-	///if is_paint
-	static show_bake_material = () => {
-		ui_box_show_custom((ui: zui_t) => {
-
-			if (BoxExport.files == null) {
-				BoxExport.fetch_presets();
-				BoxExport.hpreset.position = BoxExport.files.indexOf("generic");
-			}
-			if (BoxExport.preset == null) {
-				BoxExport.parse_preset();
-				BoxExport.hpreset.children = null;
-			}
-
-			BoxExport.tab_export_textures(ui, tr("Bake to Textures"), true);
-			BoxExport.tab_presets(ui);
-
-		}, 540, 310);
-	}
-	///end
-
-	///if (is_paint || is_lab)
-	static tab_export_textures = (ui: zui_t, title: string, bake_material: bool = false) => {
-		let tab_vertical: bool = config_raw.touch_ui;
-		if (zui_tab(BoxExport.htab, title, tab_vertical)) {
-
-			zui_row([0.5, 0.5]);
-
-			///if is_paint
-			///if (krom_android || krom_ios)
-			zui_combo(base_res_handle, ["128", "256", "512", "1K", "2K", "4K"], tr("Resolution"), true);
-			///else
-			zui_combo(base_res_handle, ["128", "256", "512", "1K", "2K", "4K", "8K", "16K"], tr("Resolution"), true);
-			///end
-			///end
-
-			///if is_lab
-			///if (krom_android || krom_ios)
-			zui_combo(base_res_handle, ["2K", "4K"], tr("Resolution"), true);
-			///else
-			zui_combo(base_res_handle, ["2K", "4K", "8K", "16K"], tr("Resolution"), true);
-			///end
-			///end
-
-			if (base_res_handle.changed) {
-				base_on_layers_resized();
-			}
-
-			///if (is_lab || krom_android || krom_ios)
-			zui_combo(base_bits_handle, ["8bit"], tr("Color"), true);
-			///else
-			zui_combo(base_bits_handle, ["8bit", "16bit", "32bit"], tr("Color"), true);
-			///end
-
-			///if is_paint
-			if (base_bits_handle.changed) {
-				app_notify_on_init(base_set_layer_bits);
-			}
-			///end
-
-			zui_row([0.5, 0.5]);
-			if (base_bits_handle.position == texture_bits_t.BITS8) {
-				context_raw.format_type = zui_combo(zui_handle("boxexport_0", { position: context_raw.format_type }), ["png", "jpg"], tr("Format"), true);
-			}
-			else {
-				context_raw.format_type = zui_combo(zui_handle("boxexport_1", { position: context_raw.format_type }), ["exr"], tr("Format"), true);
-			}
-
-			ui.enabled = context_raw.format_type == texture_ldr_format_t.JPG && base_bits_handle.position == texture_bits_t.BITS8;
-			context_raw.format_quality = zui_slider(zui_handle("boxexport_2", { value: context_raw.format_quality }), tr("Quality"), 0.0, 100.0, true, 1);
-			ui.enabled = true;
-
-			///if is_paint
-			zui_row([0.5, 0.5]);
-			ui.enabled = !bake_material;
-			let layers_export_handle: zui_handle_t = zui_handle("boxexport_3");
-			layers_export_handle.position = context_raw.layers_export;
-			context_raw.layers_export = zui_combo(layers_export_handle, [tr("Visible"), tr("Selected"), tr("Per Object"), tr("Per Udim Tile")], tr("Layers"), true);
-			ui.enabled = true;
-			///end
-
-			zui_combo(BoxExport.hpreset, BoxExport.files, tr("Preset"), true);
-			if (BoxExport.hpreset.changed) BoxExport.preset = null;
-
-			let layers_destination_handle: zui_handle_t = zui_handle("boxexport_4");
-			layers_destination_handle.position = context_raw.layers_destination;
-			context_raw.layers_destination = zui_combo(layers_destination_handle, [tr("Disk"), tr("Packed")], tr("Destination"), true);
-
-			zui_end_element();
-
-			zui_row([0.5, 0.5]);
-			if (zui_button(tr("Cancel"))) {
-				ui_box_hide();
-			}
-			if (zui_button(tr("Export"))) {
-				ui_box_hide();
-				if (context_raw.layers_destination == export_destination_t.PACKED) {
-					context_raw.texture_export_path = "/";
-					let _init = () => {
-						///if is_paint
-						ExportTexture.run(context_raw.texture_export_path, bake_material);
-						///end
-						///if is_lab
-						ExportTexture.run(context_raw.texture_export_path);
-						///end
-					}
-					app_notify_on_init(_init);
-				}
-				else {
-					let filters = base_bits_handle.position != texture_bits_t.BITS8 ? "exr" : context_raw.format_type == texture_ldr_format_t.PNG ? "png" : "jpg";
-					ui_files_show(filters, true, false, (path: string) => {
-						context_raw.texture_export_path = path;
-						let doExport = () => {
-							let _init = () => {
-								///if is_paint
-								ExportTexture.run(context_raw.texture_export_path, bake_material);
-								///end
-								///if is_lab
-								ExportTexture.run(context_raw.texture_export_path);
-								///end
-							}
-							app_notify_on_init(_init);
-						}
-						///if (krom_android || krom_ios)
-						base_notify_on_next_frame(() => {
-							console_toast(tr("Exporting textures"));
-							base_notify_on_next_frame(doExport);
-						});
-						///else
-						doExport();
-						///end
-					});
-				}
-			}
-			if (ui.is_hovered) zui_tooltip(tr("Export texture files") + ` (${config_keymap.file_export_textures})`);
-		}
-	}
-
-	static tab_presets = (ui: zui_t) => {
-		let tab_vertical: bool = config_raw.touch_ui;
-		if (zui_tab(BoxExport.htab, tr("Presets"), tab_vertical)) {
-			zui_row([3 / 5, 1 / 5, 1 / 5]);
-
-			zui_combo(BoxExport.hpreset, BoxExport.files, tr("Preset"));
-			if (BoxExport.hpreset.changed) BoxExport.preset = null;
-
-			if (zui_button(tr("New"))) {
-				ui_box_show_custom((ui: zui_t) => {
-					let tab_vertical: bool = config_raw.touch_ui;
-					if (zui_tab(zui_handle("boxexport_5"), tr("New Preset"), tab_vertical)) {
-						zui_row([0.5, 0.5]);
-						let preset_name: string = zui_text_input(zui_handle("boxexport_6", { text: "new_preset" }), tr("Name"));
-						if (zui_button(tr("OK")) || ui.is_return_down) {
-							BoxExport.new_preset(preset_name);
-							BoxExport.fetch_presets();
-							BoxExport.preset = null;
-							BoxExport.hpreset.position = BoxExport.files.indexOf(preset_name);
-							ui_box_hide();
-							BoxExport.htab.position = 1; // Presets
-							BoxExport.show_textures();
-						}
-					}
-				});
-			}
-
-			if (zui_button(tr("Import"))) {
-				ui_files_show("json", false, false, (path: string) => {
-					path = path.toLowerCase();
-					if (path.endsWith(".json")) {
-						let filename: string = path.substr(path.lastIndexOf(path_sep) + 1);
-						let dst_path: string = path_data() + path_sep + "export_presets" + path_sep + filename;
-						file_copy(path, dst_path); // Copy to presets folder
-						BoxExport.fetch_presets();
-						BoxExport.preset = null;
-						BoxExport.hpreset.position = BoxExport.files.indexOf(filename.substr(0, filename.length - 5)); // Strip .json
-						console_info(tr("Preset imported:") + " " + filename);
-					}
-					else console_error(strings_error1());
-				});
-			}
-
-			if (BoxExport.preset == null) {
-				BoxExport.parse_preset();
-				BoxExport.hpreset.children = null;
-			}
-
-			// Texture list
-			zui_separator(10, false);
-			zui_row([1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6]);
-			zui_text(tr("Texture"));
-			zui_text(tr("R"));
-			zui_text(tr("G"));
-			zui_text(tr("B"));
-			zui_text(tr("A"));
-			zui_text(tr("Color Space"));
-			ui.changed = false;
-			for (let i: i32 = 0; i < BoxExport.preset.textures.length; ++i) {
-				let t: export_preset_texture_t = BoxExport.preset.textures[i];
-				zui_row([1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6]);
-				let htex: zui_handle_t = zui_nest(BoxExport.hpreset, i);
-				htex.text = t.name;
-				t.name = zui_text_input(htex);
-
-				if (ui.is_hovered && ui.input_released_r) {
-					ui_menu_draw((ui: zui_t) => {
-						if (ui_menu_button(ui, tr("Delete"))) {
-							array_remove(BoxExport.preset.textures, t);
-							BoxExport.save_preset();
-						}
-					}, 1);
-				}
-
-				let hr: zui_handle_t = zui_nest(htex, 0);
-				hr.position = BoxExport.channels.indexOf(t.channels[0]);
-				let hg: zui_handle_t = zui_nest(htex, 1);
-				hg.position = BoxExport.channels.indexOf(t.channels[1]);
-				let hb: zui_handle_t = zui_nest(htex, 2);
-				hb.position = BoxExport.channels.indexOf(t.channels[2]);
-				let ha: zui_handle_t = zui_nest(htex, 3);
-				ha.position = BoxExport.channels.indexOf(t.channels[3]);
-
-				zui_combo(hr, BoxExport.channels, tr("R"));
-				if (hr.changed) t.channels[0] = BoxExport.channels[hr.position];
-				zui_combo(hg, BoxExport.channels, tr("G"));
-				if (hg.changed) t.channels[1] = BoxExport.channels[hg.position];
-				zui_combo(hb, BoxExport.channels, tr("B"));
-				if (hb.changed) t.channels[2] = BoxExport.channels[hb.position];
-				zui_combo(ha, BoxExport.channels, tr("A"));
-				if (ha.changed) t.channels[3] = BoxExport.channels[ha.position];
-
-				let hspace: zui_handle_t = zui_nest(htex, 4);
-				hspace.position = BoxExport.color_spaces.indexOf(t.color_space);
-				zui_combo(hspace, BoxExport.color_spaces, tr("Color Space"));
-				if (hspace.changed) t.color_space = BoxExport.color_spaces[hspace.position];
-			}
-
-			if (ui.changed) {
-				BoxExport.save_preset();
-			}
-
-			zui_row([1 / 8]);
-			if (zui_button(tr("Add"))) {
-				BoxExport.preset.textures.push({ name: "base", channels: ["base_r", "base_g", "base_b", "1.0"], color_space: "linear" });
-				BoxExport.hpreset.children = null;
-				BoxExport.save_preset();
-			}
-		}
-	}
-	///end
-
-	///if is_paint
-	static tab_atlases = (ui: zui_t) => {
-		let tab_vertical: bool = config_raw.touch_ui;
-		if (zui_tab(BoxExport.htab, tr("Atlases"), tab_vertical)) {
-			if (project_atlas_objects == null || project_atlas_objects.length != project_paint_objects.length) {
-				project_atlas_objects = [];
-				project_atlas_names = [];
-				for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
-					project_atlas_objects.push(0);
-					project_atlas_names.push(tr("Atlas") + " " + (i + 1));
-				}
-			}
-			for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
-				zui_row([1 / 2, 1 / 2]);
-				zui_text(project_paint_objects[i].base.name);
-				let hatlas: zui_handle_t = zui_nest(zui_handle("boxexport_7"), i);
-				hatlas.position = project_atlas_objects[i];
-				project_atlas_objects[i] = zui_combo(hatlas, project_atlas_names, tr("Atlas"));
-			}
-		}
-	}
-	///end
-
-	static show_mesh = () => {
-		BoxExport.export_mesh_handle.position = context_raw.export_mesh_index;
-		ui_box_show_custom((ui: zui_t) => {
-			let htab: zui_handle_t = zui_handle("boxexport_8");
-			BoxExport.tab_export_mesh(ui, htab);
-		});
-	}
-
-	static tab_export_mesh = (ui: zui_t, htab: zui_handle_t) => {
-		let tab_vertical: bool = config_raw.touch_ui;
-		if (zui_tab(htab, tr("Export Mesh"), tab_vertical)) {
-
-			zui_row([1 / 2, 1 / 2]);
-
-			context_raw.export_mesh_format = zui_combo(zui_handle("boxexport_9", { position: context_raw.export_mesh_format }), ["obj", "arm"], tr("Format"), true);
-
-			let ar: string[] = [tr("All")];
-			for (let p of project_paint_objects) ar.push(p.base.name);
-			zui_combo(BoxExport.export_mesh_handle, ar, tr("Meshes"), true);
-
-			let apply_displacement: bool = zui_check(zui_handle("boxexport_10"), tr("Apply Displacement"));
-
-			let tris: i32 = 0;
-			let pos: i32 = BoxExport.export_mesh_handle.position;
-			let paint_objects: mesh_object_t[] = pos == 0 ? project_paint_objects : [project_paint_objects[pos - 1]];
-			for (let po of paint_objects) {
-				for (let inda of po.data.index_arrays) {
-					tris += math_floor(inda.values.length / 3);
-				}
-			}
-			zui_text(tris + " " + tr("triangles"));
-
-			zui_row([0.5, 0.5]);
-			if (zui_button(tr("Cancel"))) {
-				ui_box_hide();
-			}
-			if (zui_button(tr("Export"))) {
-				ui_box_hide();
-				ui_files_show(context_raw.export_mesh_format == mesh_format_t.OBJ ? "obj" : "arm", true, false, (path: string) => {
-					///if (krom_android || krom_ios)
-					let f: string = sys_title();
-					///else
-					let f: string = ui_files_filename;
-					///end
-					if (f == "") f = tr("untitled");
-					let doExport = () => {
-						ExportMesh.run(path + path_sep + f, BoxExport.export_mesh_handle.position == 0 ? null : [project_paint_objects[BoxExport.export_mesh_handle.position - 1]], apply_displacement);
-					}
-					///if (krom_android || krom_ios)
-					base_notify_on_next_frame(() => {
-						console_toast(tr("Exporting mesh"));
-						base_notify_on_next_frame(doExport);
-					});
-					///else
-					doExport();
-					///end
-				});
-			}
-		}
-	}
-
-	///if (is_paint || is_sculpt)
-	static show_material = () => {
-		ui_box_show_custom((ui: zui_t) => {
-			let htab: zui_handle_t = zui_handle("boxexport_11");
-			let tab_vertical: bool = config_raw.touch_ui;
-			if (zui_tab(htab, tr("Export Material"), tab_vertical)) {
-				let h1: zui_handle_t = zui_handle("boxexport_12");
-				let h2: zui_handle_t = zui_handle("boxexport_13");
-				h1.selected = context_raw.pack_assets_on_export;
-				h2.selected = context_raw.write_icon_on_export;
-				context_raw.pack_assets_on_export = zui_check(h1, tr("Pack Assets"));
-				context_raw.write_icon_on_export = zui_check(h2, tr("Export Icon"));
-				zui_row([0.5, 0.5]);
-				if (zui_button(tr("Cancel"))) {
-					ui_box_hide();
-				}
-				if (zui_button(tr("Export"))) {
-					ui_box_hide();
-					ui_files_show("arm", true, false, (path: string) => {
-						let f: string = ui_files_filename;
-						if (f == "") f = tr("untitled");
-						app_notify_on_init(() => {
-							ExportArm.run_material(path + path_sep + f);
-						});
-					});
-				}
-			}
-		});
-	}
-
-	static show_brush = () => {
-		ui_box_show_custom((ui: zui_t) => {
-			let htab: zui_handle_t = zui_handle("boxexport_14");
-			let tab_vertical: bool = config_raw.touch_ui;
-			if (zui_tab(htab, tr("Export Brush"), tab_vertical)) {
-				let h1: zui_handle_t = zui_handle("boxexport_15");
-				let h2: zui_handle_t = zui_handle("boxexport_16");
-				h1.selected = context_raw.pack_assets_on_export;
-				h2.selected = context_raw.write_icon_on_export;
-				context_raw.pack_assets_on_export = zui_check(h1, tr("Pack Assets"));
-				context_raw.write_icon_on_export = zui_check(h2, tr("Export Icon"));
-				zui_row([0.5, 0.5]);
-				if (zui_button(tr("Cancel"))) {
-					ui_box_hide();
-				}
-				if (zui_button(tr("Export"))) {
-					ui_box_hide();
-					ui_files_show("arm", true, false, (path: string) => {
-						let f: string = ui_files_filename;
-						if (f == "") f = tr("untitled");
-						app_notify_on_init(() => {
-							ExportArm.run_brush(path + path_sep + f);
-						});
-					});
-				}
-			}
-		});
-	}
-	///end
-
-	///if (is_paint || is_lab)
-	static fetch_presets = () => {
-		BoxExport.files = file_read_directory(path_data() + path_sep + "export_presets");
-		for (let i: i32 = 0; i < BoxExport.files.length; ++i) {
-			BoxExport.files[i] = BoxExport.files[i].substr(0, BoxExport.files[i].length - 5); // Strip .json
-		}
-	}
-
-	static parse_preset = () => {
-		let file: string = "export_presets/" + BoxExport.files[BoxExport.hpreset.position] + ".json";
-		let blob: ArrayBuffer = data_get_blob(file);
-		BoxExport.preset = json_parse(sys_buffer_to_string(blob));
-		data_delete_blob("export_presets/" + file);
-	}
-
-	static new_preset = (name: string) => {
-		let template: string =
-`{
-	"textures": [
-		{ "name": "base", "channels": ["base_r", "base_g", "base_b", "1.0"], "color_space": "linear" }
-	]
-}
-`;
-		if (!name.endsWith(".json")) name += ".json";
-		let path: string = path_data() + path_sep + "export_presets" + path_sep + name;
-		krom_file_save_bytes(path, sys_string_to_buffer(template));
-	}
-
-	static save_preset = () => {
-		let name: string = BoxExport.files[BoxExport.hpreset.position];
-		if (name == "generic") return; // generic is const
-		let path: string = path_data() + path_sep + "export_presets" + path_sep + name + ".json";
-		krom_file_save_bytes(path, sys_string_to_buffer(json_stringify(BoxExport.preset)));
-	}
-	///end
-}

+ 0 - 692
base/Sources/BoxPreferences.ts

@@ -1,692 +0,0 @@
-
-class BoxPreferences {
-
-	static htab : zui_handle_t= zui_handle_create();
-	static files_plugin: string[] = null;
-	static files_keymap: string[] = null;
-	static theme_handle: zui_handle_t;
-	static preset_handle: zui_handle_t;
-	static locales: string[] = null;
-	static themes: string[] = null;
-	static world_color: i32 = 0xff080808;
-
-	static show = () => {
-
-		ui_box_show_custom((ui: zui_t) => {
-			if (zui_tab(BoxPreferences.htab, tr("Interface"), true)) {
-
-				if (BoxPreferences.locales == null) {
-					BoxPreferences.locales = translator_get_supported_locales();
-				}
-
-				let locale_handle: zui_handle_t = zui_handle("boxpreferences_0", { position: BoxPreferences.locales.indexOf(config_raw.locale) });
-				zui_combo(locale_handle, BoxPreferences.locales, tr("Language"), true);
-				if (locale_handle.changed) {
-					let locale_code: string = BoxPreferences.locales[locale_handle.position];
-					config_raw.locale = locale_code;
-					translator_load_translations(locale_code);
-					ui_base_tag_ui_redraw();
-				}
-
-				let hscale: zui_handle_t = zui_handle("boxpreferences_1", { value: config_raw.window_scale });
-				zui_slider(hscale, tr("UI Scale"), 1.0, 4.0, true, 10);
-				if (context_raw.hscale_was_changed && !ui.input_down) {
-					context_raw.hscale_was_changed = false;
-					if (hscale.value == null || isNaN(hscale.value)) hscale.value = 1.0;
-					config_raw.window_scale = hscale.value;
-					BoxPreferences.set_scale();
-				}
-				if (hscale.changed) context_raw.hscale_was_changed = true;
-
-				let hspeed: zui_handle_t = zui_handle("boxpreferences_2", { value: config_raw.camera_zoom_speed });
-				config_raw.camera_zoom_speed = zui_slider(hspeed, tr("Camera Zoom Speed"), 0.1, 4.0, true);
-
-				hspeed = zui_handle("boxpreferences_3", { value: config_raw.camera_rotation_speed });
-				config_raw.camera_rotation_speed = zui_slider(hspeed, tr("Camera Rotation Speed"), 0.1, 4.0, true);
-
-				hspeed = zui_handle("boxpreferences_4", { value: config_raw.camera_pan_speed });
-				config_raw.camera_pan_speed = zui_slider(hspeed, tr("Camera Pan Speed"), 0.1, 4.0, true);
-
-				let zoom_direction_handle: zui_handle_t = zui_handle("boxpreferences_5", { position: config_raw.zoom_direction });
-				zui_combo(zoom_direction_handle, [tr("Vertical"), tr("Vertical Inverted"), tr("Horizontal"), tr("Horizontal Inverted"), tr("Vertical and Horizontal"), tr("Vertical and Horizontal Inverted")], tr("Direction to Zoom"), true);
-				if (zoom_direction_handle.changed) {
-					config_raw.zoom_direction = zoom_direction_handle.position;
-				}
-
-				config_raw.wrap_mouse = zui_check(zui_handle("boxpreferences_6", { selected: config_raw.wrap_mouse }), tr("Wrap Mouse"));
-				if (ui.is_hovered) zui_tooltip(tr("Wrap mouse around view boundaries during camera control"));
-
-				config_raw.node_preview = zui_check(zui_handle("boxpreferences_7", { selected: config_raw.node_preview }), tr("Show Node Preview"));
-
-				ui.changed = false;
-				config_raw.show_asset_names = zui_check(zui_handle("boxpreferences_8", { selected: config_raw.show_asset_names }), tr("Show Asset Names"));
-				if (ui.changed) {
-					ui_base_tag_ui_redraw();
-				}
-
-				///if !(krom_android || krom_ios)
-				ui.changed = false;
-				config_raw.touch_ui = zui_check(zui_handle("boxpreferences_9", { selected: config_raw.touch_ui }), tr("Touch UI"));
-				if (ui.changed) {
-					zui_set_touch_scroll(config_raw.touch_ui);
-					zui_set_touch_hold(config_raw.touch_ui);
-					zui_set_touch_tooltip(config_raw.touch_ui);
-					config_load_theme(config_raw.theme);
-					BoxPreferences.set_scale();
-					ui_base_tag_ui_redraw();
-				}
-				///end
-
-				config_raw.splash_screen = zui_check(zui_handle("boxpreferences_10", { selected: config_raw.splash_screen }), tr("Splash Screen"));
-
-				// Zui.text("Node Editor");
-				// let grid_snap: bool = Zui.check(Zui.handle("boxpreferences_11", { selected: false }), "Grid Snap");
-
-				zui_end_element();
-				zui_row([0.5, 0.5]);
-				if (zui_button(tr("Restore")) && !ui_menu_show) {
-					ui_menu_draw((ui: zui_t) => {
-						if (ui_menu_button(ui, tr("Confirm"))) {
-							app_notify_on_init(() => {
-								ui.t.ELEMENT_H = base_default_element_h;
-								config_restore();
-								BoxPreferences.set_scale();
-								if (BoxPreferences.files_plugin != null) for (let f of BoxPreferences.files_plugin) plugin_stop(f);
-								BoxPreferences.files_plugin = null;
-								BoxPreferences.files_keymap = null;
-								MakeMaterial.parse_mesh_material();
-								MakeMaterial.parse_paint_material();
-							});
-						}
-						if (ui_menu_button(ui, tr("Import..."))) {
-							ui_files_show("json", false, false, (path: string) => {
-								let b: ArrayBuffer = data_get_blob(path);
-								let raw: config_t = json_parse(sys_buffer_to_string(b));
-								app_notify_on_init(() => {
-									ui.t.ELEMENT_H = base_default_element_h;
-									config_import_from(raw);
-									BoxPreferences.set_scale();
-									MakeMaterial.parse_mesh_material();
-									MakeMaterial.parse_paint_material();
-								});
-							});
-						}
-					}, 2);
-				}
-				if (zui_button(tr("Reset Layout")) && !ui_menu_show) {
-					ui_menu_draw((ui: zui_t) => {
-						if (ui_menu_button(ui, tr("Confirm"))) {
-							base_init_layout();
-							config_save();
-						}
-					}, 1);
-				}
-			}
-
-			if (zui_tab(BoxPreferences.htab, tr("Theme"), true)) {
-
-				if (BoxPreferences.themes == null) {
-					BoxPreferences.fetch_themes();
-				}
-				BoxPreferences.theme_handle = zui_handle("boxpreferences_12", { position: BoxPreferences.get_theme_index() });
-
-				zui_begin_sticky();
-				zui_row([1 / 4, 1 / 4, 1 / 4, 1 / 4]);
-
-				zui_combo(BoxPreferences.theme_handle, BoxPreferences.themes, tr("Theme"));
-				if (BoxPreferences.theme_handle.changed) {
-					config_raw.theme = BoxPreferences.themes[BoxPreferences.theme_handle.position] + ".json";
-					config_load_theme(config_raw.theme);
-				}
-
-				if (zui_button(tr("New"))) {
-					ui_box_show_custom((ui: zui_t) => {
-						if (zui_tab(zui_handle("boxpreferences_13"), tr("New Theme"))) {
-							zui_row([0.5, 0.5]);
-							let theme_name: string = zui_text_input(zui_handle("boxpreferences_14", { text: "new_theme" }), tr("Name"));
-							if (zui_button(tr("OK")) || ui.is_return_down) {
-								let template: string = json_stringify(base_theme);
-								if (!theme_name.endsWith(".json")) theme_name += ".json";
-								let path: string = path_data() + path_sep + "themes" + path_sep + theme_name;
-								krom_file_save_bytes(path, sys_string_to_buffer(template));
-								BoxPreferences.fetch_themes(); // Refresh file list
-								config_raw.theme = theme_name;
-								BoxPreferences.theme_handle.position = BoxPreferences.get_theme_index();
-								ui_box_hide();
-								BoxPreferences.htab.position = 1; // Themes
-								BoxPreferences.show();
-							}
-						}
-					});
-				}
-
-				if (zui_button(tr("Import"))) {
-					ui_files_show("json", false, false, (path: string) => {
-						ImportTheme.run(path);
-					});
-				}
-
-				if (zui_button(tr("Export"))) {
-					ui_files_show("json", true, false, (path: string) => {
-						path += path_sep + ui_files_filename;
-						if (!path.endsWith(".json")) path += ".json";
-						krom_file_save_bytes(path, sys_string_to_buffer(json_stringify(base_theme)));
-					});
-				}
-
-				zui_end_sticky();
-
-				let i: i32 = 0;
-				let theme: any = base_theme;
-				let hlist: zui_handle_t = zui_handle("boxpreferences_15");
-
-				// Viewport color
-				let h: zui_handle_t = zui_nest(hlist, i++, { color: BoxPreferences.world_color });
-				zui_row([1 / 8, 7 / 8]);
-				zui_text("", 0, h.color);
-				if (ui.is_hovered && ui.input_released) {
-					ui_menu_draw((ui) => {
-						ui.changed = false;
-						zui_color_wheel(h, false, null, 11 * ui.t.ELEMENT_H * zui_SCALE(ui), true);
-						if (ui.changed) ui_menu_keep_open = true;
-					}, 11);
-				}
-				let val: i32 = h.color;
-				if (val < 0) val += 4294967296;
-				h.text = val.toString(16);
-				zui_text_input(h, "VIEWPORT_COL");
-				h.color = parseInt(h.text, 16);
-
-				if (BoxPreferences.world_color != h.color) {
-					BoxPreferences.world_color = h.color;
-					let b: Uint8Array = new Uint8Array(4);
-					b[0] = color_get_rb(BoxPreferences.world_color);
-					b[1] = color_get_gb(BoxPreferences.world_color);
-					b[2] = color_get_bb(BoxPreferences.world_color);
-					b[3] = 255;
-					context_raw.empty_envmap = image_from_bytes(b.buffer, 1, 1);
-					context_raw.ddirty = 2;
-					if (!context_raw.show_envmap) {
-						scene_world._.envmap = context_raw.empty_envmap;
-					}
-				}
-
-				// Theme fields
-				for (let key of Object.getOwnPropertyNames(theme_t.prototype)) {
-					if (key == "constructor") continue;
-
-					let h: zui_handle_t = zui_nest(hlist, i++);
-					let val: any = theme[key];
-
-					let isHex: bool = key.endsWith("_COL");
-					if (isHex && val < 0) val += 4294967296;
-
-					if (isHex) {
-						zui_row([1 / 8, 7 / 8]);
-						zui_text("", 0, val);
-						if (ui.is_hovered && ui.input_released) {
-							h.color = theme[key];
-							ui_menu_draw((ui) => {
-								ui.changed = false;
-								let color: i32 = zui_color_wheel(h, false, null, 11 * ui.t.ELEMENT_H * zui_SCALE(ui), true);
-								theme[key] = color;
-								if (ui.changed) ui_menu_keep_open = true;
-							}, 11);
-						}
-					}
-
-					ui.changed = false;
-
-					if (typeof val == "boolean") {
-						h.selected = val;
-						let b: bool = zui_check(h, key);
-						theme[key] = b;
-					}
-					else if (key == "LINK_STYLE") {
-						let styles: string[] = [tr("Straight"), tr("Curved")];
-						h.position = val;
-						let i: i32 = zui_combo(h, styles, key, true);
-						theme[key] = i;
-					}
-					else {
-						h.text = isHex ? val.toString(16) : val.toString();
-						zui_text_input(h, key);
-						if (isHex) theme[key] = parseInt(h.text, 16);
-						else theme[key] = parseInt(h.text);
-					}
-
-					if (ui.changed) {
-						for (let ui of base_get_uis()) {
-							ui.elements_baked = false;
-						}
-					}
-				}
-			}
-
-			if (zui_tab(BoxPreferences.htab, tr("Usage"), true)) {
-				context_raw.undo_handle = zui_handle("boxpreferences_16", { value: config_raw.undo_steps });
-				config_raw.undo_steps = math_floor(zui_slider(context_raw.undo_handle, tr("Undo Steps"), 1, 64, false, 1));
-				if (config_raw.undo_steps < 1) {
-					config_raw.undo_steps = math_floor(context_raw.undo_handle.value = 1);
-				}
-				if (context_raw.undo_handle.changed) {
-					let current: image_t = _g2_current;
-					g2_end();
-
-					///if (is_paint || is_sculpt)
-					while (history_undo_layers.length < config_raw.undo_steps) {
-						let l: SlotLayerRaw = SlotLayer.create("_undo" + history_undo_layers.length);
-						history_undo_layers.push(l);
-					}
-					while (history_undo_layers.length > config_raw.undo_steps) {
-						let l: SlotLayerRaw = history_undo_layers.pop();
-						SlotLayer.unload(l);
-					}
-					///end
-
-					history_reset();
-					g2_begin(current);
-				}
-
-				///if is_paint
-				config_raw.dilate_radius = math_floor(zui_slider(zui_handle("boxpreferences_17", { value: config_raw.dilate_radius }), tr("Dilate Radius"), 0.0, 16.0, true, 1));
-				if (ui.is_hovered) zui_tooltip(tr("Dilate painted textures to prevent seams"));
-
-				let dilate_handle: zui_handle_t = zui_handle("boxpreferences_18", { position: config_raw.dilate });
-				zui_combo(dilate_handle, [tr("Instant"), tr("Delayed")], tr("Dilate"), true);
-				if (dilate_handle.changed) {
-					config_raw.dilate = dilate_handle.position;
-				}
-				///end
-
-				///if is_lab
-				let workspace_handle: zui_handle_t = zui_handle("boxpreferences_19", { position: config_raw.workspace });
-				zui_combo(workspace_handle, [tr("3D View"), tr("2D View")], tr("Default Workspace"), true);
-				if (workspace_handle.changed) {
-					config_raw.workspace = workspace_handle.position;
-				}
-				///end
-
-				let camera_controls_handle: zui_handle_t = zui_handle("boxpreferences_20", { position: config_raw.camera_controls });
-				zui_combo(camera_controls_handle, [tr("Orbit"), tr("Rotate"), tr("Fly")], tr("Default Camera Controls"), true);
-				if (camera_controls_handle.changed) {
-					config_raw.camera_controls = camera_controls_handle.position;
-				}
-
-				let layer_res_handle: zui_handle_t = zui_handle("boxpreferences_21", { position: config_raw.layer_res });
-
-				///if is_paint
-				///if (krom_android || krom_ios)
-				zui_combo(layer_res_handle, ["128", "256", "512", "1K", "2K", "4K"], tr("Default Layer Resolution"), true);
-				///else
-				zui_combo(layer_res_handle, ["128", "256", "512", "1K", "2K", "4K", "8K"], tr("Default Layer Resolution"), true);
-				///end
-				///end
-
-				///if is_lab
-				///if (krom_android || krom_ios)
-				zui_combo(layer_res_handle, ["2K", "4K"], tr("Default Layer Resolution"), true);
-				///else
-				zui_combo(layer_res_handle, ["2K", "4K", "8K", "16K"], tr("Default Layer Resolution"), true);
-				///end
-				///end
-
-				if (layer_res_handle.changed) {
-					config_raw.layer_res = layer_res_handle.position;
-				}
-
-				let server_handle: zui_handle_t = zui_handle("boxpreferences_22", { text: config_raw.server });
-				config_raw.server = zui_text_input(server_handle, tr("Cloud Server"));
-
-				///if (is_paint || is_sculpt)
-				let material_live_handle: zui_handle_t = zui_handle("boxpreferences_23", {selected: config_raw.material_live });
-				config_raw.material_live = zui_check(material_live_handle, tr("Live Material Preview"));
-				if (ui.is_hovered) zui_tooltip(tr("Instantly update material preview on node change"));
-
-				let brush_live_handle: zui_handle_t = zui_handle("boxpreferences_24", { selected: config_raw.brush_live });
-				config_raw.brush_live = zui_check(brush_live_handle, tr("Live Brush Preview"));
-				if (ui.is_hovered) zui_tooltip(tr("Draw live brush preview in viewport"));
-				if (brush_live_handle.changed) context_raw.ddirty = 2;
-
-				let brush_3d_handle: zui_handle_t = zui_handle("boxpreferences_25", { selected: config_raw.brush_3d });
-				config_raw.brush_3d = zui_check(brush_3d_handle, tr("3D Cursor"));
-				if (brush_3d_handle.changed) MakeMaterial.parse_paint_material();
-
-				ui.enabled = config_raw.brush_3d;
-				let brush_depth_reject_handle: zui_handle_t = zui_handle("boxpreferences_26", { selected: config_raw.brush_depth_reject });
-				config_raw.brush_depth_reject = zui_check(brush_depth_reject_handle, tr("Depth Reject"));
-				if (brush_depth_reject_handle.changed) MakeMaterial.parse_paint_material();
-
-				zui_row([0.5, 0.5]);
-
-				let brush_angle_reject_handle: zui_handle_t = zui_handle("boxpreferences_27", { selected: config_raw.brush_angle_reject });
-				config_raw.brush_angle_reject = zui_check(brush_angle_reject_handle, tr("Angle Reject"));
-				if (brush_angle_reject_handle.changed) MakeMaterial.parse_paint_material();
-
-				if (!config_raw.brush_angle_reject) ui.enabled = false;
-				let angle_dot_handle: zui_handle_t = zui_handle("boxpreferences_28", { value: context_raw.brush_angle_reject_dot });
-				context_raw.brush_angle_reject_dot = zui_slider(angle_dot_handle, tr("Angle"), 0.0, 1.0, true);
-				if (angle_dot_handle.changed) {
-					MakeMaterial.parse_paint_material();
-				}
-				ui.enabled = true;
-				///end
-
-				///if is_lab
-				config_raw.gpu_inference = zui_check(zui_handle("boxpreferences_29", { selected: config_raw.gpu_inference }), tr("Use GPU"));
-				if (ui.is_hovered) zui_tooltip(tr("Use GPU to accelerate node graph processing"));
-				///end
-			}
-
-			let pen_name: string;
-			///if krom_ios
-			pen_name = tr("Pencil");
-			///else
-			pen_name = tr("Pen");
-			///end
-
-			if (zui_tab(BoxPreferences.htab, pen_name, true)) {
-				zui_text(tr("Pressure controls"));
-				config_raw.pressure_radius = zui_check(zui_handle("boxpreferences_30", { selected: config_raw.pressure_radius }), tr("Brush Radius"));
-				config_raw.pressure_sensitivity = zui_slider(zui_handle("boxpreferences_31", { value: config_raw.pressure_sensitivity }), tr("Sensitivity"), 0.0, 10.0, true);
-				///if (is_paint || is_sculpt)
-				config_raw.pressure_hardness = zui_check(zui_handle("boxpreferences_32", { selected: config_raw.pressure_hardness }), tr("Brush Hardness"));
-				config_raw.pressure_opacity = zui_check(zui_handle("boxpreferences_33", { selected: config_raw.pressure_opacity }), tr("Brush Opacity"));
-				config_raw.pressure_angle = zui_check(zui_handle("boxpreferences_34", { selected: config_raw.pressure_angle }), tr("Brush Angle"));
-				///end
-
-				zui_end_element();
-				zui_row([0.5]);
-				if (zui_button(tr("Help"))) {
-					///if (is_paint || is_sculpt)
-					file_load_url("https://github.com/armory3d/armorpaint_docs///pen");
-					///end
-					///if is_lab
-					file_load_url("https://github.com/armory3d/armorlab_docs///pen");
-					///end
-				}
-			}
-
-			context_raw.hssao = zui_handle("boxpreferences_35", { selected: config_raw.rp_ssao });
-			context_raw.hssr = zui_handle("boxpreferences_36", { selected: config_raw.rp_ssr });
-			context_raw.hbloom = zui_handle("boxpreferences_37", { selected: config_raw.rp_bloom });
-			context_raw.hsupersample = zui_handle("boxpreferences_38", { position: config_get_super_sample_quality(config_raw.rp_supersample) });
-			context_raw.hvxao = zui_handle("boxpreferences_39", { selected: config_raw.rp_gi });
-			if (zui_tab(BoxPreferences.htab, tr("Viewport"), true)) {
-				///if (krom_direct3d12 || krom_vulkan || krom_metal)
-
-				let hpathtrace_mode: zui_handle_t = zui_handle("boxpreferences_40", { position: context_raw.pathtrace_mode });
-				context_raw.pathtrace_mode = zui_combo(hpathtrace_mode, [tr("Core"), tr("Full")], tr("Path Tracer"), true);
-				if (hpathtrace_mode.changed) {
-					RenderPathRaytrace.ready = false;
-				}
-
-				///end
-
-				let hrender_mode: zui_handle_t = zui_handle("boxpreferences_41", { position: context_raw.render_mode });
-				context_raw.render_mode = zui_combo(hrender_mode, [tr("Full"), tr("Mobile")], tr("Renderer"), true);
-				if (hrender_mode.changed) {
-					context_set_render_path();
-				}
-
-				zui_combo(context_raw.hsupersample, ["0.25x", "0.5x", "1.0x", "1.5x", "2.0x", "4.0x"], tr("Super Sample"), true);
-				if (context_raw.hsupersample.changed) config_apply();
-
-				if (context_raw.render_mode == render_mode_t.DEFERRED) {
-					///if arm_voxels
-					zui_check(context_raw.hvxao, tr("Voxel AO"));
-					if (ui.is_hovered) zui_tooltip(tr("Cone-traced AO and shadows"));
-					if (context_raw.hvxao.changed) {
-						config_apply();
-					}
-
-					ui.enabled = context_raw.hvxao.selected;
-					let h: zui_handle_t = zui_handle("boxpreferences_42", { value: context_raw.vxao_offset });
-					context_raw.vxao_offset = zui_slider(h, tr("Cone Offset"), 1.0, 4.0, true);
-					if (h.changed) context_raw.ddirty = 2;
-					h = zui_handle("boxpreferences_43", { value: context_raw.vxao_aperture });
-					context_raw.vxao_aperture = zui_slider(h, tr("Aperture"), 1.0, 4.0, true);
-					if (h.changed) context_raw.ddirty = 2;
-					ui.enabled = true;
-					///end
-
-					zui_check(context_raw.hssao, tr("SSAO"));
-					if (context_raw.hssao.changed) config_apply();
-					zui_check(context_raw.hssr, tr("SSR"));
-					if (context_raw.hssr.changed) config_apply();
-					zui_check(context_raw.hbloom, tr("Bloom"));
-					if (context_raw.hbloom.changed) config_apply();
-				}
-
-				let h: zui_handle_t = zui_handle("boxpreferences_44", { value: config_raw.rp_vignette });
-				config_raw.rp_vignette = zui_slider(h, tr("Vignette"), 0.0, 1.0, true);
-				if (h.changed) context_raw.ddirty = 2;
-
-				h = zui_handle("boxpreferences_45", { value: config_raw.rp_grain });
-				config_raw.rp_grain = zui_slider(h, tr("Noise Grain"), 0.0, 1.0, true);
-				if (h.changed) context_raw.ddirty = 2;
-
-				// let h: zui_handle_t = Zui.handle("boxpreferences_46", { value: raw.autoExposureStrength });
-				// raw.autoExposureStrength = Zui.slider(h, "Auto Exposure", 0.0, 2.0, true);
-				// if (h.changed) raw.ddirty = 2;
-
-				let cam: camera_object_t = scene_camera;
-				let cam_raw: camera_data_t = cam.data;
-				let near_handle: zui_handle_t = zui_handle("boxpreferences_47");
-				let far_handle: zui_handle_t = zui_handle("boxpreferences_48");
-				near_handle.value = math_floor(cam_raw.near_plane * 1000) / 1000;
-				far_handle.value = math_floor(cam_raw.far_plane * 100) / 100;
-				cam_raw.near_plane = zui_slider(near_handle, tr("Clip Start"), 0.001, 1.0, true);
-				cam_raw.far_plane = zui_slider(far_handle, tr("Clip End"), 50.0, 100.0, true);
-				if (near_handle.changed || far_handle.changed) {
-					camera_object_build_proj(cam);
-				}
-
-				let disp_handle: zui_handle_t = zui_handle("boxpreferences_49", { value: config_raw.displace_strength });
-				config_raw.displace_strength = zui_slider(disp_handle, tr("Displacement Strength"), 0.0, 10.0, true);
-				if (disp_handle.changed) {
-					context_raw.ddirty = 2;
-					MakeMaterial.parse_mesh_material();
-				}
-			}
-			if (zui_tab(BoxPreferences.htab, tr("Keymap"), true)) {
-
-				if (BoxPreferences.files_keymap == null) {
-					BoxPreferences.fetch_keymaps();
-				}
-
-				zui_begin_sticky();
-				zui_row([1 / 4, 1 / 4, 1 / 4, 1 / 4]);
-
-				BoxPreferences.preset_handle = zui_handle("boxpreferences_50", { position: BoxPreferences.get_preset_index() });
-				zui_combo(BoxPreferences.preset_handle, BoxPreferences.files_keymap, tr("Preset"));
-				if (BoxPreferences.preset_handle.changed) {
-					config_raw.keymap = BoxPreferences.files_keymap[BoxPreferences.preset_handle.position] + ".json";
-					config_apply();
-					config_load_keymap();
-				}
-
-				if (zui_button(tr("New"))) {
-					ui_box_show_custom((ui: zui_t) => {
-						if (zui_tab(zui_handle("boxpreferences_51"), tr("New Keymap"))) {
-							zui_row([0.5, 0.5]);
-							let keymap_name: string = zui_text_input(zui_handle("boxpreferences_52", { text: "new_keymap" }), tr("Name"));
-							if (zui_button(tr("OK")) || ui.is_return_down) {
-								let template: string = json_stringify(base_default_keymap);
-								if (!keymap_name.endsWith(".json")) keymap_name += ".json";
-								let path: string = path_data() + path_sep + "keymap_presets" + path_sep + keymap_name;
-								krom_file_save_bytes(path, sys_string_to_buffer(template));
-								BoxPreferences.fetch_keymaps(); // Refresh file list
-								config_raw.keymap = keymap_name;
-								BoxPreferences.preset_handle.position = BoxPreferences.get_preset_index();
-								ui_box_hide();
-								BoxPreferences.htab.position = 5; // Keymap
-								BoxPreferences.show();
-							}
-						}
-					});
-				}
-
-				if (zui_button(tr("Import"))) {
-					ui_files_show("json", false, false, (path: string) => {
-						ImportKeymap.run(path);
-					});
-				}
-				if (zui_button(tr("Export"))) {
-					ui_files_show("json", true, false, (dest: string) => {
-						if (!ui_files_filename.endsWith(".json")) ui_files_filename += ".json";
-						let path: string = path_data() + path_sep + "keymap_presets" + path_sep + config_raw.keymap;
-						file_copy(path, dest + path_sep + ui_files_filename);
-					});
-				}
-
-				zui_end_sticky();
-
-				zui_separator(8, false);
-
-				let i: i32 = 0;
-				ui.changed = false;
-				for (let key in config_keymap) {
-					let h: zui_handle_t = zui_nest(zui_handle("boxpreferences_53"), i++);
-					h.text = config_keymap[key];
-					let text: string = zui_text_input(h, key, zui_align_t.LEFT);
-					config_keymap[key] = text;
-				}
-				if (ui.changed) {
-					config_apply();
-					config_save_keymap();
-				}
-			}
-			if (zui_tab(BoxPreferences.htab, tr("Plugins"), true)) {
-				zui_begin_sticky();
-				zui_row([1 / 4, 1 / 4]);
-				if (zui_button(tr("New"))) {
-					ui_box_show_custom((ui: zui_t) => {
-						if (zui_tab(zui_handle("boxpreferences_54"), tr("New Plugin"))) {
-							zui_row([0.5, 0.5]);
-							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 = new Handle();
-plugin.drawUI = (ui) { =>
-	if (Zui.panel(h1, 'New Plugin')) {
-		if (Zui.button('Button')) {
-			console.error('Hello');
-		}
-	}
-}
-`;
-								if (!plugin_name.endsWith(".js")) plugin_name += ".js";
-								let path: string = path_data() + path_sep + "plugins" + path_sep + plugin_name;
-								krom_file_save_bytes(path, sys_string_to_buffer(template));
-								BoxPreferences.files_plugin = null; // Refresh file list
-								ui_box_hide();
-								BoxPreferences.htab.position = 6; // Plugins
-								BoxPreferences.show();
-							}
-						}
-					});
-				}
-				if (zui_button(tr("Import"))) {
-					ui_files_show("js,zip", false, false, (path: string) => {
-						ImportPlugin.run(path);
-					});
-				}
-				zui_end_sticky();
-
-				if (BoxPreferences.files_plugin == null) {
-					BoxPreferences.fetch_plugins();
-				}
-
-				if (config_raw.plugins == null) config_raw.plugins = [];
-				let h: zui_handle_t = zui_handle("boxpreferences_56", { selected: false });
-				for (let f of BoxPreferences.files_plugin) {
-					let is_js: bool = f.endsWith(".js");
-					if (!is_js) continue;
-					let enabled: bool = config_raw.plugins.indexOf(f) >= 0;
-					h.selected = enabled;
-					let tag: string = is_js ? f.split(".")[0] : f;
-					zui_check(h, tag);
-					if (h.changed && h.selected != enabled) {
-						h.selected ? config_enable_plugin(f) : config_disable_plugin(f);
-						base_redraw_ui();
-					}
-					if (ui.is_hovered && ui.input_released_r) {
-						ui_menu_draw((ui: zui_t) => {
-							let path: string = path_data() + path_sep + "plugins" + path_sep + f;
-							if (ui_menu_button(ui, tr("Edit in Text Editor"))) {
-								file_start(path);
-							}
-							if (ui_menu_button(ui, tr("Edit in Script Tab"))) {
-								let blob: ArrayBuffer = data_get_blob("plugins/" + f);
-								TabScript.hscript.text = sys_buffer_to_string(blob);
-								data_delete_blob("plugins/" + f);
-								console_info(tr("Script opened"));
-							}
-							if (ui_menu_button(ui, tr("Export"))) {
-								ui_files_show("js", true, false, (dest: string) => {
-									if (!ui_files_filename.endsWith(".js")) ui_files_filename += ".js";
-									file_copy(path, dest + path_sep + ui_files_filename);
-								});
-							}
-							if (ui_menu_button(ui, tr("Delete"))) {
-								if (config_raw.plugins.indexOf(f) >= 0) {
-									array_remove(config_raw.plugins, f);
-									plugin_stop(f);
-								}
-								array_remove(BoxPreferences.files_plugin, f);
-								file_delete(path);
-							}
-						}, 4);
-					}
-				}
-			}
-
-		}, 620, config_raw.touch_ui ? 480 : 420, () => { config_save(); });
-	}
-
-	static fetch_themes = () => {
-		BoxPreferences.themes = file_read_directory(path_data() + path_sep + "themes");
-		for (let i: i32 = 0; i < BoxPreferences.themes.length; ++i) BoxPreferences.themes[i] = BoxPreferences.themes[i].substr(0, BoxPreferences.themes[i].length - 5); // Strip .json
-		BoxPreferences.themes.unshift("default");
-	}
-
-	static fetch_keymaps = () => {
-		BoxPreferences.files_keymap = file_read_directory(path_data() + path_sep + "keymap_presets");
-		for (let i: i32 = 0; i < BoxPreferences.files_keymap.length; ++i) {
-			BoxPreferences.files_keymap[i] = BoxPreferences.files_keymap[i].substr(0, BoxPreferences.files_keymap[i].length - 5); // Strip .json
-		}
-		BoxPreferences.files_keymap.unshift("default");
-	}
-
-	static fetch_plugins = () => {
-		BoxPreferences.files_plugin = file_read_directory(path_data() + path_sep + "plugins");
-	}
-
-	static get_theme_index = (): i32 => {
-		return BoxPreferences.themes.indexOf(config_raw.theme.substr(0, config_raw.theme.length - 5)); // Strip .json
-	}
-
-	static get_preset_index = (): i32 => {
-		return BoxPreferences.files_keymap.indexOf(config_raw.keymap.substr(0, config_raw.keymap.length - 5)); // Strip .json
-	}
-
-	static set_scale = () => {
-		let scale: f32 = config_raw.window_scale;
-		zui_set_scale(ui_base_ui, scale);
-		ui_header_h = math_floor(ui_header_default_h * scale);
-		config_raw.layout[layout_size_t.STATUS_H] = math_floor(ui_status_default_status_h * scale);
-		ui_menubar_w = math_floor(ui_menubar_default_w * scale);
-		ui_base_set_icon_scale();
-		zui_set_scale(ui_nodes_ui, scale);
-		zui_set_scale(ui_view2d_ui, scale);
-		zui_set_scale(base_ui_box, scale);
-		zui_set_scale(base_ui_menu, scale);
-		base_resize();
-		///if (is_paint || is_sculpt)
-		config_raw.layout[layout_size_t.SIDEBAR_W] = math_floor(ui_base_default_sidebar_w * scale);
-		ui_toolbar_w = math_floor(ui_toolbar_default_w * scale);
-		///end
-	}
-}

+ 0 - 250
base/Sources/BoxProjects.ts

@@ -1,250 +0,0 @@
-
-class BoxProjects {
-
-	static htab: zui_handle_t = zui_handle_create();
-	static hsearch: zui_handle_t = zui_handle_create();
-	static icon_map: map_t<string, image_t> = null;
-
-	static show = () => {
-		if (BoxProjects.icon_map != null) {
-			for (let handle of BoxProjects.icon_map.keys()) {
-				data_delete_image(handle);
-			}
-			BoxProjects.icon_map = null;
-		}
-
-		let draggable: bool;
-		///if (krom_android || krom_ios)
-		draggable = false;
-		///else
-		draggable = true;
-		///end
-
-		ui_box_show_custom((ui: zui_t) => {
-			///if (krom_android || krom_ios)
-			BoxProjects.align_to_fullscreen();
-			///end
-
-			///if (krom_android || krom_ios)
-			BoxProjects.projects_tab(ui);
-			BoxProjects.get_started_tab(ui);
-			///else
-			BoxProjects.recent_projects_tab(ui);
-			///end
-
-		}, 600, 400, null, draggable);
-	}
-
-	static projects_tab = (ui: zui_t) => {
-		if (zui_tab(BoxProjects.htab, tr("Projects"), true)) {
-			zui_begin_sticky();
-
-			BoxProjects.draw_badge(ui);
-
-			if (zui_button(tr("New"))) {
-				project_new();
-				viewport_scale_to_bounds();
-				ui_box_hide();
-				// Pick unique name
-				let i: i32 = 0;
-				let j: i32 = 0;
-				let title: string = tr("untitled") + i;
-				while (j < config_raw.recent_projects.length) {
-					let base: string = config_raw.recent_projects[j];
-					base = base.substring(base.lastIndexOf(path_sep) + 1, base.lastIndexOf("."));
-					j++;
-					if (title == base) {
-						i++;
-						title = tr("untitled") + i;
-						j = 0;
-					}
-				}
-				sys_title_set(title);
-			}
-			zui_end_sticky();
-			zui_separator(3, false);
-
-			let slotw: i32 = math_floor(150 * zui_SCALE(ui));
-			let num: i32 = math_floor(sys_width() / slotw);
-			let recent_projects: string[] = config_raw.recent_projects;
-			let show_asset_names: bool = true;
-
-			for (let row: i32 = 0; row < math_ceil(recent_projects.length / num); ++row) {
-				let mult = show_asset_names ? 2 : 1;
-				let ar: f32[] = [];
-				for (let i: i32 = 0; i < num * mult; ++i) ar.push(1 / num);
-				zui_row(ar);
-
-				ui._x += 2;
-				let off: f32 = show_asset_names ? zui_ELEMENT_OFFSET(ui) * 16.0 : 6;
-				if (row > 0) ui._y += off;
-
-				for (let j: i32 = 0; j < num; ++j) {
-					let imgw: i32 = math_floor(128 * zui_SCALE(ui));
-					let i: i32 = j + row * num;
-					if (i >= recent_projects.length) {
-						zui_end_element(imgw);
-						if (show_asset_names) zui_end_element(0);
-						continue;
-					}
-
-					let path: string = recent_projects[i];
-
-					///if krom_ios
-					let document_directory: string = krom_save_dialog("", "");
-					document_directory = document_directory.substr(0, document_directory.length - 8); // Strip /'untitled'
-					path = document_directory + path;
-					///end
-
-					let icon_path: string = path.substr(0, path.length - 4) + "_icon.png";
-					if (BoxProjects.icon_map == null) BoxProjects.icon_map = map_create();
-					let icon: image_t = BoxProjects.icon_map.get(icon_path);
-					if (icon == null) {
-						let image: image_t = data_get_image(icon_path);
-						icon = image;
-						BoxProjects.icon_map.set(icon_path, icon);
-					}
-
-					let uix: i32 = ui._x;
-					if (icon != null) {
-						zui_fill(0, 0, 128, 128, ui.t.SEPARATOR_COL);
-
-						let state: i32 = zui_image(icon, 0xffffffff, 128  * zui_SCALE(ui));
-						if (state == zui_state_t.RELEASED) {
-							let _uix: i32 = ui._x;
-							ui._x = uix;
-							zui_fill(0, 0, 128, 128, 0x66000000);
-							ui._x = _uix;
-							let doImport = () => {
-								app_notify_on_init(() => {
-									ui_box_hide();
-									ImportArm.run_project(path);
-								});
-							}
-
-							///if (krom_android || krom_ios)
-							base_notify_on_next_frame(() => {
-								console_toast(tr("Opening project"));
-								base_notify_on_next_frame(doImport);
-							});
-							///else
-							doImport();
-							///end
-						}
-
-						let name: string = path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf("."));
-						if (ui.is_hovered && ui.input_released_r) {
-							ui_menu_draw((ui: zui_t) => {
-								// if (menuButton(ui, tr("Duplicate"))) {}
-								if (ui_menu_button(ui, tr("Delete"))) {
-									app_notify_on_init(() => {
-										file_delete(path);
-										file_delete(icon_path);
-										let data_path: string = path.substr(0, path.length - 4);
-										file_delete(data_path);
-										recent_projects.splice(i, 1);
-									});
-								}
-							}, 1);
-						}
-
-						if (show_asset_names) {
-							ui._x = uix - (150 - 128) / 2;
-							ui._y += slotw * 0.9;
-							zui_text(name, zui_align_t.CENTER);
-							if (ui.is_hovered) zui_tooltip(name);
-							ui._y -= slotw * 0.9;
-							if (i == recent_projects.length - 1) {
-								ui._y += j == num - 1 ? imgw : imgw + zui_ELEMENT_H(ui) + zui_ELEMENT_OFFSET(ui);
-							}
-						}
-					}
-					else {
-						zui_end_element(0);
-						if (show_asset_names) zui_end_element(0);
-						ui._x = uix;
-					}
-				}
-
-				ui._y += 150;
-			}
-		}
-	}
-
-	static recent_projects_tab = (ui: zui_t) => {
-		if (zui_tab(BoxProjects.htab, tr("Recent"), true)) {
-
-			BoxProjects.draw_badge(ui);
-
-			ui.enabled = config_raw.recent_projects.length > 0;
-			BoxProjects.hsearch.text = zui_text_input(BoxProjects.hsearch, tr("Search"), zui_align_t.LEFT, true, true);
-			ui.enabled = true;
-
-			for (let path of config_raw.recent_projects) {
-				let file: string = path;
-				///if krom_windows
-				file = string_replace_all(path, "/", "\\");
-				///else
-				file = string_replace_all(path, "\\", "/");
-				///end
-				file = file.substr(file.lastIndexOf(path_sep) + 1);
-
-				if (file.toLowerCase().indexOf(BoxProjects.hsearch.text.toLowerCase()) < 0) continue; // Search filter
-
-				if (zui_button(file, zui_align_t.LEFT) && file_exists(path)) {
-					let current: image_t = _g2_current;
-					let g2_in_use: bool = _g2_in_use;
-					if (g2_in_use) g2_end();
-
-					ImportArm.run_project(path);
-
-					if (g2_in_use) g2_begin(current);
-					ui_box_hide();
-				}
-				if (ui.is_hovered) zui_tooltip(path);
-			}
-
-			ui.enabled = config_raw.recent_projects.length > 0;
-			if (zui_button(tr("Clear"), zui_align_t.LEFT)) {
-				config_raw.recent_projects = [];
-				config_save();
-			}
-			ui.enabled = true;
-
-			zui_end_element();
-			if (zui_button(tr("New .."), zui_align_t.LEFT)) project_new_box();
-			if (zui_button(tr("Open..."), zui_align_t.LEFT)) project_open();
-		}
-	}
-
-	static draw_badge = (ui: zui_t) => {
-		let img: image_t = data_get_image("badge.k");
-		zui_image(img);
-		zui_end_element();
-	}
-
-	static get_started_tab = (ui: zui_t) => {
-		if (zui_tab(BoxProjects.htab, tr("Get Started"), true)) {
-			if (zui_button(tr("Manual"))) {
-				file_load_url(manifest_url + "/manual");
-			}
-			if (zui_button(tr("How To"))) {
-				file_load_url(manifest_url + "/howto");
-			}
-			if (zui_button(tr("What's New"))) {
-				file_load_url(manifest_url + "/notes");
-			}
-		}
-	}
-
-	static align_to_fullscreen = () => {
-		ui_box_modalw = math_floor(sys_width() / zui_SCALE(base_ui_box));
-		ui_box_modalh = math_floor(sys_height() / zui_SCALE(base_ui_box));
-		let appw: i32 = sys_width();
-		let apph: i32 = sys_height();
-		let mw: i32 = appw;
-		let mh: i32 = apph;
-		ui_box_hwnd.drag_x = math_floor(-appw / 2 + mw / 2);
-		ui_box_hwnd.drag_y = math_floor(-apph / 2 + mh / 2);
-	}
-}

+ 0 - 464
base/Sources/ExportArm.ts

@@ -1,464 +0,0 @@
-
-class ExportArm {
-
-	static run_mesh = (path: string, paintObjects: mesh_object_t[]) => {
-		let mesh_datas: mesh_data_t[] = [];
-		for (let p of paintObjects) mesh_datas.push(p.data);
-		let raw: scene_t = { mesh_datas: mesh_datas };
-		let b: buffer_t = armpack_encode(raw);
-		if (!path.endsWith(".arm")) path += ".arm";
-		krom_file_save_bytes(path, b, b.byteLength + 1);
-	}
-
-	static run_project = () => {
-		///if (is_paint || is_sculpt)
-		let mnodes: zui_node_canvas_t[] = [];
-		for (let m of project_materials) {
-			let c: zui_node_canvas_t = json_parse(json_stringify(m.canvas));
-			for (let n of c.nodes) ExportArm.export_node(n);
-			mnodes.push(c);
-		}
-
-		let bnodes: zui_node_canvas_t[] = [];
-		for (let b of project_brushes) bnodes.push(b.canvas);
-		///end
-
-		///if is_lab
-		let c: zui_node_canvas_t = json_parse(json_stringify(project_canvas));
-		for (let n of c.nodes) ExportArm.export_node(n);
-		///end
-
-		let mgroups: zui_node_canvas_t[] = null;
-		if (project_material_groups.length > 0) {
-			mgroups = [];
-			for (let g of project_material_groups) {
-				let c: zui_node_canvas_t = json_parse(json_stringify(g.canvas));
-				for (let n of c.nodes) ExportArm.export_node(n);
-				mgroups.push(c);
-			}
-		}
-
-		///if (is_paint || is_sculpt)
-		let md: mesh_data_t[] = [];
-		for (let p of project_paint_objects) md.push(p.data);
-		///end
-
-		///if is_lab
-		let md: mesh_data_t = project_paint_objects[0].data;
-		///end
-
-		let texture_files: string[] = ExportArm.assets_to_files(project_filepath, project_assets);
-
-		///if (is_paint || is_sculpt)
-		let font_files: string[] = ExportArm.fonts_to_files(project_filepath, project_fonts);
-		let mesh_files: string[] = ExportArm.meshes_to_files(project_filepath);
-
-		let bits_pos: i32 = base_bits_handle.position;
-		let bpp: i32 = bits_pos == texture_bits_t.BITS8 ? 8 : bits_pos == texture_bits_t.BITS16 ? 16 : 32;
-
-		let ld: layer_data_t[] = [];
-		for (let l of project_layers) {
-			ld.push({
-				name: l.name,
-				res: l.texpaint != null ? l.texpaint.width : project_layers[0].texpaint.width,
-				bpp: bpp,
-				texpaint: l.texpaint != null ? lz4_encode(image_get_pixels(l.texpaint)) : null,
-				uv_scale: l.scale,
-				uv_rot: l.angle,
-				uv_type: l.uv_type,
-				decal_mat: l.uv_type == uv_type_t.PROJECT ? mat4_to_f32_array(l.decal_mat) : null,
-				opacity_mask: l.mask_opacity,
-				fill_layer: l.fill_layer != null ? project_materials.indexOf(l.fill_layer) : -1,
-				object_mask: l.object_mask,
-				blending: l.blending,
-				parent: l.parent != null ? project_layers.indexOf(l.parent) : -1,
-				visible: l.visible,
-				///if is_paint
-				texpaint_nor: l.texpaint_nor != null ? lz4_encode(image_get_pixels(l.texpaint_nor)) : null,
-				texpaint_pack: l.texpaint_pack != null ? lz4_encode(image_get_pixels(l.texpaint_pack)) : null,
-				paint_base: l.paint_base,
-				paint_opac: l.paint_opac,
-				paint_occ: l.paint_occ,
-				paint_rough: l.paint_rough,
-				paint_met: l.paint_met,
-				paint_nor: l.paint_nor,
-				paint_nor_blend: l.paint_nor_blend,
-				paint_height: l.paint_height,
-				paint_height_blend: l.paint_height_blend,
-				paint_emis: l.paint_emis,
-				paint_subs: l.paint_subs
-				///end
-			});
-		}
-		///end
-
-		let packed_assets: packed_asset_t[] = (project_raw.packed_assets == null || project_raw.packed_assets.length == 0) ? null : project_raw.packed_assets;
-		///if krom_ios
-		let same_drive: bool = false;
-		///else
-		let same_drive: bool = project_raw.envmap != null ? project_filepath.charAt(0) == project_raw.envmap.charAt(0) : true;
-		///end
-
-		project_raw = {
-			version: manifest_version,
-			material_groups: mgroups,
-			assets: texture_files,
-			packed_assets: packed_assets,
-			swatches: project_raw.swatches,
-			envmap: project_raw.envmap != null ? (same_drive ? path_to_relative(project_filepath, project_raw.envmap) : project_raw.envmap) : null,
-			envmap_strength: scene_world.strength,
-			camera_world: mat4_to_f32_array(scene_camera.base.transform.local),
-			camera_origin: ExportArm.vec3f32(camera_origins[0]),
-			camera_fov: scene_camera.data.fov,
-
-			///if (is_paint || is_sculpt)
-			mesh_datas: md,
-			material_nodes: mnodes,
-			brush_nodes: bnodes,
-			layer_datas: ld,
-			font_assets: font_files,
-			mesh_assets: mesh_files,
-			///end
-
-			///if is_paint
-			atlas_objects: project_atlas_objects,
-			atlas_names: project_atlas_names,
-			///end
-
-			///if is_lab
-			mesh_data: md,
-			material: c,
-			///end
-
-			///if (krom_metal || krom_vulkan)
-			is_bgra: true
-			///else
-			is_bgra: false
-			///end
-		};
-
-		///if (krom_android || krom_ios)
-		let tex: image_t = render_path_render_targets.get(context_raw.render_mode == render_mode_t.FORWARD ? "buf" : "tex")._image;
-		let mesh_icon: image_t = image_create_render_target(256, 256);
-		let r: f32 = app_w() / app_h();
-		g2_begin(mesh_icon);
-		///if krom_opengl
-		g2_draw_scaled_image(tex, -(256 * r - 256) / 2, 256, 256 * r, -256);
-		///else
-		g2_draw_scaled_image(tex, -(256 * r - 256) / 2, 0, 256 * r, 256);
-		///end
-		g2_end();
-		///if krom_metal
-		// Flush command list
-		g2_begin(mesh_icon);
-		g2_end();
-		///end
-		let mesh_icon_pixels: buffer_t = image_get_pixels(mesh_icon);
-		let u8a: Uint8Array = new Uint8Array(mesh_icon_pixels);
-		for (let i: i32 = 0; i < 256 * 256 * 4; ++i) {
-			u8a[i] = math_floor(math_pow(u8a[i] / 255, 1.0 / 2.2) * 255);
-		}
-		///if (krom_metal || krom_vulkan)
-		ExportArm.bgra_swap(mesh_icon_pixels);
-		///end
-		base_notify_on_next_frame(() => {
-			image_unload(mesh_icon);
-		});
-		// raw.mesh_icons =
-		// 	///if (krom_metal || krom_vulkan)
-		// 	[encode(bgraSwap(mesh_icon_pixels)];
-		// 	///else
-		// 	[encode(mesh_icon_pixels)];
-		// 	///end
-		krom_write_png(project_filepath.substr(0, project_filepath.length - 4) + "_icon.png", mesh_icon_pixels, 256, 256, 0);
-		///end
-
-		///if (is_paint || is_sculpt)
-		let is_packed: bool = project_filepath.endsWith("_packed_.arm");
-		if (is_packed) { // Pack textures
-			ExportArm.pack_assets(project_raw, project_assets);
-		}
-		///end
-
-		let buffer: buffer_t = armpack_encode(project_raw);
-		krom_file_save_bytes(project_filepath, buffer, buffer.byteLength + 1);
-
-		// Save to recent
-		///if krom_ios
-		let recent_path: string = project_filepath.substr(project_filepath.lastIndexOf("/") + 1);
-		///else
-		let recent_path: string = project_filepath;
-		///end
-		let recent: string[] = config_raw.recent_projects;
-		array_remove(recent, recent_path);
-		recent.unshift(recent_path);
-		config_save();
-
-		console_info(tr("Project saved"));
-	}
-
-	static texture_node_name = (): string => {
-		///if (is_paint || is_sculpt)
-		return "TEX_IMAGE";
-		///else
-		return "ImageTextureNode";
-		///end
-	}
-
-	static export_node = (n: zui_node_t, assets: asset_t[] = null) => {
-		if (n.type == ExportArm.texture_node_name()) {
-			let index: i32 = n.buttons[0].default_value;
-			n.buttons[0].data = base_enum_texts(n.type)[index];
-
-			if (assets != null) {
-				let asset: asset_t = project_assets[index];
-				if (assets.indexOf(asset) == -1) {
-					assets.push(asset);
-				}
-			}
-		}
-		// Pack colors
-		if (n.color > 0) n.color -= 4294967296;
-		for (let inp of n.inputs) if (inp.color > 0) inp.color -= 4294967296;
-		for (let out of n.outputs) if (out.color > 0) out.color -= 4294967296;
-	}
-
-	///if (is_paint || is_sculpt)
-	static run_material = (path: string) => {
-		if (!path.endsWith(".arm")) path += ".arm";
-		let mnodes: zui_node_canvas_t[] = [];
-		let mgroups: zui_node_canvas_t[] = null;
-		let m: SlotMaterialRaw = context_raw.material;
-		let c: zui_node_canvas_t = json_parse(json_stringify(m.canvas));
-		let assets: asset_t[] = [];
-		if (ui_nodes_has_group(c)) {
-			mgroups = [];
-			ui_nodes_traverse_group(mgroups, c);
-			for (let gc of mgroups) for (let n of gc.nodes) ExportArm.export_node(n, assets);
-		}
-		for (let n of c.nodes) ExportArm.export_node(n, assets);
-		mnodes.push(c);
-
-		let texture_files: string[] = ExportArm.assets_to_files(path, assets);
-		let is_cloud: bool = path.endsWith("_cloud_.arm");
-		if (is_cloud) path = string_replace_all(path, "_cloud_", "");
-		let packed_assets: packed_asset_t[] = null;
-		if (!context_raw.pack_assets_on_export) {
-			packed_assets = ExportArm.get_packed_assets(path, texture_files);
-		}
-
-		let raw: project_format_t = {
-			version: manifest_version,
-			material_nodes: mnodes,
-			material_groups: mgroups,
-			material_icons: is_cloud ? null :
-				///if (krom_metal || krom_vulkan)
-				[lz4_encode(ExportArm.bgra_swap(image_get_pixels(m.image)))],
-				///else
-				[lz4_encode(image_get_pixels(m.image))],
-				///end
-			assets: texture_files,
-			packed_assets: packed_assets
-		};
-
-		if (context_raw.write_icon_on_export) { // Separate icon files
-			krom_write_png(path.substr(0, path.length - 4) + "_icon.png", image_get_pixels(m.image), m.image.width, m.image.height, 0);
-			if (is_cloud) {
-				krom_write_jpg(path.substr(0, path.length - 4) + "_icon.jpg", image_get_pixels(m.image), m.image.width, m.image.height, 0, 50);
-			}
-		}
-
-		if (context_raw.pack_assets_on_export) { // Pack textures
-			ExportArm.pack_assets(raw, assets);
-		}
-
-		let buffer: buffer_t = armpack_encode(raw);
-		krom_file_save_bytes(path, buffer, buffer.byteLength + 1);
-	}
-	///end
-
-	///if (krom_metal || krom_vulkan)
-	static bgra_swap = (buffer: ArrayBuffer) => {
-		let view: DataView = new DataView(buffer);
-		for (let i: i32 = 0; i < math_floor(buffer.byteLength / 4); ++i) {
-			let r: i32 = view.getUint8(i * 4);
-			view.setUint8(i * 4, view.getUint8(i * 4 + 2));
-			view.setUint8(i * 4 + 2, r);
-		}
-		return buffer;
-	}
-	///end
-
-	///if (is_paint || is_sculpt)
-	static run_brush = (path: string) => {
-		if (!path.endsWith(".arm")) path += ".arm";
-		let bnodes: zui_node_canvas_t[] = [];
-		let b: SlotBrushRaw = context_raw.brush;
-		let c: zui_node_canvas_t = json_parse(json_stringify(b.canvas));
-		let assets: asset_t[] = [];
-		for (let n of c.nodes) ExportArm.export_node(n, assets);
-		bnodes.push(c);
-
-		let texture_files: string[] = ExportArm.assets_to_files(path, assets);
-		let is_cloud: bool = path.endsWith("_cloud_.arm");
-		if (is_cloud) path = string_replace_all(path, "_cloud_", "");
-		let packed_assets: packed_asset_t[] = null;
-		if (!context_raw.pack_assets_on_export) {
-			packed_assets = ExportArm.get_packed_assets(path, texture_files);
-		}
-
-		let raw: project_format_t = {
-			version: manifest_version,
-			brush_nodes: bnodes,
-			brush_icons: is_cloud ? null :
-			///if (krom_metal || krom_vulkan)
-			[lz4_encode(ExportArm.bgra_swap(image_get_pixels(b.image)))],
-			///else
-			[lz4_encode(image_get_pixels(b.image))],
-			///end
-			assets: texture_files,
-			packed_assets: packed_assets
-		};
-
-		if (context_raw.write_icon_on_export) { // Separate icon file
-			krom_write_png(path.substr(0, path.length - 4) + "_icon.png", image_get_pixels(b.image), b.image.width, b.image.height, 0);
-		}
-
-		if (context_raw.pack_assets_on_export) { // Pack textures
-			ExportArm.pack_assets(raw, assets);
-		}
-
-		let buffer: buffer_t = armpack_encode(raw);
-		krom_file_save_bytes(path, buffer, buffer.byteLength + 1);
-	}
-	///end
-
-	static assets_to_files = (projectPath: string, assets: asset_t[]): string[] => {
-		let texture_files: string[] = [];
-		for (let a of assets) {
-			///if krom_ios
-			let same_drive: bool = false;
-			///else
-			let same_drive: bool = projectPath.charAt(0) == a.file.charAt(0);
-			///end
-			// Convert image path from absolute to relative
-			if (same_drive) {
-				texture_files.push(path_to_relative(projectPath, a.file));
-			}
-			else {
-				texture_files.push(a.file);
-			}
-		}
-		return texture_files;
-	}
-
-	///if (is_paint || is_sculpt)
-	static meshes_to_files = (projectPath: string): string[] => {
-		let mesh_files: string[] = [];
-		for (let file of project_mesh_assets) {
-			///if krom_ios
-			let same_drive: bool = false;
-			///else
-			let same_drive: bool = projectPath.charAt(0) == file.charAt(0);
-			///end
-			// Convert mesh path from absolute to relative
-			if (same_drive) {
-				mesh_files.push(path_to_relative(projectPath, file));
-			}
-			else {
-				mesh_files.push(file);
-			}
-		}
-		return mesh_files;
-	}
-
-	static fonts_to_files = (projectPath: string, fonts: SlotFontRaw[]): string[] => {
-		let font_files: string[] = [];
-		for (let i = 1; i <fonts.length; ++i) {
-			let f: SlotFontRaw = fonts[i];
-			///if krom_ios
-			let same_drive: bool = false;
-			///else
-			let same_drive: bool = projectPath.charAt(0) == f.file.charAt(0);
-			///end
-			// Convert font path from absolute to relative
-			if (same_drive) {
-				font_files.push(path_to_relative(projectPath, f.file));
-			}
-			else {
-				font_files.push(f.file);
-			}
-		}
-		return font_files;
-	}
-	///end
-
-	static get_packed_assets = (projectPath: string, texture_files: string[]): packed_asset_t[] => {
-		let packed_assets: packed_asset_t[] = null;
-		if (project_raw.packed_assets != null) {
-			for (let pa of project_raw.packed_assets) {
-				///if krom_ios
-				let same_drive: bool = false;
-				///else
-				let same_drive: bool = projectPath.charAt(0) == pa.name.charAt(0);
-				///end
-				// Convert path from absolute to relative
-				pa.name = same_drive ? path_to_relative(projectPath, pa.name) : pa.name;
-				for (let tf of texture_files) {
-					if (pa.name == tf) {
-						if (packed_assets == null) {
-							packed_assets = [];
-						}
-						packed_assets.push(pa);
-						break;
-					}
-				}
-			}
-		}
-		return packed_assets;
-	}
-
-	static pack_assets = (raw: project_format_t, assets: asset_t[]) => {
-		if (raw.packed_assets == null) {
-			raw.packed_assets = [];
-		}
-		let temp_images: image_t[] = [];
-		for (let i: i32 = 0; i < assets.length; ++i) {
-			if (!project_packed_asset_exists(raw.packed_assets, assets[i].file)) {
-				let image: image_t = project_get_image(assets[i]);
-				let temp: image_t = image_create_render_target(image.width, image.height);
-				g2_begin(temp);
-				g2_draw_image(image, 0, 0);
-				g2_end();
-				temp_images.push(temp);
-				raw.packed_assets.push({
-					name: assets[i].file,
-					bytes: assets[i].file.endsWith(".jpg") ?
-						krom_encode_jpg(image_get_pixels(temp), temp.width, temp.height, 0, 80) :
-						krom_encode_png(image_get_pixels(temp), temp.width, temp.height, 0)
-				});
-			}
-		}
-		base_notify_on_next_frame(() => {
-			for (let image of temp_images) image_unload(image);
-		});
-	}
-
-	static run_swatches = (path: string) => {
-		if (!path.endsWith(".arm")) path += ".arm";
-		let raw: any = {
-			version: manifest_version,
-			swatches: project_raw.swatches
-		};
-		let buffer: buffer_t = armpack_encode(raw);
-		krom_file_save_bytes(path, buffer, buffer.byteLength + 1);
-	}
-
-	static vec3f32 = (v: vec4_t): Float32Array => {
-		let res: Float32Array = new Float32Array(3);
-		res[0] = v.x;
-		res[1] = v.y;
-		res[2] = v.z;
-		return res;
-	}
-}

+ 0 - 17
base/Sources/ExportGpl.ts

@@ -1,17 +0,0 @@
-
-class ExportGpl {
-
-	static run = (path: string, name: string, swatches: swatch_color_t[]) => {
-		let o: string = "";
-		o += "GIMP Palette\n";
-		o += "Name: " + name + "\n";
-		o += "# armorpaint.org\n";
-		o += "#\n";
-
-		for (let swatch of swatches) {
-			o += String(color_get_rb(swatch.base)) + " " + String(color_get_gb(swatch.base)) + " " + String(color_get_bb(swatch.base)) + "\n";
-		}
-
-		krom_file_save_bytes(path, sys_string_to_buffer(o), o.length);
-	}
-}

+ 0 - 9
base/Sources/ExportMesh.ts

@@ -1,9 +0,0 @@
-
-class ExportMesh {
-
-	static run = (path: string, paintObjects: mesh_object_t[] = null, applyDisplacement: bool = false) => {
-		if (paintObjects == null) paintObjects = project_paint_objects;
-		if (context_raw.export_mesh_format == mesh_format_t.OBJ) ExportObj.run(path, paintObjects, applyDisplacement);
-		else ExportArm.run_mesh(path, paintObjects);
-	}
-}

+ 0 - 173
base/Sources/ExportObj.ts

@@ -1,173 +0,0 @@
-
-class ExportObj {
-
-	static write_string = (out: i32[], str: string) => {
-		for (let i: i32 = 0; i < str.length; ++i) {
-			out.push(str.charCodeAt(i));
-		}
-	}
-
-	static run = (path: string, paintObjects: mesh_object_t[], applyDisplacement: bool = false) => {
-		let o: i32[] = [];
-		ExportObj.write_string(o, "# armorpaint.org\n");
-
-		let poff: i32 = 0;
-		let noff: i32 = 0;
-		let toff: i32 = 0;
-		for (let p of paintObjects) {
-			let mesh: mesh_data_t = p.data;
-			let inv: f32 = 1 / 32767;
-			let sc: f32 = p.data.scale_pos * inv;
-			let posa: i16_array_t = mesh.vertex_arrays[0].values;
-			let nora: i16_array_t = mesh.vertex_arrays[1].values;
-			let texa: i16_array_t = mesh.vertex_arrays[2].values;
-			let len: i32 = math_floor(posa.length / 4);
-
-			// Merge shared vertices and remap indices
-			let posa2: Int16Array = new Int16Array(len * 3);
-			let nora2: Int16Array = new Int16Array(len * 3);
-			let texa2: Int16Array = new Int16Array(len * 2);
-			let posmap: map_t<i32, i32> = map_create();
-			let normap: map_t<i32, i32> = map_create();
-			let texmap: map_t<i32, i32> = map_create();
-
-			let pi: i32 = 0;
-			let ni: i32 = 0;
-			let ti: i32 = 0;
-			for (let i: i32 = 0; i < len; ++i) {
-				let found: bool = false;
-				for (let j: i32 = 0; j < pi; ++j) {
-					if (posa2[j * 3    ] == posa[i * 4    ] &&
-						posa2[j * 3 + 1] == posa[i * 4 + 1] &&
-						posa2[j * 3 + 2] == posa[i * 4 + 2]) {
-						posmap.set(i, j);
-						found = true;
-						break;
-					}
-				}
-				if (!found) {
-					posmap.set(i, pi);
-					posa2[pi * 3    ] = posa[i * 4    ];
-					posa2[pi * 3 + 1] = posa[i * 4 + 1];
-					posa2[pi * 3 + 2] = posa[i * 4 + 2];
-					pi++;
-				}
-
-				found = false;
-				for (let j: i32 = 0; j < ni; ++j) {
-					if (nora2[j * 3    ] == nora[i * 2    ] &&
-						nora2[j * 3 + 1] == nora[i * 2 + 1] &&
-						nora2[j * 3 + 2] == posa[i * 4 + 3]) {
-						normap.set(i, j);
-						found = true;
-						break;
-					}
-				}
-				if (!found) {
-					normap.set(i, ni);
-					nora2[ni * 3    ] = nora[i * 2    ];
-					nora2[ni * 3 + 1] = nora[i * 2 + 1];
-					nora2[ni * 3 + 2] = posa[i * 4 + 3];
-					ni++;
-				}
-
-				found = false;
-				for (let j: i32 = 0; j < ti; ++j) {
-					if (texa2[j * 2    ] == texa[i * 2    ] &&
-						texa2[j * 2 + 1] == texa[i * 2 + 1]) {
-						texmap.set(i, j);
-						found = true;
-						break;
-					}
-				}
-				if (!found) {
-					texmap.set(i, ti);
-					texa2[ti * 2    ] = texa[i * 2    ];
-					texa2[ti * 2 + 1] = texa[i * 2 + 1];
-					ti++;
-				}
-			}
-
-			if (applyDisplacement) {
-				// let height: buffer_t = layers[0].texpaint_pack.getPixels();
-				// let res: i32 = layers[0].texpaint_pack.width;
-				// let strength: f32 = 0.1;
-				// for (let i: i32 = 0; i < len; ++i) {
-				// 	let x: i32 = math_floor(texa2[i * 2    ] / 32767 * res);
-				// 	let y: i32 = math_floor((1.0 - texa2[i * 2 + 1] / 32767) * res);
-				// 	let h: f32 = (1.0 - height.get((y * res + x) * 4 + 3) / 255) * strength;
-				// 	posa2[i * 3    ] -= math_floor(nora2[i * 3    ] * inv * h / sc);
-				// 	posa2[i * 3 + 1] -= math_floor(nora2[i * 3 + 1] * inv * h / sc);
-				// 	posa2[i * 3 + 2] -= math_floor(nora2[i * 3 + 2] * inv * h / sc);
-				// }
-			}
-
-			ExportObj.write_string(o, "o " + p.base.name + "\n");
-			for (let i: i32 = 0; i < pi; ++i) {
-				ExportObj.write_string(o, "v ");
-				ExportObj.write_string(o, posa2[i * 3] * sc + "");
-				ExportObj.write_string(o, " ");
-				ExportObj.write_string(o, posa2[i * 3 + 2] * sc + "");
-				ExportObj.write_string(o, " ");
-				ExportObj.write_string(o, -posa2[i * 3 + 1] * sc + "");
-				ExportObj.write_string(o, "\n");
-			}
-			for (let i: i32 = 0; i < ni; ++i) {
-				ExportObj.write_string(o, "vn ");
-				ExportObj.write_string(o, nora2[i * 3] * inv + "");
-				ExportObj.write_string(o, " ");
-				ExportObj.write_string(o, nora2[i * 3 + 2] * inv + "");
-				ExportObj.write_string(o, " ");
-				ExportObj.write_string(o, -nora2[i * 3 + 1] * inv + "");
-				ExportObj.write_string(o, "\n");
-			}
-			for (let i: i32 = 0; i < ti; ++i) {
-				ExportObj.write_string(o, "vt ");
-				ExportObj.write_string(o, texa2[i * 2] * inv + "");
-				ExportObj.write_string(o, " ");
-				ExportObj.write_string(o, 1.0 - texa2[i * 2 + 1] * inv + "");
-				ExportObj.write_string(o, "\n");
-			}
-
-			let inda: u32_array_t = mesh.index_arrays[0].values;
-			for (let i: i32 = 0; i < math_floor(inda.length / 3); ++i) {
-				let pi1: i32 = posmap.get(inda[i * 3    ]) + 1 + poff;
-				let pi2: i32 = posmap.get(inda[i * 3 + 1]) + 1 + poff;
-				let pi3: i32 = posmap.get(inda[i * 3 + 2]) + 1 + poff;
-				let ni1: i32 = normap.get(inda[i * 3    ]) + 1 + noff;
-				let ni2: i32 = normap.get(inda[i * 3 + 1]) + 1 + noff;
-				let ni3: i32 = normap.get(inda[i * 3 + 2]) + 1 + noff;
-				let ti1: i32 = texmap.get(inda[i * 3    ]) + 1 + toff;
-				let ti2: i32 = texmap.get(inda[i * 3 + 1]) + 1 + toff;
-				let ti3: i32 = texmap.get(inda[i * 3 + 2]) + 1 + toff;
-				ExportObj.write_string(o, "f ");
-				ExportObj.write_string(o, pi1 + "");
-				ExportObj.write_string(o, "/");
-				ExportObj.write_string(o, ti1 + "");
-				ExportObj.write_string(o, "/");
-				ExportObj.write_string(o, ni1 + "");
-				ExportObj.write_string(o, " ");
-				ExportObj.write_string(o, pi2 + "");
-				ExportObj.write_string(o, "/");
-				ExportObj.write_string(o, ti2 + "");
-				ExportObj.write_string(o, "/");
-				ExportObj.write_string(o, ni2 + "");
-				ExportObj.write_string(o, " ");
-				ExportObj.write_string(o, pi3 + "");
-				ExportObj.write_string(o, "/");
-				ExportObj.write_string(o, ti3 + "");
-				ExportObj.write_string(o, "/");
-				ExportObj.write_string(o, ni3 + "");
-				ExportObj.write_string(o, "\n");
-			}
-			poff += pi;
-			noff += ni;
-			toff += ti;
-		}
-
-		if (!path.endsWith(".obj")) path += ".obj";
-
-		let b: ArrayBuffer = Uint8Array.from(o).buffer;
-		krom_file_save_bytes(path, b, b.byteLength);
-	}
-}

+ 0 - 434
base/Sources/ExportTexture.ts

@@ -1,434 +0,0 @@
-
-///if (is_paint || is_lab)
-
-class ExportTexture {
-
-	static gamma: f32 = 1.0 / 2.2;
-
-	static run = (path: string, bake_material: bool = false) => {
-
-		///if is_paint
-		if (bake_material) {
-			ExportTexture.run_bake_material(path);
-		}
-		else if (context_raw.layers_export == export_mode_t.PER_UDIM_TILE) {
-			let udim_tiles: string[] = [];
-			for (let l of project_layers) {
-				if (SlotLayer.get_object_mask(l) > 0) {
-					let name: string = project_paint_objects[SlotLayer.get_object_mask(l) - 1].base.name;
-					if (name.substr(name.length - 5, 2) == ".1") { // tile.1001
-						udim_tiles.push(name.substr(name.length - 5));
-					}
-				}
-			}
-			if (udim_tiles.length > 0) {
-				for (let udim_tile of udim_tiles) ExportTexture.run_layers(path, project_layers, udim_tile);
-			}
-			else ExportTexture.run_layers(path, project_layers);
-		}
-		else if (context_raw.layers_export == export_mode_t.PER_OBJECT) {
-			let object_names: string[] = [];
-			for (let l of project_layers) {
-				if (SlotLayer.get_object_mask(l) > 0) {
-					let name: string = project_paint_objects[SlotLayer.get_object_mask(l) - 1].base.name;
-					if (object_names.indexOf(name) == -1) {
-						object_names.push(name);
-					}
-				}
-			}
-			if (object_names.length > 0) {
-				for (let name of object_names) ExportTexture.run_layers(path, project_layers, name);
-			}
-			else ExportTexture.run_layers(path, project_layers);
-		}
-		else { // Visible or selected
-			let atlas_export: bool = false;
-			if (project_atlas_objects != null) {
-				for (let i: i32 = 1; i < project_atlas_objects.length; ++i) {
-					if (project_atlas_objects[i - 1] != project_atlas_objects[i]) {
-						atlas_export = true;
-						break;
-					}
-				}
-			}
-			if (atlas_export) {
-				for (let atlas_index: i32 = 0; atlas_index < project_atlas_objects.length; ++atlas_index) {
-					let layers: SlotLayerRaw[] = [];
-					for (let object_index: i32 = 0; object_index < project_atlas_objects.length; ++object_index) {
-						if (project_atlas_objects[object_index] == atlas_index) {
-							for (let l of project_layers) {
-								if (SlotLayer.get_object_mask(l) == 0 /* shared object */ || SlotLayer.get_object_mask(l) - 1 == object_index) layers.push(l);
-							}
-						}
-					}
-					if (layers.length > 0) {
-						ExportTexture.run_layers(path, layers, project_atlas_names[atlas_index]);
-					}
-				}
-			}
-			else ExportTexture.run_layers(path, context_raw.layers_export == export_mode_t.SELECTED ? (SlotLayer.is_group(context_raw.layer) ? SlotLayer.get_children(context_raw.layer) : [context_raw.layer]) : project_layers);
-		}
-		///end
-
-		///if is_lab
-		ExportTexture.run_layers(path, [BrushOutputNode.inst]);
-		///end
-
-		///if krom_ios
-		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 + "')");
-		///else
-		console_info(tr("Textures exported"));
-		///end
-		ui_files_last_path = "";
-	}
-
-	///if is_paint
-	static run_bake_material = (path: string) => {
-		if (RenderPathPaint.live_layer == null) {
-			RenderPathPaint.live_layer = SlotLayer.create("_live");
-		}
-
-		let _tool: workspace_tool_t = context_raw.tool;
-		context_raw.tool = workspace_tool_t.FILL;
-		MakeMaterial.parse_paint_material();
-		let _paint_object: mesh_object_t = context_raw.paint_object;
-		let planeo: mesh_object_t = scene_get_child(".Plane").ext;
-		planeo.base.visible = true;
-		context_raw.paint_object = planeo;
-		context_raw.pdirty = 1;
-		RenderPathPaint.use_live_layer(true);
-		RenderPathPaint.commands_paint(false);
-		RenderPathPaint.use_live_layer(false);
-		context_raw.tool = _tool;
-		MakeMaterial.parse_paint_material();
-		context_raw.pdirty = 0;
-		planeo.base.visible = false;
-		context_raw.paint_object = _paint_object;
-
-		ExportTexture.run_layers(path, [RenderPathPaint.live_layer], "", true);
-	}
-	///end
-
-	///if is_paint
-	static run_layers = (path: string, layers: SlotLayerRaw[], object_name: string = "", bake_material: bool = false) => {
-	///end
-
-	///if is_lab
-	static run_layers = (path: string, layers: any[], object_name: string = "") => {
-	///end
-
-		let texture_size_x: i32 = config_get_texture_res_x();
-		let texture_size_y: i32 = config_get_texture_res_y();
-		///if (krom_android || krom_ios)
-		let f: string = sys_title();
-		///else
-		let f: string = ui_files_filename;
-		///end
-		if (f == "") f = tr("untitled");
-		let format_type: texture_ldr_format_t = context_raw.format_type;
-		let bits: i32 = base_bits_handle.position == texture_bits_t.BITS8 ? 8 : 16;
-		let ext: string = bits == 16 ? ".exr" : format_type == texture_ldr_format_t.PNG ? ".png" : ".jpg";
-		if (f.endsWith(ext)) f = f.substr(0, f.length - 4);
-
-		///if is_paint
-		let is_udim: bool = context_raw.layers_export == export_mode_t.PER_UDIM_TILE;
-		if (is_udim) ext = object_name + ext;
-
-		base_make_temp_img();
-		base_make_export_img();
-		if (base_pipe_merge == null) base_make_pipe();
-		if (const_data_screen_aligned_vb == null) const_data_create_screen_aligned_data();
-		let empty: image_t = render_path_render_targets.get("empty_white")._image;
-
-		// Append object mask name
-		let export_selected: bool = context_raw.layers_export == export_mode_t.SELECTED;
-		if (export_selected && SlotLayer.get_object_mask(layers[0]) > 0) {
-			f += "_" + project_paint_objects[SlotLayer.get_object_mask(layers[0]) - 1].base.name;
-		}
-		if (!is_udim && !export_selected && object_name != "") {
-			f += "_" + object_name;
-		}
-
-		// Clear export layer
-		g4_begin(base_expa);
-		g4_clear(color_from_floats(0.0, 0.0, 0.0, 0.0));
-		g4_end();
-		g4_begin(base_expb);
-		g4_clear(color_from_floats(0.5, 0.5, 1.0, 0.0));
-		g4_end();
-		g4_begin(base_expc);
-		g4_clear(color_from_floats(1.0, 0.0, 0.0, 0.0));
-		g4_end();
-
-		// Flatten layers
-		for (let l1 of layers) {
-			if (!export_selected && !SlotLayer.is_visible(l1)) continue;
-			if (!SlotLayer.is_layer(l1)) continue;
-
-			if (object_name != "" && SlotLayer.get_object_mask(l1) > 0) {
-				if (is_udim && !project_paint_objects[SlotLayer.get_object_mask(l1) - 1].base.name.endsWith(object_name)) continue;
-				let per_object: bool = context_raw.layers_export == export_mode_t.PER_OBJECT;
-				if (per_object && project_paint_objects[SlotLayer.get_object_mask(l1) - 1].base.name != object_name) continue;
-			}
-
-			let mask: image_t = empty;
-			let l1masks: SlotLayerRaw[] = SlotLayer.get_masks(l1);
-			if (l1masks != null && !bake_material) {
-				if (l1masks.length > 1) {
-					base_make_temp_mask_img();
-					g2_begin(base_temp_mask_image);
-					g2_clear(0x00000000);
-					g2_end();
-					let l1: any = { texpaint: base_temp_mask_image };
-					for (let i: i32 = 0; i < l1masks.length; ++i) {
-						base_merge_layer(l1, l1masks[i]);
-					}
-					mask = base_temp_mask_image;
-				}
-				else mask = l1masks[0].texpaint;
-			}
-
-			if (l1.paint_base) {
-				g2_begin(base_temp_image); // Copy to temp
-				g2_set_pipeline(base_pipe_copy);
-				g2_draw_image(base_expa, 0, 0);
-				g2_set_pipeline(null);
-				g2_end();
-
-				g4_begin(base_expa);
-				g4_set_pipeline(base_pipe_merge);
-				g4_set_tex(base_tex0, l1.texpaint);
-				g4_set_tex(base_tex1, empty);
-				g4_set_tex(base_texmask, mask);
-				g4_set_tex(base_texa, base_temp_image);
-				g4_set_float(base_opac, SlotLayer.get_opacity(l1));
-				g4_set_int(base_blending, layers.length > 1 ? l1.blending : 0);
-				g4_set_vertex_buffer(const_data_screen_aligned_vb);
-				g4_set_index_buffer(const_data_screen_aligned_ib);
-				g4_draw();
-				g4_end();
-			}
-
-			if (l1.paint_nor) {
-				g2_begin(base_temp_image);
-				g2_set_pipeline(base_pipe_copy);
-				g2_draw_image(base_expb, 0, 0);
-				g2_set_pipeline(null);
-				g2_end();
-
-				g4_begin(base_expb);
-				g4_set_pipeline(base_pipe_merge);
-				g4_set_tex(base_tex0, l1.texpaint);
-				g4_set_tex(base_tex1, l1.texpaint_nor);
-				g4_set_tex(base_texmask, mask);
-				g4_set_tex(base_texa, base_temp_image);
-				g4_set_float(base_opac, SlotLayer.get_opacity(l1));
-				g4_set_int(base_blending, l1.paint_nor_blend ? -2 : -1);
-				g4_set_vertex_buffer(const_data_screen_aligned_vb);
-				g4_set_index_buffer(const_data_screen_aligned_ib);
-				g4_draw();
-				g4_end();
-			}
-
-			if (l1.paint_occ || l1.paint_rough || l1.paint_met || l1.paint_height) {
-				g2_begin(base_temp_image);
-				g2_set_pipeline(base_pipe_copy);
-				g2_draw_image(base_expc, 0, 0);
-				g2_set_pipeline(null);
-				g2_end();
-
-				if (l1.paint_occ && l1.paint_rough && l1.paint_met && l1.paint_height) {
-					base_commands_merge_pack(base_pipe_merge, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask, l1.paint_height_blend ? -3 : -1);
-				}
-				else {
-					if (l1.paint_occ) base_commands_merge_pack(base_pipe_merge_r, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
-					if (l1.paint_rough) base_commands_merge_pack(base_pipe_merge_g, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
-					if (l1.paint_met) base_commands_merge_pack(base_pipe_merge_b, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
-				}
-			}
-		}
-
-		///if krom_metal
-		// Flush command list
-		g2_begin(base_expa);
-		g2_end();
-		g2_begin(base_expb);
-		g2_end();
-		g2_begin(base_expc);
-		g2_end();
-		///end
-		///end
-
-		///if is_paint
-		let texpaint: image_t = base_expa;
-		let texpaint_nor: image_t = base_expb;
-		let texpaint_pack: image_t = base_expc;
-		///end
-
-		///if is_lab
-		let texpaint: image_t = BrushOutputNode.inst.texpaint;
-		let texpaint_nor: image_t = BrushOutputNode.inst.texpaint_nor;
-		let texpaint_pack: image_t = BrushOutputNode.inst.texpaint_pack;
-		///end
-
-		let pixpaint: ArrayBuffer = null;
-		let pixpaint_nor: ArrayBuffer = null;
-		let pixpaint_pack: ArrayBuffer = null;
-		let preset: export_preset_t = BoxExport.preset;
-		let pix: ArrayBuffer = null;
-
-		for (let t of preset.textures) {
-			for (let c of t.channels) {
-				if      ((c == "base_r" || c == "base_g" || c == "base_b" || c == "opac") && pixpaint == null) pixpaint = image_get_pixels(texpaint);
-				else if ((c == "nor_r" || c == "nor_g" || c == "nor_g_directx" || c == "nor_b" || c == "emis" || c == "subs") && pixpaint_nor == null) pixpaint_nor = image_get_pixels(texpaint_nor);
-				else if ((c == "occ" || c == "rough" || c == "metal" || c == "height" || c == "smooth") && pixpaint_pack == null) pixpaint_pack = image_get_pixels(texpaint_pack);
-			}
-		}
-
-		for (let t of preset.textures) {
-			let c: string[] = t.channels;
-			let tex_name = t.name != "" ? "_" + t.name : "";
-			let single_channel: bool = c[0] == c[1] && c[1] == c[2] && c[3] == "1.0";
-			if (c[0] == "base_r" && c[1] == "base_g" && c[2] == "base_b" && c[3] == "1.0" && t.color_space == "linear") {
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pixpaint, 1);
-			}
-			else if (c[0] == "nor_r" && c[1] == "nor_g" && c[2] == "nor_b" && c[3] == "1.0" && t.color_space == "linear") {
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pixpaint_nor, 1);
-			}
-			else if (c[0] == "occ" && c[1] == "rough" && c[2] == "metal" && c[3] == "1.0" && t.color_space == "linear") {
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 1);
-			}
-			else if (single_channel && c[0] == "occ" && t.color_space == "linear") {
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 0);
-			}
-			else if (single_channel && c[0] == "rough" && t.color_space == "linear") {
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 1);
-			}
-			else if (single_channel && c[0] == "metal" && t.color_space == "linear") {
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 2);
-			}
-			else if (single_channel && c[0] == "height" && t.color_space == "linear") {
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 3);
-			}
-			else if (single_channel && c[0] == "opac" && t.color_space == "linear") {
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pixpaint, 2, 3);
-			}
-			else {
-				if (pix == null) pix = new ArrayBuffer(texture_size_x * texture_size_y * 4 * math_floor(bits / 8));
-				for (let i: i32 = 0; i < 4; ++i) {
-					let c: string = t.channels[i];
-					if      (c == "base_r") ExportTexture.copy_channel(new DataView(pixpaint), 0, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "base_g") ExportTexture.copy_channel(new DataView(pixpaint), 1, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "base_b") ExportTexture.copy_channel(new DataView(pixpaint), 2, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "height") ExportTexture.copy_channel(new DataView(pixpaint_pack), 3, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "metal") ExportTexture.copy_channel(new DataView(pixpaint_pack), 2, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "nor_r") ExportTexture.copy_channel(new DataView(pixpaint_nor), 0, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "nor_g") ExportTexture.copy_channel(new DataView(pixpaint_nor), 1, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "nor_g_directx") ExportTexture.copy_channel_inv(new DataView(pixpaint_nor), 1, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "nor_b") ExportTexture.copy_channel(new DataView(pixpaint_nor), 2, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "occ") ExportTexture.copy_channel(new DataView(pixpaint_pack), 0, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "opac") ExportTexture.copy_channel(new DataView(pixpaint), 3, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "rough") ExportTexture.copy_channel(new DataView(pixpaint_pack), 1, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "smooth") ExportTexture.copy_channel_inv(new DataView(pixpaint_pack), 1, new DataView(pix), i, t.color_space == "linear");
-					else if (c == "emis") ExportTexture.extract_channel(new DataView(pixpaint_nor), 3, new DataView(pix), i, 3, 1, t.color_space == "linear");
-					else if (c == "subs") ExportTexture.extract_channel(new DataView(pixpaint_nor), 3, new DataView(pix), i, 3, 2, t.color_space == "linear");
-					else if (c == "0.0") ExportTexture.set_channel(0, new DataView(pix), i);
-					else if (c == "1.0") ExportTexture.set_channel(255, new DataView(pix), i);
-				}
-				ExportTexture.write_texture(path + path_sep + f + tex_name + ext, pix, 3);
-			}
-		}
-
-		// Release staging memory allocated in image_get_pixels()
-		texpaint.pixels = null;
-		texpaint_nor.pixels = null;
-		texpaint_pack.pixels = null;
-	}
-
-	static write_texture = (file: string, pixels: ArrayBuffer, type: i32 = 1, off: i32 = 0) => {
-		let res_x: i32 = config_get_texture_res_x();
-		let res_y: i32 = config_get_texture_res_y();
-		let bits_handle: i32 = base_bits_handle.position;
-		let bits: i32 = bits_handle == texture_bits_t.BITS8 ? 8 : bits_handle == texture_bits_t.BITS16 ? 16 : 32;
-		let format: i32 = 0; // RGBA
-		if (type == 1) format = 2; // RGB1
-		if (type == 2 && off == 0) format = 3; // RRR1
-		if (type == 2 && off == 1) format = 4; // GGG1
-		if (type == 2 && off == 2) format = 5; // BBB1
-		if (type == 2 && off == 3) format = 6; // AAA1
-
-		if (context_raw.layers_destination == export_destination_t.PACKED) {
-			let image: image_t = image_from_bytes(pixels, res_x, res_y);
-			data_cached_images.set(file, image);
-			let ar: string[] = file.split(path_sep);
-			let name: string = ar[ar.length - 1];
-			let asset: asset_t = {name: name, file: file, id: project_asset_id++};
-			project_assets.push(asset);
-			if (project_raw.assets == null) project_raw.assets = [];
-			project_raw.assets.push(asset.file);
-			project_asset_names.push(asset.name);
-			project_asset_map.set(asset.id, image);
-			ExportArm.pack_assets(project_raw, [asset]);
-			return;
-		}
-
-		if (bits == 8 && context_raw.format_type == texture_ldr_format_t.PNG) {
-			krom_write_png(file, pixels, res_x, res_y, format);
-		}
-		else if (bits == 8 && context_raw.format_type == texture_ldr_format_t.JPG) {
-			krom_write_jpg(file, pixels, res_x, res_y, format, math_floor(context_raw.format_quality));
-		}
-		else { // Exr
-			let b: ArrayBuffer = ParserExr.run(res_x, res_y, pixels, bits, type, off);
-			krom_file_save_bytes(file, b, b.byteLength);
-		}
-	}
-
-	static copy_channel = (from: DataView, fromChannel: i32, to: DataView, toChannel: i32, linear: bool = true) => {
-		for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
-			to.setUint8(i * 4 + toChannel, from.getUint8(i * 4 + fromChannel));
-		}
-		if (!linear) ExportTexture.to_srgb(to, toChannel);
-	}
-
-	static copy_channel_inv = (from: DataView, fromChannel: i32, to: DataView, toChannel: i32, linear: bool = true) => {
-		for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
-			to.setUint8(i * 4 + toChannel, 255 - from.getUint8(i * 4 + fromChannel));
-		}
-		if (!linear) ExportTexture.to_srgb(to, toChannel);
-	}
-
-	static extract_channel = (from: DataView, fromChannel: i32, to: DataView, toChannel: i32, step: i32, mask: i32, linear: bool = true) => {
-		for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
-			to.setUint8(i * 4 + toChannel, from.getUint8(i * 4 + fromChannel) % step == mask ? 255 : 0);
-		}
-		if (!linear) ExportTexture.to_srgb(to, toChannel);
-	}
-
-	static set_channel = (value: i32, to: DataView, toChannel: i32, linear: bool = true) => {
-		for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
-			to.setUint8(i * 4 + toChannel, value);
-		}
-		if (!linear) ExportTexture.to_srgb(to, toChannel);
-	}
-
-	static to_srgb = (to: DataView, toChannel: i32) => {
-		for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
-			to.setUint8(i * 4 + toChannel, math_floor(math_pow(to.getUint8(i * 4 + toChannel) / 255, ExportTexture.gamma) * 255));
-		}
-	}
-}
-
-type export_preset_t = {
-	textures?: export_preset_texture_t[];
-};
-
-type export_preset_texture_t = {
-	name?: string;
-	channels?: string[];
-	color_space?: string;
-};
-
-///end

+ 0 - 590
base/Sources/ImportArm.ts

@@ -1,590 +0,0 @@
-
-class ImportArm {
-
-	static run_project = (path: string) => {
-		let b: ArrayBuffer = data_get_blob(path);
-		let project: project_format_t = armpack_decode(b);
-
-		///if (is_paint || is_sculpt)
-		if (project.version != null && project.layer_datas == null) {
-			// Import as material
-			if (project.material_nodes != null) {
-				ImportArm.run_material_from_project(project, path);
-			}
-			// Import as brush
-			else if (project.brush_nodes != null) {
-				ImportArm.run_brush_from_project(project, path);
-			}
-			// Import as swatches
-			else if (project.swatches != null) {
-				ImportArm.run_swatches_from_project(project, path);
-			}
-			return;
-		}
-
-		let import_as_mesh: bool = project.version == null;
-		context_raw.layers_preview_dirty = true;
-		context_raw.layer_filter = 0;
-		///end
-
-		///if is_lab
-		let import_as_mesh: bool = true;
-		///end
-
-		project_new(import_as_mesh);
-		project_filepath = path;
-		ui_files_filename = path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf("."));
-		///if (krom_android || krom_ios)
-		sys_title_set(ui_files_filename);
-		///else
-		sys_title_set(ui_files_filename + " - " + manifest_title);
-		///end
-
-		///if (is_paint || is_sculpt)
-		// Import as mesh instead
-		if (import_as_mesh) {
-			ImportArm.run_mesh(project);
-			return;
-		}
-		///end
-
-		// Save to recent
-		///if krom_ios
-		let recent_path: string = path.substr(path.lastIndexOf("/") + 1);
-		///else
-		let recent_path: string = path;
-		///end
-		let recent: string[] = config_raw.recent_projects;
-		array_remove(recent, recent_path);
-		recent.unshift(recent_path);
-		config_save();
-
-		project_raw = project;
-
-		///if (is_paint || is_sculpt)
-		let l0: layer_data_t = project.layer_datas[0];
-		base_res_handle.position = config_get_texture_res_pos(l0.res);
-		let bits_pos: texture_bits_t = l0.bpp == 8 ? texture_bits_t.BITS8 : l0.bpp == 16 ? texture_bits_t.BITS16 : texture_bits_t.BITS32;
-		base_bits_handle.position = bits_pos;
-		let bytes_per_pixel: i32 = math_floor(l0.bpp / 8);
-		let format: tex_format_t = l0.bpp == 8 ? tex_format_t.RGBA32 : l0.bpp == 16 ? tex_format_t.RGBA64 : tex_format_t.RGBA128;
-		///end
-
-		let base: string = path_base_dir(path);
-		if (project_raw.envmap != null) {
-			project_raw.envmap = data_is_abs(project_raw.envmap) ? project_raw.envmap : base + project_raw.envmap;
-		}
-		if (project_raw.envmap_strength != null) {
-			scene_world.strength = project_raw.envmap_strength;
-		}
-		if (project_raw.camera_world != null) {
-			scene_camera.base.transform.local = mat4_from_f32_array(project_raw.camera_world);
-			transform_decompose(scene_camera.base.transform);
-			scene_camera.data.fov = project_raw.camera_fov;
-			camera_object_build_proj(scene_camera);
-			let origin: Float32Array = project_raw.camera_origin;
-			camera_origins[0].x = origin[0];
-			camera_origins[0].y = origin[1];
-			camera_origins[0].z = origin[2];
-		}
-
-		for (let file of project.assets) {
-			///if krom_windows
-			file = string_replace_all(file, "/", "\\");
-			///else
-			file = string_replace_all(file, "\\", "/");
-			///end
-			// Convert image path from relative to absolute
-			let abs: string = data_is_abs(file) ? file : base + file;
-			if (project.packed_assets != null) {
-				abs = path_normalize(abs);
-				ImportArm.unpack_asset(project, abs, file);
-			}
-			if (data_cached_images.get(abs) == null && !file_exists(abs)) {
-				ImportArm.make_pink(abs);
-			}
-			let hdr_as_envmap: bool = abs.endsWith(".hdr") && project_raw.envmap == abs;
-			ImportTexture.run(abs, hdr_as_envmap);
-		}
-
-		///if (is_paint || is_sculpt)
-		if (project.font_assets != null) {
-			for (let file of project.font_assets) {
-				///if krom_windows
-				file = string_replace_all(file, "/", "\\");
-				///else
-				file = string_replace_all(file, "\\", "/");
-				///end
-				// Convert font path from relative to absolute
-				let abs: string = data_is_abs(file) ? file : base + file;
-				if (file_exists(abs)) {
-					ImportFont.run(abs);
-				}
-			}
-		}
-		///end
-
-		///if (is_paint || is_sculpt)
-		let md: mesh_data_t = mesh_data_create(project.mesh_datas[0]);
-		///end
-
-		///if is_lab
-		let md: mesh_data_t = mesh_data_create(project.mesh_data);
-		///end
-
-		mesh_object_set_data(context_raw.paint_object, md);
-		vec4_set(context_raw.paint_object.base.transform.scale, 1, 1, 1);
-		transform_build_matrix(context_raw.paint_object.base.transform);
-		context_raw.paint_object.base.name = md.name;
-		project_paint_objects = [context_raw.paint_object];
-
-		///if (is_paint || is_sculpt)
-		for (let i: i32 = 1; i < project.mesh_datas.length; ++i) {
-			let raw: mesh_data_t = project.mesh_datas[i];
-			let md: mesh_data_t = mesh_data_create(raw);
-			let object: mesh_object_t = scene_add_mesh_object(md, context_raw.paint_object.materials, context_raw.paint_object.base);
-			object.base.name = md.name;
-			object.skip_context = "paint";
-			project_paint_objects.push(object);
-		}
-
-		if (project.mesh_assets != null && project.mesh_assets.length > 0) {
-			let file: string = project.mesh_assets[0];
-			let abs: string = data_is_abs(file) ? file : base + file;
-			project_mesh_assets = [abs];
-		}
-
-		///if is_paint
-		if (project.atlas_objects != null) project_atlas_objects = project.atlas_objects;
-		if (project.atlas_names != null) project_atlas_names = project.atlas_names;
-		///end
-
-		// No mask by default
-		if (context_raw.merged_object == null) util_mesh_merge();
-		///end
-
-		context_select_paint_object(context_main_object());
-		viewport_scale_to_bounds();
-		context_raw.paint_object.skip_context = "paint";
-		context_raw.merged_object.base.visible = true;
-
-		///if (is_paint || is_sculpt)
-		let tex: image_t = project_layers[0].texpaint;
-		if (tex.width != config_get_texture_res_x() || tex.height != config_get_texture_res_y()) {
-			if (history_undo_layers != null) for (let l of history_undo_layers) SlotLayer.resize_and_set_bits(l);
-			let rts: map_t<string, render_target_t> = render_path_render_targets;
-			let _texpaint_blend0: image_t = rts.get("texpaint_blend0")._image;
-			base_notify_on_next_frame(() => {
-				image_unload(_texpaint_blend0);
-			});
-			rts.get("texpaint_blend0").width = config_get_texture_res_x();
-			rts.get("texpaint_blend0").height = config_get_texture_res_y();
-			rts.get("texpaint_blend0")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8, depth_format_t.NO_DEPTH);
-			let _texpaint_blend1: image_t = rts.get("texpaint_blend1")._image;
-			base_notify_on_next_frame(() => {
-				image_unload(_texpaint_blend1);
-			});
-			rts.get("texpaint_blend1").width = config_get_texture_res_x();
-			rts.get("texpaint_blend1").height = config_get_texture_res_y();
-			rts.get("texpaint_blend1")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8, depth_format_t.NO_DEPTH);
-			context_raw.brush_blend_dirty = true;
-		}
-
-		for (let l of project_layers) SlotLayer.unload(l);
-		project_layers = [];
-		for (let i: i32 = 0; i < project.layer_datas.length; ++i) {
-			let ld: layer_data_t = project.layer_datas[i];
-			let is_group: bool = ld.texpaint == null;
-
-			///if is_paint
-			let is_mask: bool = ld.texpaint != null && ld.texpaint_nor == null;
-			///end
-			///if is_sculpt
-			let is_mask: bool = false;
-			///end
-
-			let l: SlotLayerRaw = SlotLayer.create("", is_group ? layer_slot_type_t.GROUP : is_mask ? layer_slot_type_t.MASK : layer_slot_type_t.LAYER);
-			if (ld.name != null) l.name = ld.name;
-			l.visible = ld.visible;
-			project_layers.push(l);
-
-			if (!is_group) {
-				if (base_pipe_merge == null) base_make_pipe();
-
-				let _texpaint: image_t = null;
-
-				///if is_paint
-				let _texpaint_nor: image_t = null;
-				let _texpaint_pack: image_t = null;
-				///end
-
-				if (is_mask) {
-					_texpaint = image_from_bytes(lz4_decode(ld.texpaint, ld.res * ld.res * 4), ld.res, ld.res, tex_format_t.RGBA32);
-					g2_begin(l.texpaint);
-					// g2_set_pipeline(base_pipe_copy8);
-					g2_set_pipeline(project.is_bgra ? base_pipe_copy_bgra : base_pipe_copy); // Full bits for undo support, R8 is used
-					g2_draw_image(_texpaint, 0, 0);
-					g2_set_pipeline(null);
-					g2_end();
-				}
-				else { // Layer
-					// TODO: create render target from bytes
-					_texpaint = image_from_bytes(lz4_decode(ld.texpaint, ld.res * ld.res * 4 * bytes_per_pixel), ld.res, ld.res, format);
-					g2_begin(l.texpaint);
-					g2_set_pipeline(project.is_bgra ? base_pipe_copy_bgra : base_pipe_copy);
-					g2_draw_image(_texpaint, 0, 0);
-					g2_set_pipeline(null);
-					g2_end();
-
-					///if is_paint
-					_texpaint_nor = image_from_bytes(lz4_decode(ld.texpaint_nor, ld.res * ld.res * 4 * bytes_per_pixel), ld.res, ld.res, format);
-					g2_begin(l.texpaint_nor);
-					g2_set_pipeline(project.is_bgra ? base_pipe_copy_bgra : base_pipe_copy);
-					g2_draw_image(_texpaint_nor, 0, 0);
-					g2_set_pipeline(null);
-					g2_end();
-
-					_texpaint_pack = image_from_bytes(lz4_decode(ld.texpaint_pack, ld.res * ld.res * 4 * bytes_per_pixel), ld.res, ld.res, format);
-					g2_begin(l.texpaint_pack);
-					g2_set_pipeline(project.is_bgra ? base_pipe_copy_bgra : base_pipe_copy);
-					g2_draw_image(_texpaint_pack, 0, 0);
-					g2_set_pipeline(null);
-					g2_end();
-					///end
-				}
-
-				l.scale = ld.uv_scale;
-				l.angle = ld.uv_rot;
-				l.uv_type = ld.uv_type;
-				if (ld.decal_mat != null) l.decal_mat = mat4_from_f32_array(ld.decal_mat);
-				l.mask_opacity = ld.opacity_mask;
-				l.object_mask = ld.object_mask;
-				l.blending = ld.blending;
-
-				///if is_paint
-				l.paint_base = ld.paint_base;
-				l.paint_opac = ld.paint_opac;
-				l.paint_occ = ld.paint_occ;
-				l.paint_rough = ld.paint_rough;
-				l.paint_met = ld.paint_met;
-				l.paint_nor = ld.paint_nor;
-				l.paint_nor_blend = ld.paint_nor_blend != null ? ld.paint_nor_blend : true; // TODO: deprecated
-				l.paint_height = ld.paint_height;
-				l.paint_height_blend = ld.paint_height_blend != null ? ld.paint_height_blend : true; // TODO: deprecated
-				l.paint_emis = ld.paint_emis;
-				l.paint_subs = ld.paint_subs;
-				///end
-
-				base_notify_on_next_frame(() => {
-					image_unload(_texpaint);
-					///if is_paint
-					if (_texpaint_nor != null) image_unload(_texpaint_nor);
-					if (_texpaint_pack != null) image_unload(_texpaint_pack);
-					///end
-				});
-			}
-		}
-
-		// Assign parents to groups and masks
-		for (let i: i32 = 0; i < project.layer_datas.length; ++i) {
-			let ld: layer_data_t = project.layer_datas[i];
-			if (ld.parent >= 0) {
-				project_layers[i].parent = project_layers[ld.parent];
-			}
-		}
-
-		context_set_layer(project_layers[0]);
-
-		// Materials
-		let m0: material_data_t = data_get_material("Scene", "Material");
-
-		project_materials = [];
-		for (let n of project.material_nodes) {
-			ImportArm.init_nodes(n.nodes);
-			context_raw.material = SlotMaterial.create(m0, n);
-			project_materials.push(context_raw.material);
-		}
-		///end
-
-		ui_nodes_hwnd.redraws = 2;
-		ui_nodes_group_stack = [];
-		project_material_groups = [];
-		if (project.material_groups != null) {
-			for (let g of project.material_groups) project_material_groups.push({ canvas: g, nodes: zui_nodes_create() });
-		}
-
-		///if (is_paint || is_sculpt)
-		for (let m of project_materials) {
-			context_raw.material = m;
-			MakeMaterial.parse_paint_material();
-			util_render_make_material_preview();
-		}
-
-		project_brushes = [];
-		for (let n of project.brush_nodes) {
-			ImportArm.init_nodes(n.nodes);
-			context_raw.brush = SlotBrush.create(n);
-			project_brushes.push(context_raw.brush);
-			MakeMaterial.parse_brush();
-			util_render_make_brush_preview();
-		}
-
-		// Fill layers
-		for (let i: i32 = 0; i < project.layer_datas.length; ++i) {
-			let ld: layer_data_t = project.layer_datas[i];
-			let l: SlotLayerRaw = project_layers[i];
-			let is_group: bool = ld.texpaint == null;
-			if (!is_group) {
-				l.fill_layer = ld.fill_layer > -1 ? project_materials[ld.fill_layer] : null;
-			}
-		}
-
-		ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
-		ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
-		///end
-
-		///if is_lab
-		ImportArm.init_nodes(project.material.nodes);
-		project_canvas = project.material;
-		ParserLogic.parse(project_canvas);
-		///end
-
-		context_raw.ddirty = 4;
-		data_delete_blob(path);
-	}
-
-	///if (is_paint || is_sculpt)
-	static run_mesh = (raw: scene_t) => {
-		project_paint_objects = [];
-		for (let i: i32 = 0; i < raw.mesh_datas.length; ++i) {
-			let md: mesh_data_t = mesh_data_create(raw.mesh_datas[i]);
-			let object: mesh_object_t = null;
-			if (i == 0) {
-				mesh_object_set_data(context_raw.paint_object, md);
-				object = context_raw.paint_object;
-			}
-			else {
-				object = scene_add_mesh_object(md, context_raw.paint_object.materials, context_raw.paint_object.base);
-				object.base.name = md.name;
-				object.skip_context = "paint";
-				md._.handle = md.name;
-				data_cached_meshes.set(md._.handle, md);
-			}
-			vec4_set(object.base.transform.scale, 1, 1, 1);
-			transform_build_matrix(object.base.transform);
-			object.base.name = md.name;
-			project_paint_objects.push(object);
-			util_mesh_merge();
-			viewport_scale_to_bounds();
-		}
-		app_notify_on_init(base_init_layers);
-		history_reset();
-	}
-
-	static run_material = (path: string) => {
-		let b: ArrayBuffer = data_get_blob(path);
-		let project: project_format_t = armpack_decode(b);
-		if (project.version == null) { data_delete_blob(path); return; }
-		ImportArm.run_material_from_project(project, path);
-	}
-
-	static run_material_from_project = (project: project_format_t, path: string) => {
-		let base: string = path_base_dir(path);
-		for (let file of project.assets) {
-			///if krom_windows
-			file = string_replace_all(file, "/", "\\");
-			///else
-			file = string_replace_all(file, "\\", "/");
-			///end
-			// Convert image path from relative to absolute
-			let abs: string = data_is_abs(file) ? file : base + file;
-			if (project.packed_assets != null) {
-				abs = path_normalize(abs);
-				ImportArm.unpack_asset(project, abs, file);
-			}
-			if (data_cached_images.get(abs) == null && !file_exists(abs)) {
-				ImportArm.make_pink(abs);
-			}
-			ImportTexture.run(abs);
-		}
-
-		let m0: material_data_t = data_get_material("Scene", "Material");
-
-		let imported: SlotMaterialRaw[] = [];
-
-		for (let c of project.material_nodes) {
-			ImportArm.init_nodes(c.nodes);
-			context_raw.material = SlotMaterial.create(m0, c);
-			project_materials.push(context_raw.material);
-			imported.push(context_raw.material);
-			history_new_material();
-		}
-
-		if (project.material_groups != null) {
-			for (let c of project.material_groups) {
-				while (ImportArm.group_exists(c)) ImportArm.rename_group(c.name, imported, project.material_groups); // Ensure unique group name
-				ImportArm.init_nodes(c.nodes);
-				project_material_groups.push({ canvas: c, nodes: zui_nodes_create() });
-			}
-		}
-
-		let _init = () => {
-			for (let m of imported) {
-				context_set_material(m);
-				MakeMaterial.parse_paint_material();
-				util_render_make_material_preview();
-			}
-		}
-		app_notify_on_init(_init);
-
-		ui_nodes_group_stack = [];
-		ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
-		data_delete_blob(path);
-	}
-
-	static group_exists = (c: zui_node_canvas_t): bool => {
-		for (let g of project_material_groups) {
-			if (g.canvas.name == c.name) return true;
-		}
-		return false;
-	}
-
-	static rename_group = (name: string, materials: SlotMaterialRaw[], groups: zui_node_canvas_t[]) => {
-		for (let m of materials) {
-			for (let n of m.canvas.nodes) {
-				if (n.type == "GROUP" && n.name == name) n.name += ".1";
-			}
-		}
-		for (let c of groups) {
-			if (c.name == name) c.name += ".1";
-			for (let n of c.nodes) {
-				if (n.type == "GROUP" && n.name == name) n.name += ".1";
-			}
-		}
-	}
-
-	static run_brush = (path: string) => {
-		let b: ArrayBuffer = data_get_blob(path);
-		let project: project_format_t = armpack_decode(b);
-		if (project.version == null) { data_delete_blob(path); return; }
-		ImportArm.run_brush_from_project(project, path);
-	}
-
-	static run_brush_from_project = (project: project_format_t, path: string) => {
-		let base: string = path_base_dir(path);
-		for (let file of project.assets) {
-			///if krom_windows
-			file = string_replace_all(file, "/", "\\");
-			///else
-			file = string_replace_all(file, "\\", "/");
-			///end
-			// Convert image path from relative to absolute
-			let abs: string = data_is_abs(file) ? file : base + file;
-			if (project.packed_assets != null) {
-				abs = path_normalize(abs);
-				ImportArm.unpack_asset(project, abs, file);
-			}
-			if (data_cached_images.get(abs) == null && !file_exists(abs)) {
-				ImportArm.make_pink(abs);
-			}
-			ImportTexture.run(abs);
-		}
-
-		let imported: SlotBrushRaw[] = [];
-
-		for (let n of project.brush_nodes) {
-			ImportArm.init_nodes(n.nodes);
-			context_raw.brush = SlotBrush.create(n);
-			project_brushes.push(context_raw.brush);
-			imported.push(context_raw.brush);
-		}
-
-		let _init = () => {
-			for (let b of imported) {
-				context_set_brush(b);
-				util_render_make_brush_preview();
-			}
-		}
-		app_notify_on_init(_init);
-
-		ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
-		data_delete_blob(path);
-	}
-	///end
-
-	static run_swatches = (path: string, replaceExisting: bool = false) => {
-		let b: ArrayBuffer = data_get_blob(path);
-		let project: project_format_t = armpack_decode(b);
-		if (project.version == null) { data_delete_blob(path); return; }
-		ImportArm.run_swatches_from_project(project, path, replaceExisting);
-	}
-
-	static run_swatches_from_project = (project: project_format_t, path: string, replaceExisting: bool = false) => {
-		if (replaceExisting) {
-			project_raw.swatches = [];
-
-			if (project.swatches == null) { // No swatches contained
-				project_raw.swatches.push(make_swatch());
-			}
-		}
-
-		if (project.swatches != null) {
-			for (let s of project.swatches) {
-				project_raw.swatches.push(s);
-			}
-		}
-		ui_base_hwnds[tab_area_t.STATUS].redraws = 2;
-		data_delete_blob(path);
-	}
-
-	static make_pink = (abs: string) => {
-		console_error(strings_error2() + " " + abs);
-		let b: Uint8Array = new Uint8Array(4);
-		b[0] = 255;
-		b[1] = 0;
-		b[2] = 255;
-		b[3] = 255;
-		let pink: image_t = image_from_bytes(b.buffer, 1, 1);
-		data_cached_images.set(abs, pink);
-	}
-
-	static texture_node_name = (): string => {
-		///if (is_paint || is_sculpt)
-		return "TEX_IMAGE";
-		///else
-		return "ImageTextureNode";
-		///end
-	}
-
-	static init_nodes = (nodes: zui_node_t[]) => {
-		for (let node of nodes) {
-			if (node.type == ImportArm.texture_node_name()) {
-				node.buttons[0].default_value = base_get_asset_index(node.buttons[0].data);
-				node.buttons[0].data = "";
-			}
-		}
-	}
-
-	static unpack_asset = (project: project_format_t, abs: string, file: string) => {
-		if (project_raw.packed_assets == null) {
-			project_raw.packed_assets = [];
-		}
-		for (let pa of project.packed_assets) {
-			///if krom_windows
-			pa.name = string_replace_all(pa.name, "/", "\\");
-			///else
-			pa.name = string_replace_all(pa.name, "\\", "/");
-			///end
-			pa.name = path_normalize(pa.name);
-			if (pa.name == file) pa.name = abs; // From relative to absolute
-			if (pa.name == abs) {
-				if (!project_packed_asset_exists(project_raw.packed_assets, pa.name)) {
-					project_raw.packed_assets.push(pa);
-				}
-				let image: image_t = image_from_encoded_bytes(pa.bytes, pa.name.endsWith(".jpg") ? ".jpg" : ".png");
-				data_cached_images.set(abs, image);
-				break;
-			}
-		}
-	}
-}

+ 0 - 83
base/Sources/ImportAsset.ts

@@ -1,83 +0,0 @@
-
-class ImportAsset {
-
-	static run = (path: string, dropX: f32 = -1.0, dropY: f32 = -1.0, showBox: bool = true, hdrAsEnvmap: bool = true, done: ()=>void = null) => {
-
-		if (path.startsWith("cloud")) {
-			let do_cache_cloud = () => {
-				file_cache_cloud(path, (abs: string) => {
-					if (abs == null) return;
-					ImportAsset.run(abs, dropX, dropY, showBox, hdrAsEnvmap, done);
-				});
-			}
-
-			///if (krom_android || krom_ios)
-			base_notify_on_next_frame(() => {
-				console_toast(tr("Downloading"));
-				base_notify_on_next_frame(do_cache_cloud);
-			});
-			///else
-			do_cache_cloud();
-			///end
-
-			return;
-		}
-
-		if (path_is_mesh(path)) {
-			showBox ? project_import_mesh_box(path) : ImportMesh.run(path);
-			if (dropX > 0) ui_box_click_to_hide = false; // Prevent closing when going back to window after drag and drop
-		}
-		else if (path_is_texture(path)) {
-			ImportTexture.run(path, hdrAsEnvmap);
-			// Place image node
-			let x0: i32 = ui_nodes_wx;
-			let x1: i32 = ui_nodes_wx + ui_nodes_ww;
-			if (ui_nodes_show && dropX > x0 && dropX < x1) {
-				let asset_index: i32 = 0;
-				for (let i: i32 = 0; i < project_assets.length; ++i) {
-					if (project_assets[i].file == path) {
-						asset_index = i;
-						break;
-					}
-				}
-				ui_nodes_accept_asset_drag(asset_index);
-				ui_nodes_get_nodes().nodesDrag = false;
-				ui_nodes_hwnd.redraws = 2;
-			}
-
-			///if is_paint
-			if (context_raw.tool == workspace_tool_t.COLORID && project_asset_names.length == 1) {
-				ui_header_handle.redraws = 2;
-				context_raw.ddirty = 2;
-			}
-			///end
-		}
-		else if (path_is_project(path)) {
-			ImportArm.run_project(path);
-		}
-		else if (path_is_plugin(path)) {
-			ImportPlugin.run(path);
-		}
-		else if (path_is_gimp_color_palette(path)) {
-			ImportGpl.run(path, false);
-		}
-		///if is_paint
-		else if (path_is_font(path)) {
-			ImportFont.run(path);
-		}
-		else if (path_is_folder(path)) {
-			ImportFolder.run(path);
-		}
-		///end
-		else {
-			if (context_enable_import_plugin(path)) {
-				ImportAsset.run(path, dropX, dropY, showBox);
-			}
-			else {
-				console_error(strings_error1());
-			}
-		}
-
-		if (done != null) done();
-	}
-}

+ 0 - 294
base/Sources/ImportBlendMaterial.ts

@@ -1,294 +0,0 @@
-
-///if (is_paint || is_sculpt)
-
-class ImportBlendMaterial {
-
-	static run = (path: string) => {
-		let b: ArrayBuffer = data_get_blob(path);
-		let bl: BlendRaw = ParserBlend.init(b);
-		if (bl.dna == null) {
-			console_error(strings_error3());
-			return;
-		}
-
-		let mats: BlHandleRaw[] = ParserBlend.get(bl, "Material");
-		if (mats.length == 0) {
-			console_error("Error: No materials found");
-			return;
-		}
-
-		let imported: SlotMaterialRaw[] = [];
-
-		for (let mat of mats) {
-			// Material slot
-			context_raw.material = SlotMaterial.create(project_materials[0].data);
-			project_materials.push(context_raw.material);
-			imported.push(context_raw.material);
-			let nodes: zui_nodes_t = context_raw.material.nodes;
-			let canvas: zui_node_canvas_t = context_raw.material.canvas;
-			canvas.name = BlHandle.get(BlHandle.get(mat, "id"), "name").substr(2); // MAWood
-			let nout: zui_node_t = null;
-			for (let n of canvas.nodes) {
-				if (n.type == "OUTPUT_MATERIAL_PBR") {
-					nout = n;
-					break;
-				}
-			}
-			for (let n of canvas.nodes) {
-				if (n.name == "RGB") {
-					zui_remove_node(n, canvas);
-					break;
-				}
-			}
-
-			// Parse nodetree
-			let nodetree: any = BlHandle.get(mat, "nodetree"); // bNodeTree
-			let blnodes: any = BlHandle.get(nodetree, "nodes"); // ListBase
-			let bllinks: any = BlHandle.get(nodetree, "links"); // bNodeLink
-
-			// Look for Principled BSDF node
-			let node: any = BlHandle.get(blnodes, "first", 0, "bNode");
-			let last: any = BlHandle.get(blnodes, "last", 0, "bNode");
-			while (true) {
-				if (BlHandle.get(node, "idname") == "ShaderNodeBsdfPrincipled") break;
-				if (BlHandle.get(node, "name") == BlHandle.get(last, "name")) break;
-				node = BlHandle.get(node, "next");
-			}
-			if (BlHandle.get(node, "idname") != "ShaderNodeBsdfPrincipled") {
-				console_error("Error: No Principled BSDF node found");
-				continue;
-			}
-
-			// Use Principled BSDF as material output
-			nout.name = BlHandle.get(node, "name");
-			nout.x = BlHandle.get(node, "locx") + 400;
-			nout.y = -BlHandle.get(node, "locy") + 400;
-
-			// Place nodes
-			node = BlHandle.get(blnodes, "first", 0, "bNode");
-			while (true) {
-				// Search for node in list
-				let search: string = BlHandle.get(node, "idname").substr(10).toLowerCase();
-				let base: zui_node_t = null;
-				for (let list of NodesMaterial.list) {
-					let found: bool = false;
-					for (let n of list) {
-						let s: string = string_replace_all(n.type, "_", "").toLowerCase();
-						if (search == s) {
-							base = n;
-							found = true;
-							break;
-						}
-					}
-					if (found) break;
-				}
-
-				if (base != null) {
-					let n: zui_node_t = ui_nodes_make_node(base, nodes, canvas);
-					n.x = BlHandle.get(node, "locx") + 400;
-					n.y = -BlHandle.get(node, "locy") + 400;
-					n.name = BlHandle.get(node, "name");
-
-					// Fill input socket values
-					let inputs: any = BlHandle.get(node, "inputs");
-					let sock: any = BlHandle.get(inputs, "first", 0, "bNodeSocket");
-					let pos: i32 = 0;
-					while (true) {
-						if (pos >= n.inputs.length) break;
-						n.inputs[pos].default_value = ImportBlendMaterial.read_blend_socket(sock);
-
-						let last: any = sock;
-						sock = BlHandle.get(sock, "next");
-						if (last.block == sock.block) break;
-						pos++;
-					}
-
-					// Fill button values
-					if (search == "teximage") {
-						let img: any = BlHandle.get(node, "id", 0, "Image");
-						let file: string = BlHandle.get(img, "name").substr(2); // '//desktop\logo.png'
-						file = path_base_dir(path) + file;
-						ImportTexture.run(file);
-						let ar: string[] = file.split(path_sep);
-						let filename: string = ar[ar.length - 1];
-						n.buttons[0].default_value = base_get_asset_index(filename);
-					}
-					else if (search == "valtorgb") {
-						let ramp: any = BlHandle.get(node, "storage", 0, "ColorBand");
-						n.buttons[0].data = BlHandle.get(ramp, "ipotype") == 0 ? 0 : 1; // Linear / Constant
-						let elems: f32[][] = n.buttons[0].default_value;
-						for (let i: i32 = 0; i < BlHandle.get(ramp, "tot"); ++i) {
-							if (i >= elems.length) elems.push([1.0, 1.0, 1.0, 1.0, 0.0]);
-							let cbdata: any = BlHandle.get(ramp, "data", i, "CBData");
-							elems[i][0] = math_floor(BlHandle.get(cbdata, "r") * 100) / 100;
-							elems[i][1] = math_floor(BlHandle.get(cbdata, "g") * 100) / 100;
-							elems[i][2] = math_floor(BlHandle.get(cbdata, "b") * 100) / 100;
-							elems[i][3] = math_floor(BlHandle.get(cbdata, "a") * 100) / 100;
-							elems[i][4] = math_floor(BlHandle.get(cbdata, "pos") * 100) / 100;
-						}
-					}
-					else if (search == "mixrgb" || search == "math") {
-						n.buttons[0].default_value = BlHandle.get(node, "custom1");
-						n.buttons[1].default_value = BlHandle.get(node, "custom2") & 2;
-					}
-					else if (search == "mapping") {
-						let storage: any = BlHandle.get(node, "storage", 0, "TexMapping");
-						n.buttons[0].default_value = BlHandle.get(storage, "loc");
-						n.buttons[1].default_value = BlHandle.get(storage, "rot");
-						n.buttons[2].default_value = BlHandle.get(storage, "size");
-						// let mat: any = BlHandle.get(storage, "mat"); float[4][4]
-						// storage.flag & 1 // use_min
-						// storage.flag & 2 // use_max
-						// storage.min[0]
-						// storage.min[1]
-						// storage.min[2]
-						// storage.max[0]
-						// storage.max[1]
-						// storage.max[2]
-					}
-
-					// Fill output socket values
-					let outputs: any = BlHandle.get(node, "outputs");
-					sock = BlHandle.get(outputs, "first", 0, "bNodeSocket");
-					pos = 0;
-					while (true) {
-						if (pos >= n.outputs.length) break;
-						n.outputs[pos].default_value = ImportBlendMaterial.read_blend_socket(sock);
-
-						let last: any = sock;
-						sock = BlHandle.get(sock, "next");
-						if (last.block == sock.block) break;
-						pos++;
-					}
-
-					canvas.nodes.push(n);
-				}
-
-				if (BlHandle.get(node, "name") == BlHandle.get(last, "name")) break;
-				node = BlHandle.get(node, "next");
-			}
-
-			// Place links
-			let link: any = BlHandle.get(bllinks, "first", 0, "bNodeLink");
-			while (true) {
-				let fromnode: any = BlHandle.get(BlHandle.get(link, "fromnode"), "name");
-				let tonode: any = BlHandle.get(BlHandle.get(link, "tonode"), "name");
-				let fromsock: any = BlHandle.get(link, "fromsock");
-				let tosock: any = BlHandle.get(link, "tosock");
-
-				let from_id: i32 = -1;
-				let to_id: i32 = -1;
-				for (let n of canvas.nodes) {
-					if (n.name == fromnode) {
-						from_id = n.id;
-						break;
-					}
-				}
-				for (let n of canvas.nodes) {
-					if (n.name == tonode) {
-						to_id = n.id;
-						break;
-					}
-				}
-
-				if (from_id >= 0 && to_id >= 0) {
-					let from_socket: i32 = 0;
-					let sock: any = fromsock;
-					while (true) {
-						let last: any = sock;
-						sock = BlHandle.get(sock, "prev");
-						if (last.block == sock.block) break;
-						from_socket++;
-					}
-
-					let to_socket: i32 = 0;
-					sock = tosock;
-					while (true) {
-						let last: any = sock;
-						sock = BlHandle.get(sock, "prev");
-						if (last.block == sock.block) break;
-						to_socket++;
-					}
-
-					let valid: bool = true;
-
-					// Remap principled
-					if (tonode == nout.name) {
-						if (to_socket == 0) to_socket = 0; // Base
-						else if (to_socket == 18) to_socket = 1; // Opac
-						else if (to_socket == 7) to_socket = 3; // Rough
-						else if (to_socket == 4) to_socket = 4; // Met
-						else if (to_socket == 19) to_socket = 5; // TODO: auto-remove normal_map node
-						else if (to_socket == 17) to_socket = 6; // Emis
-						else if (to_socket == 1) to_socket = 8; // Subs
-						else valid = false;
-					}
-
-					if (valid) {
-						let raw: zui_node_link_t = {
-							id: zui_get_link_id(canvas.links),
-							from_id: from_id,
-							from_socket: from_socket,
-							to_id: to_id,
-							to_socket: to_socket
-						};
-						canvas.links.push(raw);
-					}
-				}
-
-				let last: any = link;
-				link = BlHandle.get(link, "next");
-				if (last.block == link.block) break;
-			}
-			history_new_material();
-		}
-
-		let _init = () => {
-			for (let m of imported) {
-				context_set_material(m);
-				MakeMaterial.parse_paint_material();
-				util_render_make_material_preview();
-			}
-		}
-		app_notify_on_init(_init);
-
-		ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
-		data_delete_blob(path);
-	}
-
-	static read_blend_socket = (sock: any): any => {
-		let idname: any = BlHandle.get(sock, "idname");
-		if (idname.startsWith("NodeSocketVector")) {
-			let v: any = BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueVector"), "value");
-			v[0] = math_floor(v[0] * 100) / 100;
-			v[1] = math_floor(v[1] * 100) / 100;
-			v[2] = math_floor(v[2] * 100) / 100;
-			return v;
-		}
-		else if (idname.startsWith("NodeSocketColor")) {
-			let v: any = BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueRGBA"), "value");
-			v[0] = math_floor(v[0] * 100) / 100;
-			v[1] = math_floor(v[1] * 100) / 100;
-			v[2] = math_floor(v[2] * 100) / 100;
-			v[3] = math_floor(v[3] * 100) / 100;
-			return v;
-		}
-		else if (idname.startsWith("NodeSocketFloat")) {
-			let v: any = BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueFloat"), "value");
-			v = math_floor(v * 100) / 100;
-			return v;
-		}
-		else if (idname.startsWith("NodeSocketInt")) {
-			return BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueInt"), "value");
-		}
-		else if (idname.startsWith("NodeSocketBoolean")) {
-			return BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueBoolean"), "value");
-		}
-		else if (idname.startsWith("NodeSocketString")) {
-			return BlHandle.get(BlHandle.get(sock, "default_value", 0, "bNodeSocketValueString"), "value");
-		}
-		return null;
-	}
-}
-
-///end

+ 0 - 454
base/Sources/ImportBlendMesh.ts

@@ -1,454 +0,0 @@
-
-class ImportBlendMesh {
-
-	static eps: f32 = 1.0 / 32767;
-
-	static run = (path: string, replaceExisting: bool = true) => {
-		let b: ArrayBuffer = data_get_blob(path);
-		let bl: BlendRaw = ParserBlend.init(b);
-		if (bl.dna == null) {
-			console_error(strings_error3());
-			return;
-		}
-
-		let obs: BlHandleRaw[] = ParserBlend.get(bl, "Object");
-		if (obs == null || obs.length == 0) { ImportMesh.make_mesh(null, path); return; }
-
-		let first: bool = true;
-		for (let ob of obs) {
-			if (BlHandle.get(ob, "type") != 1) continue;
-
-			let name: string = BlHandle.get(BlHandle.get(ob, "id"), "name");
-			name = name.substring(2, name.length);
-
-			let m: any = BlHandle.get(ob, "data", 0, "Mesh");
-			if (m == null) continue;
-
-			let totpoly: i32 = BlHandle.get(m, "totpoly");
-			if (totpoly == 0) continue;
-
-			let numtri: i32 = 0;
-			for (let i: i32 = 0; i < totpoly; ++i) {
-				let poly: any = BlHandle.get(m, "mpoly", i);
-				let totloop: i32 = BlHandle.get(poly, "totloop");
-				numtri += totloop - 2;
-			}
-			let inda: Uint32Array = new Uint32Array(numtri * 3);
-			for (let i: i32 = 0; i < inda.length; ++i) inda[i] = i;
-
-			let posa32: Float32Array = new Float32Array(numtri * 3 * 4);
-			let posa: Int16Array = new Int16Array(numtri * 3 * 4);
-			let nora: Int16Array = new Int16Array(numtri * 3 * 2);
-
-			// pdata, 25 == CD_MPOLY
-			// let vdata: any = BlHandle.get(m, "vdata");
-			// let codata: any = null;
-			// let codata_pos: i32 = 0;
-			// for (let i: i32 = 0; i < BlHandle.get(vdata, "totlayer"); ++i) {
-			// 	let l: any = BlHandle.get(vdata, "layers", i);
-			// 	if (BlHandle.get(l, "type") == 0) { // CD_MVERT
-			// 		let ptr: any = BlHandle.get(l, "data");
-			// 		codata_pos = bl.BlHandle.get(map, ptr).pos;
-			// 		codata = l;
-			// 	}
-			// }
-
-			let ldata: any = BlHandle.get(m, "ldata");
-			let uvdata: any = null;
-			let uvdata_pos: i32 = 0;
-			let coldata: any = null;
-			let coldata_pos: i32 = 0;
-
-			for (let i: i32 = 0; i < BlHandle.get(ldata, "totlayer"); ++i) {
-				let l: any = BlHandle.get(ldata, "layers", i);
-				if (BlHandle.get(l, "type") == 16) { // CD_MLOOPUV
-					let ptr: any = BlHandle.get(l, "data");
-					uvdata_pos = bl.map.get(ptr).pos;
-					uvdata = l;
-				}
-				else if (BlHandle.get(l, "type") == 17) { // CD_PROP_BYTE_COLOR
-					let ptr: any = BlHandle.get(l, "data");
-					coldata_pos = bl.map.get(ptr).pos;
-					coldata = l;
-				}
-				// CD_MLOOP == 26
-			}
-
-			let hasuv: bool = uvdata != null;
-			let texa: Int16Array = hasuv ? new Int16Array(numtri * 3 * 2) : null;
-			let hascol: bool = context_raw.parse_vcols && coldata != null;
-			let cola: Int16Array = hascol ? new Int16Array(numtri * 3 * 4) : null;
-
-			let tri: i32 = 0;
-			let vec0: vec4_t = vec4_create();
-			let vec1: vec4_t = vec4_create();
-			let vec2: vec4_t = vec4_create();
-			for (let i: i32 = 0; i < totpoly; ++i) {
-				let poly: any = BlHandle.get(m, "mpoly", i);
-				// let smooth: bool = BlHandle.get(poly, "flag") & 1 == 1; // ME_SMOOTH
-				let smooth: bool = false; // TODO: fetch smooth normals
-				let loopstart: i32 = BlHandle.get(poly, "loopstart");
-				let totloop: i32 = BlHandle.get(poly, "totloop");
-				if (totloop <= 4) { // Convex, fan triangulation
-					let v0: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, loopstart + totloop - 1);
-					let v1: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, loopstart);
-					let co0: any = BlHandle.get(v0, "co");
-					let co1: any = BlHandle.get(v1, "co");
-					let no0: any = BlHandle.get(v0, "no");
-					let no1: any = BlHandle.get(v1, "no");
-					if (smooth) {
-						vec4_normalize(vec4_set(vec0, no0[0] / 32767, no0[1] / 32767, no0[2] / 32767)); // shortmax
-						vec4_normalize(vec4_set(vec1, no1[0] / 32767, no1[1] / 32767, no1[2] / 32767));
-					}
-					let uv0: Float32Array = null;
-					let uv1: Float32Array = null;
-					let uv2: Float32Array = null;
-					if (hasuv) {
-						bl.pos = uvdata_pos + (loopstart + totloop - 1) * 4 * 3; // * 3 = x, y, flag
-						uv0 = ParserBlend.read_f32array(bl, 2);
-						if (uv0[0] > 1.0 + ImportBlendMesh.eps) uv0[0] = uv0[0] - math_floor(uv0[0]);
-						if (uv0[1] > 1.0 + ImportBlendMesh.eps) uv0[1] = uv0[1] - math_floor(uv0[1]);
-						bl.pos = uvdata_pos + (loopstart) * 4 * 3;
-						uv1 = ParserBlend.read_f32array(bl, 2);
-						if (uv1[0] > 1.0 + ImportBlendMesh.eps) uv1[0] = uv1[0] - math_floor(uv1[0]);
-						if (uv1[1] > 1.0 + ImportBlendMesh.eps) uv1[1] = uv1[1] - math_floor(uv1[1]);
-					}
-					let col0r: i32 = 0;
-					let col0g: i32 = 0;
-					let col0b: i32 = 0;
-					let col1r: i32 = 0;
-					let col1g: i32 = 0;
-					let col1b: i32 = 0;
-					let col2r: i32 = 0;
-					let col2g: i32 = 0;
-					let col2b: i32 = 0;
-					if (hascol) {
-						bl.pos = coldata_pos + (loopstart + totloop - 1) * 1 * 4; // * 4 = r, g, b, a
-						col0r = ParserBlend.read_i8(bl);
-						col0g = ParserBlend.read_i8(bl);
-						col0b = ParserBlend.read_i8(bl);
-						bl.pos = coldata_pos + (loopstart) * 1 * 4;
-						col1r = ParserBlend.read_i8(bl);
-						col1g = ParserBlend.read_i8(bl);
-						col1b = ParserBlend.read_i8(bl);
-					}
-					for (let j: i32 = 0; j < totloop - 2; ++j) {
-						let v2: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, loopstart + j + 1);
-						let co2: any = BlHandle.get(v2, "co");
-						let no2: any = BlHandle.get(v2, "no");
-						if (smooth) {
-							vec4_normalize(vec4_set(vec2, no2[0] / 32767, no2[1] / 32767, no2[2] / 32767));
-						}
-						else {
-							vec4_set(vec2, co2[0], co2[1], co2[2]);
-							vec4_set(vec1, co1[0], co1[1], co1[2]);
-							vec4_sub_vecs(vec0, vec2, vec1);
-							vec4_set(vec2, co0[0], co0[1], co0[2]);
-							vec4_sub_vecs(vec1, vec2, vec1);
-							vec4_cross(vec0, vec1);
-							vec4_normalize(vec0);
-						}
-						posa32[tri * 9    ] = co0[0];
-						posa32[tri * 9 + 1] = co0[1];
-						posa32[tri * 9 + 2] = co0[2];
-						posa32[tri * 9 + 3] = co1[0];
-						posa32[tri * 9 + 4] = co1[1];
-						posa32[tri * 9 + 5] = co1[2];
-						posa32[tri * 9 + 6] = co2[0];
-						posa32[tri * 9 + 7] = co2[1];
-						posa32[tri * 9 + 8] = co2[2];
-						posa[tri * 12 + 3] = math_floor(vec0.z * 32767);
-						posa[tri * 12 + 7] = math_floor((smooth ? vec1.z : vec0.z) * 32767);
-						posa[tri * 12 + 11] = math_floor((smooth ? vec2.z : vec0.z) * 32767);
-						nora[tri * 6    ] = math_floor(vec0.x * 32767);
-						nora[tri * 6 + 1] = math_floor(vec0.y * 32767);
-						nora[tri * 6 + 2] = math_floor((smooth ? vec1.x : vec0.x) * 32767);
-						nora[tri * 6 + 3] = math_floor((smooth ? vec1.y : vec0.y) * 32767);
-						nora[tri * 6 + 4] = math_floor((smooth ? vec2.x : vec0.x) * 32767);
-						nora[tri * 6 + 5] = math_floor((smooth ? vec2.y : vec0.y) * 32767);
-						co1 = co2;
-						no1 = no2;
-						vec4_set_from(vec1, vec2);
-						if (hasuv) {
-							bl.pos = uvdata_pos + (loopstart + j + 1) * 4 * 3;
-							uv2 = ParserBlend.read_f32array(bl, 2);
-							if (uv2[0] > 1.0 + ImportBlendMesh.eps) uv2[0] = uv2[0] - math_floor(uv2[0]);
-							if (uv2[1] > 1.0 + ImportBlendMesh.eps) uv2[1] = uv2[1] - math_floor(uv2[1]);
-							texa[tri * 6    ] = math_floor(uv0[0] * 32767);
-							texa[tri * 6 + 1] = math_floor((1.0 - uv0[1]) * 32767);
-							texa[tri * 6 + 2] = math_floor(uv1[0] * 32767);
-							texa[tri * 6 + 3] = math_floor((1.0 - uv1[1]) * 32767);
-							texa[tri * 6 + 4] = math_floor(uv2[0] * 32767);
-							texa[tri * 6 + 5] = math_floor((1.0 - uv2[1]) * 32767);
-							uv1 = uv2;
-						}
-						if (hascol) {
-							bl.pos = coldata_pos + (loopstart + j + 1) * 1 * 4;
-							col2r = ParserBlend.read_i8(bl);
-							col2g = ParserBlend.read_i8(bl);
-							col2b = ParserBlend.read_i8(bl);
-							cola[tri * 12    ] = col0r * 128;
-							cola[tri * 12 + 1] = col0g * 128;
-							cola[tri * 12 + 2] = col0b * 128;
-							cola[tri * 12 + 3] = col1r * 128;
-							cola[tri * 12 + 4] = col1g * 128;
-							cola[tri * 12 + 5] = col1b * 128;
-							cola[tri * 12 + 6] = col2r * 128;
-							cola[tri * 12 + 7] = col2g * 128;
-							cola[tri * 12 + 8] = col2b * 128;
-							col1r = col2r;
-							col1g = col2g;
-							col1b = col2b;
-						}
-						tri++;
-					}
-				}
-				else { // Convex or concave, ear clipping
-					let va: i32[] = [];
-					for (let i: i32 = 0; i < totloop; ++i) va.push(loopstart + i);
-					let v0: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, loopstart);
-					let v1: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, loopstart + 1);
-					let v2: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, loopstart + 2);
-					let co0: any = BlHandle.get(v0, "co");
-					let co1: any = BlHandle.get(v1, "co");
-					let co2: any = BlHandle.get(v2, "co");
-					vec4_set(vec2, co2[0], co2[1], co2[2]);
-					vec4_set(vec1, co1[0], co1[1], co1[2]);
-					vec4_sub_vecs(vec0, vec2, vec1);
-					vec4_set(vec2, co0[0], co0[1], co0[2]);
-					vec4_sub_vecs(vec1, vec2, vec1);
-					vec4_cross(vec0, vec1);
-					vec4_normalize(vec0, );
-
-					let nx: f32 = vec0.x;
-					let ny: f32 = vec0.y;
-					let nz: f32 = vec0.z;
-					let nxabs: f32 = math_abs(nx);
-					let nyabs: f32 = math_abs(ny);
-					let nzabs: f32 = math_abs(nz);
-					let flip: bool = nx + ny + nz > 0;
-					let axis: i32 = nxabs > nyabs && nxabs > nzabs ? 0 : nyabs > nxabs && nyabs > nzabs ? 1 : 2;
-					let axis0: i32 = axis == 0 ? (flip ? 2 : 1) : axis == 1 ? (flip ? 0 : 2) : (flip ? 1 : 0);
-					let axis1: i32 = axis == 0 ? (flip ? 1 : 2) : axis == 1 ? (flip ? 2 : 0) : (flip ? 0 : 1);
-
-					let winding: f32 = 0.0;
-					for (let i: i32 = 0; i < totloop; ++i) {
-						let v0: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, loopstart + i);
-						let v1: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, loopstart + ((i + 1) % totloop));
-						let co0: any = BlHandle.get(v0, "co");
-						let co1: any = BlHandle.get(v1, "co");
-						winding += (co1[axis0] - co0[axis0]) * (co1[axis1] + co0[axis1]);
-					}
-					flip = winding > 0 ? nx + ny + nz > 0 : nx + ny + nz < 0;
-					axis0 = axis == 0 ? (flip ? 2 : 1) : axis == 1 ? (flip ? 0 : 2) : (flip ? 1 : 0);
-					axis1 = axis == 0 ? (flip ? 1 : 2) : axis == 1 ? (flip ? 2 : 0) : (flip ? 0 : 1);
-
-					let vi: i32 = totloop;
-					let loops: i32 = 0;
-					let i: i32 = -1;
-					while (vi > 2 && loops++ < vi) {
-						i = (i + 1) % vi;
-						let i1: i32 = (i + 1) % vi;
-						let i2: i32 = (i + 2) % vi;
-						let v0: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, va[i ]);
-						let v1: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, va[i1]);
-						let v2: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, va[i2]);
-						let co0: any = BlHandle.get(v0, "co");
-						let co1: any = BlHandle.get(v1, "co");
-						let co2: any = BlHandle.get(v2, "co");
-						let v0x: f32 = co0[axis0];
-						let v0y: f32 = co0[axis1];
-						let v1x: f32 = co1[axis0];
-						let v1y: f32 = co1[axis1];
-						let v2x: f32 = co2[axis0];
-						let v2y: f32 = co2[axis1];
-
-						let e0x: f32 = v0x - v1x; // Not an interior vertex
-						let e0y: f32 = v0y - v1y;
-						let e1x: f32 = v2x - v1x;
-						let e1y: f32 = v2y - v1y;
-						let cross: f32 = e0x * e1y - e0y * e1x;
-						if (cross <= 0) continue;
-
-						let overlap: bool = false; // Other vertex found inside this triangle
-						for (let j: i32 = 0; j < vi - 3; ++j) {
-							let j0: i32 = (i + 3 + j) % vi;
-							let v: BlHandleRaw = ImportBlendMesh.get_mvert_v(m, va[j0]);
-							let co: any = BlHandle.get(v, "co");
-							let px: f32 = co[axis0];
-							let py: f32 = co[axis1];
-
-							if (util_mesh_pnpoly(v0x, v0y, v1x, v1y, v2x, v2y, px, py)) {
-								overlap = true;
-								break;
-							}
-						}
-						if (overlap) continue;
-
-						// Found ear
-						{
-							let no0: any = BlHandle.get(v0, "no");
-							let no1: any = BlHandle.get(v1, "no");
-							let no2: any = BlHandle.get(v2, "no");
-							if (smooth) {
-								vec4_normalize(vec4_set(vec0, no0[0] / 32767, no0[1] / 32767, no0[2] / 32767)); // shortmax
-								vec4_normalize(vec4_set(vec1, no1[0] / 32767, no1[1] / 32767, no1[2] / 32767));
-								vec4_normalize(vec4_set(vec2, no2[0] / 32767, no2[1] / 32767, no2[2] / 32767));
-							}
-							else {
-								vec4_set(vec2, co2[0], co2[1], co2[2]);
-								vec4_set(vec1, co1[0], co1[1], co1[2]);
-								vec4_sub_vecs(vec0, vec2, vec1);
-								vec4_set(vec2, co0[0], co0[1], co0[2]);
-								vec4_sub_vecs(vec1, vec2, vec1);
-								vec4_cross(vec0, vec1);
-								vec4_normalize(vec0, );
-							}
-							let uv0: Float32Array = null;
-							let uv1: Float32Array = null;
-							let uv2: Float32Array = null;
-							if (hasuv) {
-								bl.pos = uvdata_pos + (va[i ]) * 4 * 3;
-								uv0 = ParserBlend.read_f32array(bl, 2);
-								if (uv0[0] > 1.0 + ImportBlendMesh.eps) uv0[0] = uv0[0] - math_floor(uv0[0]);
-								if (uv0[1] > 1.0 + ImportBlendMesh.eps) uv0[1] = uv0[1] - math_floor(uv0[1]);
-								bl.pos = uvdata_pos + (va[i1]) * 4 * 3;
-								uv1 = ParserBlend.read_f32array(bl, 2);
-								if (uv1[0] > 1.0 + ImportBlendMesh.eps) uv1[0] = uv1[0] - math_floor(uv1[0]);
-								if (uv1[1] > 1.0 + ImportBlendMesh.eps) uv1[1] = uv1[1] - math_floor(uv1[1]);
-								bl.pos = uvdata_pos + (va[i2]) * 4 * 3;
-								uv2 = ParserBlend.read_f32array(bl, 2);
-								if (uv2[0] > 1.0 + ImportBlendMesh.eps) uv2[0] = uv2[0] - math_floor(uv2[0]);
-								if (uv2[1] > 1.0 + ImportBlendMesh.eps) uv2[1] = uv2[1] - math_floor(uv2[1]);
-							}
-							let col0r: i32 = 0;
-							let col0g: i32 = 0;
-							let col0b: i32 = 0;
-							let col1r: i32 = 0;
-							let col1g: i32 = 0;
-							let col1b: i32 = 0;
-							let col2r: i32 = 0;
-							let col2g: i32 = 0;
-							let col2b: i32 = 0;
-							if (hascol) {
-								bl.pos = coldata_pos + (va[i ]) * 1 * 4;
-								col0r = ParserBlend.read_i8(bl);
-								col0g = ParserBlend.read_i8(bl);
-								col0b = ParserBlend.read_i8(bl);
-								bl.pos = coldata_pos + (va[i1]) * 1 * 4;
-								col1r = ParserBlend.read_i8(bl);
-								col1g = ParserBlend.read_i8(bl);
-								col1b = ParserBlend.read_i8(bl);
-								bl.pos = coldata_pos + (va[i2]) * 1 * 4;
-								col2r = ParserBlend.read_i8(bl);
-								col2g = ParserBlend.read_i8(bl);
-								col2b = ParserBlend.read_i8(bl);
-							}
-							posa32[tri * 9    ] = co0[0];
-							posa32[tri * 9 + 1] = co0[1];
-							posa32[tri * 9 + 2] = co0[2];
-							posa32[tri * 9 + 3] = co1[0];
-							posa32[tri * 9 + 4] = co1[1];
-							posa32[tri * 9 + 5] = co1[2];
-							posa32[tri * 9 + 6] = co2[0];
-							posa32[tri * 9 + 7] = co2[1];
-							posa32[tri * 9 + 8] = co2[2];
-							posa[tri * 12 + 3] = math_floor(vec0.z * 32767);
-							posa[tri * 12 + 7] = math_floor((smooth ? vec1.z : vec0.z) * 32767);
-							posa[tri * 12 + 11] = math_floor((smooth ? vec2.z : vec0.z) * 32767);
-							nora[tri * 6    ] = math_floor(vec0.x * 32767);
-							nora[tri * 6 + 1] = math_floor(vec0.y * 32767);
-							nora[tri * 6 + 2] = math_floor((smooth ? vec1.x : vec0.x) * 32767);
-							nora[tri * 6 + 3] = math_floor((smooth ? vec1.y : vec0.y) * 32767);
-							nora[tri * 6 + 4] = math_floor((smooth ? vec2.x : vec0.x) * 32767);
-							nora[tri * 6 + 5] = math_floor((smooth ? vec2.y : vec0.y) * 32767);
-							if (hasuv) {
-								texa[tri * 6    ] = math_floor(uv0[0] * 32767);
-								texa[tri * 6 + 1] = math_floor((1.0 - uv0[1]) * 32767);
-								texa[tri * 6 + 2] = math_floor(uv1[0] * 32767);
-								texa[tri * 6 + 3] = math_floor((1.0 - uv1[1]) * 32767);
-								texa[tri * 6 + 4] = math_floor(uv2[0] * 32767);
-								texa[tri * 6 + 5] = math_floor((1.0 - uv2[1]) * 32767);
-							}
-							if (hascol) {
-								cola[tri * 12    ] = col0r * 128;
-								cola[tri * 12 + 1] = col0g * 128;
-								cola[tri * 12 + 2] = col0b * 128;
-								cola[tri * 12 + 3] = col1r * 128;
-								cola[tri * 12 + 4] = col1g * 128;
-								cola[tri * 12 + 5] = col1b * 128;
-								cola[tri * 12 + 6] = col2r * 128;
-								cola[tri * 12 + 7] = col2g * 128;
-								cola[tri * 12 + 8] = col2b * 128;
-							}
-							tri++;
-						}
-
-						for (let j: i32 = ((i + 1) % vi); j < vi - 1; ++j) { // Consume vertex
-							va[j] = va[j + 1];
-						}
-						vi--;
-						i--;
-						loops = 0;
-					}
-				}
-			}
-
-			// Apply world matrix
-			let obmat: any = BlHandle.get(ob, "obmat", 0, "float", 16);
-			let mat: mat4_t = mat4_transpose(mat4_from_f32_array(obmat));
-			let v: vec4_t = vec4_create();
-			for (let i: i32 = 0; i < math_floor(posa32.length / 3); ++i) {
-				vec4_set(v, posa32[i * 3], posa32[i * 3 + 1], posa32[i * 3 + 2]);
-				vec4_apply_mat4(v, mat);
-				posa32[i * 3    ] = v.x;
-				posa32[i * 3 + 1] = v.y;
-				posa32[i * 3 + 2] = v.z;
-			}
-			mat4_get_inv(mat, mat);
-			mat4_transpose3x3(mat);
-			mat.m[12] = mat.m[13] = mat.m[14] = mat.m[15] = 0;
-			for (let i: i32 = 0; i < math_floor(nora.length / 2); ++i) {
-				vec4_set(v, nora[i * 2] / 32767, nora[i * 2 + 1] / 32767, posa[i * 4 + 3] / 32767);
-				vec4_apply_mat(v, mat);
-				vec4_normalize(v);
-				nora[i * 2    ] = math_floor(v.x * 32767);
-				nora[i * 2 + 1] = math_floor(v.y * 32767);
-				posa[i * 4 + 3] = math_floor(v.z * 32767);
-			}
-
-			// Pack positions to (-1, 1) range
-			let scale_pos: f32 = 0.0;
-			for (let i: i32 = 0; i < posa32.length; ++i) {
-				let f: f32 = math_abs(posa32[i]);
-				if (scale_pos < f) scale_pos = f;
-			}
-			let inv: f32 = 1 / scale_pos;
-			for (let i: i32 = 0; i < math_floor(posa32.length / 3); ++i) {
-				posa[i * 4    ] = math_floor(posa32[i * 3    ] * 32767 * inv);
-				posa[i * 4 + 1] = math_floor(posa32[i * 3 + 1] * 32767 * inv);
-				posa[i * 4 + 2] = math_floor(posa32[i * 3 + 2] * 32767 * inv);
-			}
-
-			let obj: any = {
-				posa: posa,
-				nora: nora,
-				texa: texa,
-				cola: cola,
-				inda: inda,
-				name: name,
-				scale_pos: scale_pos,
-				scale_tex: 1.0
-			};
-
-			(first && replaceExisting) ? ImportMesh.make_mesh(obj, path) : ImportMesh.add_mesh(obj);
-			first = false;
-		}
-
-		data_delete_blob(path);
-	}
-
-	static get_mvert_v(m: BlHandleRaw, loopstart: i32): BlHandleRaw {
-		 return BlHandle.get(m, "mvert", BlHandle.get(BlHandle.get(m, "mloop", loopstart), "v"));
-	}
-}

+ 0 - 157
base/Sources/ImportEnvmap.ts

@@ -1,157 +0,0 @@
-
-class ImportEnvmap {
-
-	static pipeline: pipeline_t = null;
-	static params_loc: kinc_const_loc_t;
-	static params: vec4_t = vec4_create();
-	static n: vec4_t = vec4_create();
-	static radiance_loc: kinc_tex_unit_t;
-	static radiance: image_t = null;
-	static radiance_cpu: image_t = null;
-	static mips: image_t[] = null;
-	static mips_cpu: image_t[] = null;
-
-	static run = (path: string, image: image_t) => {
-
-		// Init
-		if (ImportEnvmap.pipeline == null) {
-			ImportEnvmap.pipeline = g4_pipeline_create();
-			ImportEnvmap.pipeline.vertex_shader = sys_get_shader("pass.vert");
-			ImportEnvmap.pipeline.fragment_shader = sys_get_shader("prefilter_envmap.frag");
-			let vs: vertex_struct_t = g4_vertex_struct_create();
-			g4_vertex_struct_add(vs, "pos", vertex_data_t.F32_2X);
-			ImportEnvmap.pipeline.input_layout = [vs];
-			ImportEnvmap.pipeline.color_attachment_count = 1;
-			ImportEnvmap.pipeline.color_attachments[0] = tex_format_t.RGBA128;
-			g4_pipeline_compile(ImportEnvmap.pipeline);
-			ImportEnvmap.params_loc = g4_pipeline_get_const_loc(ImportEnvmap.pipeline, "params");
-			ImportEnvmap.radiance_loc = g4_pipeline_get_tex_unit(ImportEnvmap.pipeline, "radiance");
-
-			ImportEnvmap.radiance = image_create_render_target(1024, 512, tex_format_t.RGBA128);
-
-			ImportEnvmap.mips = [];
-			let w: i32 = 512;
-			for (let i: i32 = 0; i < 10; ++i) {
-				ImportEnvmap.mips.push(image_create_render_target(w, w > 1 ? math_floor(w / 2) : 1, tex_format_t.RGBA128));
-				w = math_floor(w / 2);
-			}
-
-			if (const_data_screen_aligned_vb == null) const_data_create_screen_aligned_data();
-		}
-
-		// Down-scale to 1024x512
-		g2_begin(ImportEnvmap.radiance);
-		g2_set_pipeline(base_pipe_copy128);
-		g2_draw_scaled_image(image, 0, 0, 1024, 512);
-		g2_set_pipeline(null);
-		g2_end();
-
-		let radiance_pixels: buffer_t = image_get_pixels(ImportEnvmap.radiance);
-		if (ImportEnvmap.radiance_cpu != null) {
-			let _radiance_cpu: image_t = ImportEnvmap.radiance_cpu;
-			base_notify_on_next_frame(() => {
-				image_unload(_radiance_cpu);
-			});
-		}
-		ImportEnvmap.radiance_cpu = image_from_bytes(radiance_pixels, ImportEnvmap.radiance.width, ImportEnvmap.radiance.height, tex_format_t.RGBA128);
-
-		// Radiance
-		if (ImportEnvmap.mips_cpu != null) {
-			for (let mip of ImportEnvmap.mips_cpu) {
-				let _mip: image_t = mip;
-				base_notify_on_next_frame(() => {
-					///if (!krom_direct3d12) // TODO: crashes after 50+ imports
-					image_unload(_mip);
-					///end
-				});
-			}
-		}
-		ImportEnvmap.mips_cpu = [];
-		for (let i: i32 = 0; i < ImportEnvmap.mips.length; ++i) {
-			ImportEnvmap.get_radiance_mip(ImportEnvmap.mips[i], i, ImportEnvmap.radiance);
-			ImportEnvmap.mips_cpu.push(image_from_bytes(image_get_pixels(ImportEnvmap.mips[i]), ImportEnvmap.mips[i].width, ImportEnvmap.mips[i].height, tex_format_t.RGBA128));
-		}
-		image_set_mipmaps(ImportEnvmap.radiance_cpu, ImportEnvmap.mips_cpu);
-
-		// Irradiance
-		scene_world._.irradiance = ImportEnvmap.get_spherical_harmonics(radiance_pixels, ImportEnvmap.radiance.width, ImportEnvmap.radiance.height);
-
-		// World
-		scene_world.strength = 1.0;
-		scene_world.radiance_mipmaps = ImportEnvmap.mips_cpu.length - 2;
-		scene_world._.envmap = image;
-		scene_world.envmap = path;
-		scene_world._.radiance = ImportEnvmap.radiance_cpu;
-		scene_world._.radiance_mipmaps = ImportEnvmap.mips_cpu;
-		context_raw.saved_envmap = image;
-		if (context_raw.show_envmap_blur) {
-			scene_world._.envmap = scene_world._.radiance_mipmaps[0];
-		}
-		context_raw.ddirty = 2;
-		project_raw.envmap = path;
-	}
-
-	static get_radiance_mip = (mip: image_t, level: i32, radiance: image_t) => {
-		g4_begin(mip);
-		g4_set_vertex_buffer(const_data_screen_aligned_vb);
-		g4_set_index_buffer(const_data_screen_aligned_ib);
-		g4_set_pipeline(ImportEnvmap.pipeline);
-		ImportEnvmap.params.x = 0.1 + level / 8;
-		g4_set_float4(ImportEnvmap.params_loc, ImportEnvmap.params.x, ImportEnvmap.params.y, ImportEnvmap.params.z, ImportEnvmap.params.w);
-		g4_set_tex(ImportEnvmap.radiance_loc, radiance);
-		g4_draw();
-		g4_end();
-	}
-
-	static reverse_equirect = (x: f32, y: f32): vec4_t => {
-		let theta: f32 = x * math_pi() * 2 - math_pi();
-		let phi: f32 = y * math_pi();
-		// return n.set(math_sin(phi) * math_cos(theta), -(math_sin(phi) * math_sin(theta)), math_cos(phi));
-		return vec4_set(ImportEnvmap.n, -math_cos(phi), math_sin(phi) * math_cos(theta), -(math_sin(phi) * math_sin(theta)));
-	}
-
-	// https://ndotl.wordpress.com/2015/03/07/pbr-cubemap-filtering
-	// https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering
-	static get_spherical_harmonics = (source: ArrayBuffer, sourceWidth: i32, sourceHeight: i32): Float32Array => {
-		let sh: Float32Array = new Float32Array(9 * 3 + 1); // Align to mult of 4 - 27->28
-		let accum: f32 = 0.0;
-		let weight: f32 = 1.0;
-		let weight1: f32 = weight * 4 / 17;
-		let weight2: f32 = weight * 8 / 17;
-		let weight3: f32 = weight * 15 / 17;
-		let weight4: f32 = weight * 5 / 68;
-		let weight5: f32 = weight * 15 / 68;
-		let view: DataView = new DataView(source);
-
-		for (let x: i32 = 0; x < sourceWidth; ++x) {
-			for (let y: i32 = 0; y < sourceHeight; ++y) {
-				ImportEnvmap.n = ImportEnvmap.reverse_equirect(x / sourceWidth, y / sourceHeight);
-
-				for (let i: i32 = 0; i < 3; ++i) {
-					let value: f32 = view.getFloat32(((x + y * sourceWidth) * 16 + i * 4), true);
-					value = math_pow(value, 1.0 / 2.2);
-
-					sh[0 + i] += value * weight1;
-					sh[3 + i] += value * weight2 * ImportEnvmap.n.x;
-					sh[6 + i] += value * weight2 * ImportEnvmap.n.y;
-					sh[9 + i] += value * weight2 * ImportEnvmap.n.z;
-
-					sh[12 + i] += value * weight3 * ImportEnvmap.n.x * ImportEnvmap.n.z;
-					sh[15 + i] += value * weight3 * ImportEnvmap.n.z * ImportEnvmap.n.y;
-					sh[18 + i] += value * weight3 * ImportEnvmap.n.y * ImportEnvmap.n.x;
-
-					sh[21 + i] += value * weight4 * (3.0 * ImportEnvmap.n.z * ImportEnvmap.n.z - 1.0);
-					sh[24 + i] += value * weight5 * (ImportEnvmap.n.x * ImportEnvmap.n.x - ImportEnvmap.n.y * ImportEnvmap.n.y);
-
-					accum += weight;
-				}
-			}
-		}
-
-		for (let i: i32 = 0; i < sh.length; ++i) {
-			sh[i] /= accum / 16;
-		}
-
-		return sh;
-	}
-}

+ 0 - 39
base/Sources/ImportFont.ts

@@ -1,39 +0,0 @@
-
-///if (is_paint || is_sculpt)
-
-class ImportFont {
-
-	static run = (path: string) => {
-		for (let f of project_fonts) {
-			if (f.file == path) {
-				console_info(strings_info0());
-				return;
-			}
-		}
-		let font: g2_font_t = data_get_font(path);
-		g2_font_init(font); // Make sure font_ is ready
-		let count: i32 = krom_g2_font_count(font.font_);
-		let font_slots: SlotFontRaw[] = [];
-		for (let i: i32 = 0; i < count; ++i) {
-			let ar: string[] = path.split(path_sep);
-			let name: string = ar[ar.length - 1];
-			let f: g2_font_t = g2_font_clone(font);
-			g2_font_set_font_index(f, i);
-			let font_slot: SlotFontRaw = SlotFont.create(name, f, path);
-			font_slots.push(font_slot);
-		}
-
-		let _init = () => {
-			for (let f of font_slots) {
-				context_raw.font = f;
-				project_fonts.push(f);
-				util_render_make_font_preview();
-			}
-		}
-		app_notify_on_init(_init);
-
-		ui_base_hwnds[tab_area_t.STATUS].redraws = 2;
-	}
-}
-
-///end

+ 0 - 45
base/Sources/ImportGpl.ts

@@ -1,45 +0,0 @@
-
-class ImportGpl {
-
-	static run = (path: string, replace_existing: bool) => {
-		let b: ArrayBuffer = data_get_blob(path);
-		// let swatches: TSwatchColor[] = [];
-
-		// let str: string = sys_buffer_to_string(b);
-		// let lines: string[] = str.split("\n");
-
-		// let view: DataView = new DataView(b);
-		// // GIMP's color palette importer: https://gitlab.gnome.org/GNOME/gimp/-/blob/gimp-2-10/app/core/gimppalette-load.c#L39
-		// if (!lines[0].startsWith("GIMP Palette")) {
-		// 	console_error(tr("Not a valid GIMP color palette"));
-		// 	return;
-		// }
-
-		// let delimiter: string = ~/\s+/ig;
-		// for (let line of lines) {
-		// 	if (line.startsWith("Name:")) continue;
-		// 	else if (line.startsWith("Columns:")) continue;
-		// 	else if (line.startsWith("#")) continue;
-		// 	else {
-		// 		let tokens: string[] = delimiter.split(line);
-		// 		if (tokens.length < 3) continue;
-		// 		let swatch: TSwatchColor = makeSwatch(Color.fromBytes(String(tokens[0]), String(tokens[1]), String(tokens[2])));
-		// 		swatches.push(swatch);
-		// 	}
-		// }
-
-		// if (replaceExisting) {
-		// 	raw.swatches = [];
-
-		// 	if (swatches.length == 0) { // No swatches contained
-		// 		raw.swatches.push(makeSwatch());
-		// 	}
-		// }
-
-		// if (swatches.length > 0) {
-		// 	for (let s of swatches) {
-		// 		raw.swatches.push(s);
-		// 	}
-		// }
-	}
-}

+ 0 - 17
base/Sources/ImportKeymap.ts

@@ -1,17 +0,0 @@
-
-class ImportKeymap {
-
-	static run = (path: string) => {
-		if (!path_is_json(path)) {
-			console_error(strings_error1());
-			return;
-		}
-
-		let filename: string = path.substr(path.lastIndexOf(path_sep) + 1);
-		let dst_path: string = path_data() + path_sep + "keymap_presets" + path_sep + filename;
-		file_copy(path, dst_path); // Copy to preset folder
-		BoxPreferences.fetch_keymaps(); // Refresh file list
-		BoxPreferences.preset_handle.position = BoxPreferences.get_preset_index();
-		console_info(tr("Keymap imported:") + " " + filename);
-	}
-}

+ 0 - 242
base/Sources/ImportMesh.ts

@@ -1,242 +0,0 @@
-
-class ImportMesh {
-
-	///if (is_paint || is_sculpt)
-	static clear_layers: bool = true;
-	///end
-
-	static meshes_to_unwrap: any[] = null;
-
-	///if (is_paint || is_sculpt)
-	static run = (path: string, _clear_layers: bool = true, replace_existing: bool = true) => {
-	///end
-
-	///if is_lab
-	static run = (path: string, replace_existing: bool = true) => {
-	///end
-
-		if (!path_is_mesh(path)) {
-			if (!context_enable_import_plugin(path)) {
-				console_error(strings_error1());
-				return;
-			}
-		}
-
-		///if (is_paint || is_sculpt)
-		ImportMesh.clear_layers = _clear_layers;
-		context_raw.layer_filter = 0;
-		///end
-
-		ImportMesh.meshes_to_unwrap = null;
-
-		let p: string = path.toLowerCase();
-		if (p.endsWith(".obj")) ImportObj.run(path, replace_existing);
-		else if (p.endsWith(".blend")) ImportBlendMesh.run(path, replace_existing);
-		else {
-			let ext: string = path.substr(path.lastIndexOf(".") + 1);
-			let importer: (s: string, f: (a: any)=>void)=>void = path_mesh_importers.get(ext);
-			importer(path, (mesh: any) => {
-				replace_existing ? ImportMesh.make_mesh(mesh, path) : ImportMesh.add_mesh(mesh);
-
-				let has_next: bool = mesh.has_next;
-				while (has_next) {
-					importer(path, (mesh: any) => {
-						has_next = mesh.has_next;
-						ImportMesh.add_mesh(mesh);
-
-						// let m: mat4_t = fromFloat32Array(mesh.transform);
-						// paintObjects[paintObjects.length - 1].transform.localOnly = true;
-						// paintObjects[paintObjects.length - 1].transform.setMatrix(m);
-					});
-				}
-			});
-		}
-
-		project_mesh_assets = [path];
-
-		///if (krom_android || krom_ios)
-		sys_title_set(path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf(".")));
-		///end
-	}
-
-	static finish_import = () => {
-		if (context_raw.merged_object != null) {
-			mesh_data_delete(context_raw.merged_object.data);
-			mesh_object_remove(context_raw.merged_object);
-			context_raw.merged_object = null;
-		}
-
-		context_select_paint_object(context_main_object());
-
-		if (project_paint_objects.length > 1) {
-			// Sort by name
-			project_paint_objects.sort((a, b): i32 => {
-				if (a.base.name < b.base.name) return -1;
-				else if (a.base.name > b.base.name) return 1;
-				return 0;
-			});
-
-			// No mask by default
-			for (let p of project_paint_objects) p.base.visible = true;
-			if (context_raw.merged_object == null) util_mesh_merge();
-			context_raw.paint_object.skip_context = "paint";
-			context_raw.merged_object.base.visible = true;
-		}
-
-		viewport_scale_to_bounds();
-
-		if (context_raw.paint_object.base.name == "") context_raw.paint_object.base.name = "Object";
-		MakeMaterial.parse_paint_material();
-		MakeMaterial.parse_mesh_material();
-
-		///if (is_paint || is_sculpt)
-		ui_view2d_hwnd.redraws = 2;
-		///end
-
-		///if (krom_direct3d12 || krom_vulkan || krom_metal)
-		RenderPathRaytrace.ready = false;
-		///end
-
-		///if arm_physics
-		context_raw.paint_body = null;
-		///end
-	}
-
-	static _make_mesh = (mesh: any) => {
-		let raw: mesh_data_t = ImportMesh.raw_mesh(mesh);
-		if (mesh.cola != null) raw.vertex_arrays.push({ values: mesh.cola, attrib: "col", data: "short4norm" });
-
-		let md: mesh_data_t = mesh_data_create(raw);
-		context_raw.paint_object = context_main_object();
-
-		context_select_paint_object(context_main_object());
-		for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
-			let p: mesh_object_t = project_paint_objects[i];
-			if (p == context_raw.paint_object) continue;
-			data_delete_mesh(p.data._.handle);
-			mesh_object_remove(p);
-		}
-		let handle: string = context_raw.paint_object.data._.handle;
-		if (handle != "SceneSphere" && handle != "ScenePlane") {
-			data_delete_mesh(handle);
-		}
-
-		mesh_object_set_data(context_raw.paint_object, md);
-		context_raw.paint_object.base.name = mesh.name;
-		project_paint_objects = [context_raw.paint_object];
-
-		md._.handle = raw.name;
-		data_cached_meshes.set(md._.handle, md);
-
-		context_raw.ddirty = 4;
-
-		///if (is_paint || is_sculpt)
-		ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
-		ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
-		util_uv_uvmap_cached = false;
-		util_uv_trianglemap_cached = false;
-		util_uv_dilatemap_cached = false;
-		///end
-
-		///if (is_paint || is_sculpt)
-		if (ImportMesh.clear_layers) {
-			while (project_layers.length > 0) {
-				let l: SlotLayerRaw = project_layers.pop();
-				SlotLayer.unload(l);
-			}
-			base_new_layer(false);
-			app_notify_on_init(base_init_layers);
-			history_reset();
-		}
-		///end
-
-		// Wait for addMesh calls to finish
-		if (ImportMesh.meshes_to_unwrap != null) {
-			base_notify_on_next_frame(ImportMesh.finish_import);
-		}
-		else {
-			app_notify_on_init(ImportMesh.finish_import);
-		}
-	}
-
-	static make_mesh = (mesh: any, path: string) => {
-		if (mesh == null || mesh.posa == null || mesh.nora == null || mesh.inda == null || mesh.posa.length == 0) {
-			console_error(strings_error3());
-			return;
-		}
-
-		if (mesh.texa == null) {
-			if (ImportMesh.meshes_to_unwrap == null) {
-				ImportMesh.meshes_to_unwrap = [];
-			}
-			let first_unwrap_done = (mesh: any) => {
-				ImportMesh._make_mesh(mesh);
-				for (let mesh of ImportMesh.meshes_to_unwrap) project_unwrap_mesh_box(mesh, ImportMesh._add_mesh, true);
-			}
-			project_unwrap_mesh_box(mesh, first_unwrap_done);
-		}
-		else {
-			ImportMesh._make_mesh(mesh);
-		}
-	}
-
-	static _add_mesh = (mesh: any) => {
-		let raw: mesh_data_t = ImportMesh.raw_mesh(mesh);
-		if (mesh.cola != null) raw.vertex_arrays.push({ values: mesh.cola, attrib: "col", data: "short4norm" });
-
-		let md: mesh_data_t = mesh_data_create(raw);
-
-		let object: mesh_object_t = scene_add_mesh_object(md, context_raw.paint_object.materials, context_raw.paint_object.base);
-		object.base.name = mesh.name;
-		object.skip_context = "paint";
-
-		// Ensure unique names
-		for (let p of project_paint_objects) {
-			if (p.base.name == object.base.name) {
-				p.base.name += ".001";
-				p.data._.handle += ".001";
-				data_cached_meshes.set(p.data._.handle, p.data);
-			}
-		}
-
-		project_paint_objects.push(object);
-
-		md._.handle = raw.name;
-		data_cached_meshes.set(md._.handle, md);
-
-		context_raw.ddirty = 4;
-
-		///if (is_paint || is_sculpt)
-		ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
-		util_uv_uvmap_cached = false;
-		util_uv_trianglemap_cached = false;
-		util_uv_dilatemap_cached = false;
-		///end
-	}
-
-	static add_mesh = (mesh: any) => {
-		if (mesh.texa == null) {
-			if (ImportMesh.meshes_to_unwrap != null) ImportMesh.meshes_to_unwrap.push(mesh);
-			else project_unwrap_mesh_box(mesh, ImportMesh._add_mesh);
-		}
-		else {
-			ImportMesh._add_mesh(mesh);
-		}
-	}
-
-	static raw_mesh = (mesh: any): mesh_data_t => {
-		return {
-			name: mesh.name,
-			vertex_arrays: [
-				{ values: mesh.posa, attrib: "pos", data: "short4norm" },
-				{ values: mesh.nora, attrib: "nor", data: "short2norm" },
-				{ values: mesh.texa, attrib: "tex", data: "short2norm" }
-			],
-			index_arrays: [
-				{ values: mesh.inda, material: 0 }
-			],
-			scale_pos: mesh.scale_pos,
-			scale_tex: mesh.scale_tex
-		};
-	}
-}

+ 0 - 117
base/Sources/ImportObj.ts

@@ -1,117 +0,0 @@
-
-class ImportObj {
-
-	static run = (path: string, replace_existing: bool = true) => {
-		let i: split_type_t = context_raw.split_by;
-		let is_udim: bool = i == split_type_t.UDIM;
-		let split_code: i32 =
-			(i == split_type_t.OBJECT || is_udim) ? "o".charCodeAt(0) :
-			 i == split_type_t.GROUP 			  ? "g".charCodeAt(0) :
-			 				 			   		    "u".charCodeAt(0); // usemtl
-
-		let b: ArrayBuffer = data_get_blob(path);
-
-		if (is_udim) {
-			let part: any = krom_io_obj_parse(b, split_code, 0, is_udim);
-			let name: string = part.name;
-			for (let i: i32 = 0; i < part.udims.length; ++i) {
-				if (part.udims[i].length == 0) continue;
-				let u: i32 = i % part.udims_u;
-				let v: i32 = math_floor(i / part.udims_u);
-				part.name = name + "." + (1000 + v * 10 + u + 1);
-				part.inda = part.udims[i];
-				i == 0 ? (replace_existing ? ImportMesh.make_mesh(part, path) : ImportMesh.add_mesh(part)) : ImportMesh.add_mesh(part);
-			}
-		}
-		else {
-			let parts: any[] = [];
-			let part: any = krom_io_obj_parse(b, split_code, 0, false);
-			parts.push(part);
-			while (part.has_next) {
-				part = krom_io_obj_parse(b, split_code, part.pos, false);
-				// This part does not contain faces (may contain lines only)
-				if (part.inda.length == 0) {
-					continue;
-				}
-				parts.push(part);
-			}
-			if (context_raw.split_by == split_type_t.MATERIAL) {
-				let posa0: Int16Array;
-				let posa1: Int16Array;
-				let nora0: Int16Array;
-				let nora1: Int16Array;
-				let texa0: Int16Array;
-				let texa1: Int16Array;
-				let inda0: Uint32Array;
-				let inda1: Uint32Array;
-				// Merge to single object per material
-				for (let i: i32 = 0; i < parts.length; ++i) {
-					let j: i32 = i + 1;
-					while (j < parts.length) {
-						if (parts[i].name == parts[j].name) {
-							posa0 = parts[i].posa;
-							posa1 = parts[j].posa;
-							nora0 = parts[i].nora;
-							nora1 = parts[j].nora;
-							texa0 = parts[i].texa != null ? parts[i].texa : null;
-							texa1 = parts[j].texa != null ? parts[j].texa : null;
-							inda0 = parts[i].inda;
-							inda1 = parts[j].inda;
-							let voff: i32 = math_floor(posa0.length / 4);
-							// Repack merged positions
-							let posa32: Float32Array = new Float32Array(math_floor(posa0.length / 4) * 3 + math_floor(posa1.length / 4) * 3);
-							for (let k: i32 = 0; k < math_floor(posa0.length / 4); ++k) {
-								posa32[k * 3    ] = posa0[k * 4    ] / 32767 * parts[i].scale_pos;
-								posa32[k * 3 + 1] = posa0[k * 4 + 1] / 32767 * parts[i].scale_pos;
-								posa32[k * 3 + 2] = posa0[k * 4 + 2] / 32767 * parts[i].scale_pos;
-							}
-							for (let k: i32 = 0; k < math_floor(posa1.length / 4); ++k) {
-								posa32[voff * 3 + k * 3    ] = posa1[k * 4    ] / 32767 * parts[j].scale_pos;
-								posa32[voff * 3 + k * 3 + 1] = posa1[k * 4 + 1] / 32767 * parts[j].scale_pos;
-								posa32[voff * 3 + k * 3 + 2] = posa1[k * 4 + 2] / 32767 * parts[j].scale_pos;
-							}
-							let scale_pos: f32 = 0.0;
-							for (let k: i32 = 0; k < posa32.length; ++k) {
-								let f: f32 = math_abs(posa32[k]);
-								if (scale_pos < f) scale_pos = f;
-							}
-							let inv: f32 = 32767 * (1 / scale_pos);
-							let posa: Int16Array = new Int16Array(posa0.length + posa1.length);
-							for (let k: i32 = 0; k < math_floor(posa.length / 4); ++k) {
-								posa[k * 4    ] = math_floor(posa32[k * 3    ] * inv);
-								posa[k * 4 + 1] = math_floor(posa32[k * 3 + 1] * inv);
-								posa[k * 4 + 2] = math_floor(posa32[k * 3 + 2] * inv);
-							}
-							for (let k: i32 = 0; k < math_floor(posa0.length / 4); ++k) posa[k * 4 + 3] = posa0[k * 4 + 3];
-							for (let k: i32 = 0; k < math_floor(posa1.length / 4); ++k) posa[posa0.length + k * 4 + 3] = posa1[k * 4 + 3];
-							// Merge normals and uvs
-							let nora: Int16Array = new Int16Array(nora0.length + nora1.length);
-							let texa: Int16Array = (texa0 != null && texa1 != null) ? new Int16Array(texa0.length + texa1.length) : null;
-							let inda: Uint32Array = new Uint32Array(inda0.length + inda1.length);
-							nora.set(nora0);
-							nora.set(nora1, nora0.length);
-							if (texa != null) {
-								texa.set(texa0);
-								texa.set(texa1, texa0.length);
-							}
-							inda.set(inda0);
-							for (let k: i32 = 0; k < inda1.length; ++k) inda[k + inda0.length] = inda1[k] + voff;
-							parts[i].posa = posa;
-							parts[i].nora = nora;
-							parts[i].texa = texa;
-							parts[i].inda = inda;
-							parts[i].scale_pos = scale_pos;
-							parts.splice(j, 1);
-						}
-						else j++;
-					}
-				}
-			}
-			replace_existing ? ImportMesh.make_mesh(parts[0], path) : ImportMesh.add_mesh(parts[0]);
-			for (let i: i32 = 1; i < parts.length; ++i) {
-				ImportMesh.add_mesh(parts[i]);
-			}
-		}
-		data_delete_blob(path);
-	}
-}

+ 0 - 16
base/Sources/ImportPlugin.ts

@@ -1,16 +0,0 @@
-
-class ImportPlugin {
-
-	static run = (path: string) => {
-		if (!path_is_plugin(path)) {
-			console_error(strings_error1());
-			return;
-		}
-
-		let filename: string = path.substr(path.lastIndexOf(path_sep) + 1);
-		let dst_path: string = path_data() + path_sep + "plugins" + path_sep + filename;
-		file_copy(path, dst_path); // Copy to plugin folder
-		BoxPreferences.files_plugin = null; // Refresh file list
-		console_info(tr("Plugin imported:") + " " + filename);
-	}
-}

+ 0 - 57
base/Sources/ImportTexture.ts

@@ -1,57 +0,0 @@
-
-class ImportTexture {
-
-	static run = (path: string, hdr_as_envmap: bool = true) => {
-		if (!path_is_texture(path)) {
-			if (!context_enable_import_plugin(path)) {
-				console_error(strings_error1());
-				return;
-			}
-		}
-
-		for (let a of project_assets) {
-			// Already imported
-			if (a.file == path) {
-				// Set as envmap
-				if (hdr_as_envmap && path.toLowerCase().endsWith(".hdr")) {
-					let image: image_t = data_get_image(path);
-					base_notify_on_next_frame(() => { // Make sure file browser process did finish
-						ImportEnvmap.run(path, image);
-					});
-				}
-				console_info(strings_info0());
-				return;
-			}
-		}
-
-		let ext: string = path.substr(path.lastIndexOf(".") + 1);
-		let importer: (s: string, f: (img: image_t)=>void)=>void = path_texture_importers.get(ext);
-		let cached: bool = data_cached_images.get(path) != null; // Already loaded or pink texture for missing file
-		if (importer == null || cached) importer = ImportTexture.default_importer;
-
-		importer(path, (image: image_t) => {
-			data_cached_images.set(path, image);
-			let ar: string[] = path.split(path_sep);
-			let name: string = ar[ar.length - 1];
-			let asset: asset_t = {name: name, file: path, id: project_asset_id++};
-			project_assets.push(asset);
-			if (context_raw.texture == null) context_raw.texture = asset;
-			project_asset_names.push(name);
-			project_asset_map.set(asset.id, image);
-			ui_base_hwnds[tab_area_t.STATUS].redraws = 2;
-			console_info(tr("Texture imported:") + " " + name);
-
-			// Set as envmap
-			if (hdr_as_envmap && path.toLowerCase().endsWith(".hdr")) {
-				base_notify_on_next_frame(() => { // Make sure file browser process did finish
-					ImportEnvmap.run(path, image);
-				});
-			}
-		});
-	}
-
-	static default_importer = (path: string, done: (img: image_t)=>void) => {
-		let img: image_t = data_get_image(path);
-		done(img);
-	}
-}

+ 0 - 19
base/Sources/ImportTheme.ts

@@ -1,19 +0,0 @@
-
-class ImportTheme {
-
-	static run = (path: string) => {
-		if (!path_is_json(path)) {
-			console_error(strings_error1());
-			return;
-		}
-
-		let filename: string = path.substr(path.lastIndexOf(path_sep) + 1);
-		let dst_path: string = path_data() + path_sep + "themes" + path_sep + filename;
-		file_copy(path, dst_path); // Copy to preset folder
-		BoxPreferences.fetch_themes(); // Refresh file list
-		config_raw.theme = filename;
-		BoxPreferences.theme_handle.position = BoxPreferences.get_theme_index();
-		config_load_theme(config_raw.theme);
-		console_info(tr("Theme imported:") + " " + filename);
-	}
-}

+ 0 - 651
base/Sources/NodeShader.ts

@@ -1,651 +0,0 @@
-
-class NodeShaderRaw {
-	context: NodeShaderContextRaw;
-	shader_type: string = '';
-	includes: string[] = [];
-	ins: string[] = [];
-	outs: string[] = [];
-	shared_samplers: string[] = [];
-	uniforms: string[] = [];
-	functions: map_t<string, string> = map_create();
-	main: string = '';
-	main_init: string = '';
-	main_end: string = '';
-	main_normal: string = '';
-	main_textures: string = '';
-	main_attribs: string = '';
-	header: string = '';
-	write_pre: bool = false;
-	write_normal: i32 = 0;
-	write_textures: i32 = 0;
-	vstruct_as_vsin: bool = true;
-	lock: bool = false;
-
-	// References
-	bposition: bool = false;
-	wposition: bool = false;
-	mposition: bool = false;
-	vposition: bool = false;
-	wvpposition: bool = false;
-	ndcpos: bool = false;
-	wtangent: bool = false;
-	vvec: bool = false;
-	vvec_cam: bool = false;
-	n: bool = false;
-	nattr: bool = false;
-	dotnv: bool = false;
-	inv_tbn: bool = false;
-}
-
-class NodeShader {
-
-	static create(context: NodeShaderContextRaw, shader_type: string): NodeShaderRaw {
-		let raw: NodeShaderRaw = new NodeShaderRaw();
-		raw.context = context;
-		raw.shader_type = shader_type;
-		return raw;
-	}
-
-	static add_include = (raw: NodeShaderRaw, s: string) => {
-		raw.includes.push(s);
-	}
-
-	static add_in = (raw: NodeShaderRaw, s: string) => {
-		raw.ins.push(s);
-	}
-
-	static add_out = (raw: NodeShaderRaw, s: string) => {
-		raw.outs.push(s);
-	}
-
-	static add_uniform = (raw: NodeShaderRaw, s: string, link: string = null, included: bool = false) => {
-		let ar: string[] = s.split(' ');
-		// layout(RGBA8) image3D voxels
-		let utype: string = ar[ar.length - 2];
-		let uname: string = ar[ar.length - 1];
-		if (utype.startsWith('sampler') || utype.startsWith('image') || utype.startsWith('uimage')) {
-			let is_image: bool = (utype.startsWith('image') || utype.startsWith('uimage')) ? true : false;
-			NodeShaderContext.add_texture_unit(raw.context, utype, uname, link, is_image);
-		}
-		else {
-			// Prefer vec4[] for d3d to avoid padding
-			if (ar[0] == 'float' && ar[1].indexOf('[') >= 0) {
-				ar[0] = 'floats';
-				ar[1] = ar[1].split('[')[0];
-			}
-			else if (ar[0] == 'vec4' && ar[1].indexOf('[') >= 0) {
-				ar[0] = 'floats';
-				ar[1] = ar[1].split('[')[0];
-			}
-			NodeShaderContext.add_constant(raw.context, ar[0], ar[1], link);
-		}
-		if (included == false && raw.uniforms.indexOf(s) == -1) {
-			raw.uniforms.push(s);
-		}
-	}
-
-	static add_shared_sampler = (raw: NodeShaderRaw, s: string) => {
-		if (raw.shared_samplers.indexOf(s) == -1) {
-			raw.shared_samplers.push(s);
-			let ar: string[] = s.split(' ');
-			// layout(RGBA8) sampler2D tex
-			let utype: string = ar[ar.length - 2];
-			let uname: string = ar[ar.length - 1];
-			NodeShaderContext.add_texture_unit(raw.context, utype, uname, null, false);
-		}
-	}
-
-	static add_function = (raw: NodeShaderRaw, s: string) => {
-		let fname: string = s.split('(')[0];
-		if (raw.functions.has(fname)) return;
-		raw.functions.set(fname, s);
-	}
-
-	static contains = (raw: NodeShaderRaw, s: string): bool => {
-		return raw.main.indexOf(s) >= 0 ||
-			   raw.main_init.indexOf(s) >= 0 ||
-			   raw.main_normal.indexOf(s) >= 0 ||
-			   raw.ins.indexOf(s) >= 0 ||
-			   raw.main_textures.indexOf(s) >= 0 ||
-			   raw.main_attribs.indexOf(s) >= 0;
-	}
-
-	static write_init = (raw: NodeShaderRaw, s: string) => {
-		raw.main_init = s + '\n' + raw.main_init;
-	}
-
-	static write = (raw: NodeShaderRaw, s: string) => {
-		if (raw.lock) return;
-		if (raw.write_textures > 0) {
-			raw.main_textures += s + '\n';
-		}
-		else if (raw.write_normal > 0) {
-			raw.main_normal += s + '\n';
-		}
-		else if (raw.write_pre) {
-			raw.main_init += s + '\n';
-		}
-		else {
-			raw.main += s + '\n';
-		}
-	}
-
-	static write_header = (raw: NodeShaderRaw, s: string) => {
-		raw.header += s + '\n';
-	}
-
-	static write_end = (raw: NodeShaderRaw, s: string) => {
-		raw.main_end += s + '\n';
-	}
-
-	static write_attrib = (raw: NodeShaderRaw, s: string) => {
-		raw.main_attribs += s + '\n';
-	}
-
-	static dataSize = (raw: NodeShaderRaw, data: string): string => {
-		if (data == 'float1') return '1';
-		else if (data == 'float2') return '2';
-		else if (data == 'float3') return '3';
-		else if (data == 'float4') return '4';
-		else if (data == 'short2norm') return '2';
-		else if (data == 'short4norm') return '4';
-		else return '1';
-	}
-
-	static vstruct_to_vsin = (raw: NodeShaderRaw) => {
-		// 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 e of vs) {
-			NodeShader.add_in(raw, 'vec' + NodeShader.dataSize(raw, e.data) + ' ' + e.name);
-		}
-	}
-
-	///if (krom_direct3d11 || krom_direct3d12)
-	static get_hlsl(raw: NodeShaderRaw, sharedSampler: 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(${sharedSampler}, coord)\n`;
-		s += '#define textureLod(tex, coord, lod) tex.SampleLevel(tex ## _sampler, coord, lod)\n';
-		s += `#define textureLodShared(tex, coord, lod) tex.SampleLevel(${sharedSampler}, 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 = '';
-
-		for (let a of raw.includes) {
-			s += '#include "' + a + '"\n';
-		}
-
-		// Input structure
-		let index: i32 = 0;
-		if (raw.ins.length > 0) {
-			s += 'struct SPIRV_Cross_Input {\n';
-			index = 0;
-			raw.ins.sort((a, b): i32 => {
-				// Sort inputs by name
-				return a.substring(4) >= b.substring(4) ? 1 : -1;
-			});
-			for (let a of raw.ins) {
-				s += `${a}${in_ext} : TEXCOORD${index};\n`;
-				index++;
-			}
-			// Built-ins
-			if (raw.shader_type == 'vert' && raw.main.indexOf("gl_VertexID") >= 0) {
-				s += 'uint gl_VertexID : SV_VertexID;\n';
-				raw.ins.push('uint gl_VertexID');
-			}
-			if (raw.shader_type == 'vert' && raw.main.indexOf("gl_InstanceID") >= 0) {
-				s += 'uint gl_InstanceID : SV_InstanceID;\n';
-				raw.ins.push('uint gl_InstanceID');
-			}
-			s += '};\n';
-		}
-
-		// Output structure
-		let num: i32 = 0;
-		if (raw.outs.length > 0 || raw.shader_type == 'vert') {
-			s += 'struct SPIRV_Cross_Output {\n';
-			raw.outs.sort((a, b): i32 => {
-				// Sort outputs by name
-				return a.substring(4) >= b.substring(4) ? 1 : -1;
-			});
-			index = 0;
-			if (raw.shader_type == 'vert') {
-				for (let a of raw.outs) {
-					s += `${a}${out_ext} : TEXCOORD${index};\n`;
-					index++;
-				}
-				s += 'float4 svpos : SV_POSITION;\n';
-			}
-			else {
-				let out: string = raw.outs[0];
-				// Multiple render targets
-				if (out.charAt(out.length - 1) == ']') {
-					num = parseInt(out.charAt(out.length - 2));
-					s += `vec4 fragColor[${num}] : SV_TARGET0;\n`;
-				}
-				else {
-					s += 'vec4 fragColor : SV_TARGET0;\n';
-				}
-			}
-			s += '};\n';
-		}
-
-		for (let a of raw.uniforms) {
-			s += 'uniform ' + a + ';\n';
-			if (a.startsWith('sampler')) {
-				s += 'SamplerState ' + a.split(' ')[1] + '_sampler;\n';
-			}
-		}
-
-		if (raw.shared_samplers.length > 0) {
-			for (let a of raw.shared_samplers) {
-				s += 'uniform ' + a + ';\n';
-			}
-			s += `SamplerState ${sharedSampler};\n`;
-		}
-
-		for (let f of raw.functions.values()) {
-			s += f + '\n';
-		}
-
-		// Begin main
-		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';
-			}
-			else {
-				s += 'SPIRV_Cross_Output main() {\n';
-			}
-		}
-		else {
-			if (raw.ins.length > 0) {
-				s += 'void main(SPIRV_Cross_Input stage_input) {\n';
-			}
-			else {
-				s += 'void main() {\n';
-			}
-		}
-
-		// Declare inputs
-		for (let a of raw.ins) {
-			let b: string = a.substring(5); // Remove type 'vec4 '
-			s += `${a} = stage_input.${b};\n`;
-		}
-
-		if (raw.shader_type == 'vert') {
-			s += 'vec4 gl_Position;\n';
-			for (let a of raw.outs) {
-				s += `${a};\n`;
-			}
-		}
-		else {
-			if (raw.outs.length > 0) {
-				if (num > 0) s += `vec4 fragColor[${num}];\n`;
-				else s += 'vec4 fragColor;\n';
-			}
-		}
-
-		s += raw.main_attribs;
-		s += raw.main_textures;
-		s += raw.main_normal;
-		s += raw.main_init;
-		s += raw.main;
-		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';
-				for (let a of raw.outs) {
-					let b: string = a.substring(5); // 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`;
-					}
-				}
-				else {
-					s += 'stage_output.fragColor = fragColor;\n';
-				}
-			}
-			s += 'return stage_output;\n';
-		}
-		s += '}\n';
-		return s;
-	}
-	///end
-
-	///if krom_metal
-	static get_msl(raw: NodeShaderRaw, sharedSampler: 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(${sharedSampler}, coord)\n`;
-		s += '#define textureLod(tex, coord, lod) tex.sample(tex ## _sampler, coord, level(lod))\n';
-		s += `#define textureLodShared(tex, coord, lod) tex.sample(${sharedSampler}, 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 a of raw.includes) {
-			s += '#include "' + a + '"\n';
-		}
-
-		s += raw.header;
-
-		// Input structure
-		let index: i32 = 0;
-		//if (ins.length > 0) {
-			s += 'struct main_in {\n';
-			index = 0;
-			raw.ins.sort((a, b): i32 => {
-				// Sort inputs by name
-				return a.substring(4) >= b.substring(4) ? 1 : -1;
-			});
-			if (raw.shader_type == 'vert') {
-				for (let a of raw.ins) {
-					s += `${a} [[attribute(${index})]];\n`;
-					index++;
-				}
-			}
-			else {
-				for (let a of raw.ins) {
-					s += `${a} [[user(locn${index})]];\n`;
-					index++;
-				}
-			}
-			s += '};\n';
-		//}
-
-		// Output structure
-		let num: i32 = 0;
-		if (raw.outs.length > 0 || raw.shader_type == 'vert') {
-			s += 'struct main_out {\n';
-			raw.outs.sort((a, b): i32 => {
-				// Sort outputs by name
-				return a.substring(4) >= b.substring(4) ? 1 : -1;
-			});
-			index = 0;
-			if (raw.shader_type == 'vert') {
-				for (let a of raw.outs) {
-					s += `${a} [[user(locn${index})]];\n`;
-					index++;
-				}
-				s += 'float4 svpos [[position]];\n';
-			}
-			else {
-				let out: string = raw.outs[0];
-				// Multiple render targets
-				if (out.charAt(out.length - 1) == ']') {
-					num = parseInt(out.charAt(out.length - 2));
-					for (let i: i32 = 0; i < num; ++i) {
-						s += `float4 fragColor_${i} [[color(${i})]];\n`;
-					}
-				}
-				else {
-					s += 'float4 fragColor [[color(0)]];\n';
-				}
-			}
-			s += '};\n';
-		}
-
-		let samplers: string[] = [];
-
-		if (raw.uniforms.length > 0) {
-			s += 'struct main_uniforms {\n';
-
-			for (let a of raw.uniforms) {
-				if (a.startsWith('sampler')) {
-					samplers.push(a);
-				}
-				else {
-					s += a + ';\n';
-				}
-			}
-
-			s += '};\n';
-		}
-
-		for (let f of raw.functions.values()) {
-			s += f + '\n';
-		}
-
-		// Begin main declaration
-		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(';
-		//if (ins.length > 0) {
-			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})]]`;
-		}
-
-		if (samplers.length > 0) {
-			for (let i: i32 = 0; i < samplers.length; ++i) {
-				s += `, ${samplers[i]} [[texture(${i})]]`;
-				s += ', sampler ' + samplers[i].split(' ')[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 += `, sampler ${sharedSampler} [[sampler(${samplers.length})]]`;
-		}
-
-		// Built-ins
-		if (raw.shader_type == 'vert' && raw.main.indexOf("gl_VertexID") >= 0) {
-			s += ', uint gl_VertexID [[vertex_id]]';
-		}
-		if (raw.shader_type == 'vert' && raw.main.indexOf("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';
-
-		// Declare inputs
-		for (let a of raw.ins) {
-			let b: string = a.substring(5); // Remove type 'vec4 '
-			s += `${a} = in.${b};\n`;
-		}
-
-		for (let a of raw.uniforms) {
-			if (!a.startsWith('sampler')) {
-				let b: string = a.split(" ")[1]; // Remove type 'vec4 '
-				if (b.indexOf("[") >= 0) {
-					b = b.substring(0, b.indexOf("["));
-					let type: string = a.split(" ")[0];
-					s += `constant ${type} *${b} = uniforms.${b};\n`;
-				}
-				else {
-					s += `${a} = uniforms.${b};\n`;
-				}
-			}
-		}
-
-		if (raw.shader_type == 'vert') {
-			s += 'vec4 gl_Position;\n';
-			for (let a of raw.outs) {
-				s += `${a};\n`;
-			}
-		}
-		else {
-			if (raw.outs.length > 0) {
-				if (num > 0) s += `vec4 fragColor[${num}];\n`;
-				else s += 'vec4 fragColor;\n';
-			}
-		}
-
-		s += raw.main_attribs;
-		s += raw.main_textures;
-		s += raw.main_normal;
-		s += raw.main_init;
-		s += raw.main;
-		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';
-				for (let a of raw.outs) {
-					let b: string = a.split(" ")[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`;
-					}
-				}
-				else {
-					s += 'out.fragColor = fragColor;\n';
-				}
-			}
-			s += 'return out;\n';
-		}
-		s += '}\n';
-		return s;
-	}
-	///end
-
-	///if (krom_opengl || krom_vulkan)
-	static get_glsl(raw: NodeShaderRaw, sharedSampler: 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 += raw.header;
-
-		let in_ext: string = '';
-		let out_ext: string = '';
-
-		for (let a of raw.includes) {
-			s += '#include "' + a + '"\n';
-		}
-		for (let a of raw.ins) {
-			s += `in ${a}${in_ext};\n`;
-		}
-		for (let a of raw.outs) {
-			s += `out ${a}${out_ext};\n`;
-		}
-		for (let a of raw.uniforms) {
-			s += 'uniform ' + a + ';\n';
-		}
-		for (let a of raw.shared_samplers) {
-			s += 'uniform ' + a + ';\n';
-		}
-		for (let f of raw.functions.values()) {
-			s += f + '\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';
-		return s;
-	}
-	///end
-
-	static get = (raw: NodeShaderRaw): string => {
-
-		if (raw.shader_type == 'vert' && raw.vstruct_as_vsin) {
-			NodeShader.vstruct_to_vsin(raw);
-		}
-
-		let sharedSampler: string = 'shared_sampler';
-		if (raw.shared_samplers.length > 0) {
-			sharedSampler = raw.shared_samplers[0].split(' ')[1] + '_sampler';
-		}
-
-		///if (krom_direct3d11 || krom_direct3d12)
-		let s: string = NodeShader.get_hlsl(raw, sharedSampler);
-		///elseif krom_metal
-		let s: string = NodeShader.get_msl(raw, sharedSampler);
-		///elseif krom_vulkan
-		let version_header: string = '#version 450\n';
-		let s: string = NodeShader.get_glsl(raw, sharedSampler, 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 s: string = NodeShader.get_glsl(raw, sharedSampler, version_header);
-		///elseif krom_opengl
-		let version_header: string = '#version 330\n';
-		let s: string = NodeShader.get_glsl(raw, sharedSampler, version_header);
-		///end
-
-		return s;
-	}
-}

+ 0 - 126
base/Sources/NodeShaderContext.ts

@@ -1,126 +0,0 @@
-
-class NodeShaderContextRaw {
-	vert: NodeShaderRaw;
-	frag: NodeShaderRaw;
-	data: shader_context_t;
-	allow_vcols: bool = false;
-	material: material_t;
-	constants: shader_const_t[];
-	tunits: tex_unit_t[];
-}
-
-class NodeShaderContext {
-
-	static create(material: material_t, props: any): NodeShaderContextRaw {
-		let raw: NodeShaderContextRaw = new NodeShaderContextRaw();
-		raw.material = material;
-		raw.data = {
-			name: props.name,
-			depth_write: props.depth_write,
-			compare_mode: props.compare_mode,
-			cull_mode: props.cull_mode,
-			blend_source: props.blend_source,
-			blend_destination: props.blend_destination,
-			blend_operation: props.blend_operation,
-			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'}],
-			color_attachments: props.color_attachments,
-			depth_attachment: props.depth_attachment
-		};
-
-		if (props.color_writes_red != null) {
-			raw.data.color_writes_red = props.color_writes_red;
-		}
-		if (props.color_writes_green != null) {
-			raw.data.color_writes_green = props.color_writes_green;
-		}
-		if (props.color_writes_blue != null) {
-			raw.data.color_writes_blue = props.color_writes_blue;
-		}
-		if (props.color_writes_alpha != null) {
-			raw.data.color_writes_alpha = props.color_writes_alpha;
-		}
-
-		raw.tunits = raw.data.texture_units = [];
-		raw.constants = raw.data.constants = [];
-		return raw;
-	}
-
-	static add_elem = (raw: NodeShaderContextRaw, name: string, data_type: string) => {
-		for (let e of raw.data.vertex_elements) {
-			if (e.name == name) return;
-		}
-		let elem: vertex_element_t = { name: name, data: data_type };
-		raw.data.vertex_elements.push(elem);
-	}
-
-	static is_elem = (raw: NodeShaderContextRaw, name: string): bool => {
-		for (let elem of raw.data.vertex_elements) {
-			if (elem.name == name) {
-				return true;
-			}
-		}
-		return false;
-	}
-
-	static get_elem = (raw: NodeShaderContextRaw, name: string): vertex_element_t => {
-		for (let elem of raw.data.vertex_elements) {
-			if (elem.name == name) {
-				return elem;
-			}
-		}
-		return null;
-	}
-
-	static add_constant = (raw: NodeShaderContextRaw, ctype: string, name: string, link: string = null) => {
-		for (let c of raw.constants) {
-			if (c.name == name) {
-				return;
-			}
-		}
-
-		let c: shader_const_t = { name: name, type: ctype };
-		if (link != null) {
-			c.link = link;
-		}
-		raw.constants.push(c);
-	}
-
-	static add_texture_unit = (raw: NodeShaderContextRaw, ctype: string, name: string, link: string = null, is_image: bool = false) => {
-		for (let c of raw.tunits) {
-			if (c.name == name) {
-				return;
-			}
-		}
-
-		let c: tex_unit_t = { name: name };
-		if (link != null) {
-			c.link = link;
-		}
-		if (is_image) {
-			c.image_uniform = is_image;
-		}
-		raw.tunits.push(c);
-	}
-
-	static make_vert = (raw: NodeShaderContextRaw): NodeShaderRaw => {
-		raw.data.vertex_shader = raw.material.name + '_' + raw.data.name + '.vert';
-		raw.vert = NodeShader.create(raw, 'vert');
-		return raw.vert;
-	}
-
-	static make_frag = (raw: NodeShaderContextRaw): NodeShaderRaw => {
-		raw.data.fragment_shader = raw.material.name + '_' + raw.data.name + '.frag';
-		raw.frag = NodeShader.create(raw, 'frag');
-		return raw.frag;
-	}
-}
-
-type material_t = {
-	name?: string;
-	canvas?: zui_node_canvas_t;
-};

+ 0 - 3039
base/Sources/NodesMaterial.ts

@@ -1,3039 +0,0 @@
-
-class NodesMaterial {
-
-	static categories: string[] = [_tr("Input"), _tr("Texture"), _tr("Color"), _tr("Vector"), _tr("Converter"), _tr("Group")];
-
-	static list: zui_node_t[][] = [
-		[ // Input
-			{
-				id: 0,
-				name: _tr("Attribute"),
-				type: "ATTRIBUTE",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("Name"),
-						type: "STRING"
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Camera Data"),
-				type: "CAMERA",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("View Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("View Z Depth"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("View Distance"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Fresnel"),
-				type: "FRESNEL",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("IOR"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.45,
-						min: 0,
-						max: 3
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Geometry"),
-				type: "NEW_GEOMETRY",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Position"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Tangent"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("True Normal"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Incoming"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Parametric"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Backfacing"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Pointiness"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Random Per Island"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Layer"),
-				type: "LAYER", // extension
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Base Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Opacity"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Occlusion"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Roughness"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Metallic"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.5, 0.5, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Emission"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Height"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Subsurface"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("Layer"),
-						type: "ENUM",
-						default_value: 0,
-						data: ""
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Layer Mask"),
-				type: "LAYER_MASK", // extension
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("Layer"),
-						type: "ENUM",
-						default_value: 0,
-						data: ""
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Layer Weight"),
-				type: "LAYER_WEIGHT",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Blend"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fresnel"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Facing"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Material"),
-				type: "MATERIAL", // extension
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Base Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Opacity"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Occlusion"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Roughness"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Metallic"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.5, 0.5, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Emission"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Height"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Subsurface"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("Material"),
-						type: "ENUM",
-						default_value: 0,
-						data: ""
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Object Info"),
-				type: "OBJECT_INFO",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Location"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Object Index"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Material Index"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Random"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Picker"),
-				type: "PICKER", // extension
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Base Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Opacity"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Occlusion"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Roughness"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Metallic"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.5, 0.5, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Emission"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Height"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Subsurface"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("RGB"),
-				type: "RGB",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.5, 0.5, 0.5, 1.0])
-					}
-				],
-				buttons: [
-					{
-						name: _tr("default_value"),
-						type: "RGBA",
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Script"),
-				type: "SCRIPT_CPU", // extension
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					}
-				],
-				buttons: [
-					{
-						name: " ",
-						type: "STRING",
-						default_value: ""
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Shader"),
-				type: "SHADER_GPU", // extension
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					}
-				],
-				buttons: [
-					{
-						name: " ",
-						type: "STRING",
-						default_value: ""
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Tangent"),
-				type: "TANGENT",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Tangent"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Texture Coordinate"),
-				type: "TEX_COORD",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Generated"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("UV"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Object"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Camera"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Window"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Reflection"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("UV Map"),
-				type: "UVMAP",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("UV"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Value"),
-				type: "VALUE",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					}
-				],
-				buttons: [
-					{
-						name: _tr("default_value"),
-						type: "VALUE",
-						output: 0,
-						min: 0.0,
-						max: 10.0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Vertex Color"),
-				type: "VERTEX_COLOR",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Alpha"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Wireframe"),
-				type: "WIREFRAME",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Size"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.01,
-						max: 0.1
-					},
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("Pixel Size"),
-						type: "BOOL",
-						default_value: false,
-						output: 0
-					}
-				]
-			},
-		],
-		// [ // Output
-		// 	{
-		// 		id: 0,
-		// 		name: _tr("Material Output"),
-		// 		type: "OUTPUT_MATERIAL_PBR",
-		// 		x: 0,
-		// 		y: 0,
-		// 		color: 0xffb34f5a,
-		// 		inputs: [
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Base Color"),
-		// 				type: "RGBA",
-		// 				color: 0xffc7c729,
-		// 				default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-		// 			},
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Opacity"),
-		// 				type: "VALUE",
-		// 				color: 0xffa1a1a1,
-		// 				default_value: 1.0
-		// 			},
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Occlusion"),
-		// 				type: "VALUE",
-		// 				color: 0xffa1a1a1,
-		// 				default_value: 1.0
-		// 			},
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Roughness"),
-		// 				type: "VALUE",
-		// 				color: 0xffa1a1a1,
-		// 				default_value: 0.1
-		// 			},
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Metallic"),
-		// 				type: "VALUE",
-		// 				color: 0xffa1a1a1,
-		// 				default_value: 0.0
-		// 			},
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Normal Map"),
-		// 				type: "VECTOR",
-		// 				color: -10238109,
-		// 				default_value: new Float32Array([0.5, 0.5, 1.0])
-		// 			},
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Emission"),
-		// 				type: "VALUE",
-		// 				color: 0xffa1a1a1,
-		// 				default_value: 0.0
-		// 			},
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Height"),
-		// 				type: "VALUE",
-		// 				color: 0xffa1a1a1,
-		// 				default_value: 0.0
-		// 			},
-		// 			{
-		// 				id: 0,
-		// 				node_id: 0,
-		// 				name: _tr("Subsurface"),
-		// 				type: "VALUE",
-		// 				color: 0xffa1a1a1,
-		// 				default_value: 0.0
-		// 			}
-		// 		],
-		// 		outputs: [],
-		// 		buttons: []
-		// 	}
-		// ],
-		[ // Texture
-			{
-				id: 0,
-				name: _tr("Brick Texture"),
-				type: "TEX_BRICK",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color 1"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color 2"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.2, 0.2, 0.2])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Mortar"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Scale"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 5.0,
-						min: 0.0,
-						max: 10.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Checker Texture"),
-				type: "TEX_CHECKER",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color 1"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color 2"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.2, 0.2, 0.2])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Scale"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 5.0,
-						min: 0.0,
-						max: 10.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Curvature Bake"),
-				type: "BAKE_CURVATURE",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Strength"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0,
-						min: 0.0,
-						max: 2.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Radius"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0,
-						min: 0.0,
-						max: 2.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Offset"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0,
-						min: -2.0,
-						max: 2.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Gradient Texture"),
-				type: "TEX_GRADIENT",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("gradient_type"),
-						type: "ENUM",
-						// data: ["Linear", "Quadratic", "Easing", "Diagonal", "Radial", "Quadratic Sphere", "Spherical"],
-						data: [_tr("Linear"), _tr("Diagonal"), _tr("Radial"), _tr("Spherical")],
-						default_value: 0,
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Image Texture"),
-				type: "TEX_IMAGE",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Alpha"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("File"),
-						type: "ENUM",
-						default_value: 0,
-						data: ""
-					},
-					{
-						name: _tr("Color Space"),
-						type: "ENUM",
-						default_value: 0,
-						data: [_tr("Auto"), _tr("Linear"), _tr("sRGB"), _tr("DirectX Normal Map")]
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Magic Texture"),
-				type: "TEX_MAGIC",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Scale"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 5.0,
-						min: 0.0,
-						max: 10.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Musgrave Texture"),
-				type: "TEX_MUSGRAVE",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Scale"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 5.0,
-						min: 0.0,
-						max: 10.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Height"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Noise Texture"),
-				type: "TEX_NOISE",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Scale"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 5.0,
-						min: 0.0,
-						max: 10.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Voronoi Texture"),
-				type: "TEX_VORONOI",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Scale"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 5.0,
-						min: 0.0,
-						max: 10.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("coloring"),
-						type: "ENUM",
-						data: [_tr("Intensity"), _tr("Cells")],
-						default_value: 0,
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Wave Texture"),
-				type: "TEX_WAVE",
-				x: 0,
-				y: 0,
-				color: 0xff4982a0,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Scale"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 5.0,
-						min: 0.0,
-						max: 10.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: []
-			}
-		],
-		[ // Color
-			{
-				id: 0,
-				name: _tr("Blur"),
-				type: "BLUR", // extension
-				x: 0,
-				y: 0,
-				color: 0xff448c6d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Strength"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Bright/Contrast"),
-				type: "BRIGHTCONTRAST",
-				x: 0,
-				y: 0,
-				color: 0xff448c6d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Bright"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Contrast"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Gamma"),
-				type: "GAMMA",
-				x: 0,
-				y: 0,
-				color: 0xff448c6d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Gamma"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Hue/Saturation"),
-				type: "HUE_SAT",
-				x: 0,
-				y: 0,
-				color: 0xff448c6d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Hue"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Saturation"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Invert"),
-				type: "INVERT",
-				x: 0,
-				y: 0,
-				color: 0xff448c6d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("MixRGB"),
-				type: "MIX_RGB",
-				x: 0,
-				y: 0,
-				color: 0xff448c6d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color 1"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.5, 0.5, 0.5, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color 2"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.5, 0.5, 0.5, 1.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: [
-					{
-						name: _tr("blend_type"),
-						type: "ENUM",
-						data: [_tr("Mix"), _tr("Darken"), _tr("Multiply"), _tr("Burn"), _tr("Lighten"), _tr("Screen"), _tr("Dodge"), _tr("Add"), _tr("Overlay"), _tr("Soft Light"), _tr("Linear Light"), _tr("Difference"), _tr("Subtract"), _tr("Divide"), _tr("Hue"), _tr("Saturation"), _tr("Color"), _tr("Value")],
-						default_value: 0,
-						output: 0
-					},
-					{
-						name: _tr("use_clamp"),
-						type: "BOOL",
-						default_value: false,
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Quantize"),
-				type: "QUANTIZE",
-				x: 0,
-				y: 0,
-				color: 0xff448c6d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Stength"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.1,
-						min: 0,
-						max: 1
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Warp"),
-				type: "DIRECT_WARP", // extension
-				x: 0,
-				y: 0,
-				color: 0xff448c6d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Angle"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0,
-						min: 0.0,
-						max: 360.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Mask"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5,
-						min: 0.0,
-						max: 1.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			}
-		],
-		[ // Vector
-			{
-				id: 0,
-				name: _tr("Bump"),
-				type: "BUMP",
-				x: 0,
-				y: 0,
-				color: 0xff522c99,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Strength"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Distance"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Height"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Mapping"),
-				type: "MAPPING",
-				x: 0,
-				y: 0,
-				color: 0xff522c99,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Location"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0]),
-						display: 1
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Rotation"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0]),
-						max: 360.0,
-						display: 1
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Scale"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([1.0, 1.0, 1.0]),
-						display: 1
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Mix Normal Map"),
-				type: "MIX_NORMAL_MAP",
-				x: 0,
-				y: 0,
-				color: 0xff522c99,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map 1"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.5, 0.5, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map 2"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.5, 0.5, 1.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.5, 0.5, 1.0])
-					}
-				],
-				buttons: [
-					{
-						name: _tr("blend_type"),
-						type: "ENUM",
-						data: [_tr("Partial Derivative"), _tr("Whiteout"), _tr("Reoriented")],
-						default_value: 0,
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Normal"),
-				type: "NORMAL",
-				x: 0,
-				y: 0,
-				color: 0xff522c99,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Dot"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("Vector"),
-						type: "VECTOR",
-						default_value: new Float32Array([0.0, 0.0, 0.0]),
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Normal Map"),
-				type: "NORMAL_MAP",
-				x: 0,
-				y: 0,
-				color: 0xff522c99,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Stength"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0,
-						min: 0.0,
-						max: 2.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.5, 0.5, 1.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Normal Map"),
-						type: "VECTOR",
-						color: -10238109,
-						default_value: new Float32Array([0.5, 0.5, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Vector Curves"),
-				type: "CURVE_VEC",
-				x: 0,
-				y: 0,
-				color: 0xff522c99,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				buttons: [
-					{
-						name: "arm.NodesMaterial.vectorCurvesButton",
-						type: "CUSTOM",
-						default_value: [[new Float32Array([0.0, 0.0]), new Float32Array([0.0, 0.0])], [new Float32Array([0.0, 0.0]), new Float32Array([0.0, 0.0])], [new Float32Array([0.0, 0.0]), new Float32Array([0.0, 0.0])]],
-						output: 0,
-						height: 8.5
-					}
-				]
-			}
-		],
-		[ // Converter
-			{
-				id: 0,
-				name: _tr("Clamp"),
-				type: "CLAMP",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Min"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Max"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("operation"),
-						type: "ENUM",
-						data: [_tr("Min Max"), _tr("Range")],
-						default_value: 0,
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Color Ramp"),
-				type: "VALTORGB",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fac"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Alpha"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: [
-					{
-						name: "arm.NodesMaterial.colorRampButton",
-						type: "CUSTOM",
-						default_value: [new Float32Array([1.0, 1.0, 1.0, 1.0, 0.0])],
-						data: 0,
-						output: 0,
-						height: 4.5
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Color Mask"),
-				type: "COLMASK",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Mask Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Radius"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.1,
-						min: 0.0,
-						max: 1.74
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Fuzziness"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Mask"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Combine HSV"),
-				type: "COMBHSV",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("H"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("S"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("V"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Combine RGB"),
-				type: "COMBRGB",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("R"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("G"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("B"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Combine XYZ"),
-				type: "COMBXYZ",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("X"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Y"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Z"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Map Range"),
-				type: "MAPRANGE",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("From Min"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("From Max"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("To Min"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("To Max"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 1.0
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("use_clamp"),
-						type: "BOOL",
-						default_value: false,
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("Math"),
-				type: "MATH",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.5
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("operation"),
-						type: "ENUM",
-						data: [_tr("Add"), _tr("Subtract"), _tr("Multiply"), _tr("Divide"), _tr("Power"), _tr("Logarithm"), _tr("Square Root"), _tr("Inverse Square Root"), _tr("Absolute"), _tr("Exponent"), _tr("Minimum"), _tr("Maximum"), _tr("Less Than"), _tr("Greater Than"), _tr("Sign"), _tr("Round"), _tr("Floor"), _tr("Ceil"), _tr("Truncate"), _tr("Fraction"), _tr("Modulo"), _tr("Snap"), _tr("Ping-Pong"), _tr("Sine"), _tr("Cosine"), _tr("Tangent"), _tr("Arcsine"), _tr("Arccosine"), _tr("Arctangent"), _tr("Arctan2"), _tr("Hyperbolic Sine"), _tr("Hyperbolic Cosine"), _tr("Hyperbolic Tangent"), _tr("To Radians"), _tr("To Degrees")],
-						default_value: 0,
-						output: 0
-					},
-					{
-						name: _tr("use_clamp"),
-						type: "BOOL",
-						default_value: false,
-						output: 0
-					}
-				]
-			},
-			{
-				id: 0,
-				name: _tr("RGB to BW"),
-				type: "RGBTOBW",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.0, 0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Val"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Separate HSV"),
-				type: "SEPHSV",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.5, 0.5, 0.5, 1.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("H"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("S"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("V"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Separate RGB"),
-				type: "SEPRGB",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Color"),
-						type: "RGBA",
-						color: 0xffc7c729,
-						default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("R"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("G"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("B"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Separate XYZ"),
-				type: "SEPXYZ",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("X"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Y"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Z"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: []
-			},
-			{
-				id: 0,
-				name: _tr("Vector Math"),
-				type: "VECT_MATH",
-				x: 0,
-				y: 0,
-				color: 0xff62676d,
-				inputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					}
-				],
-				outputs: [
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Vector"),
-						type: "VECTOR",
-						color: 0xff6363c7,
-						default_value: new Float32Array([0.0, 0.0, 0.0])
-					},
-					{
-						id: 0,
-						node_id: 0,
-						name: _tr("Value"),
-						type: "VALUE",
-						color: 0xffa1a1a1,
-						default_value: 0.0
-					}
-				],
-				buttons: [
-					{
-						name: _tr("operation"),
-						type: "ENUM",
-						data: [_tr("Add"), _tr("Subtract"), _tr("Multiply"), _tr("Divide"), _tr("Average"), _tr("Cross Product"), _tr("Project"), _tr("Reflect"), _tr("Dot Product"), _tr("Distance"), _tr("Length"), _tr("Scale"), _tr("Normalize"), _tr("Absolute"), _tr("Minimum"), _tr("Maximum"), _tr("Floor"), _tr("Ceil"), _tr("Fraction"), _tr("Modulo"), _tr("Snap"), _tr("Sine"), _tr("Cosine"), _tr("Tangent")],
-						default_value: 0,
-						output: 0
-					}
-				]
-			}
-		],
-		[ // Input
-			{
-				id: 0,
-				name: _tr("New Group"),
-				type: "GROUP",
-				x: 0,
-				y: 0,
-				color: 0xffb34f5a,
-				inputs: [],
-				outputs: [],
-				buttons: [
-					{
-						name: "arm.NodesMaterial.newGroupButton",
-						type: "CUSTOM",
-						height: 1
-					}
-				]
-			}
-		]
-	];
-
-	static vector_curves_button = (ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) => {
-		let but: zui_node_button_t = node.buttons[0];
-		let nhandle: zui_handle_t = zui_nest(zui_handle("nodesmaterial_0"), node.id);
-		zui_row([1 / 3, 1 / 3, 1 / 3]);
-		zui_radio(zui_nest(zui_nest(nhandle, 0), 1), 0, "X");
-		zui_radio(zui_nest(zui_nest(nhandle, 0), 1), 1, "Y");
-		zui_radio(zui_nest(zui_nest(nhandle, 0), 1), 2, "Z");
-		// Preview
-		let axis: i32 = zui_nest(zui_nest(nhandle, 0), 1).position;
-		let val: Float32Array[] = but.default_value[axis]; // [ [[x, y], [x, y], ..], [[x, y]], ..]
-		let num: i32 = val.length;
-		// for (let i: i32 = 0; i < num; ++i) { ui.line(); }
-		ui._y += zui_nodes_LINE_H() * 5;
-		// Edit
-		zui_row([1 / 5, 1 / 5, 3 / 5]);
-		if (zui_button("+")) {
-			let f32a: Float32Array = new Float32Array(2);
-			f32a[0] = 0; f32a[1] = 0;
-			val.push(f32a);
-		}
-		if (zui_button("-")) {
-			if (val.length > 2) val.pop();
-		}
-		let ihandle: zui_handle_t = zui_nest(zui_nest(zui_nest(nhandle, 0), 2), axis, {position: 0});
-		let i: i32 = math_floor(zui_slider(ihandle, "Index", 0, num - 1, false, 1, true, zui_align_t.LEFT));
-		if (i >= val.length || i < 0) ihandle.value = i = val.length - 1; // Stay in bounds
-		zui_row([1 / 2, 1 / 2]);
-		zui_nest(zui_nest(nhandle, 0), 3).value = val[i][0];
-		zui_nest(zui_nest(nhandle, 0), 4).value = val[i][1];
-		val[i][0] = zui_slider(zui_nest(zui_nest(nhandle, 0), 3, {value: 0}), "X", -1, 1, true, 100, true, zui_align_t.LEFT);
-		val[i][1] = zui_slider(zui_nest(zui_nest(nhandle, 0), 4, {value: 0}), "Y", -1, 1, true, 100, true, zui_align_t.LEFT);
-	}
-
-	static color_ramp_button = (ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) => {
-		let but: zui_node_button_t = node.buttons[0];
-		let nhandle: zui_handle_t = zui_nest(zui_handle("nodesmaterial_1"), node.id);
-		let nx: f32 = ui._x;
-		let ny: f32 = ui._y;
-
-		// Preview
-		let vals: Float32Array[] = but.default_value; // [[r, g, b, a, pos], ..]
-		let sw: f32 = ui._w / zui_nodes_SCALE();
-		for (let val of vals) {
-			let pos: f32 = val[4];
-			let col: i32 = color_from_floats(val[0], val[1], val[2], 1.0);
-			zui_fill(pos * sw, 0, (1.0 - pos) * sw, zui_nodes_LINE_H() - 2 * zui_nodes_SCALE(), col);
-		}
-		ui._y += zui_nodes_LINE_H();
-		// Edit
-		let ihandle: zui_handle_t = zui_nest(zui_nest(nhandle, 0), 2);
-		zui_row([1 / 4, 1 / 4, 2 / 4]);
-		if (zui_button("+")) {
-			let last: Float32Array = vals[vals.length - 1];
-			let f32a: Float32Array = new Float32Array(5);
-			f32a[0] = last[0];
-			f32a[1] = last[1];
-			f32a[2] = last[2];
-			f32a[3] = last[3];
-			f32a[4] = 1.0;
-			vals.push(f32a);
-			ihandle.value += 1;
-		}
-		if (zui_button("-") && vals.length > 1) {
-			vals.pop();
-			ihandle.value -= 1;
-		}
-		but.data = zui_combo(zui_nest(zui_nest(nhandle, 0), 1, {position: but.data}), [tr("Linear"), tr("Constant")], tr("Interpolate"));
-
-		zui_row([1 / 2, 1 / 2]);
-		let i: i32 = math_floor(zui_slider(ihandle, "Index", 0, vals.length - 1, false, 1, true, zui_align_t.LEFT));
-		if (i >= vals.length || i < 0) ihandle.value = i = vals.length - 1; // Stay in bounds
-
-		let val: Float32Array = vals[i];
-		zui_nest(zui_nest(nhandle, 0), 3).value = val[4];
-		val[4] = zui_slider(zui_nest(zui_nest(nhandle, 0), 3), "Pos", 0, 1, true, 100, true, zui_align_t.LEFT);
-		if (val[4] > 1.0) val[4] = 1.0; // Stay in bounds
-		else if (val[4] < 0.0) val[4] = 0.0;
-
-		let chandle: zui_handle_t = zui_nest(zui_nest(nhandle, 0), 4);
-		chandle.color = color_from_floats(val[0], val[1], val[2], 1.0);
-		if (zui_text("", zui_align_t.RIGHT, chandle.color) == zui_state_t.STARTED) {
-			let rx: f32 = nx + ui._w - zui_nodes_p(37);
-			let ry: f32 = ny - zui_nodes_p(5);
-			nodes._inputStarted = ui.input_started = false;
-			zui_nodes_rgba_popup(ui, chandle, val, math_floor(rx), math_floor(ry + zui_ELEMENT_H(ui)));
-		}
-		val[0] = color_get_rb(chandle.color) / 255;
-		val[1] = color_get_gb(chandle.color) / 255;
-		val[2] = color_get_bb(chandle.color) / 255;
-	}
-
-	static new_group_button = (ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) => {
-		if (node.name == "New Group") {
-			for (let i: i32 = 1; i < 999; ++i) {
-				node.name = tr("Group") + " " + i;
-
-				let found: bool = false;
-				for (let g of project_material_groups) {
-					if (g.canvas.name == node.name) {
-						found = true;
-						break;
-					}
-				}
-				if (!found) break;
-			}
-
-			zui_node_replace.push(node);
-
-			let canvas: zui_node_canvas_t = {
-				name: node.name,
-				nodes: [
-					{
-						id: 0,
-						name: _tr("Group Input"),
-						type: "GROUP_INPUT",
-						x: 50,
-						y: 200,
-						color: 0xff448c6d,
-						inputs: [],
-						outputs: [],
-						buttons: [
-							{
-								name: "arm.NodesMaterial.groupInputButton",
-								type: "CUSTOM",
-								height: 1
-							}
-						]
-					},
-					{
-						id: 1,
-						name: _tr("Group Output"),
-						type: "GROUP_OUTPUT",
-						x: 450,
-						y: 200,
-						color: 0xff448c6d,
-						inputs: [],
-						outputs: [],
-						buttons: [
-							{
-								name: "arm.NodesMaterial.groupOutputButton",
-								type: "CUSTOM",
-								height: 1
-							}
-						]
-					}
-				],
-				links: []
-			};
-			project_material_groups.push({ canvas: canvas, nodes: zui_nodes_create() });
-		}
-
-		let group: node_group_t = null;
-		for (let g of project_material_groups) {
-			if (g.canvas.name == node.name) {
-				group = g;
-				break;
-			}
-		}
-
-		if (zui_button(tr("Nodes"))) {
-			ui_nodes_group_stack.push(group);
-		}
-	}
-
-	static group_input_button = (ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) => {
-		NodesMaterial.add_socket_button(ui, nodes, node, node.outputs);
-	}
-
-	static group_output_button = (ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) => {
-		NodesMaterial.add_socket_button(ui, nodes, node, node.inputs);
-	}
-
-	static add_socket_button = (ui: zui_t, nodes: zui_nodes_t, node: zui_node_t, sockets: zui_node_socket_t[]) => {
-		if (zui_button(tr("Add"))) {
-			ui_menu_draw((ui: zui_t) => {
-				let groupStack: node_group_t[] = ui_nodes_group_stack;
-				let c: zui_node_canvas_t = groupStack[groupStack.length - 1].canvas;
-				if (ui_menu_button(ui, tr("RGBA"))) {
-					sockets.push(NodesMaterial.create_socket(nodes, node, null, "RGBA", c));
-					NodesMaterial.sync_sockets(node);
-				}
-				if (ui_menu_button(ui, tr("Vector"))) {
-					sockets.push(NodesMaterial.create_socket(nodes, node, null, "VECTOR", c));
-					NodesMaterial.sync_sockets(node);
-				}
-				if (ui_menu_button(ui, tr("Value"))) {
-					sockets.push(NodesMaterial.create_socket(nodes, node, null, "VALUE", c));
-					NodesMaterial.sync_sockets(node);
-				}
-			}, 3);
-		}
-	}
-
-	static sync_sockets = (node: zui_node_t) => {
-		let groupStack: node_group_t[] = ui_nodes_group_stack;
-		let c: zui_node_canvas_t = groupStack[groupStack.length - 1].canvas;
-		for (let m of project_materials) NodesMaterial.sync_group_sockets(m.canvas, c.name, node);
-		for (let g of project_material_groups) NodesMaterial.sync_group_sockets(g.canvas, c.name, node);
-		zui_node_replace.push(node);
-	}
-
-	static sync_group_sockets = (canvas: zui_node_canvas_t, groupName: string, node: zui_node_t) => {
-		for (let n of canvas.nodes) {
-			if (n.type == "GROUP" && n.name == groupName) {
-				let isInputs: bool = node.name == "Group Input";
-				let oldSockets: zui_node_socket_t[] = isInputs ? n.inputs : n.outputs;
-				let sockets: zui_node_socket_t[] = json_parse(json_stringify(isInputs ? node.outputs : node.inputs));
-				isInputs ? n.inputs = sockets : n.outputs = sockets;
-				for (let s of sockets) s.node_id = n.id;
-				let numSockets: i32 = sockets.length < oldSockets.length ? sockets.length : oldSockets.length;
-				for (let i: i32 = 0; i < numSockets; ++i) {
-					if (sockets[i].type == oldSockets[i].type) {
-						sockets[i].default_value = oldSockets[i].default_value;
-					}
-				}
-			}
-		}
-	}
-
-	static get_socket_color = (type: string): i32 => {
-		return type == "RGBA" ? 0xffc7c729 : type == "VECTOR" ? 0xff6363c7 : 0xffa1a1a1;
-	}
-
-	static get_socket_default_value = (type: string): any => {
-		return type == "RGBA" ? new Float32Array([0.8, 0.8, 0.8, 1.0]) : type == "VECTOR" ? new Float32Array([0.0, 0.0, 0.0]) : 0.0;
-	}
-
-	static get_socket_name = (type: string): string => {
-		return type == "RGBA" ? _tr("Color") : type == "VECTOR" ? _tr("Vector") : _tr("Value");
-	}
-
-	static create_socket = (nodes: zui_nodes_t, node: zui_node_t, name: string, type: string, canvas: zui_node_canvas_t, min = 0.0, max = 1.0, default_value: any = null): zui_node_socket_t => {
-		return {
-			id: zui_get_socket_id(canvas.nodes),
-			node_id: node.id,
-			name: name == null ? NodesMaterial.get_socket_name(type) : name,
-			type: type,
-			color: NodesMaterial.get_socket_color(type),
-			default_value: default_value == null ? NodesMaterial.get_socket_default_value(type) : default_value,
-			min: min,
-			max: max
-		}
-	}
-
-	static get_node_t = (nodeType: string): zui_node_t => {
-		for (let c of NodesMaterial.list) for (let n of c) if (n.type == nodeType) return n;
-		return null;
-	}
-
-	static create_node = (nodeType: string, group: node_group_t = null): zui_node_t => {
-		let n: zui_node_t = NodesMaterial.get_node_t(nodeType);
-		if (n == null) return null;
-		let canvas: zui_node_canvas_t = group != null ? group.canvas : context_raw.material.canvas;
-		let nodes: zui_nodes_t = group != null ? group.nodes : context_raw.material.nodes;
-		let node: zui_node_t = ui_nodes_make_node(n, nodes, canvas);
-		canvas.nodes.push(node);
-		return node;
-	}
-}

+ 0 - 370
base/Sources/ParserBlend.ts

@@ -1,370 +0,0 @@
-// .blend file parser
-// Reference:
-// https://github.com/fschutt/mystery-of-the-blend-backup
-// https://web.archive.org/web/20170630054951/http://www.atmind.nl/blender/mystery_ot_blend.html
-// Usage:
-// let bl: BlendRaw = ParserBlend.init(blob: DataView);
-// krom_log(ParserBlend.dir(bl, "Scene"));
-// let scenes: any = ParserBlend.get(bl, "Scene");
-// krom_log(BlHandle.get(BlHandle.get(scenes[0], "id"), "name"));
-
-class BlendRaw {
-	pos: i32;
-	view: DataView;
-
-	// Header
-	version: string;
-	pointer_size: i32;
-	little_endian: bool;
-	// Data
-	blocks: Block[] = [];
-	dna: Dna = null;
-	map: map_t<any, Block> = map_create(); // Map blocks by memory address
-}
-
-class ParserBlend {
-
-	static init = (buffer: ArrayBuffer): BlendRaw => {
-		let raw: BlendRaw = new BlendRaw();
-		raw.view = new DataView(buffer);
-		raw.pos = 0;
-		if (ParserBlend.read_chars(raw, 7) != "BLENDER") {
-			raw.view = new DataView(krom_inflate(buffer, false));
-			raw.pos = 0;
-			if (ParserBlend.read_chars(raw, 7) != "BLENDER") return null;
-		}
-		ParserBlend.parse(raw);
-		return raw;
-	}
-
-	static dir = (raw: BlendRaw, type: string): string[] => {
-		// Return structure fields
-		let type_index: i32 = ParserBlend.get_type_index(raw.dna, type);
-		if (type_index == -1) return null;
-		let ds: DnaStruct = ParserBlend.get_struct(raw.dna, type_index);
-		let fields: string[] = [];
-		for (let i: i32 = 0; i < ds.field_names.length; ++i) {
-			let name_index: i32 = ds.field_names[i];
-			let type_index: i32 = ds.field_types[i];
-			fields.push(raw.dna.types[type_index] + " " + raw.dna.names[name_index]);
-		}
-		return fields;
-	}
-
-	static get = (raw: BlendRaw, type: string): BlHandleRaw[] => {
-		if (raw.dna == null) return null;
-		// Return all structures of type
-		let type_index: i32 = ParserBlend.get_type_index(raw.dna, type);
-		if (type_index == -1) return null;
-		let ds: DnaStruct = ParserBlend.get_struct(raw.dna, type_index);
-		let handles: BlHandleRaw[] = [];
-		for (let b of raw.blocks) {
-			if (raw.dna.structs[b.sdna_index].type == type_index) {
-				let h: BlHandleRaw = new BlHandleRaw();
-				handles.push(h);
-				h.block = b;
-				h.ds = ds;
-			}
-		}
-		return handles;
-	}
-
-	static get_struct = (dna: Dna, typeIndex: i32): DnaStruct => {
-		for (let ds of dna.structs) if (ds.type == typeIndex) return ds;
-		return null;
-	}
-
-	static get_type_index = (dna: Dna, type: string): i32 => {
-		for (let i: i32 = 0; i < dna.types.length; ++i) if (type == dna.types[i]) return i;
-		return -1;
-	}
-
-	static parse = (raw: BlendRaw) => {
-		// Pointer size: _ 32bit, - 64bit
-		raw.pointer_size = ParserBlend.read_char(raw) == "_" ? 4 : 8;
-
-		// v - little endian, V - big endian
-		raw.little_endian = ParserBlend.read_char(raw) == "v";
-
-		raw.version = ParserBlend.read_chars(raw, 3);
-
-		// Reading file blocks
-		// Header - data
-		while (raw.pos < raw.view.byteLength) {
-			ParserBlend.align(raw);
-			let b: Block = new Block();
-
-			// Block type
-			b.code = ParserBlend.read_chars(raw, 4);
-			if (b.code == "ENDB") break;
-
-			raw.blocks.push(b);
-			b.blend = raw;
-
-			// Total block length
-			b.size = ParserBlend.read_i32(raw);
-
-			// Memory address
-			let addr: any = ParserBlend.read_pointer(raw);
-			if (!raw.map.has(addr)) raw.map.set(addr, b);
-
-			// Index of dna struct contained in this block
-			b.sdna_index = ParserBlend.read_i32(raw);
-
-			// Number of dna structs in this block
-			b.count = ParserBlend.read_i32(raw);
-
-			b.pos = raw.pos;
-
-			// This block stores dna structures
-			if (b.code == "DNA1") {
-				raw.dna = new Dna();
-
-				ParserBlend.read_chars(raw, 4); // SDNA
-				ParserBlend.read_chars(raw, 4); // NAME
-				let names_count: i32 = ParserBlend.read_i32(raw);
-				for (let i: i32 = 0; i < names_count; ++i) {
-					raw.dna.names.push(ParserBlend.read_string(raw));
-				}
-				ParserBlend.align(raw);
-
-				ParserBlend.read_chars(raw, 4); // TYPE
-				let types_count: i32 = ParserBlend.read_i32(raw);
-				for (let i: i32 = 0; i < types_count; ++i) {
-					raw.dna.types.push(ParserBlend.read_string(raw));
-				}
-				ParserBlend.align(raw);
-
-				ParserBlend.read_chars(raw, 4); // TLEN
-				for (let i: i32 = 0; i < types_count; ++i) {
-					raw.dna.types_length.push(ParserBlend.read_i16(raw));
-				}
-				ParserBlend.align(raw);
-
-				ParserBlend.read_chars(raw, 4); // STRC
-				let struct_count: i32 = ParserBlend.read_i32(raw);
-				for (let i: i32 = 0; i < struct_count; ++i) {
-					let ds: DnaStruct = new DnaStruct();
-					raw.dna.structs.push(ds);
-					ds.dna = raw.dna;
-					ds.type = ParserBlend.read_i16(raw);
-					let field_count: i32 = ParserBlend.read_i16(raw);
-					if (field_count > 0) {
-						ds.field_types = [];
-						ds.field_names = [];
-						for (let j: i32 = 0; j < field_count; ++j) {
-							ds.field_types.push(ParserBlend.read_i16(raw));
-							ds.field_names.push(ParserBlend.read_i16(raw));
-						}
-					}
-				}
-			}
-			else {
-				raw.pos += b.size;
-			}
-		}
-	}
-
-	static align = (raw: BlendRaw) => {
-		// 4 bytes aligned
-		let mod: i32 = raw.pos % 4;
-		if (mod > 0) raw.pos += 4 - mod;
-	}
-
-	static read_i8 = (raw: BlendRaw): i32 => {
-		let i: i32 = raw.view.getUint8(raw.pos);
-		raw.pos += 1;
-		return i;
-	}
-
-	static read_i16 = (raw: BlendRaw): i32 => {
-		let i: i32 = raw.view.getInt16(raw.pos, raw.little_endian);
-		raw.pos += 2;
-		return i;
-	}
-
-	static read_i32 = (raw: BlendRaw): i32 => {
-		let i: i32 = raw.view.getInt32(raw.pos, raw.little_endian);
-		raw.pos += 4;
-		return i;
-	}
-
-	static read_i64 = (raw: BlendRaw): any => {
-		let aview: any = raw.view;
-		let i: i32 = aview.getBigInt64(raw.pos, raw.little_endian);
-		raw.pos += 8;
-		return i;
-	}
-
-	static read_f32 = (raw: BlendRaw): f32 => {
-		let f: f32 = raw.view.getFloat32(raw.pos, raw.little_endian);
-		raw.pos += 4;
-		return f;
-	}
-
-	static read_i8array = (raw: BlendRaw, len: i32): Int32Array => {
-		let ar: Int32Array = new Int32Array(len);
-		for (let i: i32 = 0; i < len; ++i) ar[i] = ParserBlend.read_i8(raw);
-		return ar;
-	}
-
-	static read_i16array = (raw: BlendRaw, len: i32): Int32Array => {
-		let ar: Int32Array = new Int32Array(len);
-		for (let i: i32 = 0; i < len; ++i) ar[i] = ParserBlend.read_i16(raw);
-		return ar;
-	}
-
-	static read_i32array = (raw: BlendRaw, len: i32): Int32Array => {
-		let ar: Int32Array = new Int32Array(len);
-		for (let i: i32 = 0; i < len; ++i) ar[i] = ParserBlend.read_i32(raw);
-		return ar;
-	}
-
-	static read_f32array = (raw: BlendRaw, len: i32): Float32Array => {
-		let ar: Float32Array = new Float32Array(len);
-		for (let i: i32 = 0; i < len; ++i) ar[i] = ParserBlend.read_f32(raw);
-		return ar;
-	}
-
-	static read_string = (raw: BlendRaw): string => {
-		let s: string = "";
-		while (true) {
-			let ch: i32 = ParserBlend.read_i8(raw);
-			if (ch == 0) break;
-			s += String.fromCharCode(ch);
-		}
-		return s;
-	}
-
-	static read_chars = (raw: BlendRaw, len: i32): string => {
-		let s: string = "";
-		for (let i: i32 = 0; i < len; ++i) s += ParserBlend.read_char(raw);
-		return s;
-	}
-
-	static read_char = (raw: BlendRaw): string => {
-		return String.fromCharCode(ParserBlend.read_i8(raw));
-	}
-
-	static read_pointer = (raw: BlendRaw): any => {
-		return raw.pointer_size == 4 ? ParserBlend.read_i32(raw) : ParserBlend.read_i64(raw);
-	}
-}
-
-class Block {
-	blend: BlendRaw;
-	code: string;
-	size: i32;
-	sdna_index: i32;
-	count: i32;
-	pos: i32; // Byte pos of data start in blob
-}
-
-class Dna {
-	names: string[] = [];
-	types: string[] = [];
-	types_length: i32[] = [];
-	structs: DnaStruct[] = [];
-}
-
-class DnaStruct {
-	dna: Dna;
-	type: i32; // Index in dna.types
-	field_types: i32[]; // Index in dna.types
-	field_names: i32[]; // Index in dna.names
-}
-
-class BlHandleRaw {
-	block: Block;
-	offset: i32 = 0; // Block data bytes offset
-	ds: DnaStruct;
-}
-
-class BlHandle {
-	static get_size = (raw: BlHandleRaw, index: i32): i32 => {
-		let name_index: i32 = raw.ds.field_names[index];
-		let type_index: i32 = raw.ds.field_types[index];
-		let dna: Dna = raw.ds.dna;
-		let n: string = dna.names[name_index];
-		let size: i32 = 0;
-		if (n.indexOf("*") >= 0) size = raw.block.blend.pointer_size;
-		else size = dna.types_length[type_index];
-		if (n.indexOf("[") > 0) size *= BlHandle.get_array_len(n);
-		return size;
-	}
-
-	static base_name = (s: string): string => {
-		while (s.charAt(0) == "*") s = s.substring(1, s.length);
-		if (s.charAt(s.length - 1) == "]") s = s.substring(0, s.indexOf("["));
-		return s;
-	}
-
-	static get_array_len = (s: string): i32 => {
-		return parseInt(s.substring(s.indexOf("[") + 1, s.indexOf("]")));
-	}
-
-	static get = (raw: BlHandleRaw, name: string, index: i32 = 0, asType: string = null, arrayLen: i32 = 0): any => {
-		// Return raw type or structure
-		let dna: Dna = raw.ds.dna;
-		for (let i: i32 = 0; i < raw.ds.field_names.length; ++i) {
-			let name_index: i32 = raw.ds.field_names[i];
-			let dna_name: string = dna.names[name_index];
-			if (name == BlHandle.base_name(dna_name)) {
-				let type_index: i32 = raw.ds.field_types[i];
-				let type: string = dna.types[type_index];
-				let new_offset: i32 = raw.offset;
-				for (let j: i32 = 0; j < i; ++j) new_offset += BlHandle.get_size(raw, j);
-				// Cast void * to type
-				if (asType != null) {
-					for (let i: i32 = 0; i < dna.types.length; ++i) {
-						if (dna.types[i] == asType) {
-							type_index = i;
-							break;
-						}
-					}
-				}
-				// Raw type
-				if (type_index < 12) {
-					let blend: BlendRaw = raw.block.blend;
-					blend.pos = raw.block.pos + new_offset;
-					let is_array: bool = dna_name.charAt(dna_name.length - 1) == "]";
-					let len: i32 = is_array ? (arrayLen > 0 ? arrayLen : this.get_array_len(dna_name)) : 1;
-					switch (type) {
-						case "int": return is_array ? ParserBlend.read_i32array(blend, len) : ParserBlend.read_i32(blend);
-						case "char": return is_array ? ParserBlend.read_string(blend) : ParserBlend.read_i8(blend);
-						case "uchar": return is_array ? ParserBlend.read_i8array(blend, len) : ParserBlend.read_i8(blend);
-						case "short": return is_array ? ParserBlend.read_i16array(blend, len) : ParserBlend.read_i16(blend);
-						case "ushort": return is_array ? ParserBlend.read_i16array(blend, len) : ParserBlend.read_i16(blend);
-						case "float": return is_array ? ParserBlend.read_f32array(blend, len) : ParserBlend.read_f32(blend);
-						case "double": return 0; //ParserBlend.readf64(blend);
-						case "long": return is_array ? ParserBlend.read_i32array(blend, len) : ParserBlend.read_i32(blend);
-						case "ulong": return is_array ? ParserBlend.read_i32array(blend, len) : ParserBlend.read_i32(blend);
-						case "int64_t": return ParserBlend.read_i64(blend);
-						case "uint64_t": return ParserBlend.read_i64(blend);
-						case "void": if (dna_name.charAt(0) == "*") { return ParserBlend.read_i64(blend); };
-					}
-				}
-				// Structure
-				let h: BlHandleRaw = new BlHandleRaw();
-				h.ds = ParserBlend.get_struct(dna, type_index);
-				let is_pointer: bool = dna_name.charAt(0) == "*";
-				if (is_pointer) {
-					raw.block.blend.pos = raw.block.pos + new_offset;
-					let addr: any = ParserBlend.read_pointer(raw.block.blend);
-					if (raw.block.blend.map.has(addr)) {
-						h.block = raw.block.blend.map.get(addr);
-					}
-					else h.block = raw.block;
-					h.offset = 0;
-				}
-				else {
-					h.block = raw.block;
-					h.offset = new_offset;
-				}
-				h.offset += dna.types_length[type_index] * index;
-				return h;
-			}
-		}
-		return null;
-	}
-}

+ 0 - 323
base/Sources/ParserExr.ts

@@ -1,323 +0,0 @@
-// Based on miniexr.cpp - public domain - 2013 Aras Pranckevicius / Unity Technologies
-// https://github.com/aras-p/miniexr
-// https://www.openexr.com/documentation/openexrfilelayout.pdf
-
-class ParserExr {
-
-	static write_string = (out: i32[], str: string) => {
-		for (let i: i32 = 0; i < str.length; ++i) {
-			out.push(str.charCodeAt(i));
-		}
-	}
-
-	static run = (width: i32, height: i32, src: ArrayBuffer, bits: i32 = 16, type: i32 = 1, off: i32 = 0): ArrayBuffer => {
-		let out: u8[] = [];
-		out.push(0x76); // magic
-		out.push(0x2f);
-		out.push(0x31);
-		out.push(0x01);
-		out.push(2); // version, scanline
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		ParserExr.write_string(out, "channels");
-		out.push(0);
-		ParserExr.write_string(out, "chlist");
-		out.push(0);
-
-		out.push(55);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		let attrib: i32 = bits == 16 ? 1 : 2; // half, float
-
-		out.push("B".charCodeAt(0)); // B
-		out.push(0);
-
-		out.push(attrib);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(1);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(1);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push("G".charCodeAt(0)); // G
-		out.push(0);
-
-		out.push(attrib);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(1);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(1);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push("R".charCodeAt(0)); // R
-		out.push(0);
-
-		out.push(attrib);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(1);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(1);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-
-		ParserExr.write_string(out, "compression");
-		out.push(0);
-		ParserExr.write_string(out, "compression");
-		out.push(0);
-
-		out.push(1);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0); // no compression
-
-		ParserExr.write_string(out, "dataWindow");
-		out.push(0);
-		ParserExr.write_string(out, "box2i");
-		out.push(0);
-
-		out.push(16);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		let ww: i32 = width - 1;
-		let hh: i32 = height - 1;
-
-		out.push(ww & 0xff);
-		out.push((ww >> 8) & 0xff);
-		out.push((ww >> 16) & 0xff);
-		out.push((ww >> 24) & 0xff);
-
-		out.push(hh & 0xff);
-		out.push((hh >> 8) & 0xff);
-		out.push((hh >> 16) & 0xff);
-		out.push((hh >> 24) & 0xff);
-
-		ParserExr.write_string(out, "displayWindow");
-		out.push(0);
-		ParserExr.write_string(out, "box2i");
-		out.push(0);
-
-		out.push(16);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(ww & 0xff);
-		out.push((ww >> 8) & 0xff);
-		out.push((ww >> 16) & 0xff);
-		out.push((ww >> 24) & 0xff);
-
-		out.push(hh & 0xff);
-		out.push((hh >> 8) & 0xff);
-		out.push((hh >> 16) & 0xff);
-		out.push((hh >> 24) & 0xff);
-
-		ParserExr.write_string(out, "lineOrder");
-		out.push(0);
-		ParserExr.write_string(out, "lineOrder");
-		out.push(0);
-
-		out.push(1);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0); // increasing Y
-
-		ParserExr.write_string(out, "pixelAspectRatio");
-		out.push(0);
-		ParserExr.write_string(out, "float");
-		out.push(0);
-
-		out.push(4);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0); // 1.0f
-		out.push(0);
-		out.push(0x80);
-		out.push(0x3f);
-
-		ParserExr.write_string(out, "screenWindowCenter");
-		out.push(0);
-
-		ParserExr.write_string(out, "v2f");
-		out.push(0);
-
-		out.push(8);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		ParserExr.write_string(out, "screenWindowWidth");
-		out.push(0);
-
-		ParserExr.write_string(out, "float");
-		out.push(0);
-
-		out.push(4);
-		out.push(0);
-		out.push(0);
-		out.push(0);
-
-		out.push(0); // 1.0f
-		out.push(0);
-		out.push(0x80);
-		out.push(0x3f);
-
-		out.push(0); // end of header
-
-		let channels: i32 = 4;
-		let byte_size: i32 = bits == 16 ? 2 : 4;
-		let k_header_size: i32 = out.length;
-		let k_scanline_table_size: i32 = 8 * height;
-		let pixel_row_size: i32 = width * 3 * byte_size;
-		let full_row_size: i32 = pixel_row_size + 8;
-
-		// line offset table
-		let ofs: i32 = k_header_size + k_scanline_table_size;
-		for (let y: i32 = 0; y < height; ++y) {
-			out.push(ofs & 0xff);
-			out.push((ofs >> 8) & 0xff);
-			out.push((ofs >> 16) & 0xff);
-			out.push((ofs >> 24) & 0xff);
-			out.push(0);
-			out.push(0);
-			out.push(0);
-			out.push(0);
-			ofs += full_row_size;
-		}
-
-		// scanline data
-		let stride: i32 = channels * byte_size;
-		let pos: i32 = 0;
-		let srcView: DataView = new DataView(src);
-
-		let write_line16 = (bytePos: i32) => {
-			for (let x: i32 = 0; x < width; ++x) {
-				out.push(srcView.getUint8(bytePos    ));
-				out.push(srcView.getUint8(bytePos + 1));
-				bytePos += stride;
-			}
-		}
-
-		let write_line32 = (bytePos: i32) => {
-			for (let x: i32 = 0; x < width; ++x) {
-				out.push(srcView.getUint8(bytePos    ));
-				out.push(srcView.getUint8(bytePos + 1));
-				out.push(srcView.getUint8(bytePos + 2));
-				out.push(srcView.getUint8(bytePos + 3));
-				bytePos += stride;
-			}
-		}
-
-		let write_line = bits == 16 ? write_line16 : write_line32;
-
-		let write_bgr = (off: i32) => {
-			write_line(pos + byte_size * 2);
-			write_line(pos + byte_size);
-			write_line(pos);
-		}
-
-		let write_single = (off: i32) => {
-			write_line(pos + off * byte_size);
-			write_line(pos + off * byte_size);
-			write_line(pos + off * byte_size);
-		}
-
-		let write_data = type == 1 ? write_bgr : write_single;
-
-		for (let y: i32 = 0; y < height; ++y) {
-			// coordinate
-			out.push(y & 0xff);
-			out.push((y >> 8) & 0xff);
-			out.push((y >> 16) & 0xff);
-			out.push((y >> 24) & 0xff);
-			// data size
-			out.push(pixel_row_size & 0xff);
-			out.push((pixel_row_size >> 8) & 0xff);
-			out.push((pixel_row_size >> 16) & 0xff);
-			out.push((pixel_row_size >> 24) & 0xff);
-			// data
-			write_data(off);
-			pos += width * stride;
-		}
-
-		return Uint8Array.from(out).buffer;
-	}
-}

+ 0 - 207
base/Sources/ParserLogic.ts

@@ -1,207 +0,0 @@
-
-class ParserLogic {
-
-	static custom_nodes: map_t<any, any> = map_create();
-	static nodes: zui_node_t[];
-	static links: zui_node_link_t[];
-
-	static parsed_nodes: string[] = null;
-	static parsed_labels: map_t<string, string> = null;
-	static node_map: map_t<string, LogicNode>;
-	static raw_map: map_t<LogicNode, zui_node_t>;
-
-	static get_logic_node = (node: zui_node_t): LogicNode => {
-		return ParserLogic.node_map.get(ParserLogic.node_name(node));
-	}
-
-	static get_raw_node = (node: LogicNode): zui_node_t => {
-		return ParserLogic.raw_map.get(node);
-	}
-
-	static get_node = (id: i32): zui_node_t => {
-		for (let n of ParserLogic.nodes) if (n.id == id) return n;
-		return null;
-	}
-
-	static get_link = (id: i32): zui_node_link_t => {
-		for (let l of ParserLogic.links) if (l.id == id) return l;
-		return null;
-	}
-
-	static get_input_link = (inp: zui_node_socket_t): zui_node_link_t => {
-		for (let l of ParserLogic.links) {
-			if (l.to_id == inp.node_id) {
-				let node: zui_node_t = ParserLogic.get_node(inp.node_id);
-				if (node.inputs.length <= l.to_socket) return null;
-				if (node.inputs[l.to_socket] == inp) return l;
-			}
-		}
-		return null;
-	}
-
-	static get_output_links = (out: zui_node_socket_t): zui_node_link_t[] => {
-		let res: zui_node_link_t[] = [];
-		for (let l of ParserLogic.links) {
-			if (l.from_id == out.node_id) {
-				let node: zui_node_t = ParserLogic.get_node(out.node_id);
-				if (node.outputs.length <= l.from_socket) continue;
-				if (node.outputs[l.from_socket] == out) res.push(l);
-			}
-		}
-		return res;
-	}
-
-	static safe_src = (s: string): string => {
-		return string_replace_all(s, " ", "");
-	}
-
-	static node_name = (node: zui_node_t): string => {
-		let s: string = ParserLogic.safe_src(node.name) + node.id;
-		return s;
-	}
-
-	static parse = (canvas: zui_node_canvas_t) => {
-		ParserLogic.nodes = canvas.nodes;
-		ParserLogic.links = canvas.links;
-
-		ParserLogic.parsed_nodes = [];
-		ParserLogic.parsed_labels = map_create();
-		ParserLogic.node_map = map_create();
-		ParserLogic.raw_map = map_create();
-		let root_nodes: zui_node_t[] = ParserLogic.get_root_nodes(canvas);
-
-		for (let node of root_nodes) ParserLogic.build_node(node);
-	}
-
-	static build_node = (node: zui_node_t): string => {
-		// Get node name
-		let name: string = ParserLogic.node_name(node);
-
-		// Check if node already exists
-		if (ParserLogic.parsed_nodes.indexOf(name) != -1) {
-			return name;
-		}
-
-		ParserLogic.parsed_nodes.push(name);
-
-		// Create node
-		let v: any = ParserLogic.create_class_instance(node.type, []);
-		ParserLogic.node_map.set(name, v);
-		ParserLogic.raw_map.set(v, node);
-
-		// Expose button values in node class
-		for (let b of node.buttons) {
-			if (b.type == "ENUM") {
-				// let arrayData: bool = Array.isArray(b.data);
-				let array_data: bool = b.data.length > 1;
-				let texts: string[] = array_data ? b.data : zui_enum_texts_js(node.type);
-				v[b.name] = texts[b.default_value];
-			}
-			else {
-				v[b.name] = b.default_value;
-			}
-		}
-
-		// Create inputs
-		let inp_node: LogicNode = null;
-		let inp_from: i32 = 0;
-		for (let i: i32 = 0; i < node.inputs.length; ++i) {
-			let inp: zui_node_socket_t = node.inputs[i];
-			// Is linked - find node
-			let l: zui_node_link_t = ParserLogic.get_input_link(inp);
-			if (l != null) {
-				inp_node = ParserLogic.node_map.get(ParserLogic.build_node(ParserLogic.get_node(l.from_id)));
-				inp_from = l.from_socket;
-			}
-			// Not linked - create node with default values
-			else {
-				inp_node = ParserLogic.build_default_node(inp);
-				inp_from = 0;
-			}
-			// Add input
-			v.add_input(inp_node, inp_from);
-		}
-
-		// Create outputss
-		for (let out of node.outputs) {
-			let out_nodes: LogicNode[] = [];
-			let ls: zui_node_link_t[] = ParserLogic.get_output_links(out);
-			if (ls != null && ls.length > 0) {
-				for (let l of ls) {
-					let n: zui_node_t = ParserLogic.get_node(l.to_id);
-					let out_name: string = ParserLogic.build_node(n);
-					out_nodes.push(ParserLogic.node_map.get(out_name));
-				}
-			}
-			// Not linked - create node with default values
-			else {
-				out_nodes.push(ParserLogic.build_default_node(out));
-			}
-			// Add outputs
-			v.add_outputs(out_nodes);
-		}
-
-		return name;
-	}
-
-	static get_root_nodes = (node_group: zui_node_canvas_t): zui_node_t[] => {
-		let roots: zui_node_t[] = [];
-		for (let node of node_group.nodes) {
-			let linked: bool = false;
-			for (let out of node.outputs) {
-				let ls: zui_node_link_t[] = ParserLogic.get_output_links(out);
-				if (ls != null && ls.length > 0) {
-					linked = true;
-					break;
-				}
-			}
-			if (!linked) { // Assume node with no connected outputs as roots
-				roots.push(node);
-			}
-		}
-		return roots;
-	}
-
-	static build_default_node = (inp: zui_node_socket_t): LogicNode => {
-		let v: LogicNode = null;
-
-		if (inp.type == "VECTOR") {
-			if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO
-			v = ParserLogic.create_class_instance("VectorNode", [inp.default_value[0], inp.default_value[1], inp.default_value[2]]);
-		}
-		else if (inp.type == "RGBA") {
-			if (inp.default_value == null) inp.default_value = [0, 0, 0, 0]; // TODO
-			v = ParserLogic.create_class_instance("ColorNode", [inp.default_value[0], inp.default_value[1], inp.default_value[2], inp.default_value[3]]);
-		}
-		else if (inp.type == "RGB") {
-			if (inp.default_value == null) inp.default_value = [0, 0, 0, 0]; // TODO
-			v = ParserLogic.create_class_instance("ColorNode", [inp.default_value[0], inp.default_value[1], inp.default_value[2], inp.default_value[3]]);
-		}
-		else if (inp.type == "VALUE") {
-			v = ParserLogic.create_class_instance("FloatNode", [inp.default_value]);
-		}
-		else if (inp.type == "INT") {
-			v = ParserLogic.create_class_instance("IntegerNode", [inp.default_value]);
-		}
-		else if (inp.type == "BOOLEAN") {
-			v = ParserLogic.create_class_instance("BooleanNode", [inp.default_value]);
-		}
-		else if (inp.type == "STRING") {
-			v = ParserLogic.create_class_instance("StringNode", [inp.default_value]);
-		}
-		else {
-			v = ParserLogic.create_class_instance("NullNode", []);
-		}
-		return v;
-	}
-
-	static create_class_instance = (className: string, args: any[]): any => {
-		if (ParserLogic.custom_nodes.get(className) != null) {
-			let node: LogicNode = new LogicNode();
-			node.get = (from: i32) => { return ParserLogic.custom_nodes.get(className)(node, from); }
-			return node;
-		}
-		let dynamic_class: any = eval(`${className}`);
-		return new dynamic_class(args);
-	}
-}

+ 0 - 1934
base/Sources/ParserMaterial.ts

@@ -1,1934 +0,0 @@
-//
-// This module builds upon Cycles nodes work licensed as
-// Copyright 2011-2013 Blender Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-class ParserMaterial {
-
-	static con: NodeShaderContextRaw;
-	static vert: NodeShaderRaw;
-	static frag: NodeShaderRaw;
-	static curshader: NodeShaderRaw;
-	static matcon: material_context_t;
-	static parsed: string[];
-	static parents: zui_node_t[];
-
-	static canvases: zui_node_canvas_t[];
-	static nodes: zui_node_t[];
-	static links: zui_node_link_t[];
-
-	static cotangent_frame_written: bool;
-	static tex_coord: string = "texCoord";
-	static eps: f32 = 0.000001;
-
-	static custom_nodes: map_t<any, any> = map_create();
-	static parse_surface: bool = true;
-	static parse_opacity: bool = true;
-	static parse_height: bool = false;
-	static parse_height_as_channel: bool = false;
-	static parse_emission: bool = false;
-	static parse_subsurface: bool = false;
-	static parsing_basecolor: bool = false;
-	static triplanar: bool = false; // Sample using texCoord/1/2 & texCoordBlend
-	static sample_keep_aspect: bool = false; // Adjust uvs to preserve texture aspect ratio
-	static sample_uv_scale: string = "1.0";
-	static transform_color_space: bool = true;
-
-	static blur_passthrough: bool = false;
-	static warp_passthrough: bool = false;
-	static bake_passthrough: bool = false;
-	static bake_passthrough_strength: string = "0.0";
-	static bake_passthrough_radius: string = "0.0";
-	static bake_passthrough_offset: string = "0.0";
-	static start_group: zui_node_canvas_t = null;
-	static start_parents: zui_node_t[] = null;
-	static start_node: zui_node_t = null;
-
-	static arm_export_tangents: bool = true;
-	static out_normaltan: string; // Raw tangent space normal parsed from normal map
-
-	static script_links: map_t<string, string> = null;
-
-	static parsedMap: map_t<string, string> = map_create();
-	static textureMap: map_t<string, string> = map_create();
-
-	static get_node = (id: i32): zui_node_t => {
-		for (let n of ParserMaterial.nodes) if (n.id == id) return n;
-		return null;
-	}
-
-	static get_link = (id: i32): zui_node_link_t => {
-		for (let l of ParserMaterial.links) if (l.id == id) return l;
-		return null;
-	}
-
-	static get_input_link = (inp: zui_node_socket_t): zui_node_link_t => {
-		for (let l of ParserMaterial.links) {
-			if (l.to_id == inp.node_id) {
-				let node: zui_node_t = ParserMaterial.get_node(inp.node_id);
-				if (node.inputs.length <= l.to_socket) return null;
-				if (node.inputs[l.to_socket] == inp) return l;
-			}
-		}
-		return null;
-	}
-
-	static get_output_links = (out: zui_node_socket_t): zui_node_link_t[] => {
-		let ls: zui_node_link_t[] = null;
-		for (let l of ParserMaterial.links) {
-			if (l.from_id == out.node_id) {
-				let node: zui_node_t = ParserMaterial.get_node(out.node_id);
-				if (node.outputs.length <= l.from_socket) continue;
-				if (node.outputs[l.from_socket] == out) {
-					if (ls == null) ls = [];
-					ls.push(l);
-				}
-			}
-		}
-		return ls;
-	}
-
-	static init = () => {
-		ParserMaterial.parsed = [];
-		ParserMaterial.parents = [];
-		ParserMaterial.cotangent_frame_written = false;
-		ParserMaterial.out_normaltan = "vec3(0.5, 0.5, 1.0)";
-		ParserMaterial.script_links = null;
-		ParserMaterial.parsing_basecolor = false;
-	}
-
-	static parse = (canvas: zui_node_canvas_t, _con: NodeShaderContextRaw, _vert: NodeShaderRaw, _frag: NodeShaderRaw, _matcon: material_context_t): shader_out_t => {
-		zui_nodes_update_canvas_format(canvas);
-		ParserMaterial.init();
-		ParserMaterial.canvases = [canvas];
-		ParserMaterial.nodes = canvas.nodes;
-		ParserMaterial.links = canvas.links;
-		ParserMaterial.con = _con;
-		ParserMaterial.vert = _vert;
-		ParserMaterial.frag = _frag;
-		ParserMaterial.curshader = ParserMaterial.frag;
-		ParserMaterial.matcon = _matcon;
-
-		if (ParserMaterial.start_group != null) {
-			ParserMaterial.push_group(ParserMaterial.start_group);
-			ParserMaterial.parents = ParserMaterial.start_parents;
-		}
-
-		if (ParserMaterial.start_node != null) {
-			let link: zui_node_link_t = { id: 99999, from_id: ParserMaterial.start_node.id, from_socket: 0, to_id: -1, to_socket: -1 };
-			ParserMaterial.write_result(link);
-			return {
-				out_basecol: `vec3(0.0, 0.0, 0.0)`,
-				out_roughness: `0.0`,
-				out_metallic: `0.0`,
-				out_occlusion: `1.0`,
-				out_opacity: `1.0`,
-				out_height: `0.0`,
-				out_emission: `0.0`,
-				out_subsurface: `0.0`
-			}
-		}
-
-		let output_node: zui_node_t = ParserMaterial.node_by_type(ParserMaterial.nodes, "OUTPUT_MATERIAL");
-		if (output_node != null) {
-			return ParserMaterial.parse_output(output_node);
-		}
-		output_node = ParserMaterial.node_by_type(ParserMaterial.nodes, "OUTPUT_MATERIAL_PBR");
-		if (output_node != null) {
-			return ParserMaterial.parse_output_pbr(output_node);
-		}
-		return null;
-	}
-
-	static finalize = (con: NodeShaderContextRaw) => {
-		let vert: NodeShaderRaw = con.vert;
-		let frag: NodeShaderRaw = con.frag;
-
-		if (frag.dotnv) {
-			frag.vvec = true;
-			frag.n = true;
-		}
-		if (frag.vvec) {
-			vert.wposition = true;
-		}
-
-		if (frag.bposition) {
-			if (ParserMaterial.triplanar) {
-				NodeShader.write_attrib(frag, `vec3 bposition = vec3(
-					texCoord1.x * texCoordBlend.y + texCoord2.x * texCoordBlend.z,
-					texCoord.x * texCoordBlend.x + texCoord2.y * texCoordBlend.z,
-					texCoord.y * texCoordBlend.x + texCoord1.y * texCoordBlend.y);`);
-			}
-			else if (frag.ndcpos) {
-				NodeShader.add_out(vert, "vec3 bposition");
-				NodeShader.write(vert, `bposition = (ndc.xyz / ndc.w);`);
-			}
-			else {
-				NodeShader.add_out(vert, "vec3 bposition");
-				NodeShader.add_uniform(vert, "vec3 dim", "_dim");
-				NodeShader.add_uniform(vert, "vec3 hdim", "_half_dim");
-				NodeShader.write_attrib(vert, `bposition = (pos.xyz + hdim) / dim;`);
-			}
-		}
-		if (frag.wposition) {
-			NodeShader.add_uniform(vert, "mat4 W", "_world_matrix");
-			NodeShader.add_out(vert, "vec3 wposition");
-			NodeShader.write_attrib(vert, `wposition = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;`);
-		}
-		else if (vert.wposition) {
-			NodeShader.add_uniform(vert, "mat4 W", "_world_matrix");
-			NodeShader.write_attrib(vert, `vec3 wposition = vec4(mul(vec4(pos.xyz, 1.0), W)).xyz;`);
-		}
-		if (frag.vposition) {
-			NodeShader.add_uniform(vert, "mat4 WV", "_world_view_matrix");
-			NodeShader.add_out(vert, "vec3 vposition");
-			NodeShader.write_attrib(vert, `vposition = vec4(mul(vec4(pos.xyz, 1.0), WV)).xyz;`);
-		}
-		if (frag.mposition) {
-			NodeShader.add_out(vert, "vec3 mposition");
-			if (frag.ndcpos) {
-				NodeShader.write(vert, `mposition = (ndc.xyz / ndc.w);`);
-			}
-			else {
-				NodeShader.write_attrib(vert, `mposition = pos.xyz;`);
-			}
-		}
-		if (frag.wtangent) {
-			// NodeShaderadd_elem(con, "tang", "short4norm");
-			// NodeShader.add_uniform(vert, "mat3 N", "_normal_matrix");
-			NodeShader.add_out(vert, "vec3 wtangent");
-			// NodeShader.write_attrib(vert, `wtangent = normalize(mul(tang.xyz, N));`);
-			NodeShader.write_attrib(vert, `wtangent = vec3(0.0, 0.0, 0.0);`);
-		}
-		if (frag.vvec_cam) {
-			NodeShader.add_uniform(vert, "mat4 WV", "_world_view_matrix");
-			NodeShader.add_out(vert, "vec3 eyeDirCam");
-			NodeShader.write_attrib(vert, `eyeDirCam = vec4(mul(vec4(pos.xyz, 1.0), WV)).xyz; eyeDirCam.z *= -1.0;`);
-			NodeShader.write_attrib(frag, `vec3 vVecCam = normalize(eyeDirCam);`);
-		}
-		if (frag.vvec) {
-			NodeShader.add_uniform(vert, "vec3 eye", "_camera_pos");
-			NodeShader.add_out(vert, "vec3 eyeDir");
-			NodeShader.write_attrib(vert, `eyeDir = eye - wposition;`);
-			NodeShader.write_attrib(frag, `vec3 vVec = normalize(eyeDir);`);
-		}
-		if (frag.n) {
-			NodeShader.add_uniform(vert, "mat3 N", "_normal_matrix");
-			NodeShader.add_out(vert, "vec3 wnormal");
-			NodeShader.write_attrib(vert, `wnormal = mul(vec3(nor.xy, pos.w), N);`);
-			NodeShader.write_attrib(frag, `vec3 n = normalize(wnormal);`);
-		}
-		else if (vert.n) {
-			NodeShader.add_uniform(vert, "mat3 N", "_normal_matrix");
-			NodeShader.write_attrib(vert, `vec3 wnormal = normalize(mul(vec3(nor.xy, pos.w), N));`);
-		}
-		if (frag.nattr) {
-			NodeShader.add_out(vert, "vec3 nAttr");
-			NodeShader.write_attrib(vert, `nAttr = vec3(nor.xy, pos.w);`);
-		}
-		if (frag.dotnv) {
-			NodeShader.write_attrib(frag, `float dotNV = max(dot(n, vVec), 0.0);`);
-		}
-		if (frag.wvpposition) {
-			NodeShader.add_out(vert, "vec4 wvpposition");
-			NodeShader.write_end(vert, `wvpposition = gl_Position;`);
-		}
-		if (NodeShaderContext.is_elem(con, `col`)) {
-			NodeShader.add_out(vert, `vec3 vcolor`);
-			NodeShader.write_attrib(vert, `vcolor = col.rgb;`);
-		}
-	}
-
-	static parse_output = (node: zui_node_t): shader_out_t => {
-		if (ParserMaterial.parse_surface || ParserMaterial.parse_opacity) {
-			return ParserMaterial.parse_shader_input(node.inputs[0]);
-		}
-		return null;
-		// Parse volume, displacement..
-	}
-
-	static parse_output_pbr = (node: zui_node_t): shader_out_t => {
-		if (ParserMaterial.parse_surface || ParserMaterial.parse_opacity) {
-			return ParserMaterial.parse_shader(node, null);
-		}
-		return null;
-		// Parse volume, displacement..
-	}
-
-	static get_group = (name: string): zui_node_canvas_t => {
-		for (let g of project_material_groups) if (g.canvas.name == name) return g.canvas;
-		return null;
-	}
-
-	static push_group = (g: zui_node_canvas_t) => {
-		ParserMaterial.canvases.push(g);
-		ParserMaterial.nodes = g.nodes;
-		ParserMaterial.links = g.links;
-	}
-
-	static pop_group = () => {
-		ParserMaterial.canvases.pop();
-		let g: zui_node_canvas_t = ParserMaterial.canvases[ParserMaterial.canvases.length - 1];
-		ParserMaterial.nodes = g.nodes;
-		ParserMaterial.links = g.links;
-	}
-
-	static parse_group = (node: zui_node_t, socket: zui_node_socket_t): string => { // Entering group
-		ParserMaterial.parents.push(node);
-		ParserMaterial.push_group(ParserMaterial.get_group(node.name));
-		let output_node: zui_node_t = ParserMaterial.node_by_type(ParserMaterial.nodes, "GROUP_OUTPUT");
-		if (output_node == null) return null;
-		let index: i32 = ParserMaterial.socket_index(node, socket);
-		let inp: zui_node_socket_t = output_node.inputs[index];
-		let out_group: string = ParserMaterial.parse_input(inp);
-		ParserMaterial.parents.pop();
-		ParserMaterial.pop_group();
-		return out_group;
-	}
-
-	static parse_group_input = (node: zui_node_t, socket: zui_node_socket_t): string => {
-		let parent: zui_node_t = ParserMaterial.parents.pop(); // Leaving group
-		ParserMaterial.pop_group();
-		let index: i32 = ParserMaterial.socket_index(node, socket);
-		let inp: zui_node_socket_t = parent.inputs[index];
-		let res: string = ParserMaterial.parse_input(inp);
-		ParserMaterial.parents.push(parent); // Return to group
-		ParserMaterial.push_group(ParserMaterial.get_group(parent.name));
-		return res;
-	}
-
-	static parse_input = (inp: zui_node_socket_t): string => {
-		if (inp.type == "RGB") {
-			return ParserMaterial.parse_vector_input(inp);
-		}
-		else if (inp.type == "RGBA") {
-			return ParserMaterial.parse_vector_input(inp);
-		}
-		else if (inp.type == "VECTOR") {
-			return ParserMaterial.parse_vector_input(inp);
-		}
-		else if (inp.type == "VALUE") {
-			return ParserMaterial.parse_value_input(inp);
-		}
-		return null;
-	}
-
-	static parse_shader_input = (inp: zui_node_socket_t): shader_out_t => {
-		let l: zui_node_link_t = ParserMaterial.get_input_link(inp);
-		let from_node: zui_node_t = l != null ? ParserMaterial.get_node(l.from_id) : null;
-		if (from_node != null) {
-			if (from_node.type == "REROUTE") {
-				return ParserMaterial.parse_shader_input(from_node.inputs[0]);
-			}
-			return ParserMaterial.parse_shader(from_node, from_node.outputs[l.from_socket]);
-		}
-		else {
-			return {
-				out_basecol: "vec3(0.8, 0.8, 0.8)",
-				out_roughness: "0.0",
-				out_metallic: "0.0",
-				out_occlusion: "1.0",
-				out_opacity: "1.0",
-				out_height: "0.0",
-				out_emission: "0.0",
-				out_subsurface: "0.0"
-			};
-		}
-	}
-
-	static parse_shader = (node: zui_node_t, socket: zui_node_socket_t): shader_out_t => {
-		let sout: shader_out_t = {
-			out_basecol: "vec3(0.8, 0.8, 0.8)",
-			out_roughness: "0.0",
-			out_metallic: "0.0",
-			out_occlusion: "1.0",
-			out_opacity: "1.0",
-			out_height: "0.0",
-			out_emission: "0.0",
-			out_subsurface: "0.0"
-		}
-
-		if (node.type == "OUTPUT_MATERIAL_PBR") {
-			if (ParserMaterial.parse_surface) {
-				// Normal - parsed first to retrieve uv coords
-				ParserMaterial.parse_normal_map_color_input(node.inputs[5]);
-				// Base color
-				ParserMaterial.parsing_basecolor = true;
-				sout.out_basecol = ParserMaterial.parse_vector_input(node.inputs[0]);
-				ParserMaterial.parsing_basecolor = false;
-				// Occlusion
-				sout.out_occlusion = ParserMaterial.parse_value_input(node.inputs[2]);
-				// Roughness
-				sout.out_roughness = ParserMaterial.parse_value_input(node.inputs[3]);
-				// Metallic
-				sout.out_metallic = ParserMaterial.parse_value_input(node.inputs[4]);
-				// Emission
-				if (ParserMaterial.parse_emission) {
-					sout.out_emission = ParserMaterial.parse_value_input(node.inputs[6]);
-				}
-				// Subsurface
-				if (ParserMaterial.parse_subsurface) {
-					sout.out_subsurface = ParserMaterial.parse_value_input(node.inputs[8]);
-				}
-			}
-
-			if (ParserMaterial.parse_opacity) {
-				sout.out_opacity = ParserMaterial.parse_value_input(node.inputs[1]);
-			}
-
-			// Displacement / Height
-			if (node.inputs.length > 7 && ParserMaterial.parse_height) {
-				if (!ParserMaterial.parse_height_as_channel) ParserMaterial.curshader = ParserMaterial.vert;
-				sout.out_height = ParserMaterial.parse_value_input(node.inputs[7]);
-				if (!ParserMaterial.parse_height_as_channel) ParserMaterial.curshader = ParserMaterial.frag;
-			}
-		}
-
-		return sout;
-	}
-
-	static parse_vector_input = (inp: zui_node_socket_t): string => {
-		let l: zui_node_link_t = ParserMaterial.get_input_link(inp);
-		let from_node: zui_node_t = l != null ? ParserMaterial.get_node(l.from_id) : null;
-		if (from_node != null) {
-			if (from_node.type == "REROUTE") {
-				return ParserMaterial.parse_vector_input(from_node.inputs[0]);
-			}
-
-			let res_var: string = ParserMaterial.write_result(l);
-			let st: string = from_node.outputs[l.from_socket].type;
-			if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
-				return res_var;
-			}
-			else {// VALUE
-				return ParserMaterial.to_vec3(res_var);
-			}
-		}
-		else {
-			if (inp.type == "VALUE") { // Unlinked reroute
-				return ParserMaterial.vec3([0.0, 0.0, 0.0]);
-			}
-			else {
-				return ParserMaterial.vec3(inp.default_value);
-			}
-		}
-	}
-
-	static parse_vector = (node: zui_node_t, socket: zui_node_socket_t): string => {
-		if (node.type == `GROUP`) {
-			return ParserMaterial.parse_group(node, socket);
-		}
-		else if (node.type == `GROUP_INPUT`) {
-			return ParserMaterial.parse_group_input(node, socket);
-		}
-		else if (node.type == "ATTRIBUTE") {
-			if (socket == node.outputs[0]) { // Color
-				if (ParserMaterial.curshader.context.allow_vcols) {
-					NodeShaderContext.add_elem(ParserMaterial.curshader.context, "col", "short4norm"); // Vcols only for now
-					return "vcolor";
-				}
-				else {
-					return("vec3(0.0, 0.0, 0.0)");
-				}
-			}
-			else { // Vector
-				NodeShaderContext.add_elem(ParserMaterial.curshader.context, "tex", "short2norm"); // UVMaps only for now
-				return "vec3(texCoord.x, texCoord.y, 0.0)";
-			}
-		}
-		else if (node.type == "VERTEX_COLOR") {
-			if (ParserMaterial.curshader.context.allow_vcols) {
-				NodeShaderContext.add_elem(ParserMaterial.curshader.context, "col", "short4norm");
-				return "vcolor";
-			}
-			else {
-				return("vec3(0.0, 0.0, 0.0)");
-			}
-
-		}
-		else if (node.type == "RGB") {
-			return ParserMaterial.vec3(socket.default_value);
-		}
-		else if (node.type == "TEX_BRICK") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_brick);
-			let co: string = ParserMaterial.get_coord(node);
-			let col1: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let col2: string = ParserMaterial.parse_vector_input(node.inputs[2]);
-			let col3: string = ParserMaterial.parse_vector_input(node.inputs[3]);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[4]);
-			let res: string = `tex_brick(${co} * ${scale}, ${col1}, ${col2}, ${col3})`;
-			return res;
-		}
-		else if (node.type == "TEX_CHECKER") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_checker);
-			let co: string = ParserMaterial.get_coord(node);
-			let col1: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let col2: string = ParserMaterial.parse_vector_input(node.inputs[2]);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[3]);
-			let res: string = `tex_checker(${co}, ${col1}, ${col2}, ${scale})`;
-			return res;
-		}
-		else if (node.type == "TEX_GRADIENT") {
-			let co: string = ParserMaterial.get_coord(node);
-			let but: zui_node_button_t = node.buttons[0]; //gradient_type;
-			let grad: string = but.data[but.default_value].toUpperCase();
-			grad = string_replace_all(grad, " ", "_");
-			let f: string = ParserMaterial.get_gradient(grad, co);
-			let res: string = ParserMaterial.to_vec3(`clamp(${f}, 0.0, 1.0)`);
-			return res;
-		}
-		else if (node.type == "TEX_IMAGE") {
-			// Already fetched
-			if (ParserMaterial.parsed.indexOf(ParserMaterial.res_var_name(node, node.outputs[1])) >= 0) { // TODO: node.outputs[0]
-				let varname: string = ParserMaterial.store_var_name(node);
-				return `${varname}.rgb`;
-			}
-			let tex_name: string = ParserMaterial.node_name(node);
-			let tex: bind_tex_t = ParserMaterial.make_texture(node, tex_name);
-			if (tex != null) {
-				let color_space: i32 = node.buttons[1].default_value;
-				let texstore: string = ParserMaterial.texture_store(node, tex, tex_name, color_space);
-				return `${texstore}.rgb`;
-			}
-			else {
-				let tex_store: string = ParserMaterial.store_var_name(node); // Pink color for missing texture
-				NodeShader.write(ParserMaterial.curshader, `vec4 ${tex_store} = vec4(1.0, 0.0, 1.0, 1.0);`);
-				return `${tex_store}.rgb`;
-			}
-		}
-		else if (node.type == "TEX_MAGIC") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_magic);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let res: string = `tex_magic(${co} * ${scale} * 4.0)`;
-			return res;
-		}
-		else if (node.type == "TEX_NOISE") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_noise);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let res: string = `vec3(tex_noise(${co} * ${scale}), tex_noise(${co} * ${scale} + 0.33), tex_noise(${co} * ${scale} + 0.66))`;
-			return res;
-		}
-		else if (node.type == "TEX_VORONOI") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_voronoi);
-			NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D snoise256", "$noise256.k");
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let but: zui_node_button_t = node.buttons[0]; //coloring;
-			let coloring: string = but.data[but.default_value].toUpperCase();
-			coloring = string_replace_all(coloring, " ", "_");
-			let res: string = "";
-			if (coloring == "INTENSITY") {
-				res = ParserMaterial.to_vec3(`tex_voronoi(${co} * ${scale}, texturePass(snoise256)).a`);
-			}
-			else { // Cells
-				res = `tex_voronoi(${co} * ${scale}, texturePass(snoise256)).rgb`;
-			}
-			return res;
-		}
-		else if (node.type == "TEX_WAVE") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_wave);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let res: string = ParserMaterial.to_vec3(`tex_wave_f(${co} * ${scale})`);
-			return res;
-		}
-		else if (node.type == "BRIGHTCONTRAST") {
-			let out_col: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			let bright: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let contr: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			NodeShader.add_function(ParserMaterial.curshader, str_brightcontrast);
-			return `brightcontrast(${out_col}, ${bright}, ${contr})`;
-		}
-		else if (node.type == "GAMMA") {
-			let out_col: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			let gamma: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			return `pow(${out_col}, ` + ParserMaterial.to_vec3(`${gamma}`) + ")";
-		}
-		else if (node.type == "DIRECT_WARP") {
-			if (ParserMaterial.warp_passthrough) return ParserMaterial.parse_vector_input(node.inputs[0]);
-			let angle: string = ParserMaterial.parse_value_input(node.inputs[1], true);
-			let mask: string = ParserMaterial.parse_value_input(node.inputs[2], true);
-			let tex_name: string = "texwarp_" + ParserMaterial.node_name(node);
-			NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D " + tex_name, "_" + tex_name);
-			let store: string = ParserMaterial.store_var_name(node);
-			NodeShader.write(ParserMaterial.curshader, `float ${store}_rad = ${angle} * (${math_pi()} / 180);`);
-			NodeShader.write(ParserMaterial.curshader, `float ${store}_x = cos(${store}_rad);`);
-			NodeShader.write(ParserMaterial.curshader, `float ${store}_y = sin(${store}_rad);`);
-			return `texture(${tex_name}, texCoord + vec2(${store}_x, ${store}_y) * ${mask}).rgb;`;
-		}
-		else if (node.type == "BLUR") {
-			if (ParserMaterial.blur_passthrough) return ParserMaterial.parse_vector_input(node.inputs[0]);
-			let strength: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			if (strength == "0.0") return "vec3(0.0, 0.0, 0.0)";
-			let steps: string = `int(${strength} * 10 + 1)`;
-			let tex_name: string = "texblur_" + ParserMaterial.node_name(node);
-			NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D " + tex_name, "_" + tex_name);
-			let store: string = ParserMaterial.store_var_name(node);
-			NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_res = vec3(0.0, 0.0, 0.0);`);
-			NodeShader.write(ParserMaterial.curshader, `for (int i = -${steps}; i <= ${steps}; ++i) {`);
-			NodeShader.write(ParserMaterial.curshader, `for (int j = -${steps}; j <= ${steps}; ++j) {`);
-			NodeShader.write(ParserMaterial.curshader, `${store}_res += texture(${tex_name}, texCoord + vec2(i, j) / vec2(textureSize(${tex_name}, 0))).rgb;`);
-			NodeShader.write(ParserMaterial.curshader, `}`);
-			NodeShader.write(ParserMaterial.curshader, `}`);
-			NodeShader.write(ParserMaterial.curshader, `${store}_res /= (${steps} * 2 + 1) * (${steps} * 2 + 1);`);
-			return `${store}_res`;
-		}
-		else if (node.type == "HUE_SAT") {
-			NodeShader.add_function(ParserMaterial.curshader, str_hue_sat);
-			let hue: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let sat: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let val: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			let fac: string = ParserMaterial.parse_value_input(node.inputs[3]);
-			let col: string = ParserMaterial.parse_vector_input(node.inputs[4]);
-			return `hue_sat(${col}, vec4(${hue}-0.5, ${sat}, ${val}, 1.0-${fac}))`;
-		}
-		else if (node.type == "INVERT") {
-			let fac: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let out_col: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			return `mix(${out_col}, vec3(1.0, 1.0, 1.0) - (${out_col}), ${fac})`;
-		}
-		else if (node.type == "MIX_RGB") {
-			let fac: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let fac_var: string = ParserMaterial.node_name(node) + "_fac";
-			NodeShader.write(ParserMaterial.curshader, `float ${fac_var} = ${fac};`);
-			let col1: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let col2: string = ParserMaterial.parse_vector_input(node.inputs[2]);
-			let but: zui_node_button_t = node.buttons[0]; // blend_type
-			let blend: string = but.data[but.default_value].toUpperCase();
-			blend = string_replace_all(blend, " ", "_");
-			let use_clamp: bool = node.buttons[1].default_value == true;
-			let out_col: string = "";
-			if (blend == "MIX") {
-				out_col = `mix(${col1}, ${col2}, ${fac_var})`;
-			}
-			else if (blend == "DARKEN") {
-				out_col = `min(${col1}, ${col2} * ${fac_var})`;
-			}
-			else if (blend == "MULTIPLY") {
-				out_col = `mix(${col1}, ${col1} * ${col2}, ${fac_var})`;
-			}
-			else if (blend == "BURN") {
-				out_col = `mix(${col1}, vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - ${col1}) / ${col2}, ${fac_var})`;
-			}
-			else if (blend == "LIGHTEN") {
-				out_col = `max(${col1}, ${col2} * ${fac_var})`;
-			}
-			else if (blend == "SCREEN") {
-				out_col = `(vec3(1.0, 1.0, 1.0) - (` + ParserMaterial.to_vec3(`1.0 - ${fac_var}`) + ` + ${fac_var} * (vec3(1.0, 1.0, 1.0) - ${col2})) * (vec3(1.0, 1.0, 1.0) - ${col1}))`;
-			}
-			else if (blend == "DODGE") {
-				out_col = `mix(${col1}, ${col1} / (vec3(1.0, 1.0, 1.0) - ${col2}), ${fac_var})`;
-			}
-			else if (blend == "ADD") {
-				out_col = `mix(${col1}, ${col1} + ${col2}, ${fac_var})`;
-			}
-			else if (blend == "OVERLAY") {
-				out_col = `mix(${col1}, vec3(
-					${col1}.r < 0.5 ? 2.0 * ${col1}.r * ${col2}.r : 1.0 - 2.0 * (1.0 - ${col1}.r) * (1.0 - ${col2}.r),
-					${col1}.g < 0.5 ? 2.0 * ${col1}.g * ${col2}.g : 1.0 - 2.0 * (1.0 - ${col1}.g) * (1.0 - ${col2}.g),
-					${col1}.b < 0.5 ? 2.0 * ${col1}.b * ${col2}.b : 1.0 - 2.0 * (1.0 - ${col1}.b) * (1.0 - ${col2}.b)
-				), ${fac_var})`;
-			}
-			else if (blend == "SOFT_LIGHT") {
-				out_col = `((1.0 - ${fac_var}) * ${col1} + ${fac_var} * ((vec3(1.0, 1.0, 1.0) - ${col1}) * ${col2} * ${col1} + ${col1} * (vec3(1.0, 1.0, 1.0) - (vec3(1.0, 1.0, 1.0) - ${col2}) * (vec3(1.0, 1.0, 1.0) - ${col1}))))`;
-			}
-			else if (blend == "LINEAR_LIGHT") {
-				out_col = `(${col1} + ${fac_var} * (vec3(2.0, 2.0, 2.0) * (${col2} - vec3(0.5, 0.5, 0.5))))`;
-			}
-			else if (blend == "DIFFERENCE") {
-				out_col = `mix(${col1}, abs(${col1} - ${col2}), ${fac_var})`;
-			}
-			else if (blend == "SUBTRACT") {
-				out_col = `mix(${col1}, ${col1} - ${col2}, ${fac_var})`;
-			}
-			else if (blend == "DIVIDE") {
-				let eps: f32 = 0.000001;
-				col2 = `max(${col2}, vec3(${eps}, ${eps}, ${eps}))`;
-				out_col = "(" + ParserMaterial.to_vec3(`(1.0 - ${fac_var}) * ${col1} + ${fac_var} * ${col1} / ${col2}`) + ")";
-			}
-			else if (blend == "HUE") {
-				NodeShader.add_function(ParserMaterial.curshader, str_hue_sat);
-				out_col = `mix(${col1}, hsv_to_rgb(vec3(rgb_to_hsv(${col2}).r, rgb_to_hsv(${col1}).g, rgb_to_hsv(${col1}).b)), ${fac_var})`;
-			}
-			else if (blend == "SATURATION") {
-				NodeShader.add_function(ParserMaterial.curshader, str_hue_sat);
-				out_col = `mix(${col1}, hsv_to_rgb(vec3(rgb_to_hsv(${col1}).r, rgb_to_hsv(${col2}).g, rgb_to_hsv(${col1}).b)), ${fac_var})`;
-			}
-			else if (blend == "COLOR") {
-				NodeShader.add_function(ParserMaterial.curshader, str_hue_sat);
-				out_col = `mix(${col1}, hsv_to_rgb(vec3(rgb_to_hsv(${col2}).r, rgb_to_hsv(${col2}).g, rgb_to_hsv(${col1}).b)), ${fac_var})`;
-			}
-			else if (blend == "VALUE") {
-				NodeShader.add_function(ParserMaterial.curshader, str_hue_sat);
-				out_col = `mix(${col1}, hsv_to_rgb(vec3(rgb_to_hsv(${col1}).r, rgb_to_hsv(${col1}).g, rgb_to_hsv(${col2}).b)), ${fac_var})`;
-			}
-			if (use_clamp) return `clamp(${out_col}, vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0))`;
-			else return out_col;
-		}
-		else if (node.type == "QUANTIZE") {
-			let strength: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let col: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			return `(floor(100.0 * ${strength} * ${col}) / (100.0 * ${strength}))`;
-		}
-		else if (node.type == "VALTORGB") { // ColorRamp
-			let fac: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let interp: string = node.buttons[0].data == 0 ? "LINEAR" : "CONSTANT";
-			let elems: f32[][] = node.buttons[0].default_value;
-			if (elems.length == 1) {
-				return ParserMaterial.vec3(elems[0]);
-			}
-			// Write cols array
-			let cols_var: string = ParserMaterial.node_name(node) + "_cols";
-			NodeShader.write(ParserMaterial.curshader, `vec3 ${cols_var}[${elems.length}];`); // TODO: Make const
-			for (let i: i32 = 0; i < elems.length; ++i) {
-				NodeShader.write(ParserMaterial.curshader, `${cols_var}[${i}] = ${ParserMaterial.vec3(elems[i])};`);
-			}
-			// Get index
-			let fac_var: string = ParserMaterial.node_name(node) + "_fac";
-			NodeShader.write(ParserMaterial.curshader, `float ${fac_var} = ${fac};`);
-			let index: string = "0";
-			for (let i: i32 = 1; i < elems.length; ++i) {
-				index += ` + (${fac_var} > ${elems[i][4]} ? 1 : 0)`;
-			}
-			// Write index
-			let index_var: string = ParserMaterial.node_name(node) + "_i";
-			NodeShader.write(ParserMaterial.curshader, `int ${index_var} = ${index};`);
-			if (interp == "CONSTANT") {
-				return `${cols_var}[${index_var}]`;
-			}
-			else { // Linear
-				// Write facs array
-				let facs_var: string = ParserMaterial.node_name(node) + "_facs";
-				NodeShader.write(ParserMaterial.curshader, `float ${facs_var}[${elems.length}];`); // TODO: Make const
-				for (let i: i32 = 0; i < elems.length; ++i) {
-					NodeShader.write(ParserMaterial.curshader, `${facs_var}[${i}] = ${elems[i][4]};`);
-				}
-				// Mix color
-				// float f = (pos - start) * (1.0 / (finish - start))
-				return `mix(${cols_var}[${index_var}], ${cols_var}[${index_var} + 1], (${fac_var} - ${facs_var}[${index_var}]) * (1.0 / (${facs_var}[${index_var} + 1] - ${facs_var}[${index_var}]) ))`;
-			}
-		}
-		else if (node.type == "CURVE_VEC") {
-			let fac: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let vec: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let curves: any = node.buttons[0].default_value;
-			let name: string = ParserMaterial.node_name(node);
-			let vc0: string = ParserMaterial.vector_curve(name + "0", vec + ".x", curves[0]);
-			let vc1: string = ParserMaterial.vector_curve(name + "1", vec + ".y", curves[1]);
-			let vc2: string = ParserMaterial.vector_curve(name + "2", vec + ".z", curves[2]);
-			// mapping.curves[0].points[0].handle_type // bezier curve
-			return `(vec3(${vc0}, ${vc1}, ${vc2}) * ${fac})`;
-		}
-		else if (node.type == "CURVE_RGB") { // RGB Curves
-			let fac: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let vec: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let curves: any = node.buttons[0].default_value;
-			let name: string = ParserMaterial.node_name(node);
-			// mapping.curves[0].points[0].handle_type
-			let vc0: string = ParserMaterial.vector_curve(name + "0", vec + ".x", curves[0]);
-			let vc1: string = ParserMaterial.vector_curve(name + "1", vec + ".y", curves[1]);
-			let vc2: string = ParserMaterial.vector_curve(name + "2", vec + ".z", curves[2]);
-			let vc3a: string = ParserMaterial.vector_curve(name + "3a", vec + ".x", curves[3]);
-			let vc3b: string = ParserMaterial.vector_curve(name + "3b", vec + ".y", curves[3]);
-			let vc3c: string = ParserMaterial.vector_curve(name + "3c", vec + ".z", curves[3]);
-			return `(sqrt(vec3(${vc0}, ${vc1}, ${vc2}) * vec3(${vc3a}, ${vc3b}, ${vc3c})) * ${fac})`;
-		}
-		else if (node.type == "COMBHSV") {
-			NodeShader.add_function(ParserMaterial.curshader, str_hue_sat);
-			let h: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let s: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let v: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			return `hsv_to_rgb(vec3(${h}, ${s}, ${v}))`;
-		}
-		else if (node.type == "COMBRGB") {
-			let r: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let g: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let b: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			return `vec3(${r}, ${g}, ${b})`;
-		}
-		else if (node.type == "WAVELENGTH") {
-			NodeShader.add_function(ParserMaterial.curshader, str_wavelength_to_rgb);
-			let wl: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			NodeShader.add_function(ParserMaterial.curshader, str_wavelength_to_rgb);
-			return `wavelength_to_rgb((${wl} - 450.0) / 150.0)`;
-		}
-		else if (node.type == "CAMERA") {
-			ParserMaterial.curshader.vvec_cam = true;
-			return "vVecCam";
-		}
-		else if (node.type == "LAYER") {
-			let l: any = node.buttons[0].default_value;
-			if (socket == node.outputs[0]) { // Base
-				NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D texpaint" + l, "_texpaint" + l);
-				return "texture(texpaint" + l + ", texCoord).rgb";
-			}
-			else if (socket == node.outputs[5]) { // Normal
-				NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D texpaint_nor" + l, "_texpaint_nor" + l);
-				return "texture(texpaint_nor" + l + ", texCoord).rgb";
-			}
-		}
-		else if (node.type == "MATERIAL") {
-			let result: string = "vec3(0.0, 0.0, 0.0)";
-			let mi: any = node.buttons[0].default_value;
-			if (mi >= project_materials.length) return result;
-			let m: SlotMaterialRaw = project_materials[mi];
-			let _nodes: zui_node_t[] = ParserMaterial.nodes;
-			let _links: zui_node_link_t[] = ParserMaterial.links;
-			ParserMaterial.nodes = m.canvas.nodes;
-			ParserMaterial.links = m.canvas.links;
-			ParserMaterial.parents.push(node);
-			let output_node: zui_node_t = ParserMaterial.node_by_type(ParserMaterial.nodes, "OUTPUT_MATERIAL_PBR");
-			if (socket == node.outputs[0]) { // Base
-				result = ParserMaterial.parse_vector_input(output_node.inputs[0]);
-			}
-			else if (socket == node.outputs[5]) { // Normal
-				result = ParserMaterial.parse_vector_input(output_node.inputs[5]);
-			}
-			ParserMaterial.nodes = _nodes;
-			ParserMaterial.links = _links;
-			ParserMaterial.parents.pop();
-			return result;
-		}
-		else if (node.type == "PICKER") {
-			if (socket == node.outputs[0]) { // Base
-				NodeShader.add_uniform(ParserMaterial.curshader, "vec3 pickerBase", "_pickerBase");
-				return "pickerBase";
-			}
-			else if (socket == node.outputs[5]) { // Normal
-				NodeShader.add_uniform(ParserMaterial.curshader, "vec3 pickerNormal", "_pickerNormal");
-				return "pickerNormal";
-			}
-		}
-		else if (node.type == "NEW_GEOMETRY") {
-			if (socket == node.outputs[0]) { // Position
-				ParserMaterial.curshader.wposition = true;
-				return "wposition";
-			}
-			else if (socket == node.outputs[1]) { // Normal
-				ParserMaterial.curshader.n = true;
-				return "n";
-			}
-			else if (socket == node.outputs[2]) { // Tangent
-				ParserMaterial.curshader.wtangent = true;
-				return "wtangent";
-			}
-			else if (socket == node.outputs[3]) { // True Normal
-				ParserMaterial.curshader.n = true;
-				return "n";
-			}
-			else if (socket == node.outputs[4]) { // Incoming
-				ParserMaterial.curshader.vvec = true;
-				return "vVec";
-			}
-			else if (socket == node.outputs[5]) { // Parametric
-				ParserMaterial.curshader.mposition = true;
-				return "mposition";
-			}
-		}
-		else if (node.type == "OBJECT_INFO") {
-			if (socket == node.outputs[0]) { // Location
-				ParserMaterial.curshader.wposition = true;
-				return "wposition";
-			}
-			else if (socket == node.outputs[1]) { // Color
-				return "vec3(0.0, 0.0, 0.0)";
-			}
-		}
-		// else if (node.type == "PARTICLE_INFO") {
-		// 	if (socket == node.outputs[3]) { // Location
-		// 		return "vec3(0.0, 0.0, 0.0)";
-		// 	}
-		// 	else if (socket == node.outputs[5]) { // Velocity
-		// 		return "vec3(0.0, 0.0, 0.0)";
-		// 	}
-		// 	else if (socket == node.outputs[6]) { // Angular Velocity
-		// 		return "vec3(0.0, 0.0, 0.0)";
-		// 	}
-		// }
-		else if (node.type == "TANGENT") {
-			ParserMaterial.curshader.wtangent = true;
-			return "wtangent";
-		}
-		else if (node.type == "TEX_COORD") {
-			if (socket == node.outputs[0]) { // Generated - bounds
-				ParserMaterial.curshader.bposition = true;
-				return "bposition";
-			}
-			else if (socket == node.outputs[1]) { // Normal
-				ParserMaterial.curshader.n = true;
-				return "n";
-			}
-			else if (socket == node.outputs[2]) {// UV
-				NodeShaderContext.add_elem(ParserMaterial.curshader.context, "tex", "short2norm");
-				return "vec3(texCoord.x, texCoord.y, 0.0)";
-			}
-			else if (socket == node.outputs[3]) { // Object
-				ParserMaterial.curshader.mposition = true;
-				return "mposition";
-			}
-			else if (socket == node.outputs[4]) { // Camera
-				ParserMaterial.curshader.vposition = true;
-				return "vposition";
-			}
-			else if (socket == node.outputs[5]) { // Window
-				ParserMaterial.curshader.wvpposition = true;
-				return "wvpposition.xyz";
-			}
-			else if (socket == node.outputs[6]) { // Reflection
-				return "vec3(0.0, 0.0, 0.0)";
-			}
-		}
-		else if (node.type == "UVMAP") {
-			NodeShaderContext.add_elem(ParserMaterial.curshader.context, "tex", "short2norm");
-			return "vec3(texCoord.x, texCoord.y, 0.0)";
-		}
-		else if (node.type == "BUMP") {
-			let strength: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			// let distance: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let height: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			let nor: string = ParserMaterial.parse_vector_input(node.inputs[3]);
-			let sample_bump_res: string = ParserMaterial.store_var_name(node) + "_bump";
-			NodeShader.write(ParserMaterial.curshader, `float ${sample_bump_res}_x = dFdx(float(${height})) * (${strength}) * 16.0;`);
-			NodeShader.write(ParserMaterial.curshader, `float ${sample_bump_res}_y = dFdy(float(${height})) * (${strength}) * 16.0;`);
-			return `(normalize(vec3(${sample_bump_res}_x, ${sample_bump_res}_y, 1.0) + ${nor}) * vec3(0.5, 0.5, 0.5) + vec3(0.5, 0.5, 0.5))`;
-		}
-		else if (node.type == "MAPPING") {
-			let out: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			let node_translation: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let node_rotation: string = ParserMaterial.parse_vector_input(node.inputs[2]);
-			let node_scale: string = ParserMaterial.parse_vector_input(node.inputs[3]);
-			if (node_scale != `vec3(1, 1, 1)`) {
-				out = `(${out} * ${node_scale})`;
-			}
-			if (node_rotation != `vec3(0, 0, 0)`) {
-				// ZYX rotation, Z axis for now..
-				let a: string = `${node_rotation}.z * (3.1415926535 / 180)`;
-				// x * cos(theta) - y * sin(theta)
-				// x * sin(theta) + y * cos(theta)
-				out = `vec3(${out}.x * cos(${a}) - ${out}.y * sin(${a}), ${out}.x * sin(${a}) + ${out}.y * cos(${a}), 0.0)`;
-			}
-			// if node.rotation[1] != 0.0:
-			//     a = node.rotation[1]
-			//     out = `vec3({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1}, 0.0)`.format(out, math_cos(a), math_sin(a))
-			// if node.rotation[0] != 0.0:
-			//     a = node.rotation[0]
-			//     out = `vec3({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1}, 0.0)`.format(out, math_cos(a), math_sin(a))
-			if (node_translation != `vec3(0, 0, 0)`) {
-				out = `(${out} + ${node_translation})`;
-			}
-			// if node.use_min:
-				// out = `max({0}, vec3({1}, {2}, {3}))`.format(out, node.min[0], node.min[1])
-			// if node.use_max:
-				 // out = `min({0}, vec3({1}, {2}, {3}))`.format(out, node.max[0], node.max[1])
-			return out;
-		}
-		else if (node.type == "NORMAL") {
-			if (socket == node.outputs[0]) {
-				return ParserMaterial.vec3(node.outputs[0].default_value);
-			}
-			else if (socket == node.outputs[1]) {
-				let nor: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-				let norout: string = ParserMaterial.vec3(node.outputs[0].default_value);
-				return ParserMaterial.to_vec3(`dot(${norout}, ${nor})`);
-			}
-		}
-		else if (node.type == "NORMAL_MAP") {
-			let strength: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let norm: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-
-			let store: string = ParserMaterial.store_var_name(node);
-			NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_texn = ${norm} * 2.0 - 1.0;`);
-			NodeShader.write(ParserMaterial.curshader, `${store}_texn.xy = ${strength} * ${store}_texn.xy;`);
-			NodeShader.write(ParserMaterial.curshader, `${store}_texn = normalize(${store}_texn);`);
-
-			return `(0.5 * ${store}_texn + 0.5)`;
-		}
-		else if (node.type == "MIX_NORMAL_MAP") {
-			let nm1: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			let nm2: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let but: zui_node_button_t = node.buttons[0];
-			let blend: string = but.data[but.default_value].toUpperCase(); // blend_type
-			blend = string_replace_all(blend, " ", "_");
-			let store: string = ParserMaterial.store_var_name(node);
-
-			// The blending algorithms are based on the paper `Blending in Detail` by Colin Barré-Brisebois and Stephen Hill 2012
-			// https://blog.selfshadow.com/publications/blending-in-detail/
-			if (blend == "PARTIAL_DERIVATIVE") { //partial derivate blending
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_n1 = ${nm1} * 2.0 - 1.0;`);
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_n2 = ${nm2} * 2.0 - 1.0;`);
-				return `0.5 * normalize(vec3(${store}_n1.xy * ${store}_n2.z + ${store}_n2.xy * ${store}_n1.z, ${store}_n1.z * ${store}_n2.z)) + 0.5;`;
-			}
-			else if (blend == "WHITEOUT") { //whiteout blending
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_n1 = ${nm1} * 2.0 - 1.0;`);
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_n2 = ${nm2} * 2.0 - 1.0;`);
-				return `0.5 * normalize(vec3(${store}_n1.xy + ${store}_n2.xy, ${store}_n1.z * ${store}_n2.z)) + 0.5;`;
-			}
-			else if (blend == "REORIENTED") { //reoriented normal mapping
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_n1 = ${nm1} * 2.0 - vec3(1.0, 1.0, 0.0);`);
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_n2 = ${nm2} * vec3(-2.0, -2.0, 2.0) - vec3(-1.0, -1.0, 1.0);`);
-				return `0.5 * normalize(${store}_n1 * dot(${store}_n1, ${store}_n2) - ${store}_n2 * ${store}_n1.z) + 0.5`;
-			}
-		}
-		else if (node.type == "VECT_TRANSFORM") {
-		// 	type = node.vector_type
-		// 	conv_from = node.convert_from
-		// 	conv_to = node.convert_to
-		// 	// Pass throuh
-		// 	return ParserMaterial.parse_vector_input(node.inputs[0])
-		}
-		else if (node.type == "COMBXYZ") {
-			let x: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let y: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let z: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			return `vec3(${x}, ${y}, ${z})`;
-		}
-		else if (node.type == "VECT_MATH") {
-			let vec1: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			let vec2: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let but: zui_node_button_t = node.buttons[0]; //operation;
-			let op: string = but.data[but.default_value].toUpperCase();
-			op = string_replace_all(op, " ", "_");
-			if (op == "ADD") {
-				return `(${vec1} + ${vec2})`;
-			}
-			else if (op == "SUBTRACT") {
-				return `(${vec1} - ${vec2})`;
-			}
-			else if (op == "AVERAGE") {
-				return `((${vec1} + ${vec2}) / 2.0)`;
-			}
-			else if (op == "DOT_PRODUCT") {
-				return ParserMaterial.to_vec3(`dot(${vec1}, ${vec2})`);
-			}
-			else if (op == "LENGTH") {
-				return ParserMaterial.to_vec3(`length(${vec1})`);
-			}
-			else if (op == "DISTANCE") {
-				return ParserMaterial.to_vec3(`distance(${vec1}, ${vec2})`);
-			}
-			else if (op == "CROSS_PRODUCT") {
-				return `cross(${vec1}, ${vec2})`;
-			}
-			else if (op == "NORMALIZE") {
-				return `normalize(${vec1})`;
-			}
-			else if (op == "MULTIPLY") {
-				return `(${vec1} * ${vec2})`;
-			}
-			else if (op == "DIVIDE") {
-				return `vec3(${vec1}.x / (${vec2}.x == 0 ? 0.000001 : ${vec2}.x), ${vec1}.y / (${vec2}.y == 0 ? 0.000001 : ${vec2}.y), ${vec1}.z / (${vec2}.z == 0 ? 0.000001 : ${vec2}.z))`;
-			}
-			else if (op == "PROJECT") {
-				return `(dot(${vec1}, ${vec2}) / dot(${vec2}, ${vec2}) * ${vec2})`;
-			}
-			else if (op == "REFLECT") {
-				return `reflect(${vec1}, normalize(${vec2}))`;
-			}
-			else if (op == "SCALE") {
-				return `(${vec2}.x * ${vec1})`;
-			}
-			else if (op == "ABSOLUTE") {
-				return `abs(${vec1})`;
-			}
-			else if (op == "MINIMUM") {
-				return `min(${vec1}, ${vec2})`;
-			}
-			else if (op == "MAXIMUM") {
-				return `max(${vec1}, ${vec2})`;
-			}
-			else if (op == "FLOOR") {
-				return `floor(${vec1})`;
-			}
-			else if (op == "CEIL") {
-				return `ceil(${vec1})`;
-			}
-			else if (op == "FRACTION") {
-				return `fract(${vec1})`;
-			}
-			else if (op == "MODULO") {
-				return `mod(${vec1}, ${vec2})`;
-			}
-			else if(op == "SNAP") {
-				return `(floor(${vec1} / ${vec2}) * ${vec2})`;
-			}
-			else if (op == "SINE") {
-				return `sin(${vec1})`;
-			}
-			else if (op == "COSINE") {
-				return `cos(${vec1})`;
-			}
-			else if (op == "TANGENT") {
-				return `tan(${vec1})`;
-			}
-		}
-		else if (node.type == "Displacement") {
-			let height: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			return ParserMaterial.to_vec3(`${height}`);
-		}
-		else if (ParserMaterial.custom_nodes.get(node.type) != null) {
-			return ParserMaterial.custom_nodes.get(node.type)(node, socket);
-		}
-		return "vec3(0.0, 0.0, 0.0)";
-	}
-
-	static parse_normal_map_color_input = (inp: zui_node_socket_t) => {
-		ParserMaterial.frag.write_normal++;
-		ParserMaterial.out_normaltan = ParserMaterial.parse_vector_input(inp);
-		if (!ParserMaterial.arm_export_tangents) {
-			NodeShader.write(ParserMaterial.frag, `vec3 texn = (${ParserMaterial.out_normaltan}) * 2.0 - 1.0;`);
-			NodeShader.write(ParserMaterial.frag, `texn.y = -texn.y;`);
-			if (!ParserMaterial.cotangent_frame_written) {
-				ParserMaterial.cotangent_frame_written = true;
-				NodeShader.add_function(ParserMaterial.frag, str_cotangent_frame);
-			}
-			ParserMaterial.frag.n = true;
-			///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-			NodeShader.write(ParserMaterial.frag, `mat3 TBN = cotangentFrame(n, vVec, texCoord);`);
-			///else
-			NodeShader.write(ParserMaterial.frag, `mat3 TBN = cotangentFrame(n, -vVec, texCoord);`);
-			///end
-
-			NodeShader.write(ParserMaterial.frag, `n = mul(normalize(texn), TBN);`);
-		}
-		ParserMaterial.frag.write_normal--;
-	}
-
-	static parse_value_input = (inp: zui_node_socket_t, vector_as_grayscale = false) : string => {
-		let l: zui_node_link_t = ParserMaterial.get_input_link(inp);
-		let from_node: zui_node_t = l != null ? ParserMaterial.get_node(l.from_id) : null;
-		if (from_node != null) {
-			if (from_node.type == "REROUTE") {
-				return ParserMaterial.parse_value_input(from_node.inputs[0]);
-			}
-
-			let res_var: string = ParserMaterial.write_result(l);
-			let st: string = from_node.outputs[l.from_socket].type;
-			if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
-				if (vector_as_grayscale) {
-					return `dot(${res_var}.rbg, vec3(0.299, 0.587, 0.114))`;
-				}
-				else {
-					return `${res_var}.x`;
-				}
-			}
-			else { // VALUE
-				return res_var;
-			}
-		}
-		else {
-			return ParserMaterial.vec1(inp.default_value);
-		}
-	}
-
-	static parse_value = (node: zui_node_t, socket: zui_node_socket_t): string => {
-		if (node.type == `GROUP`) {
-			return ParserMaterial.parse_group(node, socket);
-		}
-		else if (node.type == `GROUP_INPUT`) {
-			return ParserMaterial.parse_group_input(node, socket);
-		}
-		else if (node.type == "ATTRIBUTE") {
-			NodeShader.add_uniform(ParserMaterial.curshader, "float time", "_time");
-			return "time";
-		}
-		else if (node.type == "VERTEX_COLOR") {
-			return "1.0";
-		}
-		else if (node.type == "WIREFRAME") {
-			NodeShader.add_uniform(ParserMaterial.curshader, `sampler2D texuvmap`, `_texuvmap`);
-			// let use_pixel_size: bool = node.buttons[0].default_value == "true";
-			// let pixel_size: f32 = ParserMaterial.parse_value_input(node.inputs[0]);
-			return "textureLod(texuvmap, texCoord, 0.0).r";
-		}
-		else if (node.type == "CAMERA") {
-			if (socket == node.outputs[1]) { // View Z Depth
-				NodeShader.add_uniform(ParserMaterial.curshader, "vec2 cameraProj", "_camera_plane_proj");
-				///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-				ParserMaterial.curshader.wvpposition = true;
-				return "(cameraProj.y / ((wvpposition.z / wvpposition.w) - cameraProj.x))";
-				///else
-				return "(cameraProj.y / (gl_FragCoord.z - cameraProj.x))";
-				///end
-			}
-			else { // View Distance
-				NodeShader.add_uniform(ParserMaterial.curshader, "vec3 eye", "_camera_pos");
-				ParserMaterial.curshader.wposition = true;
-				return "distance(eye, wposition)";
-			}
-		}
-		else if (node.type == "LAYER") {
-			let l: any = node.buttons[0].default_value;
-			if (socket == node.outputs[1]) { // Opac
-				NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D texpaint" + l, "_texpaint" + l);
-				return "texture(texpaint" + l + ", texCoord).a";
-			}
-			else if (socket == node.outputs[2]) { // Occ
-				NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
-				return "texture(texpaint_pack" + l + ", texCoord).r";
-			}
-			else if (socket == node.outputs[3]) { // Rough
-				NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
-				return "texture(texpaint_pack" + l + ", texCoord).g";
-			}
-			else if (socket == node.outputs[4]) { // Metal
-				NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
-				return "texture(texpaint_pack" + l + ", texCoord).b";
-			}
-			else if (socket == node.outputs[7]) { // Height
-				NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D texpaint_pack" + l, "_texpaint_pack" + l);
-				return "texture(texpaint_pack" + l + ", texCoord).a";
-			}
-		}
-		else if (node.type == "LAYER_MASK") {
-			if (socket == node.outputs[0]) {
-				let l: any = node.buttons[0].default_value;
-				NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D texpaint" + l, "_texpaint" + l);
-				return "texture(texpaint" + l + ", texCoord).r";
-			}
-		}
-		else if (node.type == "MATERIAL") {
-			let result: string = "0.0";
-			let mi: any = node.buttons[0].default_value;
-			if (mi >= project_materials.length) return result;
-			let m: SlotMaterialRaw = project_materials[mi];
-			let _nodes: zui_node_t[] = ParserMaterial.nodes;
-			let _links: zui_node_link_t[] = ParserMaterial.links;
-			ParserMaterial.nodes = m.canvas.nodes;
-			ParserMaterial.links = m.canvas.links;
-			ParserMaterial.parents.push(node);
-			let output_node: zui_node_t = ParserMaterial.node_by_type(ParserMaterial.nodes, "OUTPUT_MATERIAL_PBR");
-			if (socket == node.outputs[1]) { // Opac
-				result = ParserMaterial.parse_value_input(output_node.inputs[1]);
-			}
-			else if (socket == node.outputs[2]) { // Occ
-				result = ParserMaterial.parse_value_input(output_node.inputs[2]);
-			}
-			else if (socket == node.outputs[3]) { // Rough
-				result = ParserMaterial.parse_value_input(output_node.inputs[3]);
-			}
-			else if (socket == node.outputs[4]) { // Metal
-				result = ParserMaterial.parse_value_input(output_node.inputs[4]);
-			}
-			else if (socket == node.outputs[7]) { // Height
-				result = ParserMaterial.parse_value_input(output_node.inputs[7]);
-			}
-			ParserMaterial.nodes = _nodes;
-			ParserMaterial.links = _links;
-			ParserMaterial.parents.pop();
-			return result;
-		}
-		else if (node.type == "PICKER") {
-			if (socket == node.outputs[1]) {
-				NodeShader.add_uniform(ParserMaterial.curshader, "float pickerOpacity", "_pickerOpacity");
-				return "pickerOpacity";
-			}
-			else if (socket == node.outputs[2]) {
-				NodeShader.add_uniform(ParserMaterial.curshader, "float pickerOcclusion", "_pickerOcclusion");
-				return "pickerOcclusion";
-			}
-			else if (socket == node.outputs[3]) {
-				NodeShader.add_uniform(ParserMaterial.curshader, "float pickerRoughness", "_pickerRoughness");
-				return "pickerRoughness";
-			}
-			else if (socket == node.outputs[4]) {
-				NodeShader.add_uniform(ParserMaterial.curshader, "float pickerMetallic", "_pickerMetallic");
-				return "pickerMetallic";
-			}
-			else if (socket == node.outputs[7]) {
-				NodeShader.add_uniform(ParserMaterial.curshader, "float pickerHeight", "_pickerHeight");
-				return "pickerHeight";
-			}
-		}
-		else if (node.type == "FRESNEL") {
-			let ior: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			ParserMaterial.curshader.dotnv = true;
-			return `pow(1.0 - dotNV, 7.25 / ${ior})`;
-		}
-		else if (node.type == "NEW_GEOMETRY") {
-			if (socket == node.outputs[6]) { // Backfacing
-				///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-				return "0.0"; // SV_IsFrontFace
-				///else
-				return "(1.0 - float(gl_FrontFacing))";
-				///end
-			}
-			else if (socket == node.outputs[7]) { // Pointiness
-				let strength: f32 = 1.0;
-				let radius: f32 = 1.0;
-				let offset: f32 = 0.0;
-				let store: string = ParserMaterial.store_var_name(node);
-				ParserMaterial.curshader.n = true;
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_dx = dFdx(n);`);
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${store}_dy = dFdy(n);`);
-				NodeShader.write(ParserMaterial.curshader, `float ${store}_curvature = max(dot(${store}_dx, ${store}_dx), dot(${store}_dy, ${store}_dy));`);
-				NodeShader.write(ParserMaterial.curshader, `${store}_curvature = clamp(pow(${store}_curvature, (1.0 / ` + radius + `) * 0.25) * ` + strength + ` * 2.0 + ` + offset + ` / 10.0, 0.0, 1.0);`);
-				return `${store}_curvature`;
-			}
-			else if (socket == node.outputs[8]) { // Random Per Island
-				return "0.0";
-			}
-		}
-		else if (node.type == "HAIR_INFO") {
-			return "0.5";
-		}
-		else if (node.type == "LAYER_WEIGHT") {
-			let blend: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			if (socket == node.outputs[0]) { // Fresnel
-				ParserMaterial.curshader.dotnv = true;
-				return `clamp(pow(1.0 - dotNV, (1.0 - ${blend}) * 10.0), 0.0, 1.0)`;
-			}
-			else if (socket == node.outputs[1]) { // Facing
-				ParserMaterial.curshader.dotnv = true;
-				return `((1.0 - dotNV) * ${blend})`;
-			}
-		}
-		else if (node.type == "OBJECT_INFO") {
-			if (socket == node.outputs[1]) { // Object Index
-				NodeShader.add_uniform(ParserMaterial.curshader, "float objectInfoIndex", "_object_info_index");
-				return "objectInfoIndex";
-			}
-			else if (socket == node.outputs[2]) { // Material Index
-				NodeShader.add_uniform(ParserMaterial.curshader, "float objectInfoMaterialIndex", "_object_info_material_index");
-				return "objectInfoMaterialIndex";
-			}
-			else if (socket == node.outputs[3]) { // Random
-				NodeShader.add_uniform(ParserMaterial.curshader, "float objectInfoRandom", "_object_info_random");
-				return "objectInfoRandom";
-			}
-		}
-		else if (node.type == "VALUE") {
-			return ParserMaterial.vec1(node.outputs[0].default_value);
-		}
-		else if (node.type == "TEX_BRICK") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_brick);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[4]);
-			let res: string = `tex_brick_f(${co} * ${scale})`;
-			return res;
-		}
-		else if (node.type == "TEX_CHECKER") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_checker);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[3]);
-			let res: string = `tex_checker_f(${co}, ${scale})`;
-			return res;
-		}
-		else if (node.type == "TEX_GRADIENT") {
-			let co: string = ParserMaterial.get_coord(node);
-			let but: zui_node_button_t = node.buttons[0]; //gradient_type;
-			let grad: string = but.data[but.default_value].toUpperCase();
-			grad = string_replace_all(grad, " ", "_");
-			let f: string = ParserMaterial.get_gradient(grad, co);
-			let res: string = `(clamp(${f}, 0.0, 1.0))`;
-			return res;
-		}
-		else if (node.type == "TEX_IMAGE") {
-			// Already fetched
-			if (ParserMaterial.parsed.indexOf(ParserMaterial.res_var_name(node, node.outputs[0])) >= 0) { // TODO: node.outputs[1]
-				let varname: string = ParserMaterial.store_var_name(node);
-				return `${varname}.a`;
-			}
-			let tex_name: string = ParserMaterial.node_name(node);
-			let tex: bind_tex_t = ParserMaterial.make_texture(node, tex_name);
-			if (tex != null) {
-				let color_space: i32 = node.buttons[1].default_value;
-				let texstore: string = ParserMaterial.texture_store(node, tex, tex_name, color_space);
-				return `${texstore}.a`;
-			}
-		}
-		else if (node.type == "TEX_MAGIC") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_magic);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let res: string = `tex_magic_f(${co} * ${scale} * 4.0)`;
-			return res;
-		}
-		else if (node.type == "TEX_MUSGRAVE") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_musgrave);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let res: string = `tex_musgrave_f(${co} * ${scale} * 0.5)`;
-			return res;
-		}
-		else if (node.type == "TEX_NOISE") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_noise);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let res: string = `tex_noise(${co} * ${scale})`;
-			return res;
-		}
-		else if (node.type == "TEX_VORONOI") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_voronoi);
-			NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D snoise256", "$noise256.k");
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let but: zui_node_button_t = node.buttons[0]; // coloring
-			let coloring: string = but.data[but.default_value].toUpperCase();
-			coloring = string_replace_all(coloring, " ", "_");
-			let res: string = "";
-			if (coloring == "INTENSITY") {
-				res = `tex_voronoi(${co} * ${scale}, texturePass(snoise256)).a`;
-			}
-			else { // Cells
-				res = `tex_voronoi(${co} * ${scale}, texturePass(snoise256)).r`;
-			}
-			return res;
-		}
-		else if (node.type == "TEX_WAVE") {
-			NodeShader.add_function(ParserMaterial.curshader, str_tex_wave);
-			let co: string = ParserMaterial.get_coord(node);
-			let scale: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let res: string = `tex_wave_f(${co} * ${scale})`;
-			return res;
-		}
-		else if (node.type == "BAKE_CURVATURE") {
-			if (ParserMaterial.bake_passthrough) {
-				ParserMaterial.bake_passthrough_strength = ParserMaterial.parse_value_input(node.inputs[0]);
-				ParserMaterial.bake_passthrough_radius = ParserMaterial.parse_value_input(node.inputs[1]);
-				ParserMaterial.bake_passthrough_offset = ParserMaterial.parse_value_input(node.inputs[2]);
-				return "0.0";
-			}
-			let tex_name: string = "texbake_" + ParserMaterial.node_name(node);
-			NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D " + tex_name, "_" + tex_name);
-			let store: string = ParserMaterial.store_var_name(node);
-			NodeShader.write(ParserMaterial.curshader, `float ${store}_res = texture(${tex_name}, texCoord).r;`);
-			return `${store}_res`;
-		}
-		else if (node.type == "NORMAL") {
-			let nor: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			let norout: string = ParserMaterial.vec3(node.outputs[0].default_value);
-			return `dot(${norout}, ${nor})`;
-		}
-		else if (node.type == "COLMASK") {
-			let inputColor: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			let maskColor: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let radius: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			let fuzziness: string = ParserMaterial.parse_value_input(node.inputs[3]);
-			return `clamp(1.0 - (distance(${inputColor}, ${maskColor}) - ${radius}) / max(${fuzziness}, ${ParserMaterial.eps}), 0.0, 1.0)`;
-		}
-		else if (node.type == "MATH") {
-			let val1: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let val2: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let but: zui_node_button_t = node.buttons[0]; // operation
-			let op: string = but.data[but.default_value].toUpperCase();
-			op = string_replace_all(op, " ", "_");
-			let use_clamp: bool = node.buttons[1].default_value == true;
-			let out_val: string = "";
-			if (op == "ADD") {
-				out_val = `(${val1} + ${val2})`;
-			}
-			else if (op == "SUBTRACT") {
-				out_val = `(${val1} - ${val2})`;
-			}
-			else if (op == "MULTIPLY") {
-				out_val = `(${val1} * ${val2})`;
-			}
-			else if (op == "DIVIDE") {
-				val2 = `(${val2} == 0.0 ? ${ParserMaterial.eps} : ${val2})`;
-				out_val = `(${val1} / ${val2})`;
-			}
-			else if (op == "POWER") {
-				out_val = `pow(${val1}, ${val2})`;
-			}
-			else if (op == "LOGARITHM") {
-				out_val = `log(${val1})`;
-			}
-			else if (op == "SQUARE_ROOT") {
-				out_val = `sqrt(${val1})`;
-			}
-			else if(op == "INVERSE_SQUARE_ROOT") {
-				out_val = `inversesqrt(${val1})`;
-			}
-			else if (op == "EXPONENT") {
-				out_val = `exp(${val1})`;
-			}
-			else if (op == "ABSOLUTE") {
-				out_val = `abs(${val1})`;
-			}
-			else if (op == "MINIMUM") {
-				out_val = `min(${val1}, ${val2})`;
-			}
-			else if (op == "MAXIMUM") {
-				out_val = `max(${val1}, ${val2})`;
-			}
-			else if (op == "LESS_THAN") {
-				out_val = `float(${val1} < ${val2})`;
-			}
-			else if (op == "GREATER_THAN") {
-				out_val = `float(${val1} > ${val2})`;
-			}
-			else if (op == "SIGN") {
-				out_val = `sign(${val1})`;
-			}
-			else if (op == "ROUND") {
-				out_val = `floor(${val1} + 0.5)`;
-			}
-			else if (op == "FLOOR") {
-				out_val = `floor(${val1})`;
-			}
-			else if (op == "CEIL") {
-				out_val = `ceil(${val1})`;
-			}
-			else if(op == "SNAP") {
-				out_val = `(floor(${val1} / ${val2}) * ${val2})`;
-			}
-			else if (op == "TRUNCATE") {
-				out_val = `trunc(${val1})`;
-			}
-			else if (op == "FRACTION") {
-				out_val = `fract(${val1})`;
-			}
-			else if (op == "MODULO") {
-				out_val = `mod(${val1}, ${val2})`;
-			}
-			else if (op == "PING-PONG") {
-				out_val = `((${val2} != 0.0) ? abs(fract((${val1} - ${val2}) / (${val2} * 2.0)) * ${val2} * 2.0 - ${val2}) : 0.0)`;
-			}
-			else if (op == "SINE") {
-				out_val = `sin(${val1})`;
-			}
-			else if (op == "COSINE") {
-				out_val = `cos(${val1})`;
-			}
-			else if (op == "TANGENT") {
-				out_val = `tan(${val1})`;
-			}
-			else if (op == "ARCSINE") {
-				out_val = `asin(${val1})`;
-			}
-			else if (op == "ARCCOSINE") {
-				out_val = `acos(${val1})`;
-			}
-			else if (op == "ARCTANGENT") {
-				out_val = `atan(${val1})`;
-			}
-			else if (op == "ARCTAN2") {
-				out_val = `atan2(${val1}, ${val2})`;
-			}
-			else if (op == "HYPERBOLIC_SINE") {
-				out_val = `sinh(${val1})`;
-			}
-			else if (op == "HYPERBOLIC_COSINE") {
-				out_val = `cosh(${val1})`;
-			}
-			else if (op == "HYPERBOLIC_TANGENT") {
-				out_val = `tanh(${val1})`;
-			}
-			else if (op == "TO_RADIANS") {
-				out_val = `radians(${val1})`;
-			}
-			else if (op == "TO_DEGREES") {
-				out_val = `degrees(${val1})`;
-			}
-			if (use_clamp) {
-				return `clamp(${out_val}, 0.0, 1.0)`;
-			}
-			else {
-				return out_val;
-			}
-		}
-		else if (node.type == "SCRIPT_CPU") {
-			if (ParserMaterial.script_links == null) ParserMaterial.script_links = map_create();
-			let script: any = node.buttons[0].default_value;
-			let link: string = ParserMaterial.node_name(node);
-			ParserMaterial.script_links.set(link, script);
-			NodeShader.add_uniform(ParserMaterial.curshader, "float " + link, "_" + link);
-			return link;
-		}
-		else if (node.type == "SHADER_GPU") {
-			let shader: any = node.buttons[0].default_value;
-			return shader == "" ? "0.0" : shader;
-		}
-		else if (node.type == "RGBTOBW") {
-			let col: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			return `(((${col}.r * 0.3 + ${col}.g * 0.59 + ${col}.b * 0.11) / 3.0) * 2.5)`;
-		}
-		else if (node.type == "SEPHSV") {
-			NodeShader.add_function(ParserMaterial.curshader, str_hue_sat);
-			let col: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			if (socket == node.outputs[0]) {
-				return `rgb_to_hsv(${col}).r`;
-			}
-			else if (socket == node.outputs[1]) {
-				return `rgb_to_hsv(${col}).g`;
-			}
-			else if (socket == node.outputs[2]) {
-				return `rgb_to_hsv(${col}).b`;
-			}
-		}
-		else if (node.type == "SEPRGB") {
-			let col: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			if (socket == node.outputs[0]) {
-				return `${col}.r`;
-			}
-			else if (socket == node.outputs[1]) {
-				return `${col}.g`;
-			}
-			else if (socket == node.outputs[2]) {
-				return `${col}.b`;
-			}
-		}
-		else if (node.type == "SEPXYZ") {
-			let vec: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			if (socket == node.outputs[0]) {
-				return `${vec}.x`;
-			}
-			else if (socket == node.outputs[1]) {
-				return `${vec}.y`;
-			}
-			else if (socket == node.outputs[2]) {
-				return `${vec}.z`;
-			}
-		}
-		else if (node.type == "VECT_MATH") {
-			let vec1: string = ParserMaterial.parse_vector_input(node.inputs[0]);
-			let vec2: string = ParserMaterial.parse_vector_input(node.inputs[1]);
-			let but: zui_node_button_t = node.buttons[0]; //operation;
-			let op: string = but.data[but.default_value].toUpperCase();
-			op = string_replace_all(op, " ", "_");
-			if (op == "DOT_PRODUCT") {
-				return `dot(${vec1}, ${vec2})`;
-			}
-			else if (op == "LENGTH") {
-				return `length(${vec1})`;
-			}
-			else if (op == "DISTANCE") {
-				return `distance(${vec1}, ${vec2})`;
-			}
-			else {
-				return "0.0";
-			}
-		}
-		else if (node.type == "CLAMP") {
-			let val: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let min: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let max: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			let but: zui_node_button_t = node.buttons[0]; //operation;
-			let op: string = but.data[but.default_value].toUpperCase();
-			op = string_replace_all(op, " ", "_");
-
-			if (op == "MIN_MAX") {
-				return `(clamp(${val}, ${min}, ${max}))`;
-			}
-			else if (op == "RANGE") {
-				return `(clamp(${val}, min(${min}, ${max}), max(${min}, ${max})))`;
-			}
-		}
-		else if (node.type == "MAPRANGE") {
-			let val: string = ParserMaterial.parse_value_input(node.inputs[0]);
-			let fmin: string = ParserMaterial.parse_value_input(node.inputs[1]);
-			let fmax: string = ParserMaterial.parse_value_input(node.inputs[2]);
-			let tmin: string = ParserMaterial.parse_value_input(node.inputs[3]);
-			let tmax: string = ParserMaterial.parse_value_input(node.inputs[4]);
-
-			let use_clamp: bool = node.buttons[0].default_value == true;
-
-			let a: string = `((${tmin} - ${tmax}) / (${fmin} - ${fmax}))`;
-			let out_val: string = `(${a} * ${val} + ${tmin} - ${a} * ${fmin})`;
-			if (use_clamp) {
-				return `(clamp(${out_val}, ${tmin}, ${tmax}))`;
-			}
-			else {
-				return out_val;
-			}
-		}
-		else if (ParserMaterial.custom_nodes.get(node.type) != null) {
-			return ParserMaterial.custom_nodes.get(node.type)(node, socket);
-		}
-		return "0.0";
-	}
-
-	static get_coord = (node: zui_node_t): string => {
-		if (ParserMaterial.get_input_link(node.inputs[0]) != null) {
-			return ParserMaterial.parse_vector_input(node.inputs[0]);
-		}
-		else {
-			ParserMaterial.curshader.bposition = true;
-			return "bposition";
-		}
-	}
-
-	static get_gradient = (grad: string, co: string): string => {
-		if (grad == "LINEAR") {
-			return `${co}.x`;
-		}
-		else if (grad == "QUADRATIC") {
-			return "0.0";
-		}
-		else if (grad == "EASING") {
-			return "0.0";
-		}
-		else if (grad == "DIAGONAL") {
-			return `(${co}.x + ${co}.y) * 0.5`;
-		}
-		else if (grad == "RADIAL") {
-			return `atan2(${co}.x, ${co}.y) / (3.141592 * 2.0) + 0.5`;
-		}
-		else if (grad == "QUADRATIC_SPHERE") {
-			return "0.0";
-		}
-		else { // "SPHERICAL"
-			return `max(1.0 - sqrt(${co}.x * ${co}.x + ${co}.y * ${co}.y + ${co}.z * ${co}.z), 0.0)`;
-		}
-	}
-
-	static vector_curve = (name: string, fac: string, points: Float32Array[]): string => {
-		// Write Ys array
-		let ys_var: string = name + "_ys";
-		let num: i32 = points.length;
-		NodeShader.write(ParserMaterial.curshader, `float ${ys_var}[${num}];`); // TODO: Make const
-		for (let i: i32 = 0; i < num; ++i) {
-			NodeShader.write(ParserMaterial.curshader, `${ys_var}[${i}] = ${points[i][1]};`);
-		}
-		// Get index
-		let fac_var: string = name + "_fac";
-		NodeShader.write(ParserMaterial.curshader, `float ${fac_var} = ${fac};`);
-		let index: string = "0";
-		for (let i: i32 = 1; i < num; ++i) {
-			index += ` + (${fac_var} > ${points[i][0]} ? 1 : 0)`;
-		}
-		// Write index
-		let index_var: string = name + "_i";
-		NodeShader.write(ParserMaterial.curshader, `int ${index_var} = ${index};`);
-		// Linear
-		// Write Xs array
-		let facs_var: string = name + "_xs";
-		NodeShader.write(ParserMaterial.curshader, `float ${facs_var}[${num}];`); // TODO: Make const
-		for (let i: i32 = 0; i < num; ++i) {
-			NodeShader.write(ParserMaterial.curshader, `${facs_var}[${i}] = ${points[i][0]};`);
-		}
-		// Map vector
-		return `mix(${ys_var}[${index_var}], ${ys_var}[${index_var} + 1], (${fac_var} - ${facs_var}[${index_var}]) * (1.0 / (${facs_var}[${index_var} + 1] - ${facs_var}[${index_var}])))`;
-	}
-
-	static res_var_name = (node: zui_node_t, socket: zui_node_socket_t): string => {
-		return ParserMaterial.node_name(node) + "_" + ParserMaterial.safesrc(socket.name) + "_res";
-	}
-
-	static write_result = (l: zui_node_link_t): string => {
-		let from_node: zui_node_t = ParserMaterial.get_node(l.from_id);
-		let from_socket: zui_node_socket_t = from_node.outputs[l.from_socket];
-		let res_var: string = ParserMaterial.res_var_name(from_node, from_socket);
-		let st: string = from_socket.type;
-		if (ParserMaterial.parsed.indexOf(res_var) < 0) {
-			ParserMaterial.parsed.push(res_var);
-			if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
-				let res: string = ParserMaterial.parse_vector(from_node, from_socket);
-				if (res == null) {
-					return null;
-				}
-				ParserMaterial.parsedMap.set(res_var, res);
-				NodeShader.write(ParserMaterial.curshader, `vec3 ${res_var} = ${res};`);
-			}
-			else if (st == "VALUE") {
-				let res: string = ParserMaterial.parse_value(from_node, from_socket);
-				if (res == null) {
-					return null;
-				}
-				ParserMaterial.parsedMap.set(res_var, res);
-				NodeShader.write(ParserMaterial.curshader, `float ${res_var} = ${res};`);
-			}
-		}
-		return res_var;
-	}
-
-	static store_var_name = (node: zui_node_t): string => {
-		return ParserMaterial.node_name(node) + "_store";
-	}
-
-	static texture_store = (node: zui_node_t, tex: bind_tex_t, tex_name: string, color_space: i32): string => {
-		ParserMaterial.matcon.bind_textures.push(tex);
-		NodeShaderContext.add_elem(ParserMaterial.curshader.context, "tex", "short2norm");
-		NodeShader.add_uniform(ParserMaterial.curshader, "sampler2D " + tex_name);
-		let uv_name: string = "";
-		if (ParserMaterial.get_input_link(node.inputs[0]) != null) {
-			uv_name = ParserMaterial.parse_vector_input(node.inputs[0]);
-		}
-		else {
-			uv_name = ParserMaterial.tex_coord;
-		}
-		let tex_store: string = ParserMaterial.store_var_name(node);
-
-		if (ParserMaterial.sample_keep_aspect) {
-			NodeShader.write(ParserMaterial.curshader, `vec2 ${tex_store}_size = vec2(textureSize(${tex_name}, 0));`);
-			NodeShader.write(ParserMaterial.curshader, `float ${tex_store}_ax = ${tex_store}_size.x / ${tex_store}_size.y;`);
-			NodeShader.write(ParserMaterial.curshader, `float ${tex_store}_ay = ${tex_store}_size.y / ${tex_store}_size.x;`);
-			NodeShader.write(ParserMaterial.curshader, `vec2 ${tex_store}_uv = ((${uv_name}.xy / ${ParserMaterial.sample_uv_scale} - vec2(0.5, 0.5)) * vec2(max(${tex_store}_ay, 1.0), max(${tex_store}_ax, 1.0))) + vec2(0.5, 0.5);`);
-			NodeShader.write(ParserMaterial.curshader, `if (${tex_store}_uv.x < 0.0 || ${tex_store}_uv.y < 0.0 || ${tex_store}_uv.x > 1.0 || ${tex_store}_uv.y > 1.0) discard;`);
-			NodeShader.write(ParserMaterial.curshader, `${tex_store}_uv *= ${ParserMaterial.sample_uv_scale};`);
-			uv_name = `${tex_store}_uv`;
-		}
-
-		if (ParserMaterial.triplanar) {
-			NodeShader.write(ParserMaterial.curshader, `vec4 ${tex_store} = vec4(0.0, 0.0, 0.0, 0.0);`);
-			NodeShader.write(ParserMaterial.curshader, `if (texCoordBlend.x > 0) ${tex_store} += texture(${tex_name}, ${uv_name}.xy) * texCoordBlend.x;`);
-			NodeShader.write(ParserMaterial.curshader, `if (texCoordBlend.y > 0) ${tex_store} += texture(${tex_name}, ${uv_name}1.xy) * texCoordBlend.y;`);
-			NodeShader.write(ParserMaterial.curshader, `if (texCoordBlend.z > 0) ${tex_store} += texture(${tex_name}, ${uv_name}2.xy) * texCoordBlend.z;`);
-		}
-		else {
-			if (ParserMaterial.curshader == ParserMaterial.frag) {
-				ParserMaterial.textureMap.set(tex_store, `texture(${tex_name}, ${uv_name}.xy)`);
-				NodeShader.write(ParserMaterial.curshader, `vec4 ${tex_store} = texture(${tex_name}, ${uv_name}.xy);`);
-			}
-			else {
-				ParserMaterial.textureMap.set(tex_store, `textureLod(${tex_name}, ${uv_name}.xy, 0.0)`);
-				NodeShader.write(ParserMaterial.curshader, `vec4 ${tex_store} = textureLod(${tex_name}, ${uv_name}.xy, 0.0);`);
-			}
-			if (!tex.file.endsWith(".jpg")) { // Pre-mult alpha
-				NodeShader.write(ParserMaterial.curshader, `${tex_store}.rgb *= ${tex_store}.a;`);
-			}
-		}
-
-		if (ParserMaterial.transform_color_space) {
-			// Base color socket auto-converts from sRGB to linear
-			if (color_space == color_space_t.LINEAR && ParserMaterial.parsing_basecolor) { // Linear to sRGB
-				NodeShader.write(ParserMaterial.curshader, `${tex_store}.rgb = pow(${tex_store}.rgb, vec3(2.2, 2.2, 2.2));`);
-			}
-			else if (color_space == color_space_t.SRGB && !ParserMaterial.parsing_basecolor) { // sRGB to linear
-				NodeShader.write(ParserMaterial.curshader, `${tex_store}.rgb = pow(${tex_store}.rgb, vec3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2));`);
-			}
-			else if (color_space == color_space_t.DIRECTX_NORMAL_MAP) { // DirectX normal map to OpenGL normal map
-				NodeShader.write(ParserMaterial.curshader, `${tex_store}.y = 1.0 - ${tex_store}.y;`);
-			}
-		}
-		return tex_store;
-	}
-
-	static vec1 = (v: f32): string => {
-		///if krom_android
-		return `float(${v})`;
-		///else
-		return `${v}`;
-		///end
-	}
-
-	static vec3 = (v: f32[]): string => {
-		///if krom_android
-		return `vec3(float(${v[0]}), float(${v[1]}), float(${v[2]}))`;
-		///else
-		return `vec3(${v[0]}, ${v[1]}, ${v[2]})`;
-		///end
-	}
-
-	static to_vec3 = (s: string): string => {
-		///if (krom_direct3d11 || krom_direct3d12)
-		return `(${s}).xxx`;
-		///else
-		return `vec3(${s})`;
-		///end
-	}
-
-	static node_by_type = (nodes: zui_node_t[], ntype: string): zui_node_t => {
-		for (let n of nodes) if (n.type == ntype) return n;
-		return null;
-	}
-
-	static socket_index = (node: zui_node_t, socket: zui_node_socket_t): i32 => {
-		for (let i: i32 = 0; i < node.outputs.length; ++i) if (node.outputs[i] == socket) return i;
-		return -1;
-	}
-
-	static node_name = (node: zui_node_t, _parents: zui_node_t[] = null): string => {
-		if (_parents == null) _parents = ParserMaterial.parents;
-		let s: string = node.name;
-		for (let p of _parents) s = p.name + p.id + `_` + s;
-		s = ParserMaterial.safesrc(s) + node.id;
-		return s;
-	}
-
-	static safesrc = (s: string): string => {
-		for (let i: i32 = 0; i < s.length; ++i) {
-			let code: i32 = s.charCodeAt(i);
-			let letter: bool = (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
-			let digit: bool = code >= 48 && code <= 57;
-			if (!letter && !digit) s = string_replace_all(s, s.charAt(i), "_");
-			if (i == 0 && digit) s = "_" + s;
-		}
-		///if krom_opengl
-		while (s.indexOf("__") >= 0) s = string_replace_all(s, "__", "_");
-		///end
-		return s;
-	}
-
-	static enum_data = (s: string): string => {
-		for (let a of project_assets) if (a.name == s) return a.file;
-		return "";
-	}
-
-	static make_texture = (image_node: zui_node_t, tex_name: string, matname: string = null): bind_tex_t => {
-		let filepath: string = ParserMaterial.enum_data(base_enum_texts(image_node.type)[image_node.buttons[0].default_value]);
-		if (filepath == "" || filepath.indexOf(".") == -1) {
-			return null;
-		}
-
-		let tex: bind_tex_t = {
-			name: tex_name,
-			file: filepath
-		};
-
-		if (context_raw.texture_filter) {
-			tex.min_filter = "anisotropic";
-			tex.mag_filter = "linear";
-			tex.mipmap_filter = "linear";
-			tex.generate_mipmaps = true;
-		}
-		else {
-			tex.min_filter = "point";
-			tex.mag_filter = "point";
-			tex.mipmap_filter = "no";
-		}
-
-		tex.u_addressing = "repeat";
-		tex.v_addressing = "repeat";
-		return tex;
-	}
-
-	static is_pow = (num: i32): bool => {
-		return ((num & (num - 1)) == 0) && num != 0;
-	}
-
-	static asset_path = (s: string): string => {
-		return s;
-	}
-
-	static extract_filename = (s: string): string => {
-		let ar: string[] = s.split(".");
-		return ar[ar.length - 2] + "." + ar[ar.length - 1];
-	}
-
-	static safestr = (s: string): string => {
-		return s;
-	}
-}
-
-type shader_out_t = {
-	out_basecol?: string;
-	out_roughness?: string;
-	out_metallic?: string;
-	out_occlusion?: string;
-	out_opacity?: string;
-	out_height?: string;
-	out_emission?: string;
-	out_subsurface?: string;
-};
-
-enum color_space_t {
-	AUTO, // sRGB for base color, otherwise linear
-	LINEAR,
-	SRGB,
-	DIRECTX_NORMAL_MAP,
-}

+ 0 - 482
base/Sources/PhysicsBody.ts

@@ -1,482 +0,0 @@
-
-///if arm_physics
-
-class PhysicsBodyRaw {
-	_mass: f32 = 0.0;
-
-	get mass(): f32 {
-		return this._mass;
-	}
-
-	set mass(f: f32) {
-		if (this.ready) {
-			// remove();
-			let t: PhysicsBodyRaw = new PhysicsBodyRaw();
-			t._mass = f;
-			PhysicsBody.init(t, this.object);
-			(this.object as any).physicsBody = t;
-		}
-		else this._mass = f;
-	}
-
-	object: object_t;
-	friction: f32 = 0.5;
-	restitution: f32 = 0.0;
-	collision_margin: f32 = 0.0;
-	linear_damping: f32 = 0.04;
-	angular_damping: f32 = 0.1;
-	linear_factors: f32[] = [1.0, 1.0, 1.0];
-	angular_factors: f32[] = [1.0, 1.0, 1.0];
-	linear_threshold: f32 = 0.0;
-	angular_threshold: f32 = 0.0;
-	ccd: bool = false; // Continuous collision detection
-	trigger: bool = false;
-	group: i32 = 1;
-	mask: i32 = 1;
-	shape: shape_type_t = shape_type_t.BOX;
-	destroyed: bool = false;
-	body_scale_x: f32; // Transform scale at creation time
-	body_scale_y: f32;
-	body_scale_z: f32;
-	current_scale_x: f32;
-	current_scale_y: f32;
-	current_scale_z: f32;
-
-	body: Ammo.btRigidBody = null;
-	motion_state: Ammo.btMotionState;
-	btshape: Ammo.btCollisionShape;
-	ready: bool = false;
-	id: i32 = 0;
-	height_data: Uint8Array = null;
-}
-
-class PhysicsBody {
-
-	static next_id: i32 = 0;
-	static ammo_array: i32 = -1;
-	static gimpact_registered: bool = false;
-	static first: bool = true;
-	static vec1: Ammo.btVector3;
-	static vec2: Ammo.btVector3;
-	static vec3: Ammo.btVector3;
-	static quat1: Ammo.btQuaternion;
-	static trans1: Ammo.btTransform;
-	static trans2: Ammo.btTransform;
-	static quat: quat_t = quat_create();
-
-	static convex_hull_cache: map_t<mesh_data_t, Ammo.btConvexHullShape> = map_create();
-	static triangle_mesh_cache: map_t<mesh_data_t, Ammo.btTriangleMesh> = map_create();
-	static users_cache: map_t<mesh_data_t, i32> = map_create();
-
-	static create(): PhysicsBodyRaw {
-		if (PhysicsBody.first) {
-			PhysicsBody.first = false;
-			PhysicsBody.vec1 = new Ammo.btVector3(0, 0, 0);
-			PhysicsBody.vec2 = new Ammo.btVector3(0, 0, 0);
-			PhysicsBody.vec3 = new Ammo.btVector3(0, 0, 0);
-			PhysicsBody.quat1 = new Ammo.btQuaternion(0, 0, 0, 0);
-			PhysicsBody.trans1 = new Ammo.btTransform();
-			PhysicsBody.trans2 = new Ammo.btTransform();
-		}
-		let pb: PhysicsBodyRaw = new PhysicsBodyRaw();
-		return pb;
-	}
-
-	static with_margin = (pb: PhysicsBodyRaw, f: f32) => {
-		return f - f * pb.collision_margin;
-	}
-
-	static init = (pb: PhysicsBodyRaw, o: object_t) => {
-		pb.object = o;
-		if (pb.ready) {
-			return;
-		}
-		pb.ready = true;
-
-		if (pb.object.ext_type != "mesh_object_t") {
-			return; // No mesh data
-		}
-		let transform: transform_t = o.transform;
-		let physics: PhysicsWorldRaw = PhysicsWorld.active;
-
-		if (pb.shape == shape_type_t.BOX) {
-			PhysicsWorld.vec1.setX(PhysicsBody.with_margin(pb, transform.dim.x / 2));
-			PhysicsWorld.vec1.setY(PhysicsBody.with_margin(pb, transform.dim.y / 2));
-			PhysicsWorld.vec1.setZ(PhysicsBody.with_margin(pb, transform.dim.z / 2));
-			pb.btshape = new Ammo.btBoxShape(PhysicsWorld.vec1);
-		}
-		else if (pb.shape == shape_type_t.SPHERE) {
-			pb.btshape = new Ammo.btSphereShape(PhysicsBody.with_margin(pb, transform.dim.x / 2));
-		}
-		else if (pb.shape == shape_type_t.CONVEX_HULL) {
-			let shape_convex: Ammo.btConvexHullShape = PhysicsBody.fill_convex_hull(pb, transform.scale, pb.collision_margin);
-			pb.btshape = shape_convex;
-		}
-		else if (pb.shape == shape_type_t.CONE) {
-			let cone_z: Ammo.btConeShapeZ = new Ammo.btConeShapeZ(
-				PhysicsBody.with_margin(pb, transform.dim.x / 2), // Radius
-				PhysicsBody.with_margin(pb, transform.dim.z));	 // Height
-			let cone: Ammo.btConeShape = cone_z;
-			pb.btshape = cone;
-		}
-		else if (pb.shape == shape_type_t.CYLINDER) {
-			PhysicsWorld.vec1.setX(PhysicsBody.with_margin(pb, transform.dim.x / 2));
-			PhysicsWorld.vec1.setY(PhysicsBody.with_margin(pb, transform.dim.y / 2));
-			PhysicsWorld.vec1.setZ(PhysicsBody.with_margin(pb, transform.dim.z / 2));
-			let cyl_z: Ammo.btCylinderShapeZ = new Ammo.btCylinderShapeZ(PhysicsWorld.vec1);
-			let cyl: Ammo.btCylinderShape = cyl_z;
-			pb.btshape = cyl;
-		}
-		else if (pb.shape == shape_type_t.CAPSULE) {
-			let r: f32 = transform.dim.x / 2;
-			let caps_z: Ammo.btCapsuleShapeZ = new Ammo.btCapsuleShapeZ(
-				PhysicsBody.with_margin(pb, r), // Radius
-				PhysicsBody.with_margin(pb, transform.dim.z - r * 2)); // Distance between 2 sphere centers
-			let caps: Ammo.btCapsuleShape = caps_z;
-			pb.btshape = caps;
-		}
-		else if (pb.shape == shape_type_t.MESH) {
-			let mesh_interface: Ammo.btTriangleMesh = PhysicsBody.fill_triangle_mesh(pb, transform.scale);
-			if (pb.mass > 0) {
-				let shape_gimpact: Ammo.btGImpactMeshShape = new Ammo.btGImpactMeshShape(mesh_interface);
-				shape_gimpact.updateBound();
-				let shape_concave: Ammo.btConcaveShape = shape_gimpact;
-				pb.btshape = shape_concave;
-				if (!PhysicsBody.gimpact_registered) {
-					PhysicsBody.gimpact_registered = true;
-					new Ammo.GImpactCollisionAlgorithm().registerAlgorithm(physics.dispatcher);
-				}
-			}
-			else {
-				let shape_bvh: Ammo.btBvhTriangleMeshShape = new Ammo.btBvhTriangleMeshShape(mesh_interface, true, true);
-				let shape_tri: Ammo.btTriangleMeshShape = shape_bvh;
-				let shape_concave: Ammo.btConcaveShape = shape_tri;
-				pb.btshape = shape_concave;
-			}
-		}
-		else if (pb.shape == shape_type_t.TERRAIN) {
-			let length: i32 = pb.height_data.length;
-			if (PhysicsBody.ammo_array == -1) {
-				PhysicsBody.ammo_array = Ammo._malloc(length);
-			}
-			// From texture bytes
-			for (let i: i32 = 0; i < length; ++i) {
-				Ammo.HEAPU8[PhysicsBody.ammo_array + i] = pb.height_data[i];
-			}
-			let slice: i32 = math_floor(math_sqrt(length)); // Assuming square terrain data
-			let axis: i32 = 2; // z
-			let data_type: i32 = 5; // u8
-			pb.btshape = new Ammo.btHeightfieldTerrainShape(slice, slice, PhysicsBody.ammo_array, 1 / 255, 0, 1, axis, data_type, false);
-			PhysicsBody.vec1.setX(transform.dim.x / slice);
-			PhysicsBody.vec1.setY(transform.dim.y / slice);
-			PhysicsBody.vec1.setZ(transform.dim.z);
-			pb.btshape.setLocalScaling(PhysicsBody.vec1);
-		}
-
-		PhysicsBody.trans1.setIdentity();
-		PhysicsBody.vec1.setX(transform_world_x(transform));
-		PhysicsBody.vec1.setY(transform_world_y(transform));
-		PhysicsBody.vec1.setZ(transform_world_z(transform));
-		PhysicsBody.trans1.setOrigin(PhysicsBody.vec1);
-		quat_from_mat(PhysicsBody.quat, transform.world);
-		PhysicsBody.quat1.setValue(PhysicsBody.quat.x, PhysicsBody.quat.y, PhysicsBody.quat.z, PhysicsBody.quat.w);
-		PhysicsBody.trans1.setRotation(PhysicsBody.quat1);
-		PhysicsBody.trans2.setIdentity();
-		pb.motion_state = new Ammo.btDefaultMotionState(PhysicsBody.trans1, PhysicsBody.trans2); // Transform, center of mass offset
-
-		PhysicsBody.vec1.setX(0);
-		PhysicsBody.vec1.setY(0);
-		PhysicsBody.vec1.setZ(0);
-		let inertia: Ammo.btVector3 = PhysicsBody.vec1;
-
-		if (pb.mass > 0) {
-			pb.btshape.calculateLocalInertia(pb.mass, inertia);
-		}
-		let body_ci: Ammo.btRigidBodyConstructionInfo = new Ammo.btRigidBodyConstructionInfo(pb.mass, pb.motion_state, pb.btshape, inertia);
-		pb.body = new Ammo.btRigidBody(body_ci);
-
-		pb.body.setFriction(pb.friction);
-		if (pb.shape == shape_type_t.SPHERE || pb.shape == shape_type_t.CYLINDER || pb.shape == shape_type_t.CONE || pb.shape == shape_type_t.CAPSULE) {
-			pb.angular_damping += pb.friction;
-		}
-		pb.body.setRestitution(pb.restitution);
-		// pb.body.setSleepingThresholds(linearThreshold, angularThreshold);
-		// pb.body.setDeactivationTime(deactivationTime);
-		pb.body.setDamping(pb.linear_damping, pb.angular_damping);
-		PhysicsBody.set_linear_factor(pb, pb.linear_factors[0], pb.linear_factors[1], pb.linear_factors[2]);
-		PhysicsBody.set_angular_factor(pb, pb.angular_factors[0], pb.angular_factors[1], pb.angular_factors[2]);
-		if (pb.trigger) {
-			pb.body.setCollisionFlags(pb.body.getCollisionFlags() | collision_flags_t.CF_NO_CONTACT_RESPONSE);
-		}
-		if (pb.mass == 0.0) {
-			pb.body.setCollisionFlags(pb.body.getCollisionFlags() | collision_flags_t.CF_STATIC_OBJECT);
-		}
-		if (pb.ccd) {
-			PhysicsBody.set_ccd(pb, transform.radius);
-		}
-
-		pb.body_scale_x = pb.current_scale_x = transform.scale.x;
-		pb.body_scale_y = pb.current_scale_y = transform.scale.y;
-		pb.body_scale_z = pb.current_scale_z = transform.scale.z;
-
-		pb.id = PhysicsBody.next_id++;
-		pb.body.userIndex = pb.id;
-
-		PhysicsWorld.add_body(physics, pb);
-
-		// notifyOnRemove(removeFromWorld);
-
-		Ammo.destroy(body_ci);
-	}
-
-	static physics_update = (pb: PhysicsBodyRaw) => {
-		if (!pb.ready) {
-			return;
-		}
-		let trans: Ammo.btTransform = pb.body.getWorldTransform();
-
-		let p: Ammo.btVector3 = trans.getOrigin();
-		let q: Ammo.btQuaternion = trans.getRotation();
-		let qw: Ammo.btQuadWord = q;
-
-		let transform: transform_t = pb.object.transform;
-		vec4_set(transform.loc, p.x(), p.y(), p.z());
-		quat_set(transform.rot, qw.x(), qw.y(), qw.z(), qw.w());
-		if (pb.object.parent != null) {
-			let ptransform: transform_t = pb.object.parent.transform;
-			transform.loc.x -= transform_world_x(ptransform);
-			transform.loc.y -= transform_world_y(ptransform);
-			transform.loc.z -= transform_world_z(ptransform);
-		}
-		transform_build_matrix(transform);
-	}
-
-	static remove_from_world = (pb: PhysicsBodyRaw) => {
-		PhysicsWorld.remove_body(PhysicsWorld.active, pb);
-	}
-
-	static activate = (pb: PhysicsBodyRaw) => {
-		pb.body.activate(false);
-	}
-
-	static set_gravity = (pb: PhysicsBodyRaw, v: vec4_t) => {
-		PhysicsBody.vec1.setValue(v.x, v.y, v.z);
-		pb.body.setGravity(PhysicsBody.vec1);
-	}
-
-	static apply_force = (pb: PhysicsBodyRaw, force: vec4_t, loc: vec4_t = null) => {
-		PhysicsBody.activate(pb);
-		PhysicsBody.vec1.setValue(force.x, force.y, force.z);
-		if (loc == null) {
-			pb.body.applyCentralForce(PhysicsBody.vec1);
-		}
-		else {
-			PhysicsBody.vec2.setValue(loc.x, loc.y, loc.z);
-			pb.body.applyForce(PhysicsBody.vec1, PhysicsBody.vec2);
-		}
-	}
-
-	static apply_impulse = (pb: PhysicsBodyRaw, impulse: vec4_t, loc: vec4_t = null) => {
-		PhysicsBody.activate(pb);
-		PhysicsBody.vec1.setValue(impulse.x, impulse.y, impulse.z);
-		if (loc == null) {
-			pb.body.applyCentralImpulse(PhysicsBody.vec1);
-		}
-		else {
-			PhysicsBody.vec2.setValue(loc.x, loc.y, loc.z);
-			pb.body.applyImpulse(PhysicsBody.vec1, PhysicsBody.vec2);
-		}
-	}
-
-	static apply_torque = (pb: PhysicsBodyRaw, torque: vec4_t) => {
-		PhysicsBody.activate(pb);
-		PhysicsBody.vec1.setValue(torque.x, torque.y, torque.z);
-		pb.body.applyTorque(PhysicsBody.vec1);
-	}
-
-	static apply_torque_impulse = (pb: PhysicsBodyRaw, torque: vec4_t) => {
-		PhysicsBody.activate(pb);
-		PhysicsBody.vec1.setValue(torque.x, torque.y, torque.z);
-		pb.body.applyTorqueImpulse(PhysicsBody.vec1);
-	}
-
-	static set_linear_factor = (pb: PhysicsBodyRaw, x: f32, y: f32, z: f32) => {
-		PhysicsBody.vec1.setValue(x, y, z);
-		pb.body.setLinearFactor(PhysicsBody.vec1);
-	}
-
-	static set_angular_factor = (pb: PhysicsBodyRaw, x: f32, y: f32, z: f32) => {
-		PhysicsBody.vec1.setValue(x, y, z);
-		pb.body.setAngularFactor(PhysicsBody.vec1);
-	}
-
-	static get_linear_velocity = (pb: PhysicsBodyRaw): vec4_t => {
-		let v: Ammo.btVector3 = pb.body.getLinearVelocity();
-		return vec4_create(v.x(), v.y(), v.z());
-	}
-
-	static set_linear_velocity = (pb: PhysicsBodyRaw, x: f32, y: f32, z: f32) => {
-		PhysicsBody.vec1.setValue(x, y, z);
-		pb.body.setLinearVelocity(PhysicsBody.vec1);
-	}
-
-	static get_angular_velocity = (pb: PhysicsBodyRaw): vec4_t => {
-		let v: Ammo.btVector3 = pb.body.getAngularVelocity();
-		return vec4_create(v.x(), v.y(), v.z());
-	}
-
-	static set_angular_velocity = (pb: PhysicsBodyRaw, x: f32, y: f32, z: f32) => {
-		PhysicsBody.vec1.setValue(x, y, z);
-		pb.body.setAngularVelocity(PhysicsBody.vec1);
-	}
-
-	static set_friction = (pb: PhysicsBodyRaw, f: f32) => {
-		pb.body.setFriction(f);
-		pb.friction = f;
-	}
-
-	static set_scale = (pb: PhysicsBodyRaw, v: vec4_t) => {
-		pb.current_scale_x = v.x;
-		pb.current_scale_y = v.y;
-		pb.current_scale_z = v.z;
-		PhysicsBody.vec1.setX(v.x / pb.body_scale_x);
-		PhysicsBody.vec1.setY(v.y / pb.body_scale_y);
-		PhysicsBody.vec1.setZ(v.z / pb.body_scale_z);
-		pb.btshape.setLocalScaling(PhysicsBody.vec1);
-		let world_dyn: Ammo.btDynamicsWorld = PhysicsWorld.active.world;
-		let world_col: Ammo.btCollisionWorld = world_dyn;
-		world_col.updateSingleAabb(pb.body);
-	}
-
-	static sync_transform = (pb: PhysicsBodyRaw) => {
-		let t: transform_t = pb.object.transform;
-		transform_build_matrix(t);
-		PhysicsBody.vec1.setValue(transform_world_x(t), transform_world_y(t), transform_world_z(t));
-		PhysicsBody.trans1.setOrigin(PhysicsBody.vec1);
-		quat_from_mat(PhysicsBody.quat, t.world);
-		PhysicsBody.quat1.setValue(PhysicsBody.quat.x, PhysicsBody.quat.y, PhysicsBody.quat.z, PhysicsBody.quat.w);
-		PhysicsBody.trans1.setRotation(PhysicsBody.quat1);
-		pb.body.setWorldTransform(PhysicsBody.trans1);
-		if (pb.current_scale_x != t.scale.x || pb.current_scale_y != t.scale.y || pb.current_scale_z != t.scale.z) {
-			PhysicsBody.set_scale(pb, t.scale);
-		}
-		PhysicsBody.activate(pb);
-	}
-
-	static set_ccd = (pb: PhysicsBodyRaw, sphereRadius: f32, motionThreshold = 1e-7) => {
-		pb.body.setCcdSweptSphereRadius(sphereRadius);
-		pb.body.setCcdMotionThreshold(motionThreshold);
-	}
-
-	static fill_convex_hull = (pb: PhysicsBodyRaw, scale: vec4_t, margin: f32): Ammo.btConvexHullShape => {
-		// Check whether shape already exists
-		let data: any = pb.object.ext.data;
-		let shape: Ammo.btConvexHullShape = PhysicsBody.convex_hull_cache.get(data);
-		if (shape != null) {
-			PhysicsBody.users_cache.set(data, PhysicsBody.users_cache.get(data) + 1);
-			return shape;
-		}
-
-		shape = new Ammo.btConvexHullShape();
-		PhysicsBody.convex_hull_cache.set(data, shape);
-		PhysicsBody.users_cache.set(data, 1);
-
-		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);
-		let sz: f32 = scale.z * (1.0 - margin) * (1 / 32767);
-
-		sx *= data.scale_pos;
-		sy *= data.scale_pos;
-		sz *= data.scale_pos;
-
-		for (let i: i32 = 0; i < math_floor(positions.length / 4); ++i) {
-			PhysicsBody.vec1.setX(positions[i * 4    ] * sx);
-			PhysicsBody.vec1.setY(positions[i * 4 + 1] * sy);
-			PhysicsBody.vec1.setZ(positions[i * 4 + 2] * sz);
-			shape.addPoint(PhysicsBody.vec1, true);
-		}
-		return shape;
-	}
-
-	static fill_triangle_mesh = (pb: PhysicsBodyRaw, scale: vec4_t): Ammo.btTriangleMesh => {
-		// Check whether shape already exists
-		let data: any = pb.object.ext.data;
-		let triangle_mesh: Ammo.btTriangleMesh = PhysicsBody.triangle_mesh_cache.get(data);
-		if (triangle_mesh != null) {
-			PhysicsBody.users_cache.set(data, PhysicsBody.users_cache.get(data) + 1);
-			return triangle_mesh;
-		}
-
-		triangle_mesh = new Ammo.btTriangleMesh(true, true);
-		PhysicsBody.triangle_mesh_cache.set(data, triangle_mesh);
-		PhysicsBody.users_cache.set(data, 1);
-
-		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);
-		let sy: f32 = scale.y * (1 / 32767);
-		let sz: f32 = scale.z * (1 / 32767);
-
-		sx *= data.scale_pos;
-		sy *= data.scale_pos;
-		sz *= data.scale_pos;
-
-		for (let ar of indices) {
-			for (let i: i32 = 0; i < math_floor(ar.length / 3); ++i) {
-				PhysicsBody.vec1.setX(positions[ar[i * 3    ] * 4    ] * sx);
-				PhysicsBody.vec1.setY(positions[ar[i * 3    ] * 4 + 1] * sy);
-				PhysicsBody.vec1.setZ(positions[ar[i * 3    ] * 4 + 2] * sz);
-				PhysicsBody.vec2.setX(positions[ar[i * 3 + 1] * 4    ] * sx);
-				PhysicsBody.vec2.setY(positions[ar[i * 3 + 1] * 4 + 1] * sy);
-				PhysicsBody.vec2.setZ(positions[ar[i * 3 + 1] * 4 + 2] * sz);
-				PhysicsBody.vec3.setX(positions[ar[i * 3 + 2] * 4    ] * sx);
-				PhysicsBody.vec3.setY(positions[ar[i * 3 + 2] * 4 + 1] * sy);
-				PhysicsBody.vec3.setZ(positions[ar[i * 3 + 2] * 4 + 2] * sz);
-				triangle_mesh.addTriangle(PhysicsBody.vec1, PhysicsBody.vec2, PhysicsBody.vec3);
-			}
-		}
-		return triangle_mesh;
-	}
-
-	static delete = (pb: PhysicsBodyRaw) => {
-		Ammo.destroy(pb.motion_state);
-		Ammo.destroy(pb.body);
-
-		// Delete shape if no other user is found
-		if (pb.shape == shape_type_t.CONVEX_HULL || pb.shape == shape_type_t.MESH) {
-			let data: any = pb.object.ext.data;
-			let i: i32 = PhysicsBody.users_cache.get(data) - 1;
-			PhysicsBody.users_cache.set(data, i);
-			if (i <= 0) {
-				Ammo.destroy(pb.btshape);
-				pb.shape == shape_type_t.CONVEX_HULL ?
-					PhysicsBody.convex_hull_cache.delete(data) :
-					PhysicsBody.triangle_mesh_cache.delete(data);
-			}
-		}
-		else Ammo.destroy(pb.btshape);
-	}
-}
-
-enum shape_type_t {
-	BOX,
-	SPHERE,
-	CONVEX_HULL,
-	MESH,
-	CONE,
-	CYLINDER,
-	CAPSULE,
-	TERRAIN,
-}
-
-enum collision_flags_t {
-	CF_STATIC_OBJECT = 1,
-	CF_KINEMATIC_OBJECT = 2,
-	CF_NO_CONTACT_RESPONSE = 4,
-	CF_CHARACTER_OBJECT = 16,
-}
-
-///end

+ 0 - 200
base/Sources/PhysicsWorld.ts

@@ -1,200 +0,0 @@
-
-///if arm_physics
-
-class PhysicsWorldRaw {
-	world: Ammo.btDiscreteDynamicsWorld;
-	dispatcher: Ammo.btCollisionDispatcher;
-	contacts: pair_t[] = [];
-	body_map: map_t<i32, PhysicsBodyRaw> = map_create();
-	time_scale: f32 = 1.0;
-	time_step: f32 = 1 / 60;
-	max_steps: i32 = 1;
-}
-
-class PhysicsWorld {
-
-	static active: PhysicsWorldRaw = null;
-	static vec1: Ammo.btVector3 = null;
-	static vec2: Ammo.btVector3 = null;
-	static v1: vec4_t = vec4_create();
-	static v2: vec4_t = vec4_create();
-
-	static load = (done: ()=>void) => {
-		let b: buffer_t = krom_load_blob("data/plugins/ammo.js");
-		globalThis.eval(sys_buffer_to_string(b));
-		let print = (s: string) => { krom_log(s); };
-		Ammo({print: print}).then(done);
-	}
-
-	static create(): PhysicsWorldRaw {
-		let pw: PhysicsWorldRaw = new PhysicsWorldRaw();
-		PhysicsWorld.active = pw;
-		PhysicsWorld.vec1 = new Ammo.btVector3(0, 0, 0);
-		PhysicsWorld.vec2 = new Ammo.btVector3(0, 0, 0);
-		PhysicsWorld.init(pw);
-		return pw;
-	}
-
-	static reset = (pw: PhysicsWorldRaw) => {
-		for (let body of pw.body_map.values()) PhysicsWorld.remove_body(pw, body);
-	}
-
-	static init = (pw: PhysicsWorldRaw) => {
-		let broadphase: Ammo.btDbvtBroadphase = new Ammo.btDbvtBroadphase();
-		let collision_conf: Ammo.btDefaultCollisionConfiguration = new Ammo.btDefaultCollisionConfiguration();
-		pw.dispatcher = new Ammo.btCollisionDispatcher(collision_conf);
-		let solver: Ammo.btSequentialImpulseConstraintSolver = new Ammo.btSequentialImpulseConstraintSolver();
-		pw.world = new Ammo.btDiscreteDynamicsWorld(pw.dispatcher, broadphase, solver, collision_conf);
-		PhysicsWorld.set_gravity(pw, vec4_create(0, 0, -9.81));
-	}
-
-	static set_gravity = (pw: PhysicsWorldRaw, v: vec4_t) => {
-		PhysicsWorld.vec1.setValue(v.x, v.y, v.z);
-		pw.world.setGravity(PhysicsWorld.vec1);
-	}
-
-	static add_body = (pw: PhysicsWorldRaw, pb: PhysicsBodyRaw) => {
-		pw.world.addRigidBody(pb.body, pb.group, pb.mask);
-		pw.body_map.set(pb.id, pb);
-	}
-
-	static remove_body = (pw: PhysicsWorldRaw, pb: PhysicsBodyRaw) => {
-		if (pb.destroyed) return;
-		pb.destroyed = true;
-		if (pw.world != null) pw.world.removeRigidBody(pb.body);
-		pw.body_map.delete(pb.id);
-		PhysicsBody.delete(pb);
-	}
-
-	static get_contacts = (pw: PhysicsWorldRaw, pb: PhysicsBodyRaw): PhysicsBodyRaw[] => {
-		if (pw.contacts.length == 0) return null;
-		let res: PhysicsBodyRaw[] = [];
-		for (let i: i32 = 0; i < pw.contacts.length; ++i) {
-			let c: pair_t = pw.contacts[i];
-			let pb: PhysicsBodyRaw = null;
-			if (c.a == pb.body.userIndex) pb = pw.body_map.get(c.b);
-			else if (c.b == pb.body.userIndex) pb = pw.body_map.get(c.a);
-			if (pb != null && res.indexOf(pb) == -1) res.push(pb);
-		}
-		return res;
-	}
-
-	static get_contact_pairs = (pw: PhysicsWorldRaw, pb: PhysicsBodyRaw): pair_t[] => {
-		if (pw.contacts.length == 0) return null;
-		let res: pair_t[] = [];
-		for (let i: i32 = 0; i < pw.contacts.length; ++i) {
-			let c: pair_t = pw.contacts[i];
-			if (c.a == pb.body.userIndex) res.push(c);
-			else if (c.b == pb.body.userIndex) res.push(c);
-		}
-		return res;
-	}
-
-	static late_update = (pw: PhysicsWorldRaw) => {
-		let t: f32 = time_delta() * pw.time_scale;
-		if (t == 0.0) return; // Simulation paused
-
-		pw.world.stepSimulation(pw.time_step, pw.max_steps, t);
-		PhysicsWorld.update_contacts(pw);
-		for (let body of pw.body_map.values()) PhysicsBody.physics_update(body);
-	}
-
-	static update_contacts = (pw: PhysicsWorldRaw) => {
-		pw.contacts = [];
-		let disp: Ammo.btDispatcher = pw.dispatcher;
-		let num_manifolds: i32 = disp.getNumManifolds();
-
-		for (let i: i32 = 0; i < num_manifolds; ++i) {
-			let contact_manifold: Ammo.btPersistentManifold = disp.getManifoldByIndexInternal(i);
-			let body0: Ammo.btRigidBody = Ammo.btRigidBody.prototype.upcast(contact_manifold.getBody0());
-			let body1: Ammo.btRigidBody = Ammo.btRigidBody.prototype.upcast(contact_manifold.getBody1());
-
-			let num_contacts: i32 = contact_manifold.getNumContacts();
-			let pt: Ammo.btManifoldPoint = null;
-			let pos_a: Ammo.btVector3 = null;
-			let pos_b: Ammo.btVector3 = null;
-			let nor: Ammo.btVector3 = null;
-			for (let j: i32 = 0; j < num_contacts; ++j) {
-				pt = contact_manifold.getContactPoint(j);
-				pos_a = pt.get_m_positionWorldOnA();
-				pos_b = pt.get_m_positionWorldOnB();
-				nor = pt.get_m_normalWorldOnB();
-				let cp: pair_t = {
-					a: body0.userIndex,
-					b: body1.userIndex,
-					pos_a: vec4_create(pos_a.x(), pos_a.y(), pos_a.z()),
-					pos_b: vec4_create(pos_b.x(), pos_b.y(), pos_b.z()),
-					norm_on_b: vec4_create(nor.x(), nor.y(), nor.z()),
-					impulse: pt.getAppliedImpulse(),
-					distance: pt.getDistance()
-				};
-				pw.contacts.push(cp);
-			}
-		}
-	}
-
-	static pick_closest = (pw: PhysicsWorldRaw, inputX: f32, inputY: f32): PhysicsBodyRaw => {
-		let camera: camera_object_t = scene_camera;
-		let start: vec4_t = vec4_create();
-		let end: vec4_t = vec4_create();
-		raycast_get_dir(start, end, inputX, inputY, camera);
-		let hit: hit_t = PhysicsWorld.ray_cast(pw, mat4_get_loc(camera.base.transform.world), end);
-		let body: PhysicsBodyRaw = (hit != null) ? hit.body : null;
-		return body;
-	}
-
-	static ray_cast = (pw: PhysicsWorldRaw, from: vec4_t, to: vec4_t, group: i32 = 0x00000001, mask: i32 = 0xffffffff): hit_t => {
-		let ray_from: Ammo.btVector3 = PhysicsWorld.vec1;
-		let ray_to: Ammo.btVector3 = PhysicsWorld.vec2;
-		ray_from.setValue(from.x, from.y, from.z);
-		ray_to.setValue(to.x, to.y, to.z);
-
-		let ray_callback: Ammo.ClosestRayResultCallback = new Ammo.ClosestRayResultCallback(ray_from, ray_to);
-
-		ray_callback.set_m_collisionFilterGroup(group);
-		ray_callback.set_m_collisionFilterMask(mask);
-
-		let world_dyn: Ammo.btDynamicsWorld = pw.world;
-		let world_col: Ammo.btCollisionWorld = world_dyn;
-		world_col.rayTest(ray_from, ray_to, ray_callback);
-		let pb: PhysicsBodyRaw = null;
-		let hit_info: hit_t = null;
-
-		let rc: Ammo.RayResultCallback = ray_callback;
-		if (rc.hasHit()) {
-			let co: Ammo.btCollisionObject = ray_callback.get_m_collisionObject();
-			let body: Ammo.btRigidBody = Ammo.btRigidBody.prototype.upcast(co);
-			let hit: Ammo.btVector3 = ray_callback.get_m_hitPointWorld();
-			vec4_set(PhysicsWorld.v1, hit.x(), hit.y(), hit.z());
-			let norm: Ammo.btVector3 = ray_callback.get_m_hitNormalWorld();
-			vec4_set(PhysicsWorld.v2, norm.x(), norm.y(), norm.z());
-			pb = pw.body_map.get(body.userIndex);
-			hit_info = {
-				body: pb,
-				pos: PhysicsWorld.v1,
-				normal: PhysicsWorld.v2
-			};
-		}
-
-		Ammo.destroy(ray_callback);
-		return hit_info;
-	}
-}
-
-type hit_t = {
-	body?: PhysicsBodyRaw;
-	pos?: vec4_t;
-	normal?: vec4_t;
-};
-
-type pair_t = {
-	a?: i32;
-	b?: i32;
-	pos_a?: vec4_t;
-	pos_b?: vec4_t;
-	norm_on_b?: vec4_t;
-	impulse?: f32;
-	distance?: f32;
-};
-
-///end

+ 0 - 587
base/Sources/RenderPathBase.ts

@@ -1,587 +0,0 @@
-
-class RenderPathBase {
-
-	static taa_frame: i32 = 0;
-	static super_sample: f32 = 1.0;
-	static last_x: f32 = -1.0;
-	static last_y: f32 = -1.0;
-	static bloom_mipmaps: render_target_t[];
-	static bloom_current_mip: i32 = 0;
-	static bloom_sample_scale: f32;
-	///if arm_voxels
-	static voxels_res: i32 = 256;
-	static voxels_created: bool = false;
-	///end
-
-	static init = () => {
-		RenderPathBase.super_sample = config_raw.rp_supersample;
-	}
-
-	///if arm_voxels
-	static init_voxels = (target_name: string = "voxels") => {
-		if (config_raw.rp_gi != true || RenderPathBase.voxels_created) return;
-		RenderPathBase.voxels_created = true;
-
-		{
-			let t: render_target_t = render_target_create();
-			t.name = target_name;
-			t.format = "R8";
-			t.width = RenderPathBase.voxels_res;
-			t.height = RenderPathBase.voxels_res;
-			t.depth = RenderPathBase.voxels_res;
-			t.is_image = true;
-			t.mipmaps = true;
-			render_path_create_render_target(t);
-		}
-	}
-	///end
-
-	static apply_config = () => {
-		if (RenderPathBase.super_sample != config_raw.rp_supersample) {
-			RenderPathBase.super_sample = config_raw.rp_supersample;
-			for (let rt of render_path_render_targets.values()) {
-				if (rt.width == 0 && rt.scale != null) {
-					rt.scale = RenderPathBase.super_sample;
-				}
-			}
-			render_path_resize();
-		}
-		///if arm_voxels
-		if (!RenderPathBase.voxels_created) RenderPathBase.init_voxels();
-		///end
-	}
-
-	static get_super_sampling = (): f32 => {
-		return RenderPathBase.super_sample;
-	}
-
-	static draw_compass = () => {
-		if (context_raw.show_compass) {
-			let cam: camera_object_t = scene_camera;
-			let compass: mesh_object_t = scene_get_child(".Compass").ext;
-
-			let _visible: bool = compass.base.visible;
-			let _parent: object = compass.base.parent;
-			let _loc: vec4_t = compass.base.transform.loc;
-			let _rot: quat_t = compass.base.transform.rot;
-			let crot: quat_t = cam.base.transform.rot;
-			let ratio: f32 = app_w() / app_h();
-			let _P: mat4_t = cam.p;
-			cam.p = mat4_ortho(-8 * ratio, 8 * ratio, -8, 8, -2, 2);
-			compass.base.visible = true;
-			compass.base.parent = cam.base;
-			compass.base.transform.loc = vec4_create(7.4 * ratio, 7.0, -1);
-			compass.base.transform.rot = quat_create(-crot.x, -crot.y, -crot.z, crot.w);
-			vec4_set(compass.base.transform.scale, 0.4, 0.4, 0.4);
-			transform_build_matrix(compass.base.transform);
-			compass.frustum_culling = false;
-			mesh_object_render(compass, "overlay", []);
-
-			cam.p = _P;
-			compass.base.visible = _visible;
-			compass.base.parent = _parent;
-			compass.base.transform.loc = _loc;
-			compass.base.transform.rot = _rot;
-			transform_build_matrix(compass.base.transform);
-		}
-	}
-
-	static begin = () => {
-		// Begin split
-		if (context_raw.split_view && !context_raw.paint2d_view) {
-			if (context_raw.view_index_last == -1 && context_raw.view_index == -1) {
-				// Begin split, draw right viewport first
-				context_raw.view_index = 1;
-			}
-			else {
-				// Set current viewport
-				context_raw.view_index = mouse_view_x() > base_w() / 2 ? 1 : 0;
-			}
-
-			let cam: camera_object_t = scene_camera;
-			if (context_raw.view_index_last > -1) {
-				// Save current viewport camera
-				mat4_set_from(camera_views[context_raw.view_index_last], cam.base.transform.local);
-			}
-
-			let decal: bool = context_raw.tool == workspace_tool_t.DECAL || context_raw.tool == workspace_tool_t.TEXT;
-
-			if (context_raw.view_index_last != context_raw.view_index || decal || !config_raw.brush_3d) {
-				// Redraw on current viewport change
-				context_raw.ddirty = 1;
-			}
-
-			transform_set_matrix(cam.base.transform, camera_views[context_raw.view_index]);
-			camera_object_build_mat(cam);
-			camera_object_build_proj(cam);
-		}
-
-		// Match projection matrix jitter
-		let skip_taa: bool = context_raw.split_view || ((context_raw.tool == workspace_tool_t.CLONE || context_raw.tool == workspace_tool_t.BLUR || context_raw.tool == workspace_tool_t.SMUDGE) && context_raw.pdirty > 0);
-		scene_camera.frame = skip_taa ? 0 : RenderPathBase.taa_frame;
-		camera_object_proj_jitter(scene_camera);
-		camera_object_build_mat(scene_camera);
-	}
-
-	static end = () => {
-		// End split
-		context_raw.view_index_last = context_raw.view_index;
-		context_raw.view_index = -1;
-
-		if (context_raw.foreground_event && !mouse_down()) {
-			context_raw.foreground_event = false;
-			context_raw.pdirty = 0;
-		}
-
-		RenderPathBase.taa_frame++;
-	}
-
-	static ssaa4 = (): bool => {
-		return config_raw.rp_supersample == 4;
-	}
-
-	static is_cached = (): bool => {
-		if (sys_width() == 0 || sys_height() == 0) return true;
-
-		let mx: f32 = RenderPathBase.last_x;
-		let my: f32 = RenderPathBase.last_y;
-		RenderPathBase.last_x = mouse_view_x();
-		RenderPathBase.last_y = mouse_view_y();
-
-		if (context_raw.ddirty <= 0 && context_raw.rdirty <= 0 && context_raw.pdirty <= 0) {
-			if (mx != RenderPathBase.last_x || my != RenderPathBase.last_y || mouse_locked) context_raw.ddirty = 0;
-			///if (krom_metal || krom_android)
-			if (context_raw.ddirty > -6) {
-			///else
-			if (context_raw.ddirty > -2) {
-			///end
-				render_path_set_target("");
-				render_path_bind_target("taa", "tex");
-				RenderPathBase.ssaa4() ?
-					render_path_draw_shader("shader_datas/supersample_resolve/supersample_resolve") :
-					render_path_draw_shader("shader_datas/copy_pass/copy_pass");
-				RenderPathPaint.commands_cursor();
-				if (context_raw.ddirty <= 0) context_raw.ddirty--;
-			}
-			RenderPathBase.end();
-			return true;
-		}
-		return false;
-	}
-
-	static commands = (draw_commands: ()=>void) => {
-		if (RenderPathBase.is_cached()) return;
-		RenderPathBase.begin();
-
-		RenderPathPaint.begin();
-		RenderPathBase.draw_split(draw_commands);
-		RenderPathBase.draw_gbuffer();
-		RenderPathPaint.draw();
-
-		///if (krom_direct3d12 || krom_vulkan || krom_metal)
-		if (context_raw.viewport_mode ==  viewport_mode_t.PATH_TRACE) {
-			///if is_paint
-			let use_live_layer: bool = context_raw.tool == workspace_tool_t.MATERIAL;
-			///else
-			let use_live_layer: bool = false;
-			///end
-			RenderPathRaytrace.draw(use_live_layer);
-			return;
-		}
-		///end
-
-		draw_commands();
-		RenderPathPaint.end();
-		RenderPathBase.end();
-	}
-
-	static draw_bloom = (tex: string = "tex") => {
-		if (config_raw.rp_bloom != false) {
-			if (RenderPathBase.bloom_mipmaps == null) {
-				RenderPathBase.bloom_mipmaps = [];
-
-				let prev_scale: f32 = 1.0;
-				for (let i: i32 = 0; i < 10; ++i) {
-					let t: render_target_t = render_target_create();
-					t.name = "bloom_mip_" + i;
-					t.width = 0;
-					t.height = 0;
-					t.scale = (prev_scale *= 0.5);
-					t.format = "RGBA64";
-					RenderPathBase.bloom_mipmaps.push(render_path_create_render_target(t));
-				}
-
-				render_path_load_shader("shader_datas/bloom_pass/bloom_downsample_pass");
-				render_path_load_shader("shader_datas/bloom_pass/bloom_upsample_pass");
-			}
-
-			let bloom_radius: f32 = 6.5;
-			let min_dim: f32 = math_min(render_path_current_w, render_path_current_h);
-			let log_min_dim: f32 = math_max(1.0, math_log2(min_dim) + (bloom_radius - 8.0));
-			let num_mips: i32 = math_floor(log_min_dim);
-			RenderPathBase.bloom_sample_scale = 0.5 + log_min_dim - num_mips;
-
-			for (let i: i32 = 0; i < num_mips; ++i) {
-				RenderPathBase.bloom_current_mip = i;
-				render_path_set_target(RenderPathBase.bloom_mipmaps[i].name);
-				render_path_clear_target();
-				render_path_bind_target(i == 0 ? tex : RenderPathBase.bloom_mipmaps[i - 1].name, "tex");
-				render_path_draw_shader("shader_datas/bloom_pass/bloom_downsample_pass");
-			}
-			for (let i: i32 = 0; i < num_mips; ++i) {
-				let mip_level: i32 = num_mips - 1 - i;
-				RenderPathBase.bloom_current_mip = mip_level;
-				render_path_set_target(mip_level == 0 ? tex : RenderPathBase.bloom_mipmaps[mip_level - 1].name);
-				render_path_bind_target(RenderPathBase.bloom_mipmaps[mip_level].name, "tex");
-				render_path_draw_shader("shader_datas/bloom_pass/bloom_upsample_pass");
-			}
-		}
-	}
-
-	static draw_split = (drawCommands: ()=>void) => {
-		if (context_raw.split_view && !context_raw.paint2d_view) {
-			context_raw.ddirty = 2;
-			let cam: camera_object_t = scene_camera;
-
-			context_raw.view_index = context_raw.view_index == 0 ? 1 : 0;
-			transform_set_matrix(cam.base.transform, camera_views[context_raw.view_index]);
-			camera_object_build_mat(cam);
-			camera_object_build_proj(cam);
-
-			RenderPathBase.draw_gbuffer();
-
-			///if (krom_direct3d12 || krom_vulkan || krom_metal)
-			///if is_paint
-			let use_live_layer: bool = context_raw.tool == workspace_tool_t.MATERIAL;
-			///else
-			let use_live_layer: bool = false;
-			///end
-			context_raw.viewport_mode == viewport_mode_t.PATH_TRACE ? RenderPathRaytrace.draw(use_live_layer) : drawCommands();
-			///else
-			drawCommands();
-			///end
-
-			context_raw.view_index = context_raw.view_index == 0 ? 1 : 0;
-			transform_set_matrix(cam.base.transform, camera_views[context_raw.view_index]);
-			camera_object_build_mat(cam);
-			camera_object_build_proj(cam);
-		}
-	}
-
-	///if arm_voxels
-	static draw_voxels = () => {
-		if (config_raw.rp_gi != false) {
-			let voxelize: bool = context_raw.ddirty > 0 && RenderPathBase.taa_frame > 0;
-			if (voxelize) {
-				render_path_clear_image("voxels", 0x00000000);
-				render_path_set_target("");
-				render_path_set_viewport(RenderPathBase.voxels_res, RenderPathBase.voxels_res);
-				render_path_bind_target("voxels", "voxels");
-				if (MakeMaterial.height_used) {
-					let tid: i32 = 0; // layers[0].id;
-					render_path_bind_target("texpaint_pack" + tid, "texpaint_pack");
-				}
-				render_path_draw_meshes("voxel");
-				render_path_gen_mipmaps("voxels");
-			}
-		}
-	}
-	///end
-
-	static init_ssao = () => {
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "singlea";
-			t.width = 0;
-			t.height = 0;
-			t.format = "R8";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "singleb";
-			t.width = 0;
-			t.height = 0;
-			t.format = "R8";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		render_path_load_shader("shader_datas/ssao_pass/ssao_pass");
-		render_path_load_shader("shader_datas/ssao_blur_pass/ssao_blur_pass_x");
-		render_path_load_shader("shader_datas/ssao_blur_pass/ssao_blur_pass_y");
-	}
-
-	static draw_ssao = () => {
-		let ssao: bool = config_raw.rp_ssao != false && context_raw.camera_type == camera_type_t.PERSPECTIVE;
-		if (ssao && context_raw.ddirty > 0 && RenderPathBase.taa_frame > 0) {
-			if (render_path_render_targets.get("singlea") == null) {
-				RenderPathBase.init_ssao();
-			}
-
-			render_path_set_target("singlea");
-			render_path_bind_target("_main", "gbufferD");
-			render_path_bind_target("gbuffer0", "gbuffer0");
-			render_path_draw_shader("shader_datas/ssao_pass/ssao_pass");
-
-			render_path_set_target("singleb");
-			render_path_bind_target("singlea", "tex");
-			render_path_bind_target("gbuffer0", "gbuffer0");
-			render_path_draw_shader("shader_datas/ssao_blur_pass/ssao_blur_pass_x");
-
-			render_path_set_target("singlea");
-			render_path_bind_target("singleb", "tex");
-			render_path_bind_target("gbuffer0", "gbuffer0");
-			render_path_draw_shader("shader_datas/ssao_blur_pass/ssao_blur_pass_y");
-		}
-	}
-
-	static draw_deferred_light = () => {
-		render_path_set_target("tex");
-		render_path_bind_target("_main", "gbufferD");
-		render_path_bind_target("gbuffer0", "gbuffer0");
-		render_path_bind_target("gbuffer1", "gbuffer1");
-		let ssao: bool = config_raw.rp_ssao != false && context_raw.camera_type == camera_type_t.PERSPECTIVE;
-		if (ssao && RenderPathBase.taa_frame > 0) {
-			render_path_bind_target("singlea", "ssaotex");
-		}
-		else {
-			render_path_bind_target("empty_white", "ssaotex");
-		}
-
-		let voxelao_pass: bool = false;
-		///if arm_voxels
-		if (config_raw.rp_gi != false) {
-			voxelao_pass = true;
-			render_path_bind_target("voxels", "voxels");
-		}
-		///end
-
-		voxelao_pass ?
-			render_path_draw_shader("shader_datas/deferred_light/deferred_light_voxel") :
-			render_path_draw_shader("shader_datas/deferred_light/deferred_light");
-
-		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		render_path_set_depth_from("tex", "gbuffer0"); // Bind depth for world pass
-		///end
-
-		render_path_set_target("tex");
-		render_path_draw_skydome("shader_datas/world_pass/world_pass");
-
-		///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
-		render_path_set_depth_from("tex", "gbuffer1"); // Unbind depth
-		///end
-	}
-
-	static draw_ssr = () => {
-		if (config_raw.rp_ssr != false) {
-			if (_render_path_cached_shader_contexts.get("shader_datas/ssr_pass/ssr_pass") == null) {
-				{
-					let t: render_target_t = render_target_create();
-					t.name = "bufb";
-					t.width = 0;
-					t.height = 0;
-					t.format = "RGBA64";
-					render_path_create_render_target(t);
-				}
-				render_path_load_shader("shader_datas/ssr_pass/ssr_pass");
-				render_path_load_shader("shader_datas/ssr_blur_pass/ssr_blur_pass_x");
-				render_path_load_shader("shader_datas/ssr_blur_pass/ssr_blur_pass_y3_blend");
-			}
-			let targeta: string = "bufb";
-			let targetb: string = "gbuffer1";
-
-			render_path_set_target(targeta);
-			render_path_bind_target("tex", "tex");
-			render_path_bind_target("_main", "gbufferD");
-			render_path_bind_target("gbuffer0", "gbuffer0");
-			render_path_bind_target("gbuffer1", "gbuffer1");
-			render_path_draw_shader("shader_datas/ssr_pass/ssr_pass");
-
-			render_path_set_target(targetb);
-			render_path_bind_target(targeta, "tex");
-			render_path_bind_target("gbuffer0", "gbuffer0");
-			render_path_draw_shader("shader_datas/ssr_blur_pass/ssr_blur_pass_x");
-
-			render_path_set_target("tex");
-			render_path_bind_target(targetb, "tex");
-			render_path_bind_target("gbuffer0", "gbuffer0");
-			render_path_draw_shader("shader_datas/ssr_blur_pass/ssr_blur_pass_y3_blend");
-		}
-	}
-
-	// static draw_motion_blur = () => {
-	// 	if (config_raw.rp_motionblur != false) {
-	// 		render_path_set_target("buf");
-	// 		render_path_bind_target("tex", "tex");
-	// 		render_path_bind_target("gbuffer0", "gbuffer0");
-	// 		///if (rp_motionblur == "Camera")
-	// 		{
-	// 			render_path_bind_target("_main", "gbufferD");
-	// 			render_path_draw_shader("shader_datas/motion_blur_pass/motion_blur_pass");
-	// 		}
-	// 		///else
-	// 		{
-	// 			render_path_bind_target("gbuffer2", "sveloc");
-	// 			render_path_draw_shader("shader_datas/motion_blur_veloc_pass/motion_blur_veloc_pass");
-	// 		}
-	// 		///end
-	// 		render_path_set_target("tex");
-	// 		render_path_bind_target("buf", "tex");
-	// 		render_path_draw_shader("shader_datas/copy_pass/copy_pass");
-	// 	}
-	// }
-
-	// static draw_histogram = () => {
-	// 	{
-	// 		let t: render_target_t = RenderTarget.create();
-	// 		t.name = "histogram";
-	// 		t.width = 1;
-	// 		t.height = 1;
-	// 		t.format = "RGBA64";
-	// 		render_path_create_render_target(t);
-
-	// 		render_path_load_shader("shader_datas/histogram_pass/histogram_pass");
-	// 	}
-
-	// 	render_path_set_target("histogram");
-	// 	render_path_bind_target("taa", "tex");
-	// 	render_path_draw_shader("shader_datas/histogram_pass/histogram_pass");
-	// }
-
-	static draw_taa = () => {
-		let current: string = RenderPathBase.taa_frame % 2 == 0 ? "buf2" : "taa2";
-		let last: string = RenderPathBase.taa_frame % 2 == 0 ? "taa2" : "buf2";
-
-		render_path_set_target(current);
-		render_path_clear_target(0x00000000);
-		render_path_bind_target("buf", "colorTex");
-		render_path_draw_shader("shader_datas/smaa_edge_detect/smaa_edge_detect");
-
-		render_path_set_target("taa");
-		render_path_clear_target(0x00000000);
-		render_path_bind_target(current, "edgesTex");
-		render_path_draw_shader("shader_datas/smaa_blend_weight/smaa_blend_weight");
-
-		render_path_set_target(current);
-		render_path_bind_target("buf", "colorTex");
-		render_path_bind_target("taa", "blendTex");
-		render_path_bind_target("gbuffer2", "sveloc");
-		render_path_draw_shader("shader_datas/smaa_neighborhood_blend/smaa_neighborhood_blend");
-
-		let skip_taa: bool = context_raw.split_view;
-		if (skip_taa) {
-			render_path_set_target("taa");
-			render_path_bind_target(current, "tex");
-			render_path_draw_shader("shader_datas/copy_pass/copy_pass");
-		}
-		else {
-			render_path_set_target("taa");
-			render_path_bind_target(current, "tex");
-			render_path_bind_target(last, "tex2");
-			render_path_bind_target("gbuffer2", "sveloc");
-			render_path_draw_shader("shader_datas/taa_pass/taa_pass");
-		}
-
-		if (RenderPathBase.ssaa4()) {
-			render_path_set_target("");
-			render_path_bind_target(RenderPathBase.taa_frame % 2 == 0 ? "taa2" : "taa", "tex");
-			render_path_draw_shader("shader_datas/supersample_resolve/supersample_resolve");
-		}
-		else {
-			render_path_set_target("");
-			render_path_bind_target(RenderPathBase.taa_frame == 0 ? current : "taa", "tex");
-			render_path_draw_shader("shader_datas/copy_pass/copy_pass");
-		}
-	}
-
-	static draw_gbuffer = () => {
-		render_path_set_target("gbuffer0"); // Only clear gbuffer0
-		///if krom_metal
-		render_path_clear_target(0x00000000, 1.0, clear_flag_t.COLOR | clear_flag_t.DEPTH);
-		///else
-		render_path_clear_target(null, 1.0, clear_flag_t.DEPTH);
-		///end
-		if (MakeMesh.layer_pass_count == 1) {
-			render_path_set_target("gbuffer2");
-			render_path_clear_target(0xff000000);
-		}
-		render_path_set_target("gbuffer0", ["gbuffer1", "gbuffer2"]);
-		RenderPathPaint.bind_layers();
-		render_path_draw_meshes("mesh");
-		RenderPathPaint.unbind_layers();
-		if (MakeMesh.layer_pass_count > 1) {
-			RenderPathBase.make_gbuffer_copy_textures();
-			for (let i: i32 = 1; i < MakeMesh.layer_pass_count; ++i) {
-				let ping: string = i % 2 == 1 ? "_copy" : "";
-				let pong: string = i % 2 == 1 ? "" : "_copy";
-				if (i == MakeMesh.layer_pass_count - 1) {
-					render_path_set_target("gbuffer2" + ping);
-					render_path_clear_target(0xff000000);
-				}
-				render_path_set_target("gbuffer0" + ping, ["gbuffer1" + ping, "gbuffer2" + ping]);
-				render_path_bind_target("gbuffer0" + pong, "gbuffer0");
-				render_path_bind_target("gbuffer1" + pong, "gbuffer1");
-				render_path_bind_target("gbuffer2" + pong, "gbuffer2");
-				RenderPathPaint.bind_layers();
-				render_path_draw_meshes("mesh" + i);
-				RenderPathPaint.unbind_layers();
-			}
-			if (MakeMesh.layer_pass_count % 2 == 0) {
-				RenderPathBase.copy_to_gbuffer();
-			}
-		}
-
-		let hide: bool = operator_shortcut(config_keymap.stencil_hide, shortcut_type_t.DOWN) || keyboard_down("control");
-		let is_decal: bool = base_is_decal_layer();
-		if (is_decal && !hide) line_draw_render(context_raw.layer.decal_mat);
-	}
-
-	static make_gbuffer_copy_textures = () => {
-		let copy: render_target_t = render_path_render_targets.get("gbuffer0_copy");
-		if (copy == null || copy._image.width != render_path_render_targets.get("gbuffer0")._image.width || copy._image.height != render_path_render_targets.get("gbuffer0")._image.height) {
-			{
-				let t: render_target_t = render_target_create();
-				t.name = "gbuffer0_copy";
-				t.width = 0;
-				t.height = 0;
-				t.format = "RGBA64";
-				t.scale = RenderPathBase.get_super_sampling();
-				t.depth_buffer = "main";
-				render_path_create_render_target(t);
-			}
-			{
-				let t: render_target_t = render_target_create();
-				t.name = "gbuffer1_copy";
-				t.width = 0;
-				t.height = 0;
-				t.format = "RGBA64";
-				t.scale = RenderPathBase.get_super_sampling();
-				render_path_create_render_target(t);
-			}
-			{
-				let t: render_target_t = render_target_create();
-				t.name = "gbuffer2_copy";
-				t.width = 0;
-				t.height = 0;
-				t.format = "RGBA64";
-				t.scale = RenderPathBase.get_super_sampling();
-				render_path_create_render_target(t);
-			}
-
-			///if krom_metal
-			// TODO: Fix depth attach for gbuffer0_copy on metal
-			// Use resize to re-create buffers from scratch for now
-			render_path_resize();
-			///end
-		}
-	}
-
-	static copy_to_gbuffer = () => {
-		render_path_set_target("gbuffer0", ["gbuffer1", "gbuffer2"]);
-		render_path_bind_target("gbuffer0_copy", "tex0");
-		render_path_bind_target("gbuffer1_copy", "tex1");
-		render_path_bind_target("gbuffer2_copy", "tex2");
-		render_path_draw_shader("shader_datas/copy_mrt3_pass/copy_mrt3RGBA64_pass");
-	}
-}

+ 0 - 201
base/Sources/RenderPathDeferred.ts

@@ -1,201 +0,0 @@
-
-class RenderPathDeferred {
-
-	static init = () => {
-		render_path_create_depth_buffer("main", "DEPTH24");
-
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "gbuffer0";
-			t.width = 0;
-			t.height = 0;
-			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
-			t.depth_buffer = "main";
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "gbuffer1";
-			t.width = 0;
-			t.height = 0;
-			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "gbuffer2";
-			t.width = 0;
-			t.height = 0;
-			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "tex";
-			t.width = 0;
-			t.height = 0;
-			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
-			///if krom_opengl
-			t.depth_buffer = "main";
-			///end
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "buf";
-			t.width = 0;
-			t.height = 0;
-			///if (krom_direct3d12 || krom_vulkan)// || krom_metal)
-			// Match raytrace_target format
-			// Will cause "The render target format in slot 0 does not match that specified by the current pipeline state"
-			t.format = "RGBA64";
-			///else
-			t.format = "RGBA32";
-			///end
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "buf2";
-			t.width = 0;
-			t.height = 0;
-			t.format = "RGBA32";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "taa";
-			t.width = 0;
-			t.height = 0;
-			t.format = "RGBA32";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "taa2";
-			t.width = 0;
-			t.height = 0;
-			t.format = "RGBA32";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "empty_white";
-			t.width = 1;
-			t.height = 1;
-			t.format = "R8";
-			let b: ArrayBuffer = new ArrayBuffer(1);
-			let v: DataView = new DataView(b);
-			v.setUint8(0, 255);
-			t._image = image_from_bytes(b, t.width, t.height, tex_format_t.R8);
-			render_path_render_targets.set(t.name, t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "empty_black";
-			t.width = 1;
-			t.height = 1;
-			t.format = "RGBA32";
-			let b: ArrayBuffer = new ArrayBuffer(4);
-			let v: DataView = new DataView(b);
-			v.setUint8(0, 0);
-			v.setUint8(1, 0);
-			v.setUint8(2, 0);
-			v.setUint8(3, 0);
-			t._image = image_from_bytes(b, t.width, t.height, tex_format_t.RGBA32);
-			render_path_render_targets.set(t.name, t);
-		}
-
-		///if is_sculpt
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "gbuffer0_undo";
-			t.width = 0;
-			t.height = 0;
-			t.format = "RGBA64";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		{
-			let t: render_target_t = render_target_create();
-			t.name = "gbufferD_undo";
-			t.width = 0;
-			t.height = 0;
-			t.format = "R32";
-			t.scale = RenderPathBase.get_super_sampling();
-			render_path_create_render_target(t);
-		}
-		///end
-
-		if (config_raw.rp_ssao) {
-			RenderPathBase.init_ssao();
-		}
-
-		render_path_load_shader("shader_datas/world_pass/world_pass");
-		render_path_load_shader("shader_datas/deferred_light/deferred_light");
-		render_path_load_shader("shader_datas/compositor_pass/compositor_pass");
-		render_path_load_shader("shader_datas/copy_pass/copy_pass");
-		render_path_load_shader("shader_datas/copy_pass/copyR8_pass");
-		render_path_load_shader("shader_datas/smaa_edge_detect/smaa_edge_detect");
-		render_path_load_shader("shader_datas/smaa_blend_weight/smaa_blend_weight");
-		render_path_load_shader("shader_datas/smaa_neighborhood_blend/smaa_neighborhood_blend");
-		render_path_load_shader("shader_datas/taa_pass/taa_pass");
-		render_path_load_shader("shader_datas/supersample_resolve/supersample_resolve");
-		// render_path_load_shader("shader_datas/motion_blur_pass/motion_blur_pass");
-		// render_path_load_shader("shader_datas/motion_blur_veloc_pass/motion_blur_veloc_pass");
-		///if arm_voxels
-		{
-			RenderPathBase.init_voxels();
-			render_path_load_shader("shader_datas/deferred_light/deferred_light_voxel");
-		}
-		///end
-
-		RenderPathPaint.init();
-
-		///if (is_paint || is_sculpt)
-		RenderPathPreview.init();
-		///end
-
-		///if (krom_direct3d12 || krom_vulkan || krom_metal)
-		RenderPathRaytrace.init();
-		///end
-	}
-
-	static commands = () => {
-		///if is_paint
-		RenderPathPaint.live_brush_dirty();
-		///end
-		RenderPathBase.commands(RenderPathDeferred.draw_deferred);
-	}
-
-	static draw_deferred = () => {
-		RenderPathBase.draw_ssao();
-		///if arm_voxels
-		RenderPathBase.draw_voxels();
-		///end
-		RenderPathBase.draw_deferred_light();
-		RenderPathBase.draw_bloom();
-		RenderPathBase.draw_ssr();
-		// RenderPathBase.drawMotionBlur();
-		// RenderPathBase.drawHistogram();
-
-		render_path_set_target("buf");
-		render_path_bind_target("tex", "tex");
-		// render_path_bind_target("histogram", "histogram");
-		render_path_draw_shader("shader_datas/compositor_pass/compositor_pass");
-
-		render_path_set_target("buf");
-		RenderPathBase.draw_compass();
-		render_path_draw_meshes("overlay");
-
-		RenderPathBase.draw_taa();
-	}
-}

+ 0 - 30
base/Sources/RenderPathForward.ts

@@ -1,30 +0,0 @@
-
-class RenderPathForward {
-
-	static init = () => {
-	}
-
-	static commands = () => {
-		///if is_paint
-		RenderPathPaint.live_brush_dirty();
-		///end
-		RenderPathBase.commands(RenderPathForward.draw_forward);
-	}
-
-	static draw_forward = () => {
-		render_path_set_depth_from("gbuffer1", "gbuffer0");
-		render_path_set_target("gbuffer1");
-		render_path_draw_skydome("shader_datas/world_pass/world_pass");
-		render_path_set_depth_from("gbuffer1", "gbuffer2");
-
-		render_path_set_target("buf");
-		render_path_bind_target("gbuffer1", "tex");
-		render_path_draw_shader("shader_datas/compositor_pass/compositor_pass");
-
-		render_path_set_target("buf");
-		RenderPathBase.draw_compass();
-		render_path_draw_meshes("overlay");
-
-		RenderPathBase.draw_taa();
-	}
-}

+ 0 - 196
base/Sources/RenderPathRaytrace.ts

@@ -1,196 +0,0 @@
-
-///if (krom_direct3d12 || krom_vulkan || krom_metal)
-
-class RenderPathRaytrace {
-
-	static frame: i32 = 0;
-	static ready: bool = false;
-	static dirty: i32 = 0;
-	static uv_scale: f32 = 1.0;
-	static first: bool = true;
-	static f32a: Float32Array = new Float32Array(24);
-	static help_mat: mat4_t = mat4_identity();
-	static vb_scale: f32 = 1.0;
-	static vb: vertex_buffer_t;
-	static ib: index_buffer_t;
-
-	static last_envmap: image_t = null;
-	static is_bake: bool = false;
-
-	///if krom_direct3d12
-	static ext: string = ".cso";
-	///elseif krom_metal
-	static ext: string = ".metal";
-	///else
-	static ext: string = ".spirv";
-	///end
-
-	///if is_lab
-	static last_texpaint: image_t = null;
-	///end
-
-	static init = () => {
-	}
-
-	static commands = (useLiveLayer: bool) => {
-		if (!RenderPathRaytrace.ready || RenderPathRaytrace.is_bake) {
-			RenderPathRaytrace.ready = true;
-			RenderPathRaytrace.is_bake = false;
-			let mode: string = context_raw.pathtrace_mode == path_trace_mode_t.CORE ? "core" : "full";
-			RenderPathRaytrace.raytrace_init("raytrace_brute_" + mode + RenderPathRaytrace.ext);
-			RenderPathRaytrace.last_envmap = null;
-		}
-
-		if (!context_raw.envmap_loaded) {
-			context_load_envmap();
-			context_update_envmap();
-		}
-
-		let probe: world_data_t = scene_world;
-		let saved_envmap: image_t = context_raw.show_envmap_blur ? probe._.radiance_mipmaps[0] : context_raw.saved_envmap;
-
-		if (RenderPathRaytrace.last_envmap != saved_envmap) {
-			RenderPathRaytrace.last_envmap = saved_envmap;
-
-			let bnoise_sobol: image_t = scene_embedded.get("bnoise_sobol.k");
-			let bnoise_scramble: image_t = scene_embedded.get("bnoise_scramble.k");
-			let bnoise_rank: image_t = scene_embedded.get("bnoise_rank.k");
-
-			let l: any = base_flatten(true);
-			krom_raytrace_set_textures(l.texpaint, l.texpaint_nor, l.texpaint_pack, saved_envmap.texture_, bnoise_sobol.texture_, bnoise_scramble.texture_, bnoise_rank.texture_);
-		}
-
-		///if is_lab
-		let l: any = base_flatten(true);
-		if (l.texpaint != RenderPathRaytrace.last_texpaint) {
-			RenderPathRaytrace.last_texpaint = l.texpaint;
-
-			let bnoise_sobol: image_t = scene_embedded.get("bnoise_sobol.k");
-			let bnoise_scramble: image_t = scene_embedded.get("bnoise_scramble.k");
-			let bnoise_rank: image_t = scene_embedded.get("bnoise_rank.k");
-
-			krom_raytrace_set_textures(l.texpaint, l.texpaint_nor, l.texpaint_pack, saved_envmap.texture_, bnoise_sobol.texture_, bnoise_scramble.texture_, bnoise_rank.texture_);
-		}
-		///end
-
-		if (context_raw.pdirty > 0 || RenderPathRaytrace.dirty > 0) {
-			base_flatten(true);
-		}
-
-		let cam: camera_object_t = scene_camera;
-		let ct: transform_t = cam.base.transform;
-		mat4_set_from(RenderPathRaytrace.help_mat, cam.v);
-		mat4_mult_mat(RenderPathRaytrace.help_mat, cam.p);
-		mat4_get_inv(RenderPathRaytrace.help_mat, RenderPathRaytrace.help_mat);
-		RenderPathRaytrace.f32a[0] = transform_world_x(ct);
-		RenderPathRaytrace.f32a[1] = transform_world_y(ct);
-		RenderPathRaytrace.f32a[2] = transform_world_z(ct);
-		RenderPathRaytrace.f32a[3] = RenderPathRaytrace.frame;
-		///if krom_metal
-		// frame = (frame % (16)) + 1; // _PAINT
-		RenderPathRaytrace.frame = RenderPathRaytrace.frame + 1; // _RENDER
-		///else
-		RenderPathRaytrace.frame = (RenderPathRaytrace.frame % 4) + 1; // _PAINT
-		// frame = frame + 1; // _RENDER
-		///end
-		RenderPathRaytrace.f32a[4] = RenderPathRaytrace.help_mat.m[0];
-		RenderPathRaytrace.f32a[5] = RenderPathRaytrace.help_mat.m[1];
-		RenderPathRaytrace.f32a[6] = RenderPathRaytrace.help_mat.m[2];
-		RenderPathRaytrace.f32a[7] = RenderPathRaytrace.help_mat.m[3];
-		RenderPathRaytrace.f32a[8] = RenderPathRaytrace.help_mat.m[4];
-		RenderPathRaytrace.f32a[9] = RenderPathRaytrace.help_mat.m[5];
-		RenderPathRaytrace.f32a[10] = RenderPathRaytrace.help_mat.m[6];
-		RenderPathRaytrace.f32a[11] = RenderPathRaytrace.help_mat.m[7];
-		RenderPathRaytrace.f32a[12] = RenderPathRaytrace.help_mat.m[8];
-		RenderPathRaytrace.f32a[13] = RenderPathRaytrace.help_mat.m[9];
-		RenderPathRaytrace.f32a[14] = RenderPathRaytrace.help_mat.m[10];
-		RenderPathRaytrace.f32a[15] = RenderPathRaytrace.help_mat.m[11];
-		RenderPathRaytrace.f32a[16] = RenderPathRaytrace.help_mat.m[12];
-		RenderPathRaytrace.f32a[17] = RenderPathRaytrace.help_mat.m[13];
-		RenderPathRaytrace.f32a[18] = RenderPathRaytrace.help_mat.m[14];
-		RenderPathRaytrace.f32a[19] = RenderPathRaytrace.help_mat.m[15];
-		RenderPathRaytrace.f32a[20] = scene_world.strength * 1.5;
-		if (!context_raw.show_envmap) RenderPathRaytrace.f32a[20] = -RenderPathRaytrace.f32a[20];
-		RenderPathRaytrace.f32a[21] = context_raw.envmap_angle;
-		RenderPathRaytrace.f32a[22] = RenderPathRaytrace.uv_scale;
-		///if is_lab
-		RenderPathRaytrace.f32a[22] *= scene_meshes[0].data.scale_tex;
-		///end
-
-		let framebuffer: image_t = render_path_render_targets.get("buf")._image;
-		krom_raytrace_dispatch_rays(framebuffer.render_target_, RenderPathRaytrace.f32a.buffer);
-
-		if (context_raw.ddirty == 1 || context_raw.pdirty == 1) {
-			///if krom_metal
-			context_raw.rdirty = 128;
-			///else
-			context_raw.rdirty = 4;
-			///end
-		}
-		context_raw.ddirty--;
-		context_raw.pdirty--;
-		context_raw.rdirty--;
-
-		// raw.ddirty = 1; // _RENDER
-	}
-
-	static raytrace_init = (shaderName: string, build: bool = true) => {
-		if (RenderPathRaytrace.first) {
-			RenderPathRaytrace.first = false;
-			scene_embed_data("bnoise_sobol.k");
-			scene_embed_data("bnoise_scramble.k");
-			scene_embed_data("bnoise_rank.k");
-		}
-
-		let shader: ArrayBuffer = data_get_blob(shaderName);
-		if (build) RenderPathRaytrace.build_data();
-		krom_raytrace_init(shader, RenderPathRaytrace.vb.buffer_, RenderPathRaytrace.ib.buffer_, RenderPathRaytrace.vb_scale);
-	}
-
-	static build_data = () => {
-		if (context_raw.merged_object == null) util_mesh_merge();
-		///if is_paint
-		let mo: mesh_object_t = !context_layer_filter_used() ? context_raw.merged_object : context_raw.paint_object;
-		///else
-		let mo: mesh_object_t = scene_meshes[0];
-		///end
-		let md: mesh_data_t = mo.data;
-		let mo_scale: f32 = mo.base.transform.scale.x; // Uniform scale only
-		RenderPathRaytrace.vb_scale = md.scale_pos * mo_scale;
-		if (mo.base.parent != null) RenderPathRaytrace.vb_scale *= mo.base.parent.transform.scale.x;
-		RenderPathRaytrace.vb = md._.vertex_buffer;
-		RenderPathRaytrace.ib = md._.index_buffers[0];
-	}
-
-	static draw = (useLiveLayer: bool) => {
-		let is_live: bool = config_raw.brush_live && RenderPathPaint.live_layer_drawn > 0;
-		if (context_raw.ddirty > 1 || context_raw.pdirty > 0 || is_live) RenderPathRaytrace.frame = 0;
-
-		///if krom_metal
-		// Delay path tracing additional samples while painting
-		let down: bool = mouse_down() || pen_down();
-		if (context_in_viewport() && down) RenderPathRaytrace.frame = 0;
-		///end
-
-		RenderPathRaytrace.commands(useLiveLayer);
-
-		if (config_raw.rp_bloom != false) {
-			RenderPathBase.draw_bloom("buf");
-		}
-		render_path_set_target("buf");
-		render_path_draw_meshes("overlay");
-		render_path_set_target("buf");
-		RenderPathBase.draw_compass();
-		render_path_set_target("taa");
-		render_path_bind_target("buf", "tex");
-		render_path_draw_shader("shader_datas/compositor_pass/compositor_pass");
-		render_path_set_target("");
-		render_path_bind_target("taa", "tex");
-		render_path_draw_shader("shader_datas/copy_pass/copy_pass");
-		if (config_raw.brush_3d) {
-			RenderPathPaint.commands_cursor();
-		}
-	}
-}
-
-///end

+ 0 - 149
base/Sources/RenderPathRaytraceBake.ts

@@ -1,149 +0,0 @@
-
-///if (krom_direct3d12 || krom_vulkan || krom_metal)
-
-class RenderPathRaytraceBake {
-
-	static rays_pix: i32 = 0;
-	static rays_sec: i32 = 0;
-	static current_sample: i32 = 0;
-	static rays_timer: f32 = 0.0;
-	static rays_counter: i32 = 0;
-	static last_layer: image_t = null;
-	static last_bake: i32 = 0;
-
-	static commands = (parsePaintMaterial: (b?: bool)=>void): bool => {
-
-		if (!RenderPathRaytrace.ready || !RenderPathRaytrace.is_bake || RenderPathRaytraceBake.last_bake != context_raw.bake_type) {
-			let rebuild: bool = !(RenderPathRaytrace.ready && RenderPathRaytrace.is_bake && RenderPathRaytraceBake.last_bake != context_raw.bake_type);
-			RenderPathRaytraceBake.last_bake = context_raw.bake_type;
-			RenderPathRaytrace.ready = true;
-			RenderPathRaytrace.is_bake = true;
-			RenderPathRaytrace.last_envmap = null;
-			RenderPathRaytraceBake.last_layer = null;
-
-			if (render_path_render_targets.get("baketex0") != null) {
-				image_unload(render_path_render_targets.get("baketex0")._image);
-				image_unload(render_path_render_targets.get("baketex1")._image);
-				image_unload(render_path_render_targets.get("baketex2")._image);
-			}
-
-			{
-				let t: render_target_t = render_target_create();
-				t.name = "baketex0";
-				t.width = config_get_texture_res_x();
-				t.height = config_get_texture_res_y();
-				t.format = "RGBA64";
-				render_path_create_render_target(t);
-			}
-			{
-				let t: render_target_t = render_target_create();
-				t.name = "baketex1";
-				t.width = config_get_texture_res_x();
-				t.height = config_get_texture_res_y();
-				t.format = "RGBA64";
-				render_path_create_render_target(t);
-			}
-			{
-				let t: render_target_t = render_target_create();
-				t.name = "baketex2";
-				t.width = config_get_texture_res_x();
-				t.height = config_get_texture_res_y();
-				t.format = "RGBA64"; // Match raytrace_target format
-				render_path_create_render_target(t);
-			}
-
-			let _bake_type: bake_type_t = context_raw.bake_type;
-			context_raw.bake_type = bake_type_t.INIT;
-			parsePaintMaterial();
-			render_path_set_target("baketex0");
-			render_path_clear_target(0x00000000); // Pixels with alpha of 0.0 are skipped during raytracing
-			render_path_set_target("baketex0", ["baketex1"]);
-			render_path_draw_meshes("paint");
-			context_raw.bake_type = _bake_type;
-			let _next = () => {
-				parsePaintMaterial();
-			}
-			base_notify_on_next_frame(_next);
-
-			RenderPathRaytrace.raytrace_init(RenderPathRaytraceBake.get_bake_shader_name(), rebuild);
-
-			return false;
-		}
-
-		if (!context_raw.envmap_loaded) {
-			context_load_envmap();
-			context_update_envmap();
-		}
-		let probe: world_data_t = scene_world;
-		let saved_envmap: image_t = context_raw.show_envmap_blur ? probe._.radiance_mipmaps[0] : context_raw.saved_envmap;
-		if (RenderPathRaytrace.last_envmap != saved_envmap || RenderPathRaytraceBake.last_layer != context_raw.layer.texpaint) {
-			RenderPathRaytrace.last_envmap = saved_envmap;
-			RenderPathRaytraceBake.last_layer = context_raw.layer.texpaint;
-
-			let baketex0: image_t = render_path_render_targets.get("baketex0")._image;
-			let baketex1: image_t = render_path_render_targets.get("baketex1")._image;
-			let bnoise_sobol: image_t = scene_embedded.get("bnoise_sobol.k");
-			let bnoise_scramble: image_t = scene_embedded.get("bnoise_scramble.k");
-			let bnoise_rank: image_t = scene_embedded.get("bnoise_rank.k");
-			let texpaint_undo: image_t = render_path_render_targets.get("texpaint_undo" + history_undo_i)._image;
-			krom_raytrace_set_textures(baketex0, baketex1, texpaint_undo, saved_envmap.texture_, bnoise_sobol.texture_, bnoise_scramble.texture_, bnoise_rank.texture_);
-		}
-
-		if (context_raw.brush_time > 0) {
-			context_raw.pdirty = 2;
-			context_raw.rdirty = 2;
-		}
-
-		if (context_raw.pdirty > 0) {
-			let f32a: Float32Array = RenderPathRaytrace.f32a;
-			f32a[0] = RenderPathRaytrace.frame++;
-			f32a[1] = context_raw.bake_ao_strength;
-			f32a[2] = context_raw.bake_ao_radius;
-			f32a[3] = context_raw.bake_ao_offset;
-			f32a[4] = scene_world.strength;
-			f32a[5] = context_raw.bake_up_axis;
-			f32a[6] = context_raw.envmap_angle;
-
-			let framebuffer: image_t = render_path_render_targets.get("baketex2")._image;
-			krom_raytrace_dispatch_rays(framebuffer.render_target_, f32a.buffer);
-
-			render_path_set_target("texpaint" + context_raw.layer.id);
-			render_path_bind_target("baketex2", "tex");
-			render_path_draw_shader("shader_datas/copy_pass/copy_pass");
-
-			///if krom_metal
-			let samples_per_frame: i32 = 4;
-			///else
-			let samples_per_frame: i32 = 64;
-			///end
-
-			RenderPathRaytraceBake.rays_pix = RenderPathRaytrace.frame * samples_per_frame;
-			RenderPathRaytraceBake.rays_counter += samples_per_frame;
-			RenderPathRaytraceBake.rays_timer += time_real_delta();
-			if (RenderPathRaytraceBake.rays_timer >= 1) {
-				RenderPathRaytraceBake.rays_sec = RenderPathRaytraceBake.rays_counter;
-				RenderPathRaytraceBake.rays_timer = 0;
-				RenderPathRaytraceBake.rays_counter = 0;
-			}
-			RenderPathRaytraceBake.current_sample++;
-			krom_delay_idle_sleep();
-			return true;
-		}
-		else {
-			RenderPathRaytrace.frame = 0;
-			RenderPathRaytraceBake.rays_timer = 0;
-			RenderPathRaytraceBake.rays_counter = 0;
-			RenderPathRaytraceBake.current_sample = 0;
-			return false;
-		}
-	}
-
-	static get_bake_shader_name = (): string => {
-		return context_raw.bake_type == bake_type_t.AO  		? "raytrace_bake_ao" + RenderPathRaytrace.ext :
-			   context_raw.bake_type == bake_type_t.LIGHTMAP 	? "raytrace_bake_light" + RenderPathRaytrace.ext :
-			   context_raw.bake_type == bake_type_t.BENT_NORMAL  ? "raytrace_bake_bent" + RenderPathRaytrace.ext :
-												  				  "raytrace_bake_thick" + RenderPathRaytrace.ext;
-	}
-}
-
-///end

+ 43 - 43
base/Sources/TabBrowser.ts

@@ -1,18 +1,18 @@
 
 class TabBrowser {
 
-	static hpath: zui_handle_t = zui_handle_create();
-	static hsearch: zui_handle_t = zui_handle_create();
-	static known: bool = false;
-	static last_path: string =  "";
-
-	static show_directory = (directory: string) => {
-		TabBrowser.hpath.text = directory;
-		TabBrowser.hsearch.text = "";
+	static tab_browser_hpath: zui_handle_t = zui_handle_create();
+	static tab_browser_hsearch: zui_handle_t = zui_handle_create();
+	static tab_browser_known: bool = false;
+	static tab_browser_last_path: string =  "";
+
+	static tab_browser_show_directory = (directory: string) => {
+		TabBrowser.tab_browser_hpath.text = directory;
+		TabBrowser.tab_browser_hsearch.text = "";
 		ui_base_htabs[tab_area_t.STATUS].position = 0;
 	}
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_browser_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		let statush: i32 = config_raw.layout[layout_size_t.STATUS_H];
 		if (zui_tab(htab, tr("Browser")) && statush > ui_status_default_status_h * zui_SCALE(ui)) {
@@ -23,13 +23,13 @@ class TabBrowser {
 
 			let bookmarks_w: i32 = math_floor(100 * zui_SCALE(ui));
 
-			if (TabBrowser.hpath.text == "" && config_raw.bookmarks.length > 0) { // Init to first bookmark
-				TabBrowser.hpath.text = config_raw.bookmarks[0];
+			if (TabBrowser.tab_browser_hpath.text == "" && config_raw.bookmarks.length > 0) { // Init to first bookmark
+				TabBrowser.tab_browser_hpath.text = config_raw.bookmarks[0];
 			}
 
 			zui_begin_sticky();
 			let step: i32 = (1 - bookmarks_w / ui._w);
-			if (TabBrowser.hsearch.text != "") {
+			if (TabBrowser.tab_browser_hsearch.text != "") {
 				zui_row([bookmarks_w / ui._w, step * 0.73, step * 0.07, step * 0.17, step * 0.03]);
 			}
 			else {
@@ -37,7 +37,7 @@ class TabBrowser {
 			}
 
 			if (zui_button("+")) {
-				config_raw.bookmarks.push(TabBrowser.hpath.text);
+				config_raw.bookmarks.push(TabBrowser.tab_browser_hpath.text);
 				config_save();
 			}
 			if (ui.is_hovered) zui_tooltip(tr("Add bookmark"));
@@ -45,17 +45,17 @@ class TabBrowser {
 			///if krom_android
 			let stripped: bool = false;
 			let strip: string = "/storage/emulated/0/";
-			if (TabBrowser.hpath.text.startsWith(strip)) {
-				TabBrowser.hpath.text = TabBrowser.hpath.text.substr(strip.length - 1);
+			if (TabBrowser.tab_browser_hpath.text.startsWith(strip)) {
+				TabBrowser.tab_browser_hpath.text = TabBrowser.tab_browser_hpath.text.substr(strip.length - 1);
 				stripped = true;
 			}
 			///end
 
-			TabBrowser.hpath.text = zui_text_input(TabBrowser.hpath, tr("Path"));
+			TabBrowser.tab_browser_hpath.text = zui_text_input(TabBrowser.tab_browser_hpath, tr("Path"));
 
 			///if krom_android
 			if (stripped) {
-				TabBrowser.hpath.text = "/storage/emulated/0" + TabBrowser.hpath.text;
+				TabBrowser.tab_browser_hpath.text = "/storage/emulated/0" + TabBrowser.tab_browser_hpath.text;
 			}
 			///end
 
@@ -65,34 +65,34 @@ class TabBrowser {
 			if (zui_button(tr("Refresh")) || (in_focus && ui.is_key_pressed && ui.key == key_code_t.F5)) {
 				refresh = true;
 			}
-			TabBrowser.hsearch.text = zui_text_input(TabBrowser.hsearch, tr("Search"), zui_align_t.LEFT, true, true);
+			TabBrowser.tab_browser_hsearch.text = zui_text_input(TabBrowser.tab_browser_hsearch, tr("Search"), zui_align_t.LEFT, true, true);
 			if (ui.is_hovered) zui_tooltip(tr("ctrl+f to search") + "\n" + tr("esc to cancel"));
 			if (ui.is_ctrl_down && ui.is_key_pressed && ui.key == key_code_t.F) { // Start searching via ctrl+f
-				zui_start_text_edit(TabBrowser.hsearch);
+				zui_start_text_edit(TabBrowser.tab_browser_hsearch);
 			}
-			if (TabBrowser.hsearch.text != "" && (zui_button(tr("X")) || ui.is_escape_down)) {
-				TabBrowser.hsearch.text = "";
+			if (TabBrowser.tab_browser_hsearch.text != "" && (zui_button(tr("X")) || ui.is_escape_down)) {
+				TabBrowser.tab_browser_hsearch.text = "";
 			}
 			zui_end_sticky();
 
-			if (TabBrowser.last_path != TabBrowser.hpath.text) {
-				TabBrowser.hsearch.text = "";
+			if (TabBrowser.tab_browser_last_path != TabBrowser.tab_browser_hpath.text) {
+				TabBrowser.tab_browser_hsearch.text = "";
 			}
-			TabBrowser.last_path = TabBrowser.hpath.text;
+			TabBrowser.tab_browser_last_path = TabBrowser.tab_browser_hpath.text;
 
 			let _y: f32 = ui._y;
 			ui._x = bookmarks_w;
 			ui._w -= bookmarks_w;
-			ui_files_file_browser(ui, TabBrowser.hpath, false, true, TabBrowser.hsearch.text, refresh, (file: string) => {
+			ui_files_file_browser(ui, TabBrowser.tab_browser_hpath, false, true, TabBrowser.tab_browser_hsearch.text, refresh, (file: string) => {
 				let file_name: string = file.substr(file.lastIndexOf(path_sep) + 1);
 				if (file_name != "..") {
 					ui_menu_draw((ui: zui_t) => {
 						if (ui_menu_button(ui, tr("Import"))) {
-							ImportAsset.run(file);
+							import_asset_run(file);
 						}
 						if (path_is_texture(file)) {
 							if (ui_menu_button(ui, tr("Set as Envmap"))) {
-								ImportAsset.run(file, -1.0, -1.0, true, true, () => {
+								import_asset_run(file, -1.0, -1.0, true, true, () => {
 									base_notify_on_next_frame(() => {
 										let asset_index: i32 = -1;
 										for (let i: i32 = 0; i < project_assets.length; ++i) {
@@ -102,7 +102,7 @@ class TabBrowser {
 											}
 										}
 										if (asset_index != -1) {
-											ImportEnvmap.run(file, project_get_image(project_assets[asset_index]));
+											import_envmap_run(file, project_get_image(project_assets[asset_index]));
 										}
 									});
 								});
@@ -110,7 +110,7 @@ class TabBrowser {
 
 							///if (is_paint || is_sculpt)
 							if (ui_menu_button(ui, tr("Set as Mask"))) {
-								ImportAsset.run(file, -1.0, -1.0, true, true, () => {
+								import_asset_run(file, -1.0, -1.0, true, true, () => {
 									base_notify_on_next_frame(() => {
 										let asset_index: i32 = -1;
 										for (let i: i32 = 0; i < project_assets.length; ++i) {
@@ -129,7 +129,7 @@ class TabBrowser {
 
 							///if is_paint
 							if (ui_menu_button(ui, tr("Set as Color ID Map"))) {
-								ImportAsset.run(file, -1.0, -1.0, true, true, () => {
+								import_asset_run(file, -1.0, -1.0, true, true, () => {
 									base_notify_on_next_frame(() => {
 										let asset_index: i32 = -1;
 										for (let i: i32 = 0; i < project_assets.length; ++i) {
@@ -159,16 +159,16 @@ class TabBrowser {
 				}
 			});
 
-			if (TabBrowser.known) {
-				let path: string = TabBrowser.hpath.text;
+			if (TabBrowser.tab_browser_known) {
+				let path: string = TabBrowser.tab_browser_hpath.text;
 				app_notify_on_init(() => {
-					ImportAsset.run(path);
+					import_asset_run(path);
 				});
-				TabBrowser.hpath.text = TabBrowser.hpath.text.substr(0, TabBrowser.hpath.text.lastIndexOf(path_sep));
+				TabBrowser.tab_browser_hpath.text = TabBrowser.tab_browser_hpath.text.substr(0, TabBrowser.tab_browser_hpath.text.lastIndexOf(path_sep));
 			}
-			TabBrowser.known = TabBrowser.hpath.text.substr(TabBrowser.hpath.text.lastIndexOf(path_sep)).indexOf(".") > 0;
+			TabBrowser.tab_browser_known = TabBrowser.tab_browser_hpath.text.substr(TabBrowser.tab_browser_hpath.text.lastIndexOf(path_sep)).indexOf(".") > 0;
 			///if krom_android
-			if (TabBrowser.hpath.text.endsWith("." + manifest_title.toLowerCase())) TabBrowser.known = false;
+			if (TabBrowser.tab_browser_hpath.text.endsWith("." + manifest_title.toLowerCase())) TabBrowser.tab_browser_known = false;
 			///end
 
 			let bottom_y: i32 = ui._y;
@@ -177,27 +177,27 @@ class TabBrowser {
 			ui._w = bookmarks_w;
 
 			if (zui_button(tr("Cloud"), zui_align_t.LEFT)) {
-				TabBrowser.hpath.text = "cloud";
+				TabBrowser.tab_browser_hpath.text = "cloud";
 			}
 
 			if (zui_button(tr("Disk"), zui_align_t.LEFT)) {
 				///if krom_android
 				ui_menu_draw((ui: zui_t) => {
 					if (ui_menu_button(ui, tr("Download"))) {
-						TabBrowser.hpath.text = ui_files_default_path;
+						TabBrowser.tab_browser_hpath.text = ui_files_default_path;
 					}
 					if (ui_menu_button(ui, tr("Pictures"))) {
-						TabBrowser.hpath.text = "/storage/emulated/0/Pictures";
+						TabBrowser.tab_browser_hpath.text = "/storage/emulated/0/Pictures";
 					}
 					if (ui_menu_button(ui, tr("Camera"))) {
-						TabBrowser.hpath.text = "/storage/emulated/0/DCIM/Camera";
+						TabBrowser.tab_browser_hpath.text = "/storage/emulated/0/DCIM/Camera";
 					}
 					if (ui_menu_button(ui, tr("Projects"))) {
-						TabBrowser.hpath.text = krom_save_path();
+						TabBrowser.tab_browser_hpath.text = krom_save_path();
 					}
 				}, 4);
 				///else
-				TabBrowser.hpath.text = ui_files_default_path;
+				TabBrowser.tab_browser_hpath.text = ui_files_default_path;
 				///end
 			}
 
@@ -205,7 +205,7 @@ class TabBrowser {
 				let folder: string = b.substr(b.lastIndexOf(path_sep) + 1);
 
 				if (zui_button(folder, zui_align_t.LEFT)) {
-					TabBrowser.hpath.text = b;
+					TabBrowser.tab_browser_hpath.text = b;
 				}
 
 				if (ui.is_hovered && ui.input_released_r) {

+ 9 - 9
base/Sources/TabBrushes.ts

@@ -3,15 +3,15 @@
 
 class TabBrushes {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_brushes_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		if (zui_tab(htab, tr("Brushes"))) {
 			zui_begin_sticky();
 			zui_row([1 / 4, 1 / 4, 1 / 4]);
 			if (zui_button(tr("New"))) {
-				context_raw.brush = SlotBrush.create();
+				context_raw.brush = SlotBrush.slot_brush_create();
 				project_brushes.push(context_raw.brush);
-				MakeMaterial.parse_brush();
+				MakeMaterial.make_material_parse_brush();
 				ui_nodes_hwnd.redraws = 2;
 			}
 			if (zui_button(tr("Import"))) {
@@ -78,12 +78,12 @@ class TabBrushes {
 
 							if (ui_menu_button(ui, tr("Export"))) {
 								context_select_brush(i);
-								BoxExport.show_brush();
+								box_export_show_brush();
 							}
 
 							if (ui_menu_button(ui, tr("Duplicate"))) {
 								let _init = () => {
-									context_raw.brush = SlotBrush.create();
+									context_raw.brush = SlotBrush.slot_brush_create();
 									project_brushes.push(context_raw.brush);
 									let cloned: any = json_parse(json_stringify(project_brushes[i].canvas));
 									context_raw.brush.canvas = cloned;
@@ -94,7 +94,7 @@ class TabBrushes {
 							}
 
 							if (project_brushes.length > 1 && ui_menu_button(ui, tr("Delete"), "delete")) {
-								TabBrushes.delete_brush(project_brushes[i]);
+								TabBrushes.tab_brushes_delete_brush(project_brushes[i]);
 							}
 						}, 2 + add);
 					}
@@ -104,7 +104,7 @@ class TabBrushes {
 							app_notify_on_init(() => {
 								let _brush: SlotBrushRaw = context_raw.brush;
 								context_raw.brush = project_brushes[i];
-								MakeMaterial.parse_brush();
+								MakeMaterial.make_material_parse_brush();
 								util_render_make_brush_preview();
 								context_raw.brush = _brush;
 							});
@@ -134,12 +134,12 @@ class TabBrushes {
 						  		 ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
 			if (in_focus && ui.is_delete_down && project_brushes.length > 1) {
 				ui.is_delete_down = false;
-				TabBrushes.delete_brush(context_raw.brush);
+				TabBrushes.tab_brushes_delete_brush(context_raw.brush);
 			}
 		}
 	}
 
-	static delete_brush = (b: SlotBrushRaw) => {
+	static tab_brushes_delete_brush = (b: SlotBrushRaw) => {
 		let i: i32 = project_brushes.indexOf(b);
 		context_select_brush(i == project_brushes.length - 1 ? i - 1 : i + 1);
 		project_brushes.splice(i, 1);

+ 1 - 1
base/Sources/TabConsole.ts

@@ -1,7 +1,7 @@
 
 class TabConsole {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_console_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 
 		let title: string = console_message_timer > 0 ? console_message + "        " : tr("Console");

+ 4 - 4
base/Sources/TabFonts.ts

@@ -3,7 +3,7 @@
 
 class TabFonts {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_fonts_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		let statush: i32 = config_raw.layout[layout_size_t.STATUS_H];
 		if (zui_tab(htab, tr("Fonts")) && statush > ui_status_default_status_h * zui_SCALE(ui)) {
@@ -91,7 +91,7 @@ class TabFonts {
 						let add: i32 = project_fonts.length > 1 ? 1 : 0;
 						ui_menu_draw((ui: zui_t) => {
 							if (project_fonts.length > 1 && ui_menu_button(ui, tr("Delete"), "delete") && project_fonts[i].file != "") {
-								TabFonts.delete_font(project_fonts[i]);
+								TabFonts.tab_fonts_delete_font(project_fonts[i]);
 							}
 						}, 0 + add);
 					}
@@ -129,12 +129,12 @@ class TabFonts {
 						    	 ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
 			if (in_focus && ui.is_delete_down && project_fonts.length > 1 && context_raw.font.file != "") {
 				ui.is_delete_down = false;
-				TabFonts.delete_font(context_raw.font);
+				TabFonts.tab_fonts_delete_font(context_raw.font);
 			}
 		}
 	}
 
-	static delete_font = (font: SlotFontRaw) => {
+	static tab_fonts_delete_font = (font: SlotFontRaw) => {
 		let i: i32 = project_fonts.indexOf(font);
 		let _init = () => {
 			context_select_font(i == project_fonts.length - 1 ? i - 1 : i + 1);

+ 1 - 1
base/Sources/TabHistory.ts

@@ -3,7 +3,7 @@
 
 class TabHistory {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_history_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		if (zui_tab(htab, tr("History"))) {
 			for (let i: i32 = 0; i < history_steps.length; ++i) {

+ 30 - 30
base/Sources/TabMaterials.ts

@@ -3,43 +3,43 @@
 
 class TabMaterials {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_materials_draw = (htab: zui_handle_t) => {
 		let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_base_sidebar_mini_w;
-		mini ? TabMaterials.draw_mini(htab) : TabMaterials.draw_full(htab);
+		mini ? TabMaterials.tab_materials_draw_mini(htab) : TabMaterials.tab_materials_draw_full(htab);
 	}
 
-	static draw_mini = (htab: zui_handle_t) => {
+	static tab_materials_draw_mini = (htab: zui_handle_t) => {
 		zui_set_hovered_tab_name(tr("Materials"));
 
 		zui_begin_sticky();
 		zui_separator(5);
 
-		TabMaterials.button_nodes();
-		TabMaterials.button_new("+");
+		TabMaterials.tab_materials_button_nodes();
+		TabMaterials.tab_materials_button_new("+");
 
 		zui_end_sticky();
 		zui_separator(3, false);
-		TabMaterials.draw_slots(true);
+		TabMaterials.tab_materials_draw_slots(true);
 	}
 
-	static draw_full = (htab: zui_handle_t) => {
+	static tab_materials_draw_full = (htab: zui_handle_t) => {
 		if (zui_tab(htab, tr("Materials"))) {
 			zui_begin_sticky();
 			zui_row([1 / 4, 1 / 4, 1 / 4]);
 
-			TabMaterials.button_new(tr("New"));
+			TabMaterials.tab_materials_button_new(tr("New"));
 			if (zui_button(tr("Import"))) {
 				project_import_material();
 			}
-			TabMaterials.button_nodes();
+			TabMaterials.tab_materials_button_nodes();
 
 			zui_end_sticky();
 			zui_separator(3, false);
-			TabMaterials.draw_slots(false);
+			TabMaterials.tab_materials_draw_slots(false);
 		}
 	}
 
-	static button_nodes = () => {
+	static tab_materials_button_nodes = () => {
 		let ui: zui_t = ui_base_ui;
 		if (zui_button(tr("Nodes"))) {
 			ui_base_show_material_nodes();
@@ -47,7 +47,7 @@ class TabMaterials {
 		else if (ui.is_hovered) zui_tooltip(tr("Show Node Editor") + ` (${config_keymap.toggle_node_editor})`);
 	}
 
-	static draw_slots = (mini: bool) => {
+	static tab_materials_draw_slots = (mini: bool) => {
 		let ui: zui_t = ui_base_ui;
 		let slotw: i32 = math_floor(51 * zui_SCALE(ui));
 		let num: i32 = math_floor(config_raw.layout[layout_size_t.SIDEBAR_W] / slotw);
@@ -157,30 +157,30 @@ class TabMaterials {
 
 						if (ui_menu_button(ui, tr("Export"))) {
 							context_select_material(i);
-							BoxExport.show_material();
+							box_export_show_material();
 						}
 
 						///if is_paint
 						if (ui_menu_button(ui, tr("Bake"))) {
 							context_select_material(i);
-							BoxExport.show_bake_material();
+							box_export_show_bake_material();
 						}
 						///end
 
 						if (ui_menu_button(ui, tr("Duplicate"))) {
 							let _init = () => {
-								context_raw.material = SlotMaterial.create(project_materials[0].data);
+								context_raw.material = SlotMaterial.slot_material_create(project_materials[0].data);
 								project_materials.push(context_raw.material);
 								let cloned: zui_node_canvas_t = json_parse(json_stringify(project_materials[i].canvas));
 								context_raw.material.canvas = cloned;
-								TabMaterials.update_material();
+								TabMaterials.tab_materials_update_material();
 								history_duplicate_material();
 							}
 							app_notify_on_init(_init);
 						}
 
 						if (project_materials.length > 1 && ui_menu_button(ui, tr("Delete"), "delete")) {
-							TabMaterials.delete_material(m);
+							TabMaterials.tab_materials_delete_material(m);
 						}
 
 						let base_handle: zui_handle_t = zui_nest(zui_handle("tabmaterials_0"), m.id, {selected: m.paint_base});
@@ -219,7 +219,7 @@ class TabMaterials {
 							height_handle.changed ||
 							emis_handle.changed ||
 							subs_handle.changed) {
-							MakeMaterial.parse_paint_material();
+							MakeMaterial.make_material_parse_paint_material();
 							ui_menu_keep_open = true;
 						}
 					}, 13 + add);
@@ -256,33 +256,33 @@ class TabMaterials {
 					    	 ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
 		if (in_focus && ui.is_delete_down && project_materials.length > 1) {
 			ui.is_delete_down = false;
-			TabMaterials.delete_material(context_raw.material);
+			TabMaterials.tab_materials_delete_material(context_raw.material);
 		}
 	}
 
-	static button_new = (text: string) => {
+	static tab_materials_button_new = (text: string) => {
 		if (zui_button(text)) {
 			let current: image_t = _g2_current;
 			g2_end();
-			context_raw.material = SlotMaterial.create(project_materials[0].data);
+			context_raw.material = SlotMaterial.slot_material_create(project_materials[0].data);
 			project_materials.push(context_raw.material);
-			TabMaterials.update_material();
+			TabMaterials.tab_materials_update_material();
 			g2_begin(current);
 			history_new_material();
 		}
 	}
 
-	static update_material = () => {
+	static tab_materials_update_material = () => {
 		ui_header_handle.redraws = 2;
 		ui_nodes_hwnd.redraws = 2;
 		ui_nodes_group_stack = [];
-		MakeMaterial.parse_paint_material();
+		MakeMaterial.make_material_parse_paint_material();
 		util_render_make_material_preview();
 		let decal: bool = context_raw.tool == workspace_tool_t.DECAL || context_raw.tool == workspace_tool_t.TEXT;
 		if (decal) util_render_make_decal_preview();
 	}
 
-	static update_material_pointers = (nodes: zui_node_t[], i: i32) => {
+	static tab_materials_update_material_pointers = (nodes: zui_node_t[], i: i32) => {
 		for (let n of nodes) {
 			if (n.type == "MATERIAL") {
 				if (n.buttons[0].default_value == i) {
@@ -295,8 +295,8 @@ class TabMaterials {
 		}
 	}
 
-	static accept_swatch_drag = (swatch: swatch_color_t) => {
-		context_raw.material = SlotMaterial.create(project_materials[0].data);
+	static tab_materials_accept_swatch_drag = (swatch: swatch_color_t) => {
+		context_raw.material = SlotMaterial.slot_material_create(project_materials[0].data);
 		for (let node of context_raw.material.canvas.nodes) {
 			if (node.type == "RGB" ) {
 				node.outputs[0].default_value = [
@@ -315,18 +315,18 @@ class TabMaterials {
 			}
 		}
 		project_materials.push(context_raw.material);
-		TabMaterials.update_material();
+		TabMaterials.tab_materials_update_material();
 		history_new_material();
 	}
 
-	static delete_material = (m: SlotMaterialRaw) => {
+	static tab_materials_delete_material = (m: SlotMaterialRaw) => {
 		let i: i32 = project_materials.indexOf(m);
 		for (let l of project_layers) if (l.fill_layer == m) l.fill_layer = null;
 		history_delete_material();
 		context_select_material(i == project_materials.length - 1 ? i - 1 : i + 1);
 		project_materials.splice(i, 1);
 		ui_base_hwnds[1].redraws = 2;
-		for (let m of project_materials) TabMaterials.update_material_pointers(m.canvas.nodes, i);
+		for (let m of project_materials) TabMaterials.tab_materials_update_material_pointers(m.canvas.nodes, i);
 	}
 }
 

+ 8 - 8
base/Sources/TabMeshes.ts

@@ -1,7 +1,7 @@
 
 class TabMeshes {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_meshes_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		let statush: i32 = config_raw.layout[layout_size_t.STATUS_H];
 		if (zui_tab(htab, tr("Meshes")) && statush > ui_status_default_status_h * zui_SCALE(ui)) {
@@ -41,10 +41,10 @@ class TabMeshes {
 			///if is_lab
 			if (zui_button(tr("Set Default"))) {
 				ui_menu_draw((ui: zui_t) => {
-					if (ui_menu_button(ui, tr("Cube"))) TabMeshes.set_default_mesh(".Cube");
-					if (ui_menu_button(ui, tr("Plane"))) TabMeshes.set_default_mesh(".Plane");
-					if (ui_menu_button(ui, tr("Sphere"))) TabMeshes.set_default_mesh(".Sphere");
-					if (ui_menu_button(ui, tr("Cylinder"))) TabMeshes.set_default_mesh(".Cylinder");
+					if (ui_menu_button(ui, tr("Cube"))) TabMeshes.tab_meshes_set_default_mesh(".Cube");
+					if (ui_menu_button(ui, tr("Plane"))) TabMeshes.tab_meshes_set_default_mesh(".Plane");
+					if (ui_menu_button(ui, tr("Sphere"))) TabMeshes.tab_meshes_set_default_mesh(".Sphere");
+					if (ui_menu_button(ui, tr("Cylinder"))) TabMeshes.tab_meshes_set_default_mesh(".Cylinder");
 				}, 4);
 			}
 			///end
@@ -110,7 +110,7 @@ class TabMeshes {
 					ui_menu_draw((ui: zui_t) => {
 						if (ui_menu_button(ui, tr("Export"))) {
 							context_raw.export_mesh_index = i + 1;
-							BoxExport.show_mesh();
+							box_export_show_mesh();
 						}
 						if (project_paint_objects.length > 1 && ui_menu_button(ui, tr("Delete"))) {
 							array_remove(project_paint_objects, o);
@@ -144,7 +144,7 @@ class TabMeshes {
 	}
 
 	///if is_lab
-	static set_default_mesh = (name: string) => {
+	static tab_meshes_set_default_mesh = (name: string) => {
 		let mo: mesh_object_t = null;
 		if (name == ".Plane" || name == ".Sphere") {
 			let res: i32 = config_raw.rp_supersample > 1.0 ? 2048 : 1024;
@@ -180,7 +180,7 @@ class TabMeshes {
 		}
 
 		///if (krom_direct3d12 || krom_vulkan || krom_metal)
-		RenderPathRaytrace.ready = false;
+		render_path_raytrace_ready = false;
 		///end
 	}
 	///end

+ 1 - 1
base/Sources/TabParticles.ts

@@ -3,7 +3,7 @@
 
 class TabParticles {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_particles_draw = (htab: zui_handle_t) => {
 		if (zui_tab(htab, tr("Particles"))) {
 			zui_begin_sticky();
 			zui_row([1 / 4, 1 / 4, 1 / 4]);

+ 3 - 3
base/Sources/TabPlugins.ts

@@ -1,7 +1,7 @@
 
 class TabPlugins {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_plugins_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		if (zui_tab(htab, tr("Plugins"))) {
 
@@ -15,8 +15,8 @@ class TabPlugins {
 			///end
 
 			if (zui_button(tr("Manager"))) {
-				BoxPreferences.htab.position = 6; // Plugins
-				BoxPreferences.show();
+				box_preferences_htab.position = 6; // Plugins
+				box_preferences_show();
 			}
 			zui_end_sticky();
 

+ 15 - 15
base/Sources/TabScript.ts

@@ -1,10 +1,10 @@
 
 class TabScript {
 
-	static hscript: zui_handle_t = zui_handle_create();
-	static text_coloring: zui_text_coloring_t = null;
+	static tab_script_hscript: zui_handle_t = zui_handle_create();
+	static tab_script_text_coloring: zui_text_coloring_t = null;
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_script_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		let statush: i32 = config_raw.layout[layout_size_t.STATUS_H];
 		if (zui_tab(htab, tr("Script")) && statush > ui_status_default_status_h * zui_SCALE(ui)) {
@@ -18,24 +18,24 @@ class TabScript {
 			}
 			if (zui_button(tr("Run"))) {
 				try {
-					eval(TabScript.hscript.text);
+					eval(TabScript.tab_script_hscript.text);
 				}
 				catch(e: any) {
 					console_log(e);
 				}
 			}
 			if (zui_button(tr("Clear"))) {
-				TabScript.hscript.text = "";
+				TabScript.tab_script_hscript.text = "";
 			}
 			if (zui_button(tr("Import"))) {
 				ui_files_show("js", false, false, (path: string) => {
 					let b: ArrayBuffer = data_get_blob(path);
-					TabScript.hscript.text = sys_buffer_to_string(b);
+					TabScript.tab_script_hscript.text = sys_buffer_to_string(b);
 					data_delete_blob(path);
 				});
 			}
 			if (zui_button(tr("Export"))) {
-				let str: string = TabScript.hscript.text;
+				let str: string = TabScript.tab_script_hscript.text;
 				ui_files_show("js", true, false, (path: string) => {
 					let f: string = ui_files_filename;
 					if (f == "") f = tr("untitled");
@@ -53,8 +53,8 @@ class TabScript {
 			ui.font_size = math_floor(15 * zui_SCALE(ui));
 			zui_set_text_area_line_numbers(true);
 			zui_set_text_area_scroll_past_end(true);
-			zui_set_text_area_coloring(TabScript.get_text_coloring());
-			zui_text_area(TabScript.hscript);
+			zui_set_text_area_coloring(TabScript.tab_script_get_text_coloring());
+			zui_text_area(TabScript.tab_script_hscript);
 			zui_set_text_area_line_numbers(false);
 			zui_set_text_area_scroll_past_end(false);
 			zui_set_text_area_coloring(null);
@@ -63,15 +63,15 @@ class TabScript {
 		}
 	}
 
-	static get_text_coloring = (): zui_text_coloring_t => {
-		if (TabScript.text_coloring == null) {
+	static tab_script_get_text_coloring = (): zui_text_coloring_t => {
+		if (TabScript.tab_script_text_coloring == null) {
 			let blob: ArrayBuffer = data_get_blob("text_coloring.json");
-			TabScript.text_coloring = json_parse(sys_buffer_to_string(blob));
-			TabScript.text_coloring.default_color = math_floor(TabScript.text_coloring.default_color);
-			for (let coloring of TabScript.text_coloring.colorings) {
+			TabScript.tab_script_text_coloring = json_parse(sys_buffer_to_string(blob));
+			TabScript.tab_script_text_coloring.default_color = math_floor(TabScript.tab_script_text_coloring.default_color);
+			for (let coloring of TabScript.tab_script_text_coloring.colorings) {
 				coloring.color = math_floor(coloring.color);
 			}
 		}
-		return TabScript.text_coloring;
+		return TabScript.tab_script_text_coloring;
 	}
 }

+ 23 - 23
base/Sources/TabSwatches.ts

@@ -1,26 +1,26 @@
 
 class TabSwatches {
 
-	static _empty: image_t;
-	static drag_pos: i32 = -1;
+	static _tab_swatches_empty: image_t;
+	static tab_swatches_drag_pos: i32 = -1;
 
-	static set empty(image: image_t) {
-		TabSwatches._empty = image;
+	static set tab_swatches_empty(image: image_t) {
+		TabSwatches._tab_swatches_empty = image;
 	}
 
-	static get empty(): image_t {
-		if (TabSwatches._empty == null) {
+	static get tab_swatches_empty(): image_t {
+		if (TabSwatches._tab_swatches_empty == null) {
 			let b: Uint8Array = new Uint8Array(4);
 			b[0] = 255;
 			b[1] = 255;
 			b[2] = 255;
 			b[3] = 255;
-			TabSwatches._empty = image_from_bytes(b.buffer, 1, 1);
+			TabSwatches._tab_swatches_empty = image_from_bytes(b.buffer, 1, 1);
 		}
-		return TabSwatches._empty;
+		return TabSwatches._tab_swatches_empty;
 	}
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_swatches_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		let statush: i32 = config_raw.layout[layout_size_t.STATUS_H];
 		if (zui_tab(htab, tr("Swatches")) && statush > ui_status_default_status_h * zui_SCALE(ui)) {
@@ -99,11 +99,11 @@ class TabSwatches {
 					uiy = ui._y;
 
 					// Draw the drag position indicator
-					if (base_drag_swatch != null && TabSwatches.drag_pos == i) {
+					if (base_drag_swatch != null && TabSwatches.tab_swatches_drag_pos == i) {
 						zui_fill(-1, -2 , 2, 32, ui.t.HIGHLIGHT_COL);
 					}
 
-					let state: zui_state_t = zui_image(TabSwatches.empty, project_raw.swatches[i].base, slotw);
+					let state: zui_state_t = zui_image(TabSwatches.tab_swatches_empty, project_raw.swatches[i].base, slotw);
 
 					if (state == zui_state_t.STARTED) {
 						context_set_swatch(project_raw.swatches[i]);
@@ -113,7 +113,7 @@ class TabSwatches {
 						base_drag_swatch = context_raw.swatch;
 					}
 					else if (state == zui_state_t.HOVERED) {
-						TabSwatches.drag_pos = (mouse_x > uix + ui._window_x + slotw / 2) ? i + 1 : i; // Switch to the next position if the mouse crosses the swatch rectangle center
+						TabSwatches.tab_swatches_drag_pos = (mouse_x > uix + ui._window_x + slotw / 2) ? i + 1 : i; // Switch to the next position if the mouse crosses the swatch rectangle center
 						drag_pos_set = true;
 					}
 					else if (state == zui_state_t.RELEASED) {
@@ -182,11 +182,11 @@ class TabSwatches {
 							}
 							///end
 							else if (project_raw.swatches.length > 1 && ui_menu_button(ui, tr("Delete"), "delete")) {
-								TabSwatches.delete_swatch(project_raw.swatches[i]);
+								TabSwatches.tab_swatches_delete_swatch(project_raw.swatches[i]);
 							}
 							///if (is_paint || is_sculpt)
 							else if (ui_menu_button(ui, tr("Create Material"))) {
-								TabMaterials.accept_swatch_drag(project_raw.swatches[i]);
+								TabMaterials.tab_materials_accept_swatch_drag(project_raw.swatches[i]);
 							}
 							else if (ui_menu_button(ui, tr("Create Color Layer"))) {
 								let color: i32 = project_raw.swatches[i].base;
@@ -207,7 +207,7 @@ class TabSwatches {
 			}
 
 			// Draw the rightmost line next to the last swatch
-			if (base_drag_swatch != null && TabSwatches.drag_pos == project_raw.swatches.length) {
+			if (base_drag_swatch != null && TabSwatches.tab_swatches_drag_pos == project_raw.swatches.length) {
 				ui._x = uix; // Reset the position because otherwise it would start in the row below
 				ui._y = uiy;
 				zui_fill(28, -2, 2, 32, ui.t.HIGHLIGHT_COL);
@@ -215,36 +215,36 @@ class TabSwatches {
 
 			// Currently there is no valid dragPosition so reset it
 			if (!drag_pos_set) {
-				TabSwatches.drag_pos = -1;
+				TabSwatches.tab_swatches_drag_pos = -1;
 			}
 
 			let in_focus: bool = ui.input_x > ui._window_x && ui.input_x < ui._window_x + ui._window_w &&
 								 ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
 			if (in_focus && ui.is_delete_down && project_raw.swatches.length > 1) {
 				ui.is_delete_down = false;
-				TabSwatches.delete_swatch(context_raw.swatch);
+				TabSwatches.tab_swatches_delete_swatch(context_raw.swatch);
 			}
 		}
 	}
 
-	static accept_swatch_drag = (swatch: swatch_color_t) => {
+	static tab_swatches_accept_swatch_drag = (swatch: swatch_color_t) => {
 		// No valid position available
-		if (TabSwatches.drag_pos == -1) return;
+		if (TabSwatches.tab_swatches_drag_pos == -1) return;
 
 		let swatch_pos: i32 = project_raw.swatches.indexOf(swatch);
 		// A new swatch from color picker
 		if (swatch_pos == -1) {
-			project_raw.swatches.splice(TabSwatches.drag_pos, 0, swatch);
+			project_raw.swatches.splice(TabSwatches.tab_swatches_drag_pos, 0, swatch);
 		}
-		else if (math_abs(swatch_pos - TabSwatches.drag_pos) > 0) { // Existing swatch is reordered
+		else if (math_abs(swatch_pos - TabSwatches.tab_swatches_drag_pos) > 0) { // Existing swatch is reordered
 			array_remove(project_raw.swatches, swatch);
 			// If the new position is after the old one, decrease by one because the swatch has been deleted
-			let new_pos: i32 = TabSwatches.drag_pos - swatch_pos > 0 ? TabSwatches.drag_pos -1 : TabSwatches.drag_pos;
+			let new_pos: i32 = TabSwatches.tab_swatches_drag_pos - swatch_pos > 0 ? TabSwatches.tab_swatches_drag_pos -1 : TabSwatches.tab_swatches_drag_pos;
 			project_raw.swatches.splice(new_pos, 0, swatch);
 		}
 	}
 
-	static delete_swatch = (swatch: swatch_color_t) => {
+	static tab_swatches_delete_swatch = (swatch: swatch_color_t) => {
 		let i: i32 = project_raw.swatches.indexOf(swatch);
 		context_set_swatch(project_raw.swatches[i == project_raw.swatches.length - 1 ? i - 1 : i + 1]);
 		project_raw.swatches.splice(i, 1);

+ 13 - 13
base/Sources/TabTextures.ts

@@ -1,7 +1,7 @@
 
 class TabTextures {
 
-	static draw = (htab: zui_handle_t) => {
+	static tab_textures_draw = (htab: zui_handle_t) => {
 		let ui: zui_t = ui_base_ui;
 		let statush: i32 = config_raw.layout[layout_size_t.STATUS_H];
 		if (zui_tab(htab, tr("Textures")) && statush > ui_status_default_status_h * zui_SCALE(ui)) {
@@ -17,7 +17,7 @@ class TabTextures {
 
 			if (zui_button(tr("Import"))) {
 				ui_files_show(path_texture_formats.join(","), false, true, (path: string) => {
-					ImportAsset.run(path, -1.0, -1.0, true, false);
+					import_asset_run(path, -1.0, -1.0, true, false);
 					ui_base_hwnds[tab_area_t.STATUS].redraws = 2;
 				});
 			}
@@ -119,7 +119,7 @@ class TabTextures {
 											if (base_pipe_copy == null) base_make_pipe();
 											///end
 
-											let target: image_t = image_create_render_target(TabTextures.to_pow2(img.width), TabTextures.to_pow2(img.height));
+											let target: image_t = image_create_render_target(TabTextures.tab_textures_to_pow2(img.width), TabTextures.tab_textures_to_pow2(img.height));
 											g2_begin(target);
 											g2_set_pipeline(base_pipe_copy);
 											g2_draw_scaled_image(img, 0, 0, target.width, target.height);
@@ -149,7 +149,7 @@ class TabTextures {
 
 								if (ui_menu_button(ui, tr("Set as Envmap"))) {
 									base_notify_on_next_frame(() => {
-										ImportEnvmap.run(asset.file, img);
+										import_envmap_run(asset.file, img);
 									});
 								}
 
@@ -166,13 +166,13 @@ class TabTextures {
 								///end
 
 								if (ui_menu_button(ui, tr("Delete"), "delete")) {
-									TabTextures.delete_texture(asset);
+									TabTextures.tab_textures_delete_texture(asset);
 								}
 								if (!is_packed && ui_menu_button(ui, tr("Open Containing Directory..."))) {
 									file_start(asset.file.substr(0, asset.file.lastIndexOf(path_sep)));
 								}
 								if (!is_packed && ui_menu_button(ui, tr("Open in Browser"))) {
-									TabBrowser.show_directory(asset.file.substr(0, asset.file.lastIndexOf(path_sep)));
+									TabBrowser.tab_browser_show_directory(asset.file.substr(0, asset.file.lastIndexOf(path_sep)));
 								}
 							}, count);
 						}
@@ -201,12 +201,12 @@ class TabTextures {
 						 	 	 ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
 			if (in_focus && ui.is_delete_down && project_assets.length > 0 && project_assets.indexOf(context_raw.texture) >= 0) {
 				ui.is_delete_down = false;
-				TabTextures.delete_texture(context_raw.texture);
+				TabTextures.tab_textures_delete_texture(context_raw.texture);
 			}
 		}
 	}
 
-	static to_pow2 = (i: i32): i32 => {
+	static tab_textures_to_pow2 = (i: i32): i32 => {
 		i--;
 		i |= i >> 1;
 		i |= i >> 2;
@@ -217,7 +217,7 @@ class TabTextures {
 		return i;
 	}
 
-	static update_texture_pointers = (nodes: zui_node_t[], i: i32) => {
+	static tab_textures_update_texture_pointers = (nodes: zui_node_t[], i: i32) => {
 		for (let n of nodes) {
 			if (n.type == "TEX_IMAGE") {
 				if (n.buttons[0].default_value == i) {
@@ -230,7 +230,7 @@ class TabTextures {
 		}
 	}
 
-	static delete_texture = (asset: asset_t) => {
+	static tab_textures_delete_texture = (asset: asset_t) => {
 		let i: i32 = project_assets.indexOf(asset);
 		if (project_assets.length > 1) {
 			context_raw.texture = project_assets[i == project_assets.length - 1 ? i - 1 : i + 1];
@@ -251,7 +251,7 @@ class TabTextures {
 		project_assets.splice(i, 1);
 		project_asset_names.splice(i, 1);
 		let _next = () => {
-			MakeMaterial.parse_paint_material();
+			MakeMaterial.make_material_parse_paint_material();
 
 			///if (is_paint || is_sculpt)
 			util_render_make_material_preview();
@@ -260,9 +260,9 @@ class TabTextures {
 		}
 		base_notify_on_next_frame(_next);
 
-		for (let m of project_materials) TabTextures.update_texture_pointers(m.canvas.nodes, i);
+		for (let m of project_materials) TabTextures.tab_textures_update_texture_pointers(m.canvas.nodes, i);
 		///if (is_paint || is_sculpt)
-		for (let b of project_brushes) TabTextures.update_texture_pointers(b.canvas.nodes, i);
+		for (let b of project_brushes) TabTextures.tab_textures_update_texture_pointers(b.canvas.nodes, i);
 		///end
 	}
 }

+ 12 - 12
base/Sources/args.ts

@@ -80,10 +80,10 @@ function args_run() {
 	if (args_use) {
 		app_notify_on_init(() => {
 			if (project_filepath != "") {
-				ImportArm.run_project(project_filepath);
+				import_arm_run_project(project_filepath);
 			}
 			else if (args_asset_path != "") {
-				ImportAsset.run(args_asset_path, -1, -1, false);
+				import_asset_run(args_asset_path, -1, -1, false);
 				///if is_paint
 				if (path_is_texture(args_asset_path)) {
 					ui_base_show_2d_view(view_2d_type_t.ASSET);
@@ -132,23 +132,23 @@ function args_run() {
 						///end
 
 						// Get export preset and apply the correct one from args
-						BoxExport.files = file_read_directory(path_data() + path_sep + "export_presets");
-						for (let i: i32 = 0; i < BoxExport.files.length; ++i) {
-							BoxExport.files[i] = BoxExport.files[i].substr(0, BoxExport.files[i].length - 5); // Strip .json
+						box_export_files = file_read_directory(path_data() + path_sep + "export_presets");
+						for (let i: i32 = 0; i < box_export_files.length; ++i) {
+							box_export_files[i] = box_export_files[i].substr(0, box_export_files[i].length - 5); // Strip .json
 						}
 
-						let file: string = "export_presets/" + BoxExport.files[0] + ".json";
-						for (let f of BoxExport.files) if (f == args_export_textures_preset) {
-							file = "export_presets/" + BoxExport.files[BoxExport.files.indexOf(f)] + ".json";
+						let file: string = "export_presets/" + box_export_files[0] + ".json";
+						for (let f of box_export_files) if (f == args_export_textures_preset) {
+							file = "export_presets/" + box_export_files[box_export_files.indexOf(f)] + ".json";
 						}
 
 						let blob: ArrayBuffer = data_get_blob(file);
-						BoxExport.preset = json_parse(sys_buffer_to_string(blob));
+						box_export_preset = json_parse(sys_buffer_to_string(blob));
 						data_delete_blob("export_presets/" + file);
 
 						// Export queue
 						app_notify_on_init(() => {
-							ExportTexture.run(args_export_textures_path);
+							export_texture_run(args_export_textures_path);
 						});
 					}
 					else {
@@ -166,7 +166,7 @@ function args_run() {
 				if (path_is_folder(args_export_mesh_path)) {
 					let f: string = ui_files_filename;
 					if (f == "") f = tr("untitled");
-					ExportMesh.run(args_export_mesh_path + path_sep + f, null, false);
+					export_mesh_run(args_export_mesh_path + path_sep + f, null, false);
 				}
 				else {
 					krom_log(tr("Invalid export directory"));
@@ -177,7 +177,7 @@ function args_run() {
 			///if is_paint
 			else if (args_export_material) {
 				context_raw.write_icon_on_export = true;
-				ExportArm.run_material(args_export_material_path);
+				export_arm_run_material(args_export_material_path);
 			}
 			///end
 

+ 117 - 117
base/Sources/base.ts

@@ -291,7 +291,7 @@ function base_init() {
 	///end
 
 	if (config_raw.splash_screen && has_projects) {
-		BoxProjects.show();
+		box_projects_show();
 	}
 }
 
@@ -560,7 +560,7 @@ function base_update() {
 			else if (context_in_viewport()) {
 				if (base_drag_asset.file.toLowerCase().endsWith(".hdr")) {
 					let image: image_t = project_get_image(base_drag_asset);
-					ImportEnvmap.run(base_drag_asset.file, image);
+					import_envmap_run(base_drag_asset.file, image);
 				}
 			}
 			///if (is_paint || is_sculpt)
@@ -575,18 +575,18 @@ function base_update() {
 				ui_nodes_accept_swatch_drag(base_drag_swatch);
 			}
 			else if (context_in_swatches()) {
-				TabSwatches.accept_swatch_drag(base_drag_swatch);
+				TabSwatches.tab_swatches_accept_swatch_drag(base_drag_swatch);
 			}
 			///if (is_paint || is_sculpt)
 			else if (context_in_materials()) {
-				TabMaterials.accept_swatch_drag(base_drag_swatch);
+				TabMaterials.tab_materials_accept_swatch_drag(base_drag_swatch);
 			}
 			else if (context_in_viewport()) {
 				let color: i32 = base_drag_swatch.base;
 				color = color_set_ab(color, base_drag_swatch.opacity * 255);
 				base_create_color_layer(color, base_drag_swatch.occlusion, base_drag_swatch.roughness, base_drag_swatch.metallic);
 			}
-			else if (context_in_layers() && TabLayers.can_drop_new_layer(context_raw.drag_dest)) {
+			else if (context_in_layers() && TabLayers.tab_layers_can_drop_new_layer(context_raw.drag_dest)) {
 				let color: i32 = base_drag_swatch.base;
 				color = color_set_ab(color, base_drag_swatch.opacity * 255);
 				base_create_color_layer(color, base_drag_swatch.occlusion, base_drag_swatch.roughness, base_drag_swatch.metallic, context_raw.drag_dest);
@@ -602,7 +602,7 @@ function base_update() {
 
 				///if (is_paint || is_sculpt)
 				let material_count: i32 = project_materials.length;
-				ImportAsset.run(base_drag_file, base_drop_x, base_drop_y, true, true, function() {
+				import_asset_run(base_drag_file, base_drop_x, base_drop_y, true, true, function() {
 					// Asset was material
 					if (project_materials.length > material_count) {
 						base_drag_material = context_raw.material;
@@ -612,7 +612,7 @@ function base_update() {
 				///end
 
 				///if is_lab
-				ImportAsset.run(base_drag_file, base_drop_x, base_drop_y);
+				import_asset_run(base_drag_file, base_drop_x, base_drop_y);
 				///end
 			}
 			base_drag_file = null;
@@ -627,8 +627,8 @@ function base_update() {
 				ui_nodes_accept_layer_drag(project_layers.indexOf(base_drag_layer));
 			}
 			else if (context_in_layers() && base_is_dragging) {
-				SlotLayer.move(base_drag_layer, context_raw.drag_dest);
-				MakeMaterial.parse_mesh_material();
+				SlotLayer.slot_layer_move(base_drag_layer, context_raw.drag_dest);
+				MakeMaterial.make_material_parse_mesh_material();
 			}
 			base_drag_layer = null;
 		}
@@ -671,7 +671,7 @@ function base_material_dropped() {
 		let decal_mat: mat4_t = uv_type == uv_type_t.PROJECT ? util_render_get_decal_mat() : null;
 		base_create_fill_layer(uv_type, decal_mat);
 	}
-	if (context_in_layers() && TabLayers.can_drop_new_layer(context_raw.drag_dest)) {
+	if (context_in_layers() && TabLayers.tab_layers_can_drop_new_layer(context_raw.drag_dest)) {
 		let uv_type: uv_type_t = keyboard_down("control") ? uv_type_t.PROJECT : uv_type_t.UVMAP;
 		let decal_mat: mat4_t = uv_type == uv_type_t.PROJECT ? util_render_get_decal_mat() : null;
 		base_create_fill_layer(uv_type, decal_mat, context_raw.drag_dest);
@@ -694,7 +694,7 @@ function base_handle_drop_paths() {
 			base_drop_x = mouse_x;
 			base_drop_y = mouse_y;
 			let drop_path: string = base_drop_paths.shift();
-			ImportAsset.run(drop_path, base_drop_x, base_drop_y);
+			import_asset_run(drop_path, base_drop_x, base_drop_y);
 		}
 	}
 }
@@ -702,7 +702,7 @@ function base_handle_drop_paths() {
 ///if (is_paint || is_sculpt)
 function base_get_drag_background(): rect_t {
 	let icons: image_t = resource_get("icons.k");
-	if (base_drag_layer != null && !SlotLayer.is_group(base_drag_layer) && base_drag_layer.fill_layer == null) {
+	if (base_drag_layer != null && !SlotLayer.slot_layer_is_group(base_drag_layer) && base_drag_layer.fill_layer == null) {
 		return resource_tile50(icons, 4, 1);
 	}
 	return null;
@@ -719,7 +719,7 @@ function base_get_drag_image(): image_t {
 	if (base_drag_swatch != null) {
 		base_drag_tint = base_drag_swatch.base;
 		base_drag_size = 26;
-		return TabSwatches.empty;
+		return TabSwatches.tab_swatches_empty;
 	}
 	if (base_drag_file != null) {
 		if (base_drag_file_icon != null) return base_drag_file_icon;
@@ -733,7 +733,7 @@ function base_get_drag_image(): image_t {
 	if (base_drag_material != null) {
 		return base_drag_material.image_icon;
 	}
-	if (base_drag_layer != null && SlotLayer.is_group(base_drag_layer)) {
+	if (base_drag_layer != null && SlotLayer.slot_layer_is_group(base_drag_layer)) {
 		let icons: image_t = resource_get("icons.k");
 		let folder_closed: rect_t = resource_tile50(icons, 2, 1);
 		let folder_open: rect_t = resource_tile50(icons, 8, 1);
@@ -741,8 +741,8 @@ function base_get_drag_image(): image_t {
 		base_drag_tint = ui_base_ui.t.LABEL_COL - 0x00202020;
 		return icons;
 	}
-	if (base_drag_layer != null && SlotLayer.is_mask(base_drag_layer) && base_drag_layer.fill_layer == null) {
-		TabLayers.make_mask_preview_rgba32(base_drag_layer);
+	if (base_drag_layer != null && SlotLayer.slot_layer_is_mask(base_drag_layer) && base_drag_layer.fill_layer == null) {
+		TabLayers.tab_layers_make_mask_preview_rgba32(base_drag_layer);
 		return context_raw.mask_preview_rgba32;
 	}
 	if (base_drag_layer != null) {
@@ -762,15 +762,15 @@ function base_render() {
 		ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
 		///end
 
-		MakeMaterial.parse_mesh_material();
-		MakeMaterial.parse_paint_material();
+		MakeMaterial.make_material_parse_mesh_material();
+		MakeMaterial.make_material_parse_paint_material();
 		context_raw.ddirty = 0;
 
 		///if (is_paint || is_sculpt)
 		if (history_undo_layers == null) {
 			history_undo_layers = [];
 			for (let i: i32 = 0; i < config_raw.undo_steps; ++i) {
-				let l: SlotLayerRaw = SlotLayer.create("_undo" + history_undo_layers.length);
+				let l: SlotLayerRaw = SlotLayer.slot_layer_create("_undo" + history_undo_layers.length);
 				history_undo_layers.push(l);
 			}
 		}
@@ -789,7 +789,7 @@ function base_render() {
 		///if is_lab
 		base_notify_on_next_frame(function() {
 			base_notify_on_next_frame(function() {
-				TabMeshes.set_default_mesh(".Sphere");
+				TabMeshes.tab_meshes_set_default_mesh(".Sphere");
 			});
 		});
 		///end
@@ -1079,7 +1079,7 @@ function base_init_config() {
 
 function base_init_layers() {
 	///if (is_paint || is_sculpt)
-	SlotLayer.clear(project_layers[0], color_from_floats(base_default_base, base_default_base, base_default_base, 1.0));
+	SlotLayer.slot_layer_clear(project_layers[0], color_from_floats(base_default_base, base_default_base, base_default_base, 1.0));
 	///end
 
 	///if is_lab
@@ -1117,12 +1117,12 @@ function base_resize_layers() {
 		while (history_undo_layers.length > conf.undo_steps) {
 			let l: SlotLayerRaw = history_undo_layers.pop();
 			base_notify_on_next_frame(function() {
-				SlotLayer.unload(l);
+				SlotLayer.slot_layer_unload(l);
 			});
 		}
 	}
-	for (let l of project_layers) SlotLayer.resize_and_set_bits(l);
-	for (let l of history_undo_layers) SlotLayer.resize_and_set_bits(l);
+	for (let l of project_layers) SlotLayer.slot_layer_resize_and_set_bits(l);
+	for (let l of history_undo_layers) SlotLayer.slot_layer_resize_and_set_bits(l);
 	let rts: map_t<string, render_target_t> = render_path_render_targets;
 	let _texpaint_blend0: image_t = rts.get("texpaint_blend0")._image;
 	base_notify_on_next_frame(function() {
@@ -1150,16 +1150,16 @@ function base_resize_layers() {
 		rts.get("texpaint_blur").height = size_y;
 		rts.get("texpaint_blur")._image = image_create_render_target(size_x, size_y);
 	}
-	if (RenderPathPaint.live_layer != null) SlotLayer.resize_and_set_bits(RenderPathPaint.live_layer);
+	if (RenderPathPaint.render_path_paint_live_layer != null) SlotLayer.slot_layer_resize_and_set_bits(RenderPathPaint.render_path_paint_live_layer);
 	///if (krom_direct3d12 || krom_vulkan || krom_metal)
-	RenderPathRaytrace.ready = false; // Rebuild baketex
+	render_path_raytrace_ready = false; // Rebuild baketex
 	///end
 	context_raw.ddirty = 2;
 }
 
 function base_set_layer_bits() {
-	for (let l of project_layers) SlotLayer.resize_and_set_bits(l);
-	for (let l of history_undo_layers) SlotLayer.resize_and_set_bits(l);
+	for (let l of project_layers) SlotLayer.slot_layer_resize_and_set_bits(l);
+	for (let l of history_undo_layers) SlotLayer.slot_layer_resize_and_set_bits(l);
 }
 
 function base_make_merge_pipe(red: bool, green: bool, blue: bool, alpha: bool): pipeline_t {
@@ -1541,13 +1541,13 @@ function base_make_export_img() {
 
 ///if (is_paint || is_sculpt)
 function base_duplicate_layer(l: SlotLayerRaw) {
-	if (!SlotLayer.is_group(l)) {
-		let new_layer: SlotLayerRaw = SlotLayer.duplicate(l);
+	if (!SlotLayer.slot_layer_is_group(l)) {
+		let new_layer: SlotLayerRaw = SlotLayer.slot_layer_duplicate(l);
 		context_set_layer(new_layer);
-		let masks: SlotLayerRaw[] = SlotLayer.get_masks(l, false);
+		let masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l, false);
 		if (masks != null) {
 			for (let m of masks) {
-				m = SlotLayer.duplicate(m);
+				m = SlotLayer.slot_layer_duplicate(m);
 				m.parent = new_layer;
 				array_remove(project_layers, m);
 				project_layers.splice(project_layers.indexOf(new_layer), 0, m);
@@ -1560,25 +1560,25 @@ function base_duplicate_layer(l: SlotLayerRaw) {
 		array_remove(project_layers, new_group);
 		project_layers.splice(project_layers.indexOf(l) + 1, 0, new_group);
 		// group.show_panel = true;
-		for (let c of SlotLayer.get_children(l)) {
-			let masks: SlotLayerRaw[] = SlotLayer.get_masks(c, false);
-			let new_layer: SlotLayerRaw = SlotLayer.duplicate(c);
+		for (let c of SlotLayer.slot_layer_get_children(l)) {
+			let masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(c, false);
+			let new_layer: SlotLayerRaw = SlotLayer.slot_layer_duplicate(c);
 			new_layer.parent = new_group;
 			array_remove(project_layers, new_layer);
 			project_layers.splice(project_layers.indexOf(new_group), 0, new_layer);
 			if (masks != null) {
 				for (let m of masks) {
-					let new_mask: SlotLayerRaw = SlotLayer.duplicate(m);
+					let new_mask: SlotLayerRaw = SlotLayer.slot_layer_duplicate(m);
 					new_mask.parent = new_layer;
 					array_remove(project_layers, new_mask);
 					project_layers.splice(project_layers.indexOf(new_layer), 0, new_mask);
 				}
 			}
 		}
-		let group_masks: SlotLayerRaw[] = SlotLayer.get_masks(l);
+		let group_masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l);
 		if (group_masks != null) {
 			for (let m of group_masks) {
-				let new_mask: SlotLayerRaw = SlotLayer.duplicate(m);
+				let new_mask: SlotLayerRaw = SlotLayer.slot_layer_duplicate(m);
 				new_mask.parent = new_group;
 				array_remove(project_layers, new_mask);
 				project_layers.splice(project_layers.indexOf(new_group), 0, new_mask);
@@ -1589,14 +1589,14 @@ function base_duplicate_layer(l: SlotLayerRaw) {
 }
 
 function base_apply_masks(l: SlotLayerRaw) {
-	let masks: SlotLayerRaw[] = SlotLayer.get_masks(l);
+	let masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l);
 
 	if (masks != null) {
 		for (let i: i32 = 0; i < masks.length - 1; ++i) {
 			base_merge_layer(masks[i + 1], masks[i]);
-			SlotLayer.delete(masks[i]);
+			SlotLayer.slot_layer_delete(masks[i]);
 		}
-		SlotLayer.apply_mask(masks[masks.length - 1]);
+		SlotLayer.slot_layer_apply_mask(masks[masks.length - 1]);
 		context_raw.layer_preview_dirty = true;
 	}
 }
@@ -1604,36 +1604,36 @@ function base_apply_masks(l: SlotLayerRaw) {
 function base_merge_down() {
 	let l1: SlotLayerRaw = context_raw.layer;
 
-	if (SlotLayer.is_group(l1)) {
+	if (SlotLayer.slot_layer_is_group(l1)) {
 		l1 = base_merge_group(l1);
 	}
-	else if (SlotLayer.has_masks(l1)) { // It is a layer
+	else if (SlotLayer.slot_layer_has_masks(l1)) { // It is a layer
 		base_apply_masks(l1);
 		context_set_layer(l1);
 	}
 
 	let l0: SlotLayerRaw = project_layers[project_layers.indexOf(l1) - 1];
 
-	if (SlotLayer.is_group(l0)) {
+	if (SlotLayer.slot_layer_is_group(l0)) {
 		l0 = base_merge_group(l0);
 	}
-	else if (SlotLayer.has_masks(l0)) { // It is a layer
+	else if (SlotLayer.slot_layer_has_masks(l0)) { // It is a layer
 		base_apply_masks(l0);
 		context_set_layer(l0);
 	}
 
 	base_merge_layer(l0, l1);
-	SlotLayer.delete(l1);
+	SlotLayer.slot_layer_delete(l1);
 	context_set_layer(l0);
 	context_raw.layer_preview_dirty = true;
 }
 
 function base_merge_group(l: SlotLayerRaw) {
-	if (!SlotLayer.is_group(l)) return null;
+	if (!SlotLayer.slot_layer_is_group(l)) return null;
 
-	let children: SlotLayerRaw[] = SlotLayer.get_children(l);
+	let children: SlotLayerRaw[] = SlotLayer.slot_layer_get_children(l);
 
-	if (children.length == 1 && SlotLayer.has_masks(children[0], false)) {
+	if (children.length == 1 && SlotLayer.slot_layer_has_masks(children[0], false)) {
 		base_apply_masks(children[0]);
 	}
 
@@ -1644,24 +1644,24 @@ function base_merge_group(l: SlotLayerRaw) {
 	}
 
 	// Now apply the group masks
-	let masks: SlotLayerRaw[] = SlotLayer.get_masks(l);
+	let masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l);
 	if (masks != null) {
 		for (let i: i32 = 0; i < masks.length - 1; ++i) {
 			base_merge_layer(masks[i + 1], masks[i]);
-			SlotLayer.delete(masks[i]);
+			SlotLayer.slot_layer_delete(masks[i]);
 		}
 		base_apply_mask(children[0], masks[masks.length - 1]);
 	}
 
 	children[0].parent = null;
 	children[0].name = l.name;
-	if (children[0].fill_layer != null) SlotLayer.to_paint_layer(children[0]);
-	SlotLayer.delete(l);
+	if (children[0].fill_layer != null) SlotLayer.slot_layer_to_paint_layer(children[0]);
+	SlotLayer.slot_layer_delete(l);
 	return children[0];
 }
 
 function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool = false) {
-	if (!l1.visible || SlotLayer.is_group(l1)) return;
+	if (!l1.visible || SlotLayer.slot_layer_is_group(l1)) return;
 
 	if (base_pipe_merge == null) base_make_pipe();
 	base_make_temp_img();
@@ -1675,7 +1675,7 @@ function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool =
 
 	let empty: image_t = render_path_render_targets.get("empty_white")._image;
 	let mask: image_t = empty;
-	let l1masks: SlotLayerRaw[] =  use_mask ? SlotLayer.get_masks(l1) : null;
+	let l1masks: SlotLayerRaw[] =  use_mask ? SlotLayer.slot_layer_get_masks(l1) : null;
 	if (l1masks != null) {
 		// for (let i: i32 = 1; i < l1masks.length - 1; ++i) {
 		// 	mergeLayer(l1masks[i + 1], l1masks[i]);
@@ -1683,12 +1683,12 @@ function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool =
 		mask = l1masks[0].texpaint;
 	}
 
-	if (SlotLayer.is_mask(l1)) {
+	if (SlotLayer.slot_layer_is_mask(l1)) {
 		g4_begin(l0.texpaint);
 		g4_set_pipeline(base_pipe_merge_mask);
 		g4_set_tex(base_tex0_merge_mask, l1.texpaint);
 		g4_set_tex(base_texa_merge_mask, base_temp_image);
-		g4_set_float(base_opac_merge_mask, SlotLayer.get_opacity(l1));
+		g4_set_float(base_opac_merge_mask, SlotLayer.slot_layer_get_opacity(l1));
 		g4_set_int(base_blending_merge_mask, l1.blending);
 		g4_set_vertex_buffer(const_data_screen_aligned_vb);
 		g4_set_index_buffer(const_data_screen_aligned_ib);
@@ -1696,7 +1696,7 @@ function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool =
 		g4_end();
 	}
 
-	if (SlotLayer.is_layer(l1)) {
+	if (SlotLayer.slot_layer_is_layer(l1)) {
 		if (l1.paint_base) {
 			g4_begin(l0.texpaint);
 			g4_set_pipeline(base_pipe_merge);
@@ -1704,7 +1704,7 @@ function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool =
 			g4_set_tex(base_tex1, empty);
 			g4_set_tex(base_texmask, mask);
 			g4_set_tex(base_texa, base_temp_image);
-			g4_set_float(base_opac, SlotLayer.get_opacity(l1));
+			g4_set_float(base_opac, SlotLayer.slot_layer_get_opacity(l1));
 			g4_set_int(base_blending, l1.blending);
 			g4_set_vertex_buffer(const_data_screen_aligned_vb);
 			g4_set_index_buffer(const_data_screen_aligned_ib);
@@ -1726,7 +1726,7 @@ function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool =
 			g4_set_tex(base_tex1, l1.texpaint_nor);
 			g4_set_tex(base_texmask, mask);
 			g4_set_tex(base_texa, base_temp_image);
-			g4_set_float(base_opac, SlotLayer.get_opacity(l1));
+			g4_set_float(base_opac, SlotLayer.slot_layer_get_opacity(l1));
 			g4_set_int(base_blending, l1.paint_nor_blend ? -2 : -1);
 			g4_set_vertex_buffer(const_data_screen_aligned_vb);
 			g4_set_index_buffer(const_data_screen_aligned_ib);
@@ -1742,12 +1742,12 @@ function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool =
 
 		if (l1.paint_occ || l1.paint_rough || l1.paint_met || l1.paint_height) {
 			if (l1.paint_occ && l1.paint_rough && l1.paint_met && l1.paint_height) {
-				base_commands_merge_pack(base_pipe_merge, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask, l1.paint_height_blend ? -3 : -1);
+				base_commands_merge_pack(base_pipe_merge, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask, l1.paint_height_blend ? -3 : -1);
 			}
 			else {
-				if (l1.paint_occ) base_commands_merge_pack(base_pipe_merge_r, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
-				if (l1.paint_rough) base_commands_merge_pack(base_pipe_merge_g, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
-				if (l1.paint_met) base_commands_merge_pack(base_pipe_merge_b, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
+				if (l1.paint_occ) base_commands_merge_pack(base_pipe_merge_r, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
+				if (l1.paint_rough) base_commands_merge_pack(base_pipe_merge_g, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
+				if (l1.paint_met) base_commands_merge_pack(base_pipe_merge_b, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
 			}
 		}
 		///end
@@ -1775,11 +1775,11 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 
 	// Flatten layers
 	for (let l1 of layers) {
-		if (!SlotLayer.is_visible(l1)) continue;
-		if (!SlotLayer.is_layer(l1)) continue;
+		if (!SlotLayer.slot_layer_is_visible(l1)) continue;
+		if (!SlotLayer.slot_layer_is_layer(l1)) continue;
 
 		let mask: image_t = empty;
-		let l1masks: SlotLayerRaw[] = SlotLayer.get_masks(l1);
+		let l1masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l1);
 		if (l1masks != null) {
 			if (l1masks.length > 1) {
 				base_make_temp_mask_img();
@@ -1808,7 +1808,7 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 			g4_set_tex(base_tex1, empty);
 			g4_set_tex(base_texmask, mask);
 			g4_set_tex(base_texa, base_temp_image);
-			g4_set_float(base_opac, SlotLayer.get_opacity(l1));
+			g4_set_float(base_opac, SlotLayer.slot_layer_get_opacity(l1));
 			g4_set_int(base_blending, layers.length > 1 ? l1.blending : 0);
 			g4_set_vertex_buffer(const_data_screen_aligned_vb);
 			g4_set_index_buffer(const_data_screen_aligned_ib);
@@ -1830,7 +1830,7 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 			g4_set_tex(base_tex1, l1.texpaint_nor);
 			g4_set_tex(base_texmask, mask);
 			g4_set_tex(base_texa, base_temp_image);
-			g4_set_float(base_opac, SlotLayer.get_opacity(l1));
+			g4_set_float(base_opac, SlotLayer.slot_layer_get_opacity(l1));
 			g4_set_int(base_blending, l1.paint_nor_blend ? -2 : -1);
 			g4_set_vertex_buffer(const_data_screen_aligned_vb);
 			g4_set_index_buffer(const_data_screen_aligned_ib);
@@ -1846,12 +1846,12 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 			g2_end();
 
 			if (l1.paint_occ && l1.paint_rough && l1.paint_met && l1.paint_height) {
-				base_commands_merge_pack(base_pipe_merge, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask, l1.paint_height_blend ? -3 : -1);
+				base_commands_merge_pack(base_pipe_merge, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask, l1.paint_height_blend ? -3 : -1);
 			}
 			else {
-				if (l1.paint_occ) base_commands_merge_pack(base_pipe_merge_r, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
-				if (l1.paint_rough) base_commands_merge_pack(base_pipe_merge_g, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
-				if (l1.paint_met) base_commands_merge_pack(base_pipe_merge_b, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.get_opacity(l1), mask);
+				if (l1.paint_occ) base_commands_merge_pack(base_pipe_merge_r, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
+				if (l1.paint_rough) base_commands_merge_pack(base_pipe_merge_g, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
+				if (l1.paint_met) base_commands_merge_pack(base_pipe_merge_b, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
 			}
 		}
 		///end
@@ -1870,7 +1870,7 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 	let l0: any = { texpaint: base_expa, texpaint_nor: base_expb, texpaint_pack: base_expc };
 
 	// Merge height map into normal map
-	if (height_to_normal && MakeMaterial.height_used) {
+	if (height_to_normal && MakeMaterial.make_material_height_used) {
 
 		g2_begin(base_temp_image);
 		g2_set_pipeline(base_pipe_copy);
@@ -1896,7 +1896,7 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 }
 
 function base_apply_mask(l: SlotLayerRaw, m: SlotLayerRaw) {
-	if (!SlotLayer.is_layer(l) || !SlotLayer.is_mask(m)) return;
+	if (!SlotLayer.slot_layer_is_layer(l) || !SlotLayer.slot_layer_is_mask(m)) return;
 
 	if (base_pipe_merge == null) base_make_pipe();
 	base_make_temp_img();
@@ -1953,8 +1953,8 @@ function base_update_fill_layers() {
 
 	///if is_paint
 	if (context_raw.tool == workspace_tool_t.MATERIAL) {
-		if (RenderPathPaint.live_layer == null) {
-			RenderPathPaint.live_layer = SlotLayer.create("_live");
+		if (RenderPathPaint.render_path_paint_live_layer == null) {
+			RenderPathPaint.render_path_paint_live_layer = SlotLayer.slot_layer_create("_live");
 		}
 
 		current = _g2_current;
@@ -1962,12 +1962,12 @@ function base_update_fill_layers() {
 
 		context_raw.tool = workspace_tool_t.FILL;
 		context_raw.fill_type_handle.position = fill_type_t.OBJECT;
-		MakeMaterial.parse_paint_material(false);
+		MakeMaterial.make_material_parse_paint_material(false);
 		context_raw.pdirty = 1;
-		RenderPathPaint.use_live_layer(true);
-		RenderPathPaint.commands_paint(false);
-		RenderPathPaint.dilate(true, true);
-		RenderPathPaint.use_live_layer(false);
+		RenderPathPaint.render_path_paint_use_live_layer(true);
+		RenderPathPaint.render_path_paint_commands_paint(false);
+		RenderPathPaint.render_path_paint_dilate(true, true);
+		RenderPathPaint.render_path_paint_use_live_layer(false);
 		context_raw.tool = _tool;
 		context_raw.fill_type_handle.position = _fill_type;
 		context_raw.pdirty = 0;
@@ -1980,8 +1980,8 @@ function base_update_fill_layers() {
 
 	let has_fill_layer: bool = false;
 	let has_fill_mask: bool = false;
-	for (let l of project_layers) if (SlotLayer.is_layer(l) && l.fill_layer == context_raw.material) has_fill_layer = true;
-	for (let l of project_layers) if (SlotLayer.is_mask(l) && l.fill_layer == context_raw.material) has_fill_mask = true;
+	for (let l of project_layers) if (SlotLayer.slot_layer_is_layer(l) && l.fill_layer == context_raw.material) has_fill_layer = true;
+	for (let l of project_layers) if (SlotLayer.slot_layer_is_mask(l) && l.fill_layer == context_raw.material) has_fill_mask = true;
 
 	if (has_fill_layer || has_fill_mask) {
 		current = _g2_current;
@@ -1993,32 +1993,32 @@ function base_update_fill_layers() {
 		if (has_fill_layer) {
 			let first: bool = true;
 			for (let l of project_layers) {
-				if (SlotLayer.is_layer(l) && l.fill_layer == context_raw.material) {
+				if (SlotLayer.slot_layer_is_layer(l) && l.fill_layer == context_raw.material) {
 					context_raw.layer = l;
 					if (first) {
 						first = false;
-						MakeMaterial.parse_paint_material(false);
+						MakeMaterial.make_material_parse_paint_material(false);
 					}
 					base_set_object_mask();
-					SlotLayer.clear(l);
-					RenderPathPaint.commands_paint(false);
-					RenderPathPaint.dilate(true, true);
+					SlotLayer.slot_layer_clear(l);
+					RenderPathPaint.render_path_paint_commands_paint(false);
+					RenderPathPaint.render_path_paint_dilate(true, true);
 				}
 			}
 		}
 		if (has_fill_mask) {
 			let first: bool = true;
 			for (let l of project_layers) {
-				if (SlotLayer.is_mask(l) && l.fill_layer == context_raw.material) {
+				if (SlotLayer.slot_layer_is_mask(l) && l.fill_layer == context_raw.material) {
 					context_raw.layer = l;
 					if (first) {
 						first = false;
-						MakeMaterial.parse_paint_material(false);
+						MakeMaterial.make_material_parse_paint_material(false);
 					}
 					base_set_object_mask();
-					SlotLayer.clear(l);
-					RenderPathPaint.commands_paint(false);
-					RenderPathPaint.dilate(true, true);
+					SlotLayer.slot_layer_clear(l);
+					RenderPathPaint.render_path_paint_commands_paint(false);
+					RenderPathPaint.render_path_paint_dilate(true, true);
 				}
 			}
 		}
@@ -2032,7 +2032,7 @@ function base_update_fill_layers() {
 		base_set_object_mask();
 		context_raw.tool = _tool;
 		context_raw.fill_type_handle.position = _fill_type;
-		MakeMaterial.parse_paint_material(false);
+		MakeMaterial.make_material_parse_paint_material(false);
 	}
 }
 
@@ -2047,11 +2047,11 @@ function base_update_fill_layer(parse_paint: bool = true) {
 	context_raw.fill_type_handle.position = fill_type_t.OBJECT;
 	context_raw.pdirty = 1;
 
-	SlotLayer.clear(context_raw.layer);
+	SlotLayer.slot_layer_clear(context_raw.layer);
 
-	if (parse_paint) MakeMaterial.parse_paint_material(false);
-	RenderPathPaint.commands_paint(false);
-	RenderPathPaint.dilate(true, true);
+	if (parse_paint) MakeMaterial.make_material_parse_paint_material(false);
+	RenderPathPaint.render_path_paint_commands_paint(false);
+	RenderPathPaint.render_path_paint_dilate(true, true);
 
 	context_raw.rdirty = 2;
 	context_raw.tool = _tool;
@@ -2067,7 +2067,7 @@ function base_set_object_mask() {
 	let ar: string[] = [tr("None")];
 	for (let p of project_paint_objects) ar.push(p.base.name);
 
-	let mask: i32 = context_object_mask_used() ? SlotLayer.get_object_mask(context_raw.layer) : 0;
+	let mask: i32 = context_object_mask_used() ? SlotLayer.slot_layer_get_object_mask(context_raw.layer) : 0;
 	if (context_layer_filter_used()) mask = context_raw.layer_filter;
 	if (mask > 0) {
 		if (context_raw.merged_object != null) {
@@ -2083,9 +2083,9 @@ function base_set_object_mask() {
 		context_select_paint_object(o);
 	}
 	else {
-		let is_atlas: bool = SlotLayer.get_object_mask(context_raw.layer) > 0 && SlotLayer.get_object_mask(context_raw.layer) <= project_paint_objects.length;
+		let is_atlas: bool = SlotLayer.slot_layer_get_object_mask(context_raw.layer) > 0 && SlotLayer.slot_layer_get_object_mask(context_raw.layer) <= project_paint_objects.length;
 		if (context_raw.merged_object == null || is_atlas || context_raw.merged_object_is_atlas) {
-			let visibles: mesh_object_t[] = is_atlas ? project_get_atlas_objects(SlotLayer.get_object_mask(context_raw.layer)) : null;
+			let visibles: mesh_object_t[] = is_atlas ? project_get_atlas_objects(SlotLayer.slot_layer_get_object_mask(context_raw.layer)) : null;
 			util_mesh_merge(visibles);
 		}
 		context_select_paint_object(context_main_object());
@@ -2097,10 +2097,10 @@ function base_set_object_mask() {
 
 function base_new_layer(clear: bool = true, position: i32 = -1): SlotLayerRaw {
 	if (project_layers.length > base_max_layers) return null;
-	let l: SlotLayerRaw = SlotLayer.create();
+	let l: SlotLayerRaw = SlotLayer.slot_layer_create();
 	l.object_mask = context_raw.layer_filter;
 	if (position == -1) {
-		if (SlotLayer.is_mask(context_raw.layer)) context_set_layer(context_raw.layer.parent);
+		if (SlotLayer.slot_layer_is_mask(context_raw.layer)) context_set_layer(context_raw.layer.parent);
 		project_layers.splice(project_layers.indexOf(context_raw.layer) + 1, 0, l);
 	}
 	else {
@@ -2111,29 +2111,29 @@ function base_new_layer(clear: bool = true, position: i32 = -1): SlotLayerRaw {
 	let li: i32 = project_layers.indexOf(context_raw.layer);
 	if (li > 0) {
 		let below: SlotLayerRaw = project_layers[li - 1];
-		if (SlotLayer.is_layer(below)) {
+		if (SlotLayer.slot_layer_is_layer(below)) {
 			context_raw.layer.parent = below.parent;
 		}
 	}
-	if (clear) app_notify_on_init(function() { SlotLayer.clear(l); });
+	if (clear) app_notify_on_init(function() { SlotLayer.slot_layer_clear(l); });
 	context_raw.layer_preview_dirty = true;
 	return l;
 }
 
 function base_new_mask(clear: bool = true, parent: SlotLayerRaw, position: i32 = -1): SlotLayerRaw {
 	if (project_layers.length > base_max_layers) return null;
-	let l: SlotLayerRaw = SlotLayer.create("", layer_slot_type_t.MASK, parent);
+	let l: SlotLayerRaw = SlotLayer.slot_layer_create("", layer_slot_type_t.MASK, parent);
 	if (position == -1) position = project_layers.indexOf(parent);
 	project_layers.splice(position, 0, l);
 	context_set_layer(l);
-	if (clear) app_notify_on_init(function() { SlotLayer.clear(l); });
+	if (clear) app_notify_on_init(function() { SlotLayer.slot_layer_clear(l); });
 	context_raw.layer_preview_dirty = true;
 	return l;
 }
 
 function base_new_group(): SlotLayerRaw {
 	if (project_layers.length > base_max_layers) return null;
-	let l: SlotLayerRaw = SlotLayer.create("", layer_slot_type_t.GROUP);
+	let l: SlotLayerRaw = SlotLayer.slot_layer_create("", layer_slot_type_t.GROUP);
 	project_layers.push(l);
 	context_set_layer(l);
 	return l;
@@ -2147,20 +2147,20 @@ function base_create_fill_layer(uv_type: uv_type_t = uv_type_t.UVMAP, decal_mat:
 		if (decal_mat != null) l.decal_mat = decal_mat;
 		l.object_mask = context_raw.layer_filter;
 		history_to_fill_layer();
-		SlotLayer.to_fill_layer(l);
+		SlotLayer.slot_layer_to_fill_layer(l);
 	}
 	app_notify_on_init(_init);
 }
 
 function base_create_image_mask(asset: asset_t) {
 	let l: SlotLayerRaw = context_raw.layer;
-	if (SlotLayer.is_mask(l) || SlotLayer.is_group(l)) {
+	if (SlotLayer.slot_layer_is_mask(l) || SlotLayer.slot_layer_is_group(l)) {
 		return;
 	}
 
 	history_new_layer();
 	let m: SlotLayerRaw = base_new_mask(false, l);
-	SlotLayer.clear(m, 0x00000000, project_get_image(asset));
+	SlotLayer.slot_layer_clear(m, 0x00000000, project_get_image(asset));
 	context_raw.layer_preview_dirty = true;
 }
 
@@ -2170,7 +2170,7 @@ function base_create_color_layer(baseColor: i32, occlusion: f32 = 1.0, roughness
 		history_new_layer();
 		l.uv_type = uv_type_t.UVMAP;
 		l.object_mask = context_raw.layer_filter;
-		SlotLayer.clear(l, baseColor, null, occlusion, roughness, metallic);
+		SlotLayer.slot_layer_clear(l, baseColor, null, occlusion, roughness, metallic);
 	}
 	app_notify_on_init(_init);
 }
@@ -2189,7 +2189,7 @@ function base_on_layers_resized() {
 		}
 		context_raw.layer = _layer;
 		context_raw.material = _material;
-		MakeMaterial.parse_paint_material();
+		MakeMaterial.make_material_parse_paint_material();
 	});
 	util_uv_uvmap = null;
 	util_uv_uvmap_cached = false;
@@ -2197,7 +2197,7 @@ function base_on_layers_resized() {
 	util_uv_trianglemap_cached = false;
 	util_uv_dilatemap_cached = false;
 	///if (krom_direct3d12 || krom_vulkan || krom_metal)
-	RenderPathRaytrace.ready = false;
+	render_path_raytrace_ready = false;
 	///end
 }
 ///end
@@ -2212,7 +2212,7 @@ function base_flatten(heightToNormal: bool = false): any {
 	let canvas: zui_node_canvas_t = ui_nodes_get_canvas(true);
 	if (nodes.nodes_selected_id.length > 0) {
 		let node: zui_node_t = zui_get_node(canvas.nodes, nodes.nodes_selected_id[0]);
-		let brush_node: LogicNode = ParserLogic.get_logic_node(node);
+		let brush_node: LogicNode = parser_logic_get_logic_node(node);
 		if (brush_node != null && brush_node.get_cached_image() != null) {
 			texpaint = brush_node.get_cached_image();
 			texpaint_nor = render_path_render_targets.get("texpaint_nor_empty")._image;
@@ -2268,7 +2268,7 @@ function base_on_layers_resized() {
 	});
 
 	///if (krom_direct3d12 || krom_vulkan || krom_metal)
-	RenderPathRaytrace.ready = false;
+	render_path_raytrace_ready = false;
 	///end
 }
 ///end

+ 467 - 0
base/Sources/box_export.ts

@@ -0,0 +1,467 @@
+
+let box_export_htab: zui_handle_t = zui_handle_create();
+let box_export_files: string[] = null;
+let box_export_mesh_handle: zui_handle_t = zui_handle_create();
+
+///if (is_paint || is_lab)
+let box_export_hpreset: zui_handle_t = zui_handle_create();
+let box_export_preset: export_preset_t = null;
+let box_export_channels: string[] = ["base_r", "base_g", "base_b", "height", "metal", "nor_r", "nor_g", "nor_g_directx", "nor_b", "occ", "opac", "rough", "smooth", "emis", "subs", "0.0", "1.0"];
+let box_export_color_spaces: string[] = ["linear", "srgb"];
+///end
+
+///if (is_paint || is_lab)
+function box_export_show_textures() {
+	ui_box_show_custom(function (ui: zui_t) {
+
+		if (box_export_files == null) {
+			box_export_fetch_presets();
+			box_export_hpreset.position = box_export_files.indexOf("generic");
+		}
+		if (box_export_preset == null) {
+			box_export_parse_preset();
+			box_export_hpreset.children = null;
+		}
+
+		box_export_tab_export_textures(ui, tr("Export Textures"));
+		box_export_tab_presets(ui);
+
+		///if is_paint
+		box_export_tab_atlases(ui);
+		///if (krom_android || krom_ios)
+		box_export_tab_export_mesh(ui, box_export_htab);
+		///end
+		///end
+
+	}, 540, 310);
+}
+///end
+
+///if is_paint
+function box_export_show_bake_material() {
+	ui_box_show_custom(function (ui: zui_t) {
+
+		if (box_export_files == null) {
+			box_export_fetch_presets();
+			box_export_hpreset.position = box_export_files.indexOf("generic");
+		}
+		if (box_export_preset == null) {
+			box_export_parse_preset();
+			box_export_hpreset.children = null;
+		}
+
+		box_export_tab_export_textures(ui, tr("Bake to Textures"), true);
+		box_export_tab_presets(ui);
+
+	}, 540, 310);
+}
+///end
+
+///if (is_paint || is_lab)
+function box_export_tab_export_textures(ui: zui_t, title: string, bake_material: bool = false) {
+	let tab_vertical: bool = config_raw.touch_ui;
+	if (zui_tab(box_export_htab, title, tab_vertical)) {
+
+		zui_row([0.5, 0.5]);
+
+		///if is_paint
+		///if (krom_android || krom_ios)
+		zui_combo(base_res_handle, ["128", "256", "512", "1K", "2K", "4K"], tr("Resolution"), true);
+		///else
+		zui_combo(base_res_handle, ["128", "256", "512", "1K", "2K", "4K", "8K", "16K"], tr("Resolution"), true);
+		///end
+		///end
+
+		///if is_lab
+		///if (krom_android || krom_ios)
+		zui_combo(base_res_handle, ["2K", "4K"], tr("Resolution"), true);
+		///else
+		zui_combo(base_res_handle, ["2K", "4K", "8K", "16K"], tr("Resolution"), true);
+		///end
+		///end
+
+		if (base_res_handle.changed) {
+			base_on_layers_resized();
+		}
+
+		///if (is_lab || krom_android || krom_ios)
+		zui_combo(base_bits_handle, ["8bit"], tr("Color"), true);
+		///else
+		zui_combo(base_bits_handle, ["8bit", "16bit", "32bit"], tr("Color"), true);
+		///end
+
+		///if is_paint
+		if (base_bits_handle.changed) {
+			app_notify_on_init(base_set_layer_bits);
+		}
+		///end
+
+		zui_row([0.5, 0.5]);
+		if (base_bits_handle.position == texture_bits_t.BITS8) {
+			context_raw.format_type = zui_combo(zui_handle("boxexport_0", { position: context_raw.format_type }), ["png", "jpg"], tr("Format"), true);
+		}
+		else {
+			context_raw.format_type = zui_combo(zui_handle("boxexport_1", { position: context_raw.format_type }), ["exr"], tr("Format"), true);
+		}
+
+		ui.enabled = context_raw.format_type == texture_ldr_format_t.JPG && base_bits_handle.position == texture_bits_t.BITS8;
+		context_raw.format_quality = zui_slider(zui_handle("boxexport_2", { value: context_raw.format_quality }), tr("Quality"), 0.0, 100.0, true, 1);
+		ui.enabled = true;
+
+		///if is_paint
+		zui_row([0.5, 0.5]);
+		ui.enabled = !bake_material;
+		let layers_export_handle: zui_handle_t = zui_handle("boxexport_3");
+		layers_export_handle.position = context_raw.layers_export;
+		context_raw.layers_export = zui_combo(layers_export_handle, [tr("Visible"), tr("Selected"), tr("Per Object"), tr("Per Udim Tile")], tr("Layers"), true);
+		ui.enabled = true;
+		///end
+
+		zui_combo(box_export_hpreset, box_export_files, tr("Preset"), true);
+		if (box_export_hpreset.changed) box_export_preset = null;
+
+		let layers_destination_handle: zui_handle_t = zui_handle("boxexport_4");
+		layers_destination_handle.position = context_raw.layers_destination;
+		context_raw.layers_destination = zui_combo(layers_destination_handle, [tr("Disk"), tr("Packed")], tr("Destination"), true);
+
+		zui_end_element();
+
+		zui_row([0.5, 0.5]);
+		if (zui_button(tr("Cancel"))) {
+			ui_box_hide();
+		}
+		if (zui_button(tr("Export"))) {
+			ui_box_hide();
+			if (context_raw.layers_destination == export_destination_t.PACKED) {
+				context_raw.texture_export_path = "/";
+				let _init = () => {
+					///if is_paint
+					export_texture_run(context_raw.texture_export_path, bake_material);
+					///end
+					///if is_lab
+					export_texture_run(context_raw.texture_export_path);
+					///end
+				}
+				app_notify_on_init(_init);
+			}
+			else {
+				let filters = base_bits_handle.position != texture_bits_t.BITS8 ? "exr" : context_raw.format_type == texture_ldr_format_t.PNG ? "png" : "jpg";
+				ui_files_show(filters, true, false, (path: string) => {
+					context_raw.texture_export_path = path;
+					let doExport = () => {
+						let _init = () => {
+							///if is_paint
+							export_texture_run(context_raw.texture_export_path, bake_material);
+							///end
+							///if is_lab
+							export_texture_run(context_raw.texture_export_path);
+							///end
+						}
+						app_notify_on_init(_init);
+					}
+					///if (krom_android || krom_ios)
+					base_notify_on_next_frame(() => {
+						console_toast(tr("Exporting textures"));
+						base_notify_on_next_frame(doExport);
+					});
+					///else
+					doExport();
+					///end
+				});
+			}
+		}
+		if (ui.is_hovered) zui_tooltip(tr("Export texture files") + ` (${config_keymap.file_export_textures})`);
+	}
+}
+
+function box_export_tab_presets(ui: zui_t) {
+	let tab_vertical: bool = config_raw.touch_ui;
+	if (zui_tab(box_export_htab, tr("Presets"), tab_vertical)) {
+		zui_row([3 / 5, 1 / 5, 1 / 5]);
+
+		zui_combo(box_export_hpreset, box_export_files, tr("Preset"));
+		if (box_export_hpreset.changed) box_export_preset = null;
+
+		if (zui_button(tr("New"))) {
+			ui_box_show_custom((ui: zui_t) => {
+				let tab_vertical: bool = config_raw.touch_ui;
+				if (zui_tab(zui_handle("boxexport_5"), tr("New Preset"), tab_vertical)) {
+					zui_row([0.5, 0.5]);
+					let preset_name: string = zui_text_input(zui_handle("boxexport_6", { text: "new_preset" }), tr("Name"));
+					if (zui_button(tr("OK")) || ui.is_return_down) {
+						box_export_new_preset(preset_name);
+						box_export_fetch_presets();
+						box_export_preset = null;
+						box_export_hpreset.position = box_export_files.indexOf(preset_name);
+						ui_box_hide();
+						box_export_htab.position = 1; // Presets
+						box_export_show_textures();
+					}
+				}
+			});
+		}
+
+		if (zui_button(tr("Import"))) {
+			ui_files_show("json", false, false, (path: string) => {
+				path = path.toLowerCase();
+				if (path.endsWith(".json")) {
+					let filename: string = path.substr(path.lastIndexOf(path_sep) + 1);
+					let dst_path: string = path_data() + path_sep + "export_presets" + path_sep + filename;
+					file_copy(path, dst_path); // Copy to presets folder
+					box_export_fetch_presets();
+					box_export_preset = null;
+					box_export_hpreset.position = box_export_files.indexOf(filename.substr(0, filename.length - 5)); // Strip .json
+					console_info(tr("Preset imported:") + " " + filename);
+				}
+				else console_error(strings_error1());
+			});
+		}
+
+		if (box_export_preset == null) {
+			box_export_parse_preset();
+			box_export_hpreset.children = null;
+		}
+
+		// Texture list
+		zui_separator(10, false);
+		zui_row([1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6]);
+		zui_text(tr("Texture"));
+		zui_text(tr("R"));
+		zui_text(tr("G"));
+		zui_text(tr("B"));
+		zui_text(tr("A"));
+		zui_text(tr("Color Space"));
+		ui.changed = false;
+		for (let i: i32 = 0; i < box_export_preset.textures.length; ++i) {
+			let t: export_preset_texture_t = box_export_preset.textures[i];
+			zui_row([1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6]);
+			let htex: zui_handle_t = zui_nest(box_export_hpreset, i);
+			htex.text = t.name;
+			t.name = zui_text_input(htex);
+
+			if (ui.is_hovered && ui.input_released_r) {
+				ui_menu_draw((ui: zui_t) => {
+					if (ui_menu_button(ui, tr("Delete"))) {
+						array_remove(box_export_preset.textures, t);
+						box_export_save_preset();
+					}
+				}, 1);
+			}
+
+			let hr: zui_handle_t = zui_nest(htex, 0);
+			hr.position = box_export_channels.indexOf(t.channels[0]);
+			let hg: zui_handle_t = zui_nest(htex, 1);
+			hg.position = box_export_channels.indexOf(t.channels[1]);
+			let hb: zui_handle_t = zui_nest(htex, 2);
+			hb.position = box_export_channels.indexOf(t.channels[2]);
+			let ha: zui_handle_t = zui_nest(htex, 3);
+			ha.position = box_export_channels.indexOf(t.channels[3]);
+
+			zui_combo(hr, box_export_channels, tr("R"));
+			if (hr.changed) t.channels[0] = box_export_channels[hr.position];
+			zui_combo(hg, box_export_channels, tr("G"));
+			if (hg.changed) t.channels[1] = box_export_channels[hg.position];
+			zui_combo(hb, box_export_channels, tr("B"));
+			if (hb.changed) t.channels[2] = box_export_channels[hb.position];
+			zui_combo(ha, box_export_channels, tr("A"));
+			if (ha.changed) t.channels[3] = box_export_channels[ha.position];
+
+			let hspace: zui_handle_t = zui_nest(htex, 4);
+			hspace.position = box_export_color_spaces.indexOf(t.color_space);
+			zui_combo(hspace, box_export_color_spaces, tr("Color Space"));
+			if (hspace.changed) t.color_space = box_export_color_spaces[hspace.position];
+		}
+
+		if (ui.changed) {
+			box_export_save_preset();
+		}
+
+		zui_row([1 / 8]);
+		if (zui_button(tr("Add"))) {
+			box_export_preset.textures.push({ name: "base", channels: ["base_r", "base_g", "base_b", "1.0"], color_space: "linear" });
+			box_export_hpreset.children = null;
+			box_export_save_preset();
+		}
+	}
+}
+///end
+
+///if is_paint
+function box_export_tab_atlases(ui: zui_t) {
+	let tab_vertical: bool = config_raw.touch_ui;
+	if (zui_tab(box_export_htab, tr("Atlases"), tab_vertical)) {
+		if (project_atlas_objects == null || project_atlas_objects.length != project_paint_objects.length) {
+			project_atlas_objects = [];
+			project_atlas_names = [];
+			for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
+				project_atlas_objects.push(0);
+				project_atlas_names.push(tr("Atlas") + " " + (i + 1));
+			}
+		}
+		for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
+			zui_row([1 / 2, 1 / 2]);
+			zui_text(project_paint_objects[i].base.name);
+			let hatlas: zui_handle_t = zui_nest(zui_handle("boxexport_7"), i);
+			hatlas.position = project_atlas_objects[i];
+			project_atlas_objects[i] = zui_combo(hatlas, project_atlas_names, tr("Atlas"));
+		}
+	}
+}
+///end
+
+function box_export_show_mesh() {
+	box_export_mesh_handle.position = context_raw.export_mesh_index;
+	ui_box_show_custom((ui: zui_t) => {
+		let htab: zui_handle_t = zui_handle("boxexport_8");
+		box_export_tab_export_mesh(ui, htab);
+	});
+}
+
+function box_export_tab_export_mesh(ui: zui_t, htab: zui_handle_t) {
+	let tab_vertical: bool = config_raw.touch_ui;
+	if (zui_tab(htab, tr("Export Mesh"), tab_vertical)) {
+
+		zui_row([1 / 2, 1 / 2]);
+
+		context_raw.export_mesh_format = zui_combo(zui_handle("boxexport_9", { position: context_raw.export_mesh_format }), ["obj", "arm"], tr("Format"), true);
+
+		let ar: string[] = [tr("All")];
+		for (let p of project_paint_objects) ar.push(p.base.name);
+		zui_combo(box_export_mesh_handle, ar, tr("Meshes"), true);
+
+		let apply_displacement: bool = zui_check(zui_handle("boxexport_10"), tr("Apply Displacement"));
+
+		let tris: i32 = 0;
+		let pos: i32 = box_export_mesh_handle.position;
+		let paint_objects: mesh_object_t[] = pos == 0 ? project_paint_objects : [project_paint_objects[pos - 1]];
+		for (let po of paint_objects) {
+			for (let inda of po.data.index_arrays) {
+				tris += math_floor(inda.values.length / 3);
+			}
+		}
+		zui_text(tris + " " + tr("triangles"));
+
+		zui_row([0.5, 0.5]);
+		if (zui_button(tr("Cancel"))) {
+			ui_box_hide();
+		}
+		if (zui_button(tr("Export"))) {
+			ui_box_hide();
+			ui_files_show(context_raw.export_mesh_format == mesh_format_t.OBJ ? "obj" : "arm", true, false, (path: string) => {
+				///if (krom_android || krom_ios)
+				let f: string = sys_title();
+				///else
+				let f: string = ui_files_filename;
+				///end
+				if (f == "") f = tr("untitled");
+				let doExport = () => {
+					export_mesh_run(path + path_sep + f, box_export_mesh_handle.position == 0 ? null : [project_paint_objects[box_export_mesh_handle.position - 1]], apply_displacement);
+				}
+				///if (krom_android || krom_ios)
+				base_notify_on_next_frame(() => {
+					console_toast(tr("Exporting mesh"));
+					base_notify_on_next_frame(doExport);
+				});
+				///else
+				doExport();
+				///end
+			});
+		}
+	}
+}
+
+///if (is_paint || is_sculpt)
+function box_export_show_material() {
+	ui_box_show_custom(function (ui: zui_t) {
+		let htab: zui_handle_t = zui_handle("boxexport_11");
+		let tab_vertical: bool = config_raw.touch_ui;
+		if (zui_tab(htab, tr("Export Material"), tab_vertical)) {
+			let h1: zui_handle_t = zui_handle("boxexport_12");
+			let h2: zui_handle_t = zui_handle("boxexport_13");
+			h1.selected = context_raw.pack_assets_on_export;
+			h2.selected = context_raw.write_icon_on_export;
+			context_raw.pack_assets_on_export = zui_check(h1, tr("Pack Assets"));
+			context_raw.write_icon_on_export = zui_check(h2, tr("Export Icon"));
+			zui_row([0.5, 0.5]);
+			if (zui_button(tr("Cancel"))) {
+				ui_box_hide();
+			}
+			if (zui_button(tr("Export"))) {
+				ui_box_hide();
+				ui_files_show("arm", true, false, (path: string) => {
+					let f: string = ui_files_filename;
+					if (f == "") f = tr("untitled");
+					app_notify_on_init(() => {
+						export_arm_run_material(path + path_sep + f);
+					});
+				});
+			}
+		}
+	});
+}
+
+function box_export_show_brush() {
+	ui_box_show_custom(function (ui: zui_t) {
+		let htab: zui_handle_t = zui_handle("boxexport_14");
+		let tab_vertical: bool = config_raw.touch_ui;
+		if (zui_tab(htab, tr("Export Brush"), tab_vertical)) {
+			let h1: zui_handle_t = zui_handle("boxexport_15");
+			let h2: zui_handle_t = zui_handle("boxexport_16");
+			h1.selected = context_raw.pack_assets_on_export;
+			h2.selected = context_raw.write_icon_on_export;
+			context_raw.pack_assets_on_export = zui_check(h1, tr("Pack Assets"));
+			context_raw.write_icon_on_export = zui_check(h2, tr("Export Icon"));
+			zui_row([0.5, 0.5]);
+			if (zui_button(tr("Cancel"))) {
+				ui_box_hide();
+			}
+			if (zui_button(tr("Export"))) {
+				ui_box_hide();
+				ui_files_show("arm", true, false, (path: string) => {
+					let f: string = ui_files_filename;
+					if (f == "") f = tr("untitled");
+					app_notify_on_init(() => {
+						export_arm_run_brush(path + path_sep + f);
+					});
+				});
+			}
+		}
+	});
+}
+///end
+
+///if (is_paint || is_lab)
+function box_export_fetch_presets() {
+	box_export_files = file_read_directory(path_data() + path_sep + "export_presets");
+	for (let i: i32 = 0; i < box_export_files.length; ++i) {
+		box_export_files[i] = box_export_files[i].substr(0, box_export_files[i].length - 5); // Strip .json
+	}
+}
+
+function box_export_parse_preset() {
+	let file: string = "export_presets/" + box_export_files[box_export_hpreset.position] + ".json";
+	let blob: ArrayBuffer = data_get_blob(file);
+	box_export_preset = json_parse(sys_buffer_to_string(blob));
+	data_delete_blob("export_presets/" + file);
+}
+
+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" }
+]
+}
+`;
+	if (!name.endsWith(".json")) name += ".json";
+	let path: string = path_data() + path_sep + "export_presets" + path_sep + name;
+	krom_file_save_bytes(path, sys_string_to_buffer(template));
+}
+
+function box_export_save_preset() {
+	let name: string = box_export_files[box_export_hpreset.position];
+	if (name == "generic") return; // generic is const
+	let path: string = path_data() + path_sep + "export_presets" + path_sep + name + ".json";
+	krom_file_save_bytes(path, sys_string_to_buffer(json_stringify(box_export_preset)));
+}
+///end

+ 688 - 0
base/Sources/box_preferences.ts

@@ -0,0 +1,688 @@
+
+let box_preferences_htab: zui_handle_t = zui_handle_create();
+let box_preferences_files_plugin: string[] = null;
+let box_preferences_files_keymap: string[] = null;
+let box_preferences_theme_handle: zui_handle_t;
+let box_preferences_preset_handle: zui_handle_t;
+let box_preferences_locales: string[] = null;
+let box_preferences_themes: string[] = null;
+let box_preferences_world_color: i32 = 0xff080808;
+
+function box_preferences_show() {
+	ui_box_show_custom(function (ui: zui_t) {
+		if (zui_tab(box_preferences_htab, tr("Interface"), true)) {
+
+			if (box_preferences_locales == null) {
+				box_preferences_locales = translator_get_supported_locales();
+			}
+
+			let locale_handle: zui_handle_t = zui_handle("boxpreferences_0", { position: box_preferences_locales.indexOf(config_raw.locale) });
+			zui_combo(locale_handle, box_preferences_locales, tr("Language"), true);
+			if (locale_handle.changed) {
+				let locale_code: string = box_preferences_locales[locale_handle.position];
+				config_raw.locale = locale_code;
+				translator_load_translations(locale_code);
+				ui_base_tag_ui_redraw();
+			}
+
+			let hscale: zui_handle_t = zui_handle("boxpreferences_1", { value: config_raw.window_scale });
+			zui_slider(hscale, tr("UI Scale"), 1.0, 4.0, true, 10);
+			if (context_raw.hscale_was_changed && !ui.input_down) {
+				context_raw.hscale_was_changed = false;
+				if (hscale.value == null || isNaN(hscale.value)) hscale.value = 1.0;
+				config_raw.window_scale = hscale.value;
+				box_preferences_set_scale();
+			}
+			if (hscale.changed) context_raw.hscale_was_changed = true;
+
+			let hspeed: zui_handle_t = zui_handle("boxpreferences_2", { value: config_raw.camera_zoom_speed });
+			config_raw.camera_zoom_speed = zui_slider(hspeed, tr("Camera Zoom Speed"), 0.1, 4.0, true);
+
+			hspeed = zui_handle("boxpreferences_3", { value: config_raw.camera_rotation_speed });
+			config_raw.camera_rotation_speed = zui_slider(hspeed, tr("Camera Rotation Speed"), 0.1, 4.0, true);
+
+			hspeed = zui_handle("boxpreferences_4", { value: config_raw.camera_pan_speed });
+			config_raw.camera_pan_speed = zui_slider(hspeed, tr("Camera Pan Speed"), 0.1, 4.0, true);
+
+			let zoom_direction_handle: zui_handle_t = zui_handle("boxpreferences_5", { position: config_raw.zoom_direction });
+			zui_combo(zoom_direction_handle, [tr("Vertical"), tr("Vertical Inverted"), tr("Horizontal"), tr("Horizontal Inverted"), tr("Vertical and Horizontal"), tr("Vertical and Horizontal Inverted")], tr("Direction to Zoom"), true);
+			if (zoom_direction_handle.changed) {
+				config_raw.zoom_direction = zoom_direction_handle.position;
+			}
+
+			config_raw.wrap_mouse = zui_check(zui_handle("boxpreferences_6", { selected: config_raw.wrap_mouse }), tr("Wrap Mouse"));
+			if (ui.is_hovered) zui_tooltip(tr("Wrap mouse around view boundaries during camera control"));
+
+			config_raw.node_preview = zui_check(zui_handle("boxpreferences_7", { selected: config_raw.node_preview }), tr("Show Node Preview"));
+
+			ui.changed = false;
+			config_raw.show_asset_names = zui_check(zui_handle("boxpreferences_8", { selected: config_raw.show_asset_names }), tr("Show Asset Names"));
+			if (ui.changed) {
+				ui_base_tag_ui_redraw();
+			}
+
+			///if !(krom_android || krom_ios)
+			ui.changed = false;
+			config_raw.touch_ui = zui_check(zui_handle("boxpreferences_9", { selected: config_raw.touch_ui }), tr("Touch UI"));
+			if (ui.changed) {
+				zui_set_touch_scroll(config_raw.touch_ui);
+				zui_set_touch_hold(config_raw.touch_ui);
+				zui_set_touch_tooltip(config_raw.touch_ui);
+				config_load_theme(config_raw.theme);
+				box_preferences_set_scale();
+				ui_base_tag_ui_redraw();
+			}
+			///end
+
+			config_raw.splash_screen = zui_check(zui_handle("boxpreferences_10", { selected: config_raw.splash_screen }), tr("Splash Screen"));
+
+			// Zui.text("Node Editor");
+			// let grid_snap: bool = Zui.check(Zui.handle("boxpreferences_11", { selected: false }), "Grid Snap");
+
+			zui_end_element();
+			zui_row([0.5, 0.5]);
+			if (zui_button(tr("Restore")) && !ui_menu_show) {
+				ui_menu_draw(function (ui: zui_t) {
+					if (ui_menu_button(ui, tr("Confirm"))) {
+						app_notify_on_init(function () {
+							ui.t.ELEMENT_H = base_default_element_h;
+							config_restore();
+							box_preferences_set_scale();
+							if (box_preferences_files_plugin != null) for (let f of box_preferences_files_plugin) plugin_stop(f);
+							box_preferences_files_plugin = null;
+							box_preferences_files_keymap = null;
+							MakeMaterial.make_material_parse_mesh_material();
+							MakeMaterial.make_material_parse_paint_material();
+						});
+					}
+					if (ui_menu_button(ui, tr("Import..."))) {
+						ui_files_show("json", false, false, function (path: string) {
+							let b: ArrayBuffer = data_get_blob(path);
+							let raw: config_t = json_parse(sys_buffer_to_string(b));
+							app_notify_on_init(function () {
+								ui.t.ELEMENT_H = base_default_element_h;
+								config_import_from(raw);
+								box_preferences_set_scale();
+								MakeMaterial.make_material_parse_mesh_material();
+								MakeMaterial.make_material_parse_paint_material();
+							});
+						});
+					}
+				}, 2);
+			}
+			if (zui_button(tr("Reset Layout")) && !ui_menu_show) {
+				ui_menu_draw(function (ui: zui_t) {
+					if (ui_menu_button(ui, tr("Confirm"))) {
+						base_init_layout();
+						config_save();
+					}
+				}, 1);
+			}
+		}
+
+		if (zui_tab(box_preferences_htab, tr("Theme"), true)) {
+
+			if (box_preferences_themes == null) {
+				box_preferences_fetch_themes();
+			}
+			box_preferences_theme_handle = zui_handle("boxpreferences_12", { position: box_preferences_get_theme_index() });
+
+			zui_begin_sticky();
+			zui_row([1 / 4, 1 / 4, 1 / 4, 1 / 4]);
+
+			zui_combo(box_preferences_theme_handle, box_preferences_themes, tr("Theme"));
+			if (box_preferences_theme_handle.changed) {
+				config_raw.theme = box_preferences_themes[box_preferences_theme_handle.position] + ".json";
+				config_load_theme(config_raw.theme);
+			}
+
+			if (zui_button(tr("New"))) {
+				ui_box_show_custom(function (ui: zui_t) {
+					if (zui_tab(zui_handle("boxpreferences_13"), tr("New Theme"))) {
+						zui_row([0.5, 0.5]);
+						let theme_name: string = zui_text_input(zui_handle("boxpreferences_14", { text: "new_theme" }), tr("Name"));
+						if (zui_button(tr("OK")) || ui.is_return_down) {
+							let template: string = json_stringify(base_theme);
+							if (!theme_name.endsWith(".json")) theme_name += ".json";
+							let path: string = path_data() + path_sep + "themes" + path_sep + theme_name;
+							krom_file_save_bytes(path, sys_string_to_buffer(template));
+							box_preferences_fetch_themes(); // Refresh file list
+							config_raw.theme = theme_name;
+							box_preferences_theme_handle.position = box_preferences_get_theme_index();
+							ui_box_hide();
+							box_preferences_htab.position = 1; // Themes
+							box_preferences_show();
+						}
+					}
+				});
+			}
+
+			if (zui_button(tr("Import"))) {
+				ui_files_show("json", false, false, function (path: string) {
+					import_theme_run(path);
+				});
+			}
+
+			if (zui_button(tr("Export"))) {
+				ui_files_show("json", true, false, function (path: string) {
+					path += path_sep + ui_files_filename;
+					if (!path.endsWith(".json")) path += ".json";
+					krom_file_save_bytes(path, sys_string_to_buffer(json_stringify(base_theme)));
+				});
+			}
+
+			zui_end_sticky();
+
+			let i: i32 = 0;
+			let theme: any = base_theme;
+			let hlist: zui_handle_t = zui_handle("boxpreferences_15");
+
+			// Viewport color
+			let h: zui_handle_t = zui_nest(hlist, i++, { color: box_preferences_world_color });
+			zui_row([1 / 8, 7 / 8]);
+			zui_text("", 0, h.color);
+			if (ui.is_hovered && ui.input_released) {
+				ui_menu_draw(function (ui: zui_t) {
+					ui.changed = false;
+					zui_color_wheel(h, false, null, 11 * ui.t.ELEMENT_H * zui_SCALE(ui), true);
+					if (ui.changed) ui_menu_keep_open = true;
+				}, 11);
+			}
+			let val: i32 = h.color;
+			if (val < 0) val += 4294967296;
+			h.text = val.toString(16);
+			zui_text_input(h, "VIEWPORT_COL");
+			h.color = parseInt(h.text, 16);
+
+			if (box_preferences_world_color != h.color) {
+				box_preferences_world_color = h.color;
+				let b: Uint8Array = new Uint8Array(4);
+				b[0] = color_get_rb(box_preferences_world_color);
+				b[1] = color_get_gb(box_preferences_world_color);
+				b[2] = color_get_bb(box_preferences_world_color);
+				b[3] = 255;
+				context_raw.empty_envmap = image_from_bytes(b.buffer, 1, 1);
+				context_raw.ddirty = 2;
+				if (!context_raw.show_envmap) {
+					scene_world._.envmap = context_raw.empty_envmap;
+				}
+			}
+
+			// Theme fields
+			for (let key of Object.getOwnPropertyNames(theme_t.prototype)) {
+				if (key == "constructor") continue;
+
+				let h: zui_handle_t = zui_nest(hlist, i++);
+				let val: any = theme[key];
+
+				let isHex: bool = key.endsWith("_COL");
+				if (isHex && val < 0) val += 4294967296;
+
+				if (isHex) {
+					zui_row([1 / 8, 7 / 8]);
+					zui_text("", 0, val);
+					if (ui.is_hovered && ui.input_released) {
+						h.color = theme[key];
+						ui_menu_draw(function (ui: zui_t) {
+							ui.changed = false;
+							let color: i32 = zui_color_wheel(h, false, null, 11 * ui.t.ELEMENT_H * zui_SCALE(ui), true);
+							theme[key] = color;
+							if (ui.changed) ui_menu_keep_open = true;
+						}, 11);
+					}
+				}
+
+				ui.changed = false;
+
+				if (typeof val == "boolean") {
+					h.selected = val;
+					let b: bool = zui_check(h, key);
+					theme[key] = b;
+				}
+				else if (key == "LINK_STYLE") {
+					let styles: string[] = [tr("Straight"), tr("Curved")];
+					h.position = val;
+					let i: i32 = zui_combo(h, styles, key, true);
+					theme[key] = i;
+				}
+				else {
+					h.text = isHex ? val.toString(16) : val.toString();
+					zui_text_input(h, key);
+					if (isHex) theme[key] = parseInt(h.text, 16);
+					else theme[key] = parseInt(h.text);
+				}
+
+				if (ui.changed) {
+					for (let ui of base_get_uis()) {
+						ui.elements_baked = false;
+					}
+				}
+			}
+		}
+
+		if (zui_tab(box_preferences_htab, tr("Usage"), true)) {
+			context_raw.undo_handle = zui_handle("boxpreferences_16", { value: config_raw.undo_steps });
+			config_raw.undo_steps = math_floor(zui_slider(context_raw.undo_handle, tr("Undo Steps"), 1, 64, false, 1));
+			if (config_raw.undo_steps < 1) {
+				config_raw.undo_steps = math_floor(context_raw.undo_handle.value = 1);
+			}
+			if (context_raw.undo_handle.changed) {
+				let current: image_t = _g2_current;
+				g2_end();
+
+				///if (is_paint || is_sculpt)
+				while (history_undo_layers.length < config_raw.undo_steps) {
+					let l: SlotLayerRaw = SlotLayer.slot_layer_create("_undo" + history_undo_layers.length);
+					history_undo_layers.push(l);
+				}
+				while (history_undo_layers.length > config_raw.undo_steps) {
+					let l: SlotLayerRaw = history_undo_layers.pop();
+					SlotLayer.slot_layer_unload(l);
+				}
+				///end
+
+				history_reset();
+				g2_begin(current);
+			}
+
+			///if is_paint
+			config_raw.dilate_radius = math_floor(zui_slider(zui_handle("boxpreferences_17", { value: config_raw.dilate_radius }), tr("Dilate Radius"), 0.0, 16.0, true, 1));
+			if (ui.is_hovered) zui_tooltip(tr("Dilate painted textures to prevent seams"));
+
+			let dilate_handle: zui_handle_t = zui_handle("boxpreferences_18", { position: config_raw.dilate });
+			zui_combo(dilate_handle, [tr("Instant"), tr("Delayed")], tr("Dilate"), true);
+			if (dilate_handle.changed) {
+				config_raw.dilate = dilate_handle.position;
+			}
+			///end
+
+			///if is_lab
+			let workspace_handle: zui_handle_t = zui_handle("boxpreferences_19", { position: config_raw.workspace });
+			zui_combo(workspace_handle, [tr("3D View"), tr("2D View")], tr("Default Workspace"), true);
+			if (workspace_handle.changed) {
+				config_raw.workspace = workspace_handle.position;
+			}
+			///end
+
+			let camera_controls_handle: zui_handle_t = zui_handle("boxpreferences_20", { position: config_raw.camera_controls });
+			zui_combo(camera_controls_handle, [tr("Orbit"), tr("Rotate"), tr("Fly")], tr("Default Camera Controls"), true);
+			if (camera_controls_handle.changed) {
+				config_raw.camera_controls = camera_controls_handle.position;
+			}
+
+			let layer_res_handle: zui_handle_t = zui_handle("boxpreferences_21", { position: config_raw.layer_res });
+
+			///if is_paint
+			///if (krom_android || krom_ios)
+			zui_combo(layer_res_handle, ["128", "256", "512", "1K", "2K", "4K"], tr("Default Layer Resolution"), true);
+			///else
+			zui_combo(layer_res_handle, ["128", "256", "512", "1K", "2K", "4K", "8K"], tr("Default Layer Resolution"), true);
+			///end
+			///end
+
+			///if is_lab
+			///if (krom_android || krom_ios)
+			zui_combo(layer_res_handle, ["2K", "4K"], tr("Default Layer Resolution"), true);
+			///else
+			zui_combo(layer_res_handle, ["2K", "4K", "8K", "16K"], tr("Default Layer Resolution"), true);
+			///end
+			///end
+
+			if (layer_res_handle.changed) {
+				config_raw.layer_res = layer_res_handle.position;
+			}
+
+			let server_handle: zui_handle_t = zui_handle("boxpreferences_22", { text: config_raw.server });
+			config_raw.server = zui_text_input(server_handle, tr("Cloud Server"));
+
+			///if (is_paint || is_sculpt)
+			let material_live_handle: zui_handle_t = zui_handle("boxpreferences_23", {selected: config_raw.material_live });
+			config_raw.material_live = zui_check(material_live_handle, tr("Live Material Preview"));
+			if (ui.is_hovered) zui_tooltip(tr("Instantly update material preview on node change"));
+
+			let brush_live_handle: zui_handle_t = zui_handle("boxpreferences_24", { selected: config_raw.brush_live });
+			config_raw.brush_live = zui_check(brush_live_handle, tr("Live Brush Preview"));
+			if (ui.is_hovered) zui_tooltip(tr("Draw live brush preview in viewport"));
+			if (brush_live_handle.changed) context_raw.ddirty = 2;
+
+			let brush_3d_handle: zui_handle_t = zui_handle("boxpreferences_25", { selected: config_raw.brush_3d });
+			config_raw.brush_3d = zui_check(brush_3d_handle, tr("3D Cursor"));
+			if (brush_3d_handle.changed) MakeMaterial.make_material_parse_paint_material();
+
+			ui.enabled = config_raw.brush_3d;
+			let brush_depth_reject_handle: zui_handle_t = zui_handle("boxpreferences_26", { selected: config_raw.brush_depth_reject });
+			config_raw.brush_depth_reject = zui_check(brush_depth_reject_handle, tr("Depth Reject"));
+			if (brush_depth_reject_handle.changed) MakeMaterial.make_material_parse_paint_material();
+
+			zui_row([0.5, 0.5]);
+
+			let brush_angle_reject_handle: zui_handle_t = zui_handle("boxpreferences_27", { selected: config_raw.brush_angle_reject });
+			config_raw.brush_angle_reject = zui_check(brush_angle_reject_handle, tr("Angle Reject"));
+			if (brush_angle_reject_handle.changed) MakeMaterial.make_material_parse_paint_material();
+
+			if (!config_raw.brush_angle_reject) ui.enabled = false;
+			let angle_dot_handle: zui_handle_t = zui_handle("boxpreferences_28", { value: context_raw.brush_angle_reject_dot });
+			context_raw.brush_angle_reject_dot = zui_slider(angle_dot_handle, tr("Angle"), 0.0, 1.0, true);
+			if (angle_dot_handle.changed) {
+				MakeMaterial.make_material_parse_paint_material();
+			}
+			ui.enabled = true;
+			///end
+
+			///if is_lab
+			config_raw.gpu_inference = zui_check(zui_handle("boxpreferences_29", { selected: config_raw.gpu_inference }), tr("Use GPU"));
+			if (ui.is_hovered) zui_tooltip(tr("Use GPU to accelerate node graph processing"));
+			///end
+		}
+
+		let pen_name: string;
+		///if krom_ios
+		pen_name = tr("Pencil");
+		///else
+		pen_name = tr("Pen");
+		///end
+
+		if (zui_tab(box_preferences_htab, pen_name, true)) {
+			zui_text(tr("Pressure controls"));
+			config_raw.pressure_radius = zui_check(zui_handle("boxpreferences_30", { selected: config_raw.pressure_radius }), tr("Brush Radius"));
+			config_raw.pressure_sensitivity = zui_slider(zui_handle("boxpreferences_31", { value: config_raw.pressure_sensitivity }), tr("Sensitivity"), 0.0, 10.0, true);
+			///if (is_paint || is_sculpt)
+			config_raw.pressure_hardness = zui_check(zui_handle("boxpreferences_32", { selected: config_raw.pressure_hardness }), tr("Brush Hardness"));
+			config_raw.pressure_opacity = zui_check(zui_handle("boxpreferences_33", { selected: config_raw.pressure_opacity }), tr("Brush Opacity"));
+			config_raw.pressure_angle = zui_check(zui_handle("boxpreferences_34", { selected: config_raw.pressure_angle }), tr("Brush Angle"));
+			///end
+
+			zui_end_element();
+			zui_row([0.5]);
+			if (zui_button(tr("Help"))) {
+				///if (is_paint || is_sculpt)
+				file_load_url("https://github.com/armory3d/armorpaint_docs///pen");
+				///end
+				///if is_lab
+				file_load_url("https://github.com/armory3d/armorlab_docs///pen");
+				///end
+			}
+		}
+
+		context_raw.hssao = zui_handle("boxpreferences_35", { selected: config_raw.rp_ssao });
+		context_raw.hssr = zui_handle("boxpreferences_36", { selected: config_raw.rp_ssr });
+		context_raw.hbloom = zui_handle("boxpreferences_37", { selected: config_raw.rp_bloom });
+		context_raw.hsupersample = zui_handle("boxpreferences_38", { position: config_get_super_sample_quality(config_raw.rp_supersample) });
+		context_raw.hvxao = zui_handle("boxpreferences_39", { selected: config_raw.rp_gi });
+		if (zui_tab(box_preferences_htab, tr("Viewport"), true)) {
+			///if (krom_direct3d12 || krom_vulkan || krom_metal)
+
+			let hpathtrace_mode: zui_handle_t = zui_handle("boxpreferences_40", { position: context_raw.pathtrace_mode });
+			context_raw.pathtrace_mode = zui_combo(hpathtrace_mode, [tr("Core"), tr("Full")], tr("Path Tracer"), true);
+			if (hpathtrace_mode.changed) {
+				render_path_raytrace_ready = false;
+			}
+
+			///end
+
+			let hrender_mode: zui_handle_t = zui_handle("boxpreferences_41", { position: context_raw.render_mode });
+			context_raw.render_mode = zui_combo(hrender_mode, [tr("Full"), tr("Mobile")], tr("Renderer"), true);
+			if (hrender_mode.changed) {
+				context_set_render_path();
+			}
+
+			zui_combo(context_raw.hsupersample, ["0.25x", "0.5x", "1.0x", "1.5x", "2.0x", "4.0x"], tr("Super Sample"), true);
+			if (context_raw.hsupersample.changed) config_apply();
+
+			if (context_raw.render_mode == render_mode_t.DEFERRED) {
+				///if arm_voxels
+				zui_check(context_raw.hvxao, tr("Voxel AO"));
+				if (ui.is_hovered) zui_tooltip(tr("Cone-traced AO and shadows"));
+				if (context_raw.hvxao.changed) {
+					config_apply();
+				}
+
+				ui.enabled = context_raw.hvxao.selected;
+				let h: zui_handle_t = zui_handle("boxpreferences_42", { value: context_raw.vxao_offset });
+				context_raw.vxao_offset = zui_slider(h, tr("Cone Offset"), 1.0, 4.0, true);
+				if (h.changed) context_raw.ddirty = 2;
+				h = zui_handle("boxpreferences_43", { value: context_raw.vxao_aperture });
+				context_raw.vxao_aperture = zui_slider(h, tr("Aperture"), 1.0, 4.0, true);
+				if (h.changed) context_raw.ddirty = 2;
+				ui.enabled = true;
+				///end
+
+				zui_check(context_raw.hssao, tr("SSAO"));
+				if (context_raw.hssao.changed) config_apply();
+				zui_check(context_raw.hssr, tr("SSR"));
+				if (context_raw.hssr.changed) config_apply();
+				zui_check(context_raw.hbloom, tr("Bloom"));
+				if (context_raw.hbloom.changed) config_apply();
+			}
+
+			let h: zui_handle_t = zui_handle("boxpreferences_44", { value: config_raw.rp_vignette });
+			config_raw.rp_vignette = zui_slider(h, tr("Vignette"), 0.0, 1.0, true);
+			if (h.changed) context_raw.ddirty = 2;
+
+			h = zui_handle("boxpreferences_45", { value: config_raw.rp_grain });
+			config_raw.rp_grain = zui_slider(h, tr("Noise Grain"), 0.0, 1.0, true);
+			if (h.changed) context_raw.ddirty = 2;
+
+			// let h: zui_handle_t = Zui.handle("boxpreferences_46", { value: raw.autoExposureStrength });
+			// raw.autoExposureStrength = Zui.slider(h, "Auto Exposure", 0.0, 2.0, true);
+			// if (h.changed) raw.ddirty = 2;
+
+			let cam: camera_object_t = scene_camera;
+			let cam_raw: camera_data_t = cam.data;
+			let near_handle: zui_handle_t = zui_handle("boxpreferences_47");
+			let far_handle: zui_handle_t = zui_handle("boxpreferences_48");
+			near_handle.value = math_floor(cam_raw.near_plane * 1000) / 1000;
+			far_handle.value = math_floor(cam_raw.far_plane * 100) / 100;
+			cam_raw.near_plane = zui_slider(near_handle, tr("Clip Start"), 0.001, 1.0, true);
+			cam_raw.far_plane = zui_slider(far_handle, tr("Clip End"), 50.0, 100.0, true);
+			if (near_handle.changed || far_handle.changed) {
+				camera_object_build_proj(cam);
+			}
+
+			let disp_handle: zui_handle_t = zui_handle("boxpreferences_49", { value: config_raw.displace_strength });
+			config_raw.displace_strength = zui_slider(disp_handle, tr("Displacement Strength"), 0.0, 10.0, true);
+			if (disp_handle.changed) {
+				context_raw.ddirty = 2;
+				MakeMaterial.make_material_parse_mesh_material();
+			}
+		}
+		if (zui_tab(box_preferences_htab, tr("Keymap"), true)) {
+
+			if (box_preferences_files_keymap == null) {
+				box_preferences_fetch_keymaps();
+			}
+
+			zui_begin_sticky();
+			zui_row([1 / 4, 1 / 4, 1 / 4, 1 / 4]);
+
+			box_preferences_preset_handle = zui_handle("boxpreferences_50", { position: box_preferences_get_preset_index() });
+			zui_combo(box_preferences_preset_handle, box_preferences_files_keymap, tr("Preset"));
+			if (box_preferences_preset_handle.changed) {
+				config_raw.keymap = box_preferences_files_keymap[box_preferences_preset_handle.position] + ".json";
+				config_apply();
+				config_load_keymap();
+			}
+
+			if (zui_button(tr("New"))) {
+				ui_box_show_custom(function (ui: zui_t) {
+					if (zui_tab(zui_handle("boxpreferences_51"), tr("New Keymap"))) {
+						zui_row([0.5, 0.5]);
+						let keymap_name: string = zui_text_input(zui_handle("boxpreferences_52", { text: "new_keymap" }), tr("Name"));
+						if (zui_button(tr("OK")) || ui.is_return_down) {
+							let template: string = json_stringify(base_default_keymap);
+							if (!keymap_name.endsWith(".json")) keymap_name += ".json";
+							let path: string = path_data() + path_sep + "keymap_presets" + path_sep + keymap_name;
+							krom_file_save_bytes(path, sys_string_to_buffer(template));
+							box_preferences_fetch_keymaps(); // Refresh file list
+							config_raw.keymap = keymap_name;
+							box_preferences_preset_handle.position = box_preferences_get_preset_index();
+							ui_box_hide();
+							box_preferences_htab.position = 5; // Keymap
+							box_preferences_show();
+						}
+					}
+				});
+			}
+
+			if (zui_button(tr("Import"))) {
+				ui_files_show("json", false, false, function (path: string) {
+					import_keymap_run(path);
+				});
+			}
+			if (zui_button(tr("Export"))) {
+				ui_files_show("json", true, false, function (dest: string) {
+					if (!ui_files_filename.endsWith(".json")) ui_files_filename += ".json";
+					let path: string = path_data() + path_sep + "keymap_presets" + path_sep + config_raw.keymap;
+					file_copy(path, dest + path_sep + ui_files_filename);
+				});
+			}
+
+			zui_end_sticky();
+
+			zui_separator(8, false);
+
+			let i: i32 = 0;
+			ui.changed = false;
+			for (let key in config_keymap) {
+				let h: zui_handle_t = zui_nest(zui_handle("boxpreferences_53"), i++);
+				h.text = config_keymap[key];
+				let text: string = zui_text_input(h, key, zui_align_t.LEFT);
+				config_keymap[key] = text;
+			}
+			if (ui.changed) {
+				config_apply();
+				config_save_keymap();
+			}
+		}
+		if (zui_tab(box_preferences_htab, tr("Plugins"), true)) {
+			zui_begin_sticky();
+			zui_row([1 / 4, 1 / 4]);
+			if (zui_button(tr("New"))) {
+				ui_box_show_custom(function (ui: zui_t) {
+					if (zui_tab(zui_handle("boxpreferences_54"), tr("New Plugin"))) {
+						zui_row([0.5, 0.5]);
+						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 = new Handle();
+plugin.drawUI = function (ui) {
+if (Zui.panel(h1, 'New Plugin')) {
+	if (Zui.button('Button')) {
+		console.error('Hello');
+	}
+}
+}
+`;
+							if (!plugin_name.endsWith(".js")) plugin_name += ".js";
+							let path: string = path_data() + path_sep + "plugins" + path_sep + plugin_name;
+							krom_file_save_bytes(path, sys_string_to_buffer(template));
+							box_preferences_files_plugin = null; // Refresh file list
+							ui_box_hide();
+							box_preferences_htab.position = 6; // Plugins
+							box_preferences_show();
+						}
+					}
+				});
+			}
+			if (zui_button(tr("Import"))) {
+				ui_files_show("js,zip", false, false, (path: string) => {
+					import_plugin_run(path);
+				});
+			}
+			zui_end_sticky();
+
+			if (box_preferences_files_plugin == null) {
+				box_preferences_fetch_plugins();
+			}
+
+			if (config_raw.plugins == null) config_raw.plugins = [];
+			let h: zui_handle_t = zui_handle("boxpreferences_56", { selected: false });
+			for (let f of box_preferences_files_plugin) {
+				let is_js: bool = f.endsWith(".js");
+				if (!is_js) continue;
+				let enabled: bool = config_raw.plugins.indexOf(f) >= 0;
+				h.selected = enabled;
+				let tag: string = is_js ? f.split(".")[0] : f;
+				zui_check(h, tag);
+				if (h.changed && h.selected != enabled) {
+					h.selected ? config_enable_plugin(f) : config_disable_plugin(f);
+					base_redraw_ui();
+				}
+				if (ui.is_hovered && ui.input_released_r) {
+					ui_menu_draw(function (ui: zui_t) {
+						let path: string = path_data() + path_sep + "plugins" + path_sep + f;
+						if (ui_menu_button(ui, tr("Edit in Text Editor"))) {
+							file_start(path);
+						}
+						if (ui_menu_button(ui, tr("Edit in Script Tab"))) {
+							let blob: ArrayBuffer = data_get_blob("plugins/" + f);
+							TabScript.tab_script_hscript.text = sys_buffer_to_string(blob);
+							data_delete_blob("plugins/" + f);
+							console_info(tr("Script opened"));
+						}
+						if (ui_menu_button(ui, tr("Export"))) {
+							ui_files_show("js", true, false, function (dest: string) {
+								if (!ui_files_filename.endsWith(".js")) ui_files_filename += ".js";
+								file_copy(path, dest + path_sep + ui_files_filename);
+							});
+						}
+						if (ui_menu_button(ui, tr("Delete"))) {
+							if (config_raw.plugins.indexOf(f) >= 0) {
+								array_remove(config_raw.plugins, f);
+								plugin_stop(f);
+							}
+							array_remove(box_preferences_files_plugin, f);
+							file_delete(path);
+						}
+					}, 4);
+				}
+			}
+		}
+
+	}, 620, config_raw.touch_ui ? 480 : 420, function () { config_save(); });
+}
+
+function box_preferences_fetch_themes() {
+	box_preferences_themes = file_read_directory(path_data() + path_sep + "themes");
+	for (let i: i32 = 0; i < box_preferences_themes.length; ++i) box_preferences_themes[i] = box_preferences_themes[i].substr(0, box_preferences_themes[i].length - 5); // Strip .json
+	box_preferences_themes.unshift("default");
+}
+
+function box_preferences_fetch_keymaps() {
+	box_preferences_files_keymap = file_read_directory(path_data() + path_sep + "keymap_presets");
+	for (let i: i32 = 0; i < box_preferences_files_keymap.length; ++i) {
+		box_preferences_files_keymap[i] = box_preferences_files_keymap[i].substr(0, box_preferences_files_keymap[i].length - 5); // Strip .json
+	}
+	box_preferences_files_keymap.unshift("default");
+}
+
+function box_preferences_fetch_plugins() {
+	box_preferences_files_plugin = file_read_directory(path_data() + path_sep + "plugins");
+}
+
+function box_preferences_get_theme_index(): i32 {
+	return box_preferences_themes.indexOf(config_raw.theme.substr(0, config_raw.theme.length - 5)); // Strip .json
+}
+
+function box_preferences_get_preset_index(): i32 {
+	return box_preferences_files_keymap.indexOf(config_raw.keymap.substr(0, config_raw.keymap.length - 5)); // Strip .json
+}
+
+function box_preferences_set_scale() {
+	let scale: f32 = config_raw.window_scale;
+	zui_set_scale(ui_base_ui, scale);
+	ui_header_h = math_floor(ui_header_default_h * scale);
+	config_raw.layout[layout_size_t.STATUS_H] = math_floor(ui_status_default_status_h * scale);
+	ui_menubar_w = math_floor(ui_menubar_default_w * scale);
+	ui_base_set_icon_scale();
+	zui_set_scale(ui_nodes_ui, scale);
+	zui_set_scale(ui_view2d_ui, scale);
+	zui_set_scale(base_ui_box, scale);
+	zui_set_scale(base_ui_menu, scale);
+	base_resize();
+	///if (is_paint || is_sculpt)
+	config_raw.layout[layout_size_t.SIDEBAR_W] = math_floor(ui_base_default_sidebar_w * scale);
+	ui_toolbar_w = math_floor(ui_toolbar_default_w * scale);
+	///end
+}

+ 247 - 0
base/Sources/box_projects.ts

@@ -0,0 +1,247 @@
+
+let box_projects_htab: zui_handle_t = zui_handle_create();
+let box_projects_hsearch: zui_handle_t = zui_handle_create();
+let box_projects_icon_map: map_t<string, image_t> = null;
+
+function box_projects_show() {
+	if (box_projects_icon_map != null) {
+		for (let handle of box_projects_icon_map.keys()) {
+			data_delete_image(handle);
+		}
+		box_projects_icon_map = null;
+	}
+
+	let draggable: bool;
+	///if (krom_android || krom_ios)
+	draggable = false;
+	///else
+	draggable = true;
+	///end
+
+	ui_box_show_custom(function (ui: zui_t) {
+		///if (krom_android || krom_ios)
+		box_projects_align_to_fullscreen();
+		///end
+
+		///if (krom_android || krom_ios)
+		box_projects_tab(ui);
+		box_projects_get_started_tab(ui);
+		///else
+		box_projects_recent_tab(ui);
+		///end
+
+	}, 600, 400, null, draggable);
+}
+
+function box_projects_tab(ui: zui_t) {
+	if (zui_tab(box_projects_htab, tr("Projects"), true)) {
+		zui_begin_sticky();
+
+		box_projects_draw_badge(ui);
+
+		if (zui_button(tr("New"))) {
+			project_new();
+			viewport_scale_to_bounds();
+			ui_box_hide();
+			// Pick unique name
+			let i: i32 = 0;
+			let j: i32 = 0;
+			let title: string = tr("untitled") + i;
+			while (j < config_raw.recent_projects.length) {
+				let base: string = config_raw.recent_projects[j];
+				base = base.substring(base.lastIndexOf(path_sep) + 1, base.lastIndexOf("."));
+				j++;
+				if (title == base) {
+					i++;
+					title = tr("untitled") + i;
+					j = 0;
+				}
+			}
+			sys_title_set(title);
+		}
+		zui_end_sticky();
+		zui_separator(3, false);
+
+		let slotw: i32 = math_floor(150 * zui_SCALE(ui));
+		let num: i32 = math_floor(sys_width() / slotw);
+		let recent_projects: string[] = config_raw.recent_projects;
+		let show_asset_names: bool = true;
+
+		for (let row: i32 = 0; row < math_ceil(recent_projects.length / num); ++row) {
+			let mult = show_asset_names ? 2 : 1;
+			let ar: f32[] = [];
+			for (let i: i32 = 0; i < num * mult; ++i) ar.push(1 / num);
+			zui_row(ar);
+
+			ui._x += 2;
+			let off: f32 = show_asset_names ? zui_ELEMENT_OFFSET(ui) * 16.0 : 6;
+			if (row > 0) ui._y += off;
+
+			for (let j: i32 = 0; j < num; ++j) {
+				let imgw: i32 = math_floor(128 * zui_SCALE(ui));
+				let i: i32 = j + row * num;
+				if (i >= recent_projects.length) {
+					zui_end_element(imgw);
+					if (show_asset_names) zui_end_element(0);
+					continue;
+				}
+
+				let path: string = recent_projects[i];
+
+				///if krom_ios
+				let document_directory: string = krom_save_dialog("", "");
+				document_directory = document_directory.substr(0, document_directory.length - 8); // Strip /'untitled'
+				path = document_directory + path;
+				///end
+
+				let icon_path: string = path.substr(0, path.length - 4) + "_icon.png";
+				if (box_projects_icon_map == null) box_projects_icon_map = map_create();
+				let icon: image_t = box_projects_icon_map.get(icon_path);
+				if (icon == null) {
+					let image: image_t = data_get_image(icon_path);
+					icon = image;
+					box_projects_icon_map.set(icon_path, icon);
+				}
+
+				let uix: i32 = ui._x;
+				if (icon != null) {
+					zui_fill(0, 0, 128, 128, ui.t.SEPARATOR_COL);
+
+					let state: i32 = zui_image(icon, 0xffffffff, 128  * zui_SCALE(ui));
+					if (state == zui_state_t.RELEASED) {
+						let _uix: i32 = ui._x;
+						ui._x = uix;
+						zui_fill(0, 0, 128, 128, 0x66000000);
+						ui._x = _uix;
+						let doImport = function () {
+							app_notify_on_init(function () {
+								ui_box_hide();
+								import_arm_run_project(path);
+							});
+						}
+
+						///if (krom_android || krom_ios)
+						base_notify_on_next_frame(function () {
+							console_toast(tr("Opening project"));
+							base_notify_on_next_frame(doImport);
+						});
+						///else
+						doImport();
+						///end
+					}
+
+					let name: string = path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf("."));
+					if (ui.is_hovered && ui.input_released_r) {
+						ui_menu_draw(function (ui: zui_t) {
+							// if (menuButton(ui, tr("Duplicate"))) {}
+							if (ui_menu_button(ui, tr("Delete"))) {
+								app_notify_on_init(function () {
+									file_delete(path);
+									file_delete(icon_path);
+									let data_path: string = path.substr(0, path.length - 4);
+									file_delete(data_path);
+									recent_projects.splice(i, 1);
+								});
+							}
+						}, 1);
+					}
+
+					if (show_asset_names) {
+						ui._x = uix - (150 - 128) / 2;
+						ui._y += slotw * 0.9;
+						zui_text(name, zui_align_t.CENTER);
+						if (ui.is_hovered) zui_tooltip(name);
+						ui._y -= slotw * 0.9;
+						if (i == recent_projects.length - 1) {
+							ui._y += j == num - 1 ? imgw : imgw + zui_ELEMENT_H(ui) + zui_ELEMENT_OFFSET(ui);
+						}
+					}
+				}
+				else {
+					zui_end_element(0);
+					if (show_asset_names) zui_end_element(0);
+					ui._x = uix;
+				}
+			}
+
+			ui._y += 150;
+		}
+	}
+}
+
+function box_projects_recent_tab(ui: zui_t) {
+	if (zui_tab(box_projects_htab, tr("Recent"), true)) {
+
+		box_projects_draw_badge(ui);
+
+		ui.enabled = config_raw.recent_projects.length > 0;
+		box_projects_hsearch.text = zui_text_input(box_projects_hsearch, tr("Search"), zui_align_t.LEFT, true, true);
+		ui.enabled = true;
+
+		for (let path of config_raw.recent_projects) {
+			let file: string = path;
+			///if krom_windows
+			file = string_replace_all(path, "/", "\\");
+			///else
+			file = string_replace_all(path, "\\", "/");
+			///end
+			file = file.substr(file.lastIndexOf(path_sep) + 1);
+
+			if (file.toLowerCase().indexOf(box_projects_hsearch.text.toLowerCase()) < 0) continue; // Search filter
+
+			if (zui_button(file, zui_align_t.LEFT) && file_exists(path)) {
+				let current: image_t = _g2_current;
+				let g2_in_use: bool = _g2_in_use;
+				if (g2_in_use) g2_end();
+
+				import_arm_run_project(path);
+
+				if (g2_in_use) g2_begin(current);
+				ui_box_hide();
+			}
+			if (ui.is_hovered) zui_tooltip(path);
+		}
+
+		ui.enabled = config_raw.recent_projects.length > 0;
+		if (zui_button(tr("Clear"), zui_align_t.LEFT)) {
+			config_raw.recent_projects = [];
+			config_save();
+		}
+		ui.enabled = true;
+
+		zui_end_element();
+		if (zui_button(tr("New .."), zui_align_t.LEFT)) project_new_box();
+		if (zui_button(tr("Open..."), zui_align_t.LEFT)) project_open();
+	}
+}
+
+function box_projects_draw_badge(ui: zui_t) {
+	let img: image_t = data_get_image("badge.k");
+	zui_image(img);
+	zui_end_element();
+}
+
+function box_projects_get_started_tab(ui: zui_t) {
+	if (zui_tab(box_projects_htab, tr("Get Started"), true)) {
+		if (zui_button(tr("Manual"))) {
+			file_load_url(manifest_url + "/manual");
+		}
+		if (zui_button(tr("How To"))) {
+			file_load_url(manifest_url + "/howto");
+		}
+		if (zui_button(tr("What's New"))) {
+			file_load_url(manifest_url + "/notes");
+		}
+	}
+}
+
+function box_projects_align_to_fullscreen() {
+	ui_box_modalw = math_floor(sys_width() / zui_SCALE(base_ui_box));
+	ui_box_modalh = math_floor(sys_height() / zui_SCALE(base_ui_box));
+	let appw: i32 = sys_width();
+	let apph: i32 = sys_height();
+	let mw: i32 = appw;
+	let mh: i32 = apph;
+	ui_box_hwnd.drag_x = math_floor(-appw / 2 + mw / 2);
+	ui_box_hwnd.drag_y = math_floor(-apph / 2 + mh / 2);
+}

+ 1 - 1
base/Sources/config.ts

@@ -176,7 +176,7 @@ function config_apply() {
 	let current: image_t = _g2_current;
 	let g2_in_use: bool = _g2_in_use;
 	if (g2_in_use) g2_end();
-	RenderPathBase.apply_config();
+	render_path_base_apply_config();
 	if (g2_in_use) g2_begin(current);
 }
 

+ 18 - 18
base/Sources/context.ts

@@ -21,7 +21,7 @@ function context_select_material(i: i32) {
 function context_set_material(m: SlotMaterialRaw) {
 	if (project_materials.indexOf(m) == -1) return;
 	context_raw.material = m;
-	MakeMaterial.parse_paint_material();
+	MakeMaterial.make_material_parse_paint_material();
 	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
 	ui_header_handle.redraws = 2;
 	ui_nodes_hwnd.redraws = 2;
@@ -44,7 +44,7 @@ function context_select_brush(i: i32) {
 function context_set_brush(b: SlotBrushRaw) {
 	if (project_brushes.indexOf(b) == -1) return;
 	context_raw.brush = b;
-	MakeMaterial.parse_brush();
+	MakeMaterial.make_material_parse_brush();
 	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
 	ui_nodes_hwnd.redraws = 2;
 }
@@ -78,8 +78,8 @@ function context_set_layer(l: SlotLayerRaw) {
 	if (g2_in_use) g2_end();
 
 	base_set_object_mask();
-	MakeMaterial.parse_mesh_material();
-	MakeMaterial.parse_paint_material();
+	MakeMaterial.make_material_parse_mesh_material();
+	MakeMaterial.make_material_parse_paint_material();
 
 	if (g2_in_use) g2_begin(current);
 
@@ -90,8 +90,8 @@ function context_set_layer(l: SlotLayerRaw) {
 
 function context_select_tool(i: i32) {
 	context_raw.tool = i;
-	MakeMaterial.parse_paint_material();
-	MakeMaterial.parse_mesh_material();
+	MakeMaterial.make_material_parse_paint_material();
+	MakeMaterial.make_material_parse_mesh_material();
 	context_raw.ddirty = 3;
 	let _viewport_mode: viewport_mode_t = context_raw.viewport_mode;
 	context_raw.viewport_mode = -1 as viewport_mode_t;
@@ -116,7 +116,7 @@ function context_init_tool() {
 
 	else if (context_raw.tool == workspace_tool_t.PARTICLE) {
 		util_particle_init();
-		MakeMaterial.parse_particle_material();
+		MakeMaterial.make_material_parse_particle_material();
 	}
 
 	else if (context_raw.tool == workspace_tool_t.BAKE) {
@@ -146,7 +146,7 @@ function context_select_paint_object(o: mesh_object_t) {
 	for (let p of project_paint_objects) p.skip_context = "paint";
 	context_raw.paint_object = o;
 
-	let mask: i32 = SlotLayer.get_object_mask(context_raw.layer);
+	let mask: i32 = SlotLayer.slot_layer_get_object_mask(context_raw.layer);
 	if (context_layer_filter_used()) mask = context_raw.layer_filter;
 
 	if (context_raw.merged_object == null || mask > 0) {
@@ -185,7 +185,7 @@ function context_layer_filter_used(): bool {
 
 function context_object_mask_used(): bool {
 	///if (is_paint || is_sculpt)
-	return SlotLayer.get_object_mask(context_raw.layer) > 0 && SlotLayer.get_object_mask(context_raw.layer) <= project_paint_objects.length;
+	return SlotLayer.slot_layer_get_object_mask(context_raw.layer) > 0 && SlotLayer.slot_layer_get_object_mask(context_raw.layer) <= project_paint_objects.length;
 	///end
 
 	///if is_lab
@@ -258,14 +258,14 @@ function context_set_viewport_mode(mode: viewport_mode_t) {
 
 	context_raw.viewport_mode = mode;
 	if (context_use_deferred()) {
-		render_path_commands = RenderPathDeferred.commands;
+		render_path_commands = render_path_deferred_commands;
 	}
 	else {
-		render_path_commands = RenderPathForward.commands;
+		render_path_commands = render_path_forward_commands;
 	}
 	let _workspace: i32 = ui_header_worktab.position;
 	ui_header_worktab.position = 0;
-	MakeMaterial.parse_mesh_material();
+	MakeMaterial.make_material_parse_mesh_material();
 	ui_header_worktab.position = _workspace;
 }
 
@@ -295,23 +295,23 @@ function context_set_viewport_shader(viewportShader: (ns: NodeShaderRaw)=>string
 
 function context_set_render_path() {
 	if (context_raw.render_mode == render_mode_t.FORWARD || context_raw.viewport_shader != null) {
-		render_path_commands = RenderPathForward.commands;
+		render_path_commands = render_path_forward_commands;
 	}
 	else {
-		render_path_commands = RenderPathDeferred.commands;
+		render_path_commands = render_path_deferred_commands;
 	}
 	app_notify_on_init(function() {
-		MakeMaterial.parse_mesh_material();
+		MakeMaterial.make_material_parse_mesh_material();
 	});
 }
 
 function context_enable_import_plugin(file: string): bool {
 	// Return plugin name suitable for importing the specified file
-	if (BoxPreferences.files_plugin == null) {
-		BoxPreferences.fetch_plugins();
+	if (box_preferences_files_plugin == null) {
+		box_preferences_fetch_plugins();
 	}
 	let ext: string = file.substr(file.lastIndexOf(".") + 1);
-	for (let f of BoxPreferences.files_plugin) {
+	for (let f of box_preferences_files_plugin) {
 		if (f.startsWith("import_") && f.indexOf(ext) >= 0) {
 			config_enable_plugin(f);
 			console_info(f + " " + tr("plugin enabled"));

+ 461 - 0
base/Sources/export_arm.ts

@@ -0,0 +1,461 @@
+
+function export_arm_run_mesh(path: string, paint_objects: mesh_object_t[]) {
+	let mesh_datas: mesh_data_t[] = [];
+	for (let p of paint_objects) mesh_datas.push(p.data);
+	let raw: scene_t = { mesh_datas: mesh_datas };
+	let b: buffer_t = armpack_encode(raw);
+	if (!path.endsWith(".arm")) path += ".arm";
+	krom_file_save_bytes(path, b, b.byteLength + 1);
+}
+
+function export_arm_run_project() {
+	///if (is_paint || is_sculpt)
+	let mnodes: zui_node_canvas_t[] = [];
+	for (let m of project_materials) {
+		let c: zui_node_canvas_t = json_parse(json_stringify(m.canvas));
+		for (let n of c.nodes) export_arm_export_node(n);
+		mnodes.push(c);
+	}
+
+	let bnodes: zui_node_canvas_t[] = [];
+	for (let b of project_brushes) bnodes.push(b.canvas);
+	///end
+
+	///if is_lab
+	let c: zui_node_canvas_t = json_parse(json_stringify(project_canvas));
+	for (let n of c.nodes) export_arm_export_node(n);
+	///end
+
+	let mgroups: zui_node_canvas_t[] = null;
+	if (project_material_groups.length > 0) {
+		mgroups = [];
+		for (let g of project_material_groups) {
+			let c: zui_node_canvas_t = json_parse(json_stringify(g.canvas));
+			for (let n of c.nodes) export_arm_export_node(n);
+			mgroups.push(c);
+		}
+	}
+
+	///if (is_paint || is_sculpt)
+	let md: mesh_data_t[] = [];
+	for (let p of project_paint_objects) md.push(p.data);
+	///end
+
+	///if is_lab
+	let md: mesh_data_t = project_paint_objects[0].data;
+	///end
+
+	let texture_files: string[] = export_arm_assets_to_files(project_filepath, project_assets);
+
+	///if (is_paint || is_sculpt)
+	let font_files: string[] = export_arm_fonts_to_files(project_filepath, project_fonts);
+	let mesh_files: string[] = export_arm_meshes_to_files(project_filepath);
+
+	let bits_pos: i32 = base_bits_handle.position;
+	let bpp: i32 = bits_pos == texture_bits_t.BITS8 ? 8 : bits_pos == texture_bits_t.BITS16 ? 16 : 32;
+
+	let ld: layer_data_t[] = [];
+	for (let l of project_layers) {
+		ld.push({
+			name: l.name,
+			res: l.texpaint != null ? l.texpaint.width : project_layers[0].texpaint.width,
+			bpp: bpp,
+			texpaint: l.texpaint != null ? lz4_encode(image_get_pixels(l.texpaint)) : null,
+			uv_scale: l.scale,
+			uv_rot: l.angle,
+			uv_type: l.uv_type,
+			decal_mat: l.uv_type == uv_type_t.PROJECT ? mat4_to_f32_array(l.decal_mat) : null,
+			opacity_mask: l.mask_opacity,
+			fill_layer: l.fill_layer != null ? project_materials.indexOf(l.fill_layer) : -1,
+			object_mask: l.object_mask,
+			blending: l.blending,
+			parent: l.parent != null ? project_layers.indexOf(l.parent) : -1,
+			visible: l.visible,
+			///if is_paint
+			texpaint_nor: l.texpaint_nor != null ? lz4_encode(image_get_pixels(l.texpaint_nor)) : null,
+			texpaint_pack: l.texpaint_pack != null ? lz4_encode(image_get_pixels(l.texpaint_pack)) : null,
+			paint_base: l.paint_base,
+			paint_opac: l.paint_opac,
+			paint_occ: l.paint_occ,
+			paint_rough: l.paint_rough,
+			paint_met: l.paint_met,
+			paint_nor: l.paint_nor,
+			paint_nor_blend: l.paint_nor_blend,
+			paint_height: l.paint_height,
+			paint_height_blend: l.paint_height_blend,
+			paint_emis: l.paint_emis,
+			paint_subs: l.paint_subs
+			///end
+		});
+	}
+	///end
+
+	let packed_assets: packed_asset_t[] = (project_raw.packed_assets == null || project_raw.packed_assets.length == 0) ? null : project_raw.packed_assets;
+	///if krom_ios
+	let same_drive: bool = false;
+	///else
+	let same_drive: bool = project_raw.envmap != null ? project_filepath.charAt(0) == project_raw.envmap.charAt(0) : true;
+	///end
+
+	project_raw = {
+		version: manifest_version,
+		material_groups: mgroups,
+		assets: texture_files,
+		packed_assets: packed_assets,
+		swatches: project_raw.swatches,
+		envmap: project_raw.envmap != null ? (same_drive ? path_to_relative(project_filepath, project_raw.envmap) : project_raw.envmap) : null,
+		envmap_strength: scene_world.strength,
+		camera_world: mat4_to_f32_array(scene_camera.base.transform.local),
+		camera_origin: export_arm_vec3f32(camera_origins[0]),
+		camera_fov: scene_camera.data.fov,
+
+		///if (is_paint || is_sculpt)
+		mesh_datas: md,
+		material_nodes: mnodes,
+		brush_nodes: bnodes,
+		layer_datas: ld,
+		font_assets: font_files,
+		mesh_assets: mesh_files,
+		///end
+
+		///if is_paint
+		atlas_objects: project_atlas_objects,
+		atlas_names: project_atlas_names,
+		///end
+
+		///if is_lab
+		mesh_data: md,
+		material: c,
+		///end
+
+		///if (krom_metal || krom_vulkan)
+		is_bgra: true
+		///else
+		is_bgra: false
+		///end
+	};
+
+	///if (krom_android || krom_ios)
+	let tex: image_t = render_path_render_targets.get(context_raw.render_mode == render_mode_t.FORWARD ? "buf" : "tex")._image;
+	let mesh_icon: image_t = image_create_render_target(256, 256);
+	let r: f32 = app_w() / app_h();
+	g2_begin(mesh_icon);
+	///if krom_opengl
+	g2_draw_scaled_image(tex, -(256 * r - 256) / 2, 256, 256 * r, -256);
+	///else
+	g2_draw_scaled_image(tex, -(256 * r - 256) / 2, 0, 256 * r, 256);
+	///end
+	g2_end();
+	///if krom_metal
+	// Flush command list
+	g2_begin(mesh_icon);
+	g2_end();
+	///end
+	let mesh_icon_pixels: buffer_t = image_get_pixels(mesh_icon);
+	let u8a: Uint8Array = new Uint8Array(mesh_icon_pixels);
+	for (let i: i32 = 0; i < 256 * 256 * 4; ++i) {
+		u8a[i] = math_floor(math_pow(u8a[i] / 255, 1.0 / 2.2) * 255);
+	}
+	///if (krom_metal || krom_vulkan)
+	export_arm_bgra_swap(mesh_icon_pixels);
+	///end
+	base_notify_on_next_frame(() => {
+		image_unload(mesh_icon);
+	});
+	// raw.mesh_icons =
+	// 	///if (krom_metal || krom_vulkan)
+	// 	[encode(bgraSwap(mesh_icon_pixels)];
+	// 	///else
+	// 	[encode(mesh_icon_pixels)];
+	// 	///end
+	krom_write_png(project_filepath.substr(0, project_filepath.length - 4) + "_icon.png", mesh_icon_pixels, 256, 256, 0);
+	///end
+
+	///if (is_paint || is_sculpt)
+	let is_packed: bool = project_filepath.endsWith("_packed_.arm");
+	if (is_packed) { // Pack textures
+		export_arm_pack_assets(project_raw, project_assets);
+	}
+	///end
+
+	let buffer: buffer_t = armpack_encode(project_raw);
+	krom_file_save_bytes(project_filepath, buffer, buffer.byteLength + 1);
+
+	// Save to recent
+	///if krom_ios
+	let recent_path: string = project_filepath.substr(project_filepath.lastIndexOf("/") + 1);
+	///else
+	let recent_path: string = project_filepath;
+	///end
+	let recent: string[] = config_raw.recent_projects;
+	array_remove(recent, recent_path);
+	recent.unshift(recent_path);
+	config_save();
+
+	console_info(tr("Project saved"));
+}
+
+function export_arm_texture_node_name(): string {
+	///if (is_paint || is_sculpt)
+	return "TEX_IMAGE";
+	///else
+	return "ImageTextureNode";
+	///end
+}
+
+function export_arm_export_node(n: zui_node_t, assets: asset_t[] = null) {
+	if (n.type == export_arm_texture_node_name()) {
+		let index: i32 = n.buttons[0].default_value;
+		n.buttons[0].data = base_enum_texts(n.type)[index];
+
+		if (assets != null) {
+			let asset: asset_t = project_assets[index];
+			if (assets.indexOf(asset) == -1) {
+				assets.push(asset);
+			}
+		}
+	}
+	// Pack colors
+	if (n.color > 0) n.color -= 4294967296;
+	for (let inp of n.inputs) if (inp.color > 0) inp.color -= 4294967296;
+	for (let out of n.outputs) if (out.color > 0) out.color -= 4294967296;
+}
+
+///if (is_paint || is_sculpt)
+function export_arm_run_material(path: string) {
+	if (!path.endsWith(".arm")) path += ".arm";
+	let mnodes: zui_node_canvas_t[] = [];
+	let mgroups: zui_node_canvas_t[] = null;
+	let m: SlotMaterialRaw = context_raw.material;
+	let c: zui_node_canvas_t = json_parse(json_stringify(m.canvas));
+	let assets: asset_t[] = [];
+	if (ui_nodes_has_group(c)) {
+		mgroups = [];
+		ui_nodes_traverse_group(mgroups, c);
+		for (let gc of mgroups) for (let n of gc.nodes) export_arm_export_node(n, assets);
+	}
+	for (let n of c.nodes) export_arm_export_node(n, assets);
+	mnodes.push(c);
+
+	let texture_files: string[] = export_arm_assets_to_files(path, assets);
+	let is_cloud: bool = path.endsWith("_cloud_.arm");
+	if (is_cloud) path = string_replace_all(path, "_cloud_", "");
+	let packed_assets: packed_asset_t[] = null;
+	if (!context_raw.pack_assets_on_export) {
+		packed_assets = export_arm_get_packed_assets(path, texture_files);
+	}
+
+	let raw: project_format_t = {
+		version: manifest_version,
+		material_nodes: mnodes,
+		material_groups: mgroups,
+		material_icons: is_cloud ? null :
+			///if (krom_metal || krom_vulkan)
+			[lz4_encode(export_arm_bgra_swap(image_get_pixels(m.image)))],
+			///else
+			[lz4_encode(image_get_pixels(m.image))],
+			///end
+		assets: texture_files,
+		packed_assets: packed_assets
+	};
+
+	if (context_raw.write_icon_on_export) { // Separate icon files
+		krom_write_png(path.substr(0, path.length - 4) + "_icon.png", image_get_pixels(m.image), m.image.width, m.image.height, 0);
+		if (is_cloud) {
+			krom_write_jpg(path.substr(0, path.length - 4) + "_icon.jpg", image_get_pixels(m.image), m.image.width, m.image.height, 0, 50);
+		}
+	}
+
+	if (context_raw.pack_assets_on_export) { // Pack textures
+		export_arm_pack_assets(raw, assets);
+	}
+
+	let buffer: buffer_t = armpack_encode(raw);
+	krom_file_save_bytes(path, buffer, buffer.byteLength + 1);
+}
+///end
+
+///if (krom_metal || krom_vulkan)
+function export_arm_bgra_swap(buffer: ArrayBuffer) {
+	let view: DataView = new DataView(buffer);
+	for (let i: i32 = 0; i < math_floor(buffer.byteLength / 4); ++i) {
+		let r: i32 = view.getUint8(i * 4);
+		view.setUint8(i * 4, view.getUint8(i * 4 + 2));
+		view.setUint8(i * 4 + 2, r);
+	}
+	return buffer;
+}
+///end
+
+///if (is_paint || is_sculpt)
+function export_arm_run_brush(path: string) {
+	if (!path.endsWith(".arm")) path += ".arm";
+	let bnodes: zui_node_canvas_t[] = [];
+	let b: SlotBrushRaw = context_raw.brush;
+	let c: zui_node_canvas_t = json_parse(json_stringify(b.canvas));
+	let assets: asset_t[] = [];
+	for (let n of c.nodes) export_arm_export_node(n, assets);
+	bnodes.push(c);
+
+	let texture_files: string[] = export_arm_assets_to_files(path, assets);
+	let is_cloud: bool = path.endsWith("_cloud_.arm");
+	if (is_cloud) path = string_replace_all(path, "_cloud_", "");
+	let packed_assets: packed_asset_t[] = null;
+	if (!context_raw.pack_assets_on_export) {
+		packed_assets = export_arm_get_packed_assets(path, texture_files);
+	}
+
+	let raw: project_format_t = {
+		version: manifest_version,
+		brush_nodes: bnodes,
+		brush_icons: is_cloud ? null :
+		///if (krom_metal || krom_vulkan)
+		[lz4_encode(export_arm_bgra_swap(image_get_pixels(b.image)))],
+		///else
+		[lz4_encode(image_get_pixels(b.image))],
+		///end
+		assets: texture_files,
+		packed_assets: packed_assets
+	};
+
+	if (context_raw.write_icon_on_export) { // Separate icon file
+		krom_write_png(path.substr(0, path.length - 4) + "_icon.png", image_get_pixels(b.image), b.image.width, b.image.height, 0);
+	}
+
+	if (context_raw.pack_assets_on_export) { // Pack textures
+		export_arm_pack_assets(raw, assets);
+	}
+
+	let buffer: buffer_t = armpack_encode(raw);
+	krom_file_save_bytes(path, buffer, buffer.byteLength + 1);
+}
+///end
+
+function export_arm_assets_to_files(projectPath: string, assets: asset_t[]): string[] {
+	let texture_files: string[] = [];
+	for (let a of assets) {
+		///if krom_ios
+		let same_drive: bool = false;
+		///else
+		let same_drive: bool = projectPath.charAt(0) == a.file.charAt(0);
+		///end
+		// Convert image path from absolute to relative
+		if (same_drive) {
+			texture_files.push(path_to_relative(projectPath, a.file));
+		}
+		else {
+			texture_files.push(a.file);
+		}
+	}
+	return texture_files;
+}
+
+///if (is_paint || is_sculpt)
+function export_arm_meshes_to_files(project_path: string): string[] {
+	let mesh_files: string[] = [];
+	for (let file of project_mesh_assets) {
+		///if krom_ios
+		let same_drive: bool = false;
+		///else
+		let same_drive: bool = project_path.charAt(0) == file.charAt(0);
+		///end
+		// Convert mesh path from absolute to relative
+		if (same_drive) {
+			mesh_files.push(path_to_relative(project_path, file));
+		}
+		else {
+			mesh_files.push(file);
+		}
+	}
+	return mesh_files;
+}
+
+function export_arm_fonts_to_files(project_path: string, fonts: SlotFontRaw[]): string[] {
+	let font_files: string[] = [];
+	for (let i = 1; i <fonts.length; ++i) {
+		let f: SlotFontRaw = fonts[i];
+		///if krom_ios
+		let same_drive: bool = false;
+		///else
+		let same_drive: bool = project_path.charAt(0) == f.file.charAt(0);
+		///end
+		// Convert font path from absolute to relative
+		if (same_drive) {
+			font_files.push(path_to_relative(project_path, f.file));
+		}
+		else {
+			font_files.push(f.file);
+		}
+	}
+	return font_files;
+}
+///end
+
+function export_arm_get_packed_assets(project_path: string, texture_files: string[]): packed_asset_t[] {
+	let packed_assets: packed_asset_t[] = null;
+	if (project_raw.packed_assets != null) {
+		for (let pa of project_raw.packed_assets) {
+			///if krom_ios
+			let same_drive: bool = false;
+			///else
+			let same_drive: bool = project_path.charAt(0) == pa.name.charAt(0);
+			///end
+			// Convert path from absolute to relative
+			pa.name = same_drive ? path_to_relative(project_path, pa.name) : pa.name;
+			for (let tf of texture_files) {
+				if (pa.name == tf) {
+					if (packed_assets == null) {
+						packed_assets = [];
+					}
+					packed_assets.push(pa);
+					break;
+				}
+			}
+		}
+	}
+	return packed_assets;
+}
+
+function export_arm_pack_assets(raw: project_format_t, assets: asset_t[]) {
+	if (raw.packed_assets == null) {
+		raw.packed_assets = [];
+	}
+	let temp_images: image_t[] = [];
+	for (let i: i32 = 0; i < assets.length; ++i) {
+		if (!project_packed_asset_exists(raw.packed_assets, assets[i].file)) {
+			let image: image_t = project_get_image(assets[i]);
+			let temp: image_t = image_create_render_target(image.width, image.height);
+			g2_begin(temp);
+			g2_draw_image(image, 0, 0);
+			g2_end();
+			temp_images.push(temp);
+			raw.packed_assets.push({
+				name: assets[i].file,
+				bytes: assets[i].file.endsWith(".jpg") ?
+					krom_encode_jpg(image_get_pixels(temp), temp.width, temp.height, 0, 80) :
+					krom_encode_png(image_get_pixels(temp), temp.width, temp.height, 0)
+			});
+		}
+	}
+	base_notify_on_next_frame(() => {
+		for (let image of temp_images) image_unload(image);
+	});
+}
+
+function export_arm_run_swatches(path: string) {
+	if (!path.endsWith(".arm")) path += ".arm";
+	let raw: any = {
+		version: manifest_version,
+		swatches: project_raw.swatches
+	};
+	let buffer: buffer_t = armpack_encode(raw);
+	krom_file_save_bytes(path, buffer, buffer.byteLength + 1);
+}
+
+function export_arm_vec3f32(v: vec4_t): Float32Array {
+	let res: Float32Array = new Float32Array(3);
+	res[0] = v.x;
+	res[1] = v.y;
+	res[2] = v.z;
+	return res;
+}

+ 14 - 0
base/Sources/export_gpl.ts

@@ -0,0 +1,14 @@
+
+function export_gpl_run(path: string, name: string, swatches: swatch_color_t[]) {
+	let o: string = "";
+	o += "GIMP Palette\n";
+	o += "Name: " + name + "\n";
+	o += "# armorpaint.org\n";
+	o += "#\n";
+
+	for (let swatch of swatches) {
+		o += String(color_get_rb(swatch.base)) + " " + String(color_get_gb(swatch.base)) + " " + String(color_get_bb(swatch.base)) + "\n";
+	}
+
+	krom_file_save_bytes(path, sys_string_to_buffer(o), o.length);
+}

+ 12 - 0
base/Sources/export_mesh.ts

@@ -0,0 +1,12 @@
+
+function export_mesh_run(path: string, paint_objects: mesh_object_t[] = null, apply_disp: bool = false) {
+	if (paint_objects == null) {
+		paint_objects = project_paint_objects;
+	}
+	if (context_raw.export_mesh_format == mesh_format_t.OBJ) {
+		export_obj_run(path, paint_objects, apply_disp);
+	}
+	else {
+		export_arm_run_mesh(path, paint_objects);
+	}
+}

+ 170 - 0
base/Sources/export_obj.ts

@@ -0,0 +1,170 @@
+
+function export_obj_write_string(out: i32[], str: string) {
+	for (let i: i32 = 0; i < str.length; ++i) {
+		out.push(str.charCodeAt(i));
+	}
+}
+
+function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp: bool = false) {
+	let o: i32[] = [];
+	export_obj_write_string(o, "# armorpaint.org\n");
+
+	let poff: i32 = 0;
+	let noff: i32 = 0;
+	let toff: i32 = 0;
+	for (let p of paint_objects) {
+		let mesh: mesh_data_t = p.data;
+		let inv: f32 = 1 / 32767;
+		let sc: f32 = p.data.scale_pos * inv;
+		let posa: i16_array_t = mesh.vertex_arrays[0].values;
+		let nora: i16_array_t = mesh.vertex_arrays[1].values;
+		let texa: i16_array_t = mesh.vertex_arrays[2].values;
+		let len: i32 = math_floor(posa.length / 4);
+
+		// Merge shared vertices and remap indices
+		let posa2: Int16Array = new Int16Array(len * 3);
+		let nora2: Int16Array = new Int16Array(len * 3);
+		let texa2: Int16Array = new Int16Array(len * 2);
+		let posmap: map_t<i32, i32> = map_create();
+		let normap: map_t<i32, i32> = map_create();
+		let texmap: map_t<i32, i32> = map_create();
+
+		let pi: i32 = 0;
+		let ni: i32 = 0;
+		let ti: i32 = 0;
+		for (let i: i32 = 0; i < len; ++i) {
+			let found: bool = false;
+			for (let j: i32 = 0; j < pi; ++j) {
+				if (posa2[j * 3    ] == posa[i * 4    ] &&
+					posa2[j * 3 + 1] == posa[i * 4 + 1] &&
+					posa2[j * 3 + 2] == posa[i * 4 + 2]) {
+					posmap.set(i, j);
+					found = true;
+					break;
+				}
+			}
+			if (!found) {
+				posmap.set(i, pi);
+				posa2[pi * 3    ] = posa[i * 4    ];
+				posa2[pi * 3 + 1] = posa[i * 4 + 1];
+				posa2[pi * 3 + 2] = posa[i * 4 + 2];
+				pi++;
+			}
+
+			found = false;
+			for (let j: i32 = 0; j < ni; ++j) {
+				if (nora2[j * 3    ] == nora[i * 2    ] &&
+					nora2[j * 3 + 1] == nora[i * 2 + 1] &&
+					nora2[j * 3 + 2] == posa[i * 4 + 3]) {
+					normap.set(i, j);
+					found = true;
+					break;
+				}
+			}
+			if (!found) {
+				normap.set(i, ni);
+				nora2[ni * 3    ] = nora[i * 2    ];
+				nora2[ni * 3 + 1] = nora[i * 2 + 1];
+				nora2[ni * 3 + 2] = posa[i * 4 + 3];
+				ni++;
+			}
+
+			found = false;
+			for (let j: i32 = 0; j < ti; ++j) {
+				if (texa2[j * 2    ] == texa[i * 2    ] &&
+					texa2[j * 2 + 1] == texa[i * 2 + 1]) {
+					texmap.set(i, j);
+					found = true;
+					break;
+				}
+			}
+			if (!found) {
+				texmap.set(i, ti);
+				texa2[ti * 2    ] = texa[i * 2    ];
+				texa2[ti * 2 + 1] = texa[i * 2 + 1];
+				ti++;
+			}
+		}
+
+		if (apply_disp) {
+			// let height: buffer_t = layers[0].texpaint_pack.getPixels();
+			// let res: i32 = layers[0].texpaint_pack.width;
+			// let strength: f32 = 0.1;
+			// for (let i: i32 = 0; i < len; ++i) {
+			// 	let x: i32 = math_floor(texa2[i * 2    ] / 32767 * res);
+			// 	let y: i32 = math_floor((1.0 - texa2[i * 2 + 1] / 32767) * res);
+			// 	let h: f32 = (1.0 - height.get((y * res + x) * 4 + 3) / 255) * strength;
+			// 	posa2[i * 3    ] -= math_floor(nora2[i * 3    ] * inv * h / sc);
+			// 	posa2[i * 3 + 1] -= math_floor(nora2[i * 3 + 1] * inv * h / sc);
+			// 	posa2[i * 3 + 2] -= math_floor(nora2[i * 3 + 2] * inv * h / sc);
+			// }
+		}
+
+		export_obj_write_string(o, "o " + p.base.name + "\n");
+		for (let i: i32 = 0; i < pi; ++i) {
+			export_obj_write_string(o, "v ");
+			export_obj_write_string(o, posa2[i * 3] * sc + "");
+			export_obj_write_string(o, " ");
+			export_obj_write_string(o, posa2[i * 3 + 2] * sc + "");
+			export_obj_write_string(o, " ");
+			export_obj_write_string(o, -posa2[i * 3 + 1] * sc + "");
+			export_obj_write_string(o, "\n");
+		}
+		for (let i: i32 = 0; i < ni; ++i) {
+			export_obj_write_string(o, "vn ");
+			export_obj_write_string(o, nora2[i * 3] * inv + "");
+			export_obj_write_string(o, " ");
+			export_obj_write_string(o, nora2[i * 3 + 2] * inv + "");
+			export_obj_write_string(o, " ");
+			export_obj_write_string(o, -nora2[i * 3 + 1] * inv + "");
+			export_obj_write_string(o, "\n");
+		}
+		for (let i: i32 = 0; i < ti; ++i) {
+			export_obj_write_string(o, "vt ");
+			export_obj_write_string(o, texa2[i * 2] * inv + "");
+			export_obj_write_string(o, " ");
+			export_obj_write_string(o, 1.0 - texa2[i * 2 + 1] * inv + "");
+			export_obj_write_string(o, "\n");
+		}
+
+		let inda: u32_array_t = mesh.index_arrays[0].values;
+		for (let i: i32 = 0; i < math_floor(inda.length / 3); ++i) {
+			let pi1: i32 = posmap.get(inda[i * 3    ]) + 1 + poff;
+			let pi2: i32 = posmap.get(inda[i * 3 + 1]) + 1 + poff;
+			let pi3: i32 = posmap.get(inda[i * 3 + 2]) + 1 + poff;
+			let ni1: i32 = normap.get(inda[i * 3    ]) + 1 + noff;
+			let ni2: i32 = normap.get(inda[i * 3 + 1]) + 1 + noff;
+			let ni3: i32 = normap.get(inda[i * 3 + 2]) + 1 + noff;
+			let ti1: i32 = texmap.get(inda[i * 3    ]) + 1 + toff;
+			let ti2: i32 = texmap.get(inda[i * 3 + 1]) + 1 + toff;
+			let ti3: i32 = texmap.get(inda[i * 3 + 2]) + 1 + toff;
+			export_obj_write_string(o, "f ");
+			export_obj_write_string(o, pi1 + "");
+			export_obj_write_string(o, "/");
+			export_obj_write_string(o, ti1 + "");
+			export_obj_write_string(o, "/");
+			export_obj_write_string(o, ni1 + "");
+			export_obj_write_string(o, " ");
+			export_obj_write_string(o, pi2 + "");
+			export_obj_write_string(o, "/");
+			export_obj_write_string(o, ti2 + "");
+			export_obj_write_string(o, "/");
+			export_obj_write_string(o, ni2 + "");
+			export_obj_write_string(o, " ");
+			export_obj_write_string(o, pi3 + "");
+			export_obj_write_string(o, "/");
+			export_obj_write_string(o, ti3 + "");
+			export_obj_write_string(o, "/");
+			export_obj_write_string(o, ni3 + "");
+			export_obj_write_string(o, "\n");
+		}
+		poff += pi;
+		noff += ni;
+		toff += ti;
+	}
+
+	if (!path.endsWith(".obj")) path += ".obj";
+
+	let b: ArrayBuffer = Uint8Array.from(o).buffer;
+	krom_file_save_bytes(path, b, b.byteLength);
+}

+ 431 - 0
base/Sources/export_texture.ts

@@ -0,0 +1,431 @@
+
+///if (is_paint || is_lab)
+
+let export_texture_gamma: f32 = 1.0 / 2.2;
+
+function export_texture_run(path: string, bake_material: bool = false) {
+
+	///if is_paint
+	if (bake_material) {
+		export_texture_run_bake_material(path);
+	}
+	else if (context_raw.layers_export == export_mode_t.PER_UDIM_TILE) {
+		let udim_tiles: string[] = [];
+		for (let l of project_layers) {
+			if (SlotLayer.slot_layer_get_object_mask(l) > 0) {
+				let name: string = project_paint_objects[SlotLayer.slot_layer_get_object_mask(l) - 1].base.name;
+				if (name.substr(name.length - 5, 2) == ".1") { // tile.1001
+					udim_tiles.push(name.substr(name.length - 5));
+				}
+			}
+		}
+		if (udim_tiles.length > 0) {
+			for (let udim_tile of udim_tiles) export_texture_run_layers(path, project_layers, udim_tile);
+		}
+		else export_texture_run_layers(path, project_layers);
+	}
+	else if (context_raw.layers_export == export_mode_t.PER_OBJECT) {
+		let object_names: string[] = [];
+		for (let l of project_layers) {
+			if (SlotLayer.slot_layer_get_object_mask(l) > 0) {
+				let name: string = project_paint_objects[SlotLayer.slot_layer_get_object_mask(l) - 1].base.name;
+				if (object_names.indexOf(name) == -1) {
+					object_names.push(name);
+				}
+			}
+		}
+		if (object_names.length > 0) {
+			for (let name of object_names) export_texture_run_layers(path, project_layers, name);
+		}
+		else export_texture_run_layers(path, project_layers);
+	}
+	else { // Visible or selected
+		let atlas_export: bool = false;
+		if (project_atlas_objects != null) {
+			for (let i: i32 = 1; i < project_atlas_objects.length; ++i) {
+				if (project_atlas_objects[i - 1] != project_atlas_objects[i]) {
+					atlas_export = true;
+					break;
+				}
+			}
+		}
+		if (atlas_export) {
+			for (let atlas_index: i32 = 0; atlas_index < project_atlas_objects.length; ++atlas_index) {
+				let layers: SlotLayerRaw[] = [];
+				for (let object_index: i32 = 0; object_index < project_atlas_objects.length; ++object_index) {
+					if (project_atlas_objects[object_index] == atlas_index) {
+						for (let l of project_layers) {
+							if (SlotLayer.slot_layer_get_object_mask(l) == 0 /* shared object */ || SlotLayer.slot_layer_get_object_mask(l) - 1 == object_index) layers.push(l);
+						}
+					}
+				}
+				if (layers.length > 0) {
+					export_texture_run_layers(path, layers, project_atlas_names[atlas_index]);
+				}
+			}
+		}
+		else export_texture_run_layers(path, context_raw.layers_export == export_mode_t.SELECTED ? (SlotLayer.slot_layer_is_group(context_raw.layer) ? SlotLayer.slot_layer_get_children(context_raw.layer) : [context_raw.layer]) : project_layers);
+	}
+	///end
+
+	///if is_lab
+	export_texture_run_layers(path, [BrushOutputNode.inst]);
+	///end
+
+	///if krom_ios
+	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 + "')");
+	///else
+	console_info(tr("Textures exported"));
+	///end
+	ui_files_last_path = "";
+}
+
+///if is_paint
+function export_texture_run_bake_material(path: string) {
+	if (RenderPathPaint.render_path_paint_live_layer == null) {
+		RenderPathPaint.render_path_paint_live_layer = SlotLayer.slot_layer_create("_live");
+	}
+
+	let _tool: workspace_tool_t = context_raw.tool;
+	context_raw.tool = workspace_tool_t.FILL;
+	MakeMaterial.make_material_parse_paint_material();
+	let _paint_object: mesh_object_t = context_raw.paint_object;
+	let planeo: mesh_object_t = scene_get_child(".Plane").ext;
+	planeo.base.visible = true;
+	context_raw.paint_object = planeo;
+	context_raw.pdirty = 1;
+	RenderPathPaint.render_path_paint_use_live_layer(true);
+	RenderPathPaint.render_path_paint_commands_paint(false);
+	RenderPathPaint.render_path_paint_use_live_layer(false);
+	context_raw.tool = _tool;
+	MakeMaterial.make_material_parse_paint_material();
+	context_raw.pdirty = 0;
+	planeo.base.visible = false;
+	context_raw.paint_object = _paint_object;
+
+	export_texture_run_layers(path, [RenderPathPaint.render_path_paint_live_layer], "", true);
+}
+///end
+
+///if is_paint
+function export_texture_run_layers(path: string, layers: SlotLayerRaw[], object_name: string = "", bake_material: bool = false) {
+///end
+
+///if is_lab
+function export_texture_run_layers(path: string, layers: any[], object_name: string = "") {
+///end
+
+	let texture_size_x: i32 = config_get_texture_res_x();
+	let texture_size_y: i32 = config_get_texture_res_y();
+	///if (krom_android || krom_ios)
+	let f: string = sys_title();
+	///else
+	let f: string = ui_files_filename;
+	///end
+	if (f == "") f = tr("untitled");
+	let format_type: texture_ldr_format_t = context_raw.format_type;
+	let bits: i32 = base_bits_handle.position == texture_bits_t.BITS8 ? 8 : 16;
+	let ext: string = bits == 16 ? ".exr" : format_type == texture_ldr_format_t.PNG ? ".png" : ".jpg";
+	if (f.endsWith(ext)) f = f.substr(0, f.length - 4);
+
+	///if is_paint
+	let is_udim: bool = context_raw.layers_export == export_mode_t.PER_UDIM_TILE;
+	if (is_udim) ext = object_name + ext;
+
+	base_make_temp_img();
+	base_make_export_img();
+	if (base_pipe_merge == null) base_make_pipe();
+	if (const_data_screen_aligned_vb == null) const_data_create_screen_aligned_data();
+	let empty: image_t = render_path_render_targets.get("empty_white")._image;
+
+	// Append object mask name
+	let export_selected: bool = context_raw.layers_export == export_mode_t.SELECTED;
+	if (export_selected && SlotLayer.slot_layer_get_object_mask(layers[0]) > 0) {
+		f += "_" + project_paint_objects[SlotLayer.slot_layer_get_object_mask(layers[0]) - 1].base.name;
+	}
+	if (!is_udim && !export_selected && object_name != "") {
+		f += "_" + object_name;
+	}
+
+	// Clear export layer
+	g4_begin(base_expa);
+	g4_clear(color_from_floats(0.0, 0.0, 0.0, 0.0));
+	g4_end();
+	g4_begin(base_expb);
+	g4_clear(color_from_floats(0.5, 0.5, 1.0, 0.0));
+	g4_end();
+	g4_begin(base_expc);
+	g4_clear(color_from_floats(1.0, 0.0, 0.0, 0.0));
+	g4_end();
+
+	// Flatten layers
+	for (let l1 of layers) {
+		if (!export_selected && !SlotLayer.slot_layer_is_visible(l1)) continue;
+		if (!SlotLayer.slot_layer_is_layer(l1)) continue;
+
+		if (object_name != "" && SlotLayer.slot_layer_get_object_mask(l1) > 0) {
+			if (is_udim && !project_paint_objects[SlotLayer.slot_layer_get_object_mask(l1) - 1].base.name.endsWith(object_name)) continue;
+			let per_object: bool = context_raw.layers_export == export_mode_t.PER_OBJECT;
+			if (per_object && project_paint_objects[SlotLayer.slot_layer_get_object_mask(l1) - 1].base.name != object_name) continue;
+		}
+
+		let mask: image_t = empty;
+		let l1masks: SlotLayerRaw[] = SlotLayer.slot_layer_get_masks(l1);
+		if (l1masks != null && !bake_material) {
+			if (l1masks.length > 1) {
+				base_make_temp_mask_img();
+				g2_begin(base_temp_mask_image);
+				g2_clear(0x00000000);
+				g2_end();
+				let l1: any = { texpaint: base_temp_mask_image };
+				for (let i: i32 = 0; i < l1masks.length; ++i) {
+					base_merge_layer(l1, l1masks[i]);
+				}
+				mask = base_temp_mask_image;
+			}
+			else mask = l1masks[0].texpaint;
+		}
+
+		if (l1.paint_base) {
+			g2_begin(base_temp_image); // Copy to temp
+			g2_set_pipeline(base_pipe_copy);
+			g2_draw_image(base_expa, 0, 0);
+			g2_set_pipeline(null);
+			g2_end();
+
+			g4_begin(base_expa);
+			g4_set_pipeline(base_pipe_merge);
+			g4_set_tex(base_tex0, l1.texpaint);
+			g4_set_tex(base_tex1, empty);
+			g4_set_tex(base_texmask, mask);
+			g4_set_tex(base_texa, base_temp_image);
+			g4_set_float(base_opac, SlotLayer.slot_layer_get_opacity(l1));
+			g4_set_int(base_blending, layers.length > 1 ? l1.blending : 0);
+			g4_set_vertex_buffer(const_data_screen_aligned_vb);
+			g4_set_index_buffer(const_data_screen_aligned_ib);
+			g4_draw();
+			g4_end();
+		}
+
+		if (l1.paint_nor) {
+			g2_begin(base_temp_image);
+			g2_set_pipeline(base_pipe_copy);
+			g2_draw_image(base_expb, 0, 0);
+			g2_set_pipeline(null);
+			g2_end();
+
+			g4_begin(base_expb);
+			g4_set_pipeline(base_pipe_merge);
+			g4_set_tex(base_tex0, l1.texpaint);
+			g4_set_tex(base_tex1, l1.texpaint_nor);
+			g4_set_tex(base_texmask, mask);
+			g4_set_tex(base_texa, base_temp_image);
+			g4_set_float(base_opac, SlotLayer.slot_layer_get_opacity(l1));
+			g4_set_int(base_blending, l1.paint_nor_blend ? -2 : -1);
+			g4_set_vertex_buffer(const_data_screen_aligned_vb);
+			g4_set_index_buffer(const_data_screen_aligned_ib);
+			g4_draw();
+			g4_end();
+		}
+
+		if (l1.paint_occ || l1.paint_rough || l1.paint_met || l1.paint_height) {
+			g2_begin(base_temp_image);
+			g2_set_pipeline(base_pipe_copy);
+			g2_draw_image(base_expc, 0, 0);
+			g2_set_pipeline(null);
+			g2_end();
+
+			if (l1.paint_occ && l1.paint_rough && l1.paint_met && l1.paint_height) {
+				base_commands_merge_pack(base_pipe_merge, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask, l1.paint_height_blend ? -3 : -1);
+			}
+			else {
+				if (l1.paint_occ) base_commands_merge_pack(base_pipe_merge_r, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
+				if (l1.paint_rough) base_commands_merge_pack(base_pipe_merge_g, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
+				if (l1.paint_met) base_commands_merge_pack(base_pipe_merge_b, base_expc, l1.texpaint, l1.texpaint_pack, SlotLayer.slot_layer_get_opacity(l1), mask);
+			}
+		}
+	}
+
+	///if krom_metal
+	// Flush command list
+	g2_begin(base_expa);
+	g2_end();
+	g2_begin(base_expb);
+	g2_end();
+	g2_begin(base_expc);
+	g2_end();
+	///end
+	///end
+
+	///if is_paint
+	let texpaint: image_t = base_expa;
+	let texpaint_nor: image_t = base_expb;
+	let texpaint_pack: image_t = base_expc;
+	///end
+
+	///if is_lab
+	let texpaint: image_t = BrushOutputNode.inst.texpaint;
+	let texpaint_nor: image_t = BrushOutputNode.inst.texpaint_nor;
+	let texpaint_pack: image_t = BrushOutputNode.inst.texpaint_pack;
+	///end
+
+	let pixpaint: ArrayBuffer = null;
+	let pixpaint_nor: ArrayBuffer = null;
+	let pixpaint_pack: ArrayBuffer = null;
+	let preset: export_preset_t = box_export_preset;
+	let pix: ArrayBuffer = null;
+
+	for (let t of preset.textures) {
+		for (let c of t.channels) {
+			if      ((c == "base_r" || c == "base_g" || c == "base_b" || c == "opac") && pixpaint == null) pixpaint = image_get_pixels(texpaint);
+			else if ((c == "nor_r" || c == "nor_g" || c == "nor_g_directx" || c == "nor_b" || c == "emis" || c == "subs") && pixpaint_nor == null) pixpaint_nor = image_get_pixels(texpaint_nor);
+			else if ((c == "occ" || c == "rough" || c == "metal" || c == "height" || c == "smooth") && pixpaint_pack == null) pixpaint_pack = image_get_pixels(texpaint_pack);
+		}
+	}
+
+	for (let t of preset.textures) {
+		let c: string[] = t.channels;
+		let tex_name = t.name != "" ? "_" + t.name : "";
+		let single_channel: bool = c[0] == c[1] && c[1] == c[2] && c[3] == "1.0";
+		if (c[0] == "base_r" && c[1] == "base_g" && c[2] == "base_b" && c[3] == "1.0" && t.color_space == "linear") {
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint, 1);
+		}
+		else if (c[0] == "nor_r" && c[1] == "nor_g" && c[2] == "nor_b" && c[3] == "1.0" && t.color_space == "linear") {
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_nor, 1);
+		}
+		else if (c[0] == "occ" && c[1] == "rough" && c[2] == "metal" && c[3] == "1.0" && t.color_space == "linear") {
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 1);
+		}
+		else if (single_channel && c[0] == "occ" && t.color_space == "linear") {
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 0);
+		}
+		else if (single_channel && c[0] == "rough" && t.color_space == "linear") {
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 1);
+		}
+		else if (single_channel && c[0] == "metal" && t.color_space == "linear") {
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 2);
+		}
+		else if (single_channel && c[0] == "height" && t.color_space == "linear") {
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint_pack, 2, 3);
+		}
+		else if (single_channel && c[0] == "opac" && t.color_space == "linear") {
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pixpaint, 2, 3);
+		}
+		else {
+			if (pix == null) pix = new ArrayBuffer(texture_size_x * texture_size_y * 4 * math_floor(bits / 8));
+			for (let i: i32 = 0; i < 4; ++i) {
+				let c: string = t.channels[i];
+				if      (c == "base_r") export_texture_copy_channel(new DataView(pixpaint), 0, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "base_g") export_texture_copy_channel(new DataView(pixpaint), 1, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "base_b") export_texture_copy_channel(new DataView(pixpaint), 2, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "height") export_texture_copy_channel(new DataView(pixpaint_pack), 3, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "metal") export_texture_copy_channel(new DataView(pixpaint_pack), 2, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "nor_r") export_texture_copy_channel(new DataView(pixpaint_nor), 0, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "nor_g") export_texture_copy_channel(new DataView(pixpaint_nor), 1, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "nor_g_directx") export_texture_copy_channel_inv(new DataView(pixpaint_nor), 1, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "nor_b") export_texture_copy_channel(new DataView(pixpaint_nor), 2, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "occ") export_texture_copy_channel(new DataView(pixpaint_pack), 0, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "opac") export_texture_copy_channel(new DataView(pixpaint), 3, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "rough") export_texture_copy_channel(new DataView(pixpaint_pack), 1, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "smooth") export_texture_copy_channel_inv(new DataView(pixpaint_pack), 1, new DataView(pix), i, t.color_space == "linear");
+				else if (c == "emis") export_texture_extract_channel(new DataView(pixpaint_nor), 3, new DataView(pix), i, 3, 1, t.color_space == "linear");
+				else if (c == "subs") export_texture_extract_channel(new DataView(pixpaint_nor), 3, new DataView(pix), i, 3, 2, t.color_space == "linear");
+				else if (c == "0.0") export_texture_set_channel(0, new DataView(pix), i);
+				else if (c == "1.0") export_texture_set_channel(255, new DataView(pix), i);
+			}
+			export_texture_write_texture(path + path_sep + f + tex_name + ext, pix, 3);
+		}
+	}
+
+	// Release staging memory allocated in image_get_pixels()
+	texpaint.pixels = null;
+	texpaint_nor.pixels = null;
+	texpaint_pack.pixels = null;
+}
+
+function export_texture_write_texture(file: string, pixels: ArrayBuffer, type: i32 = 1, off: i32 = 0) {
+	let res_x: i32 = config_get_texture_res_x();
+	let res_y: i32 = config_get_texture_res_y();
+	let bits_handle: i32 = base_bits_handle.position;
+	let bits: i32 = bits_handle == texture_bits_t.BITS8 ? 8 : bits_handle == texture_bits_t.BITS16 ? 16 : 32;
+	let format: i32 = 0; // RGBA
+	if (type == 1) format = 2; // RGB1
+	if (type == 2 && off == 0) format = 3; // RRR1
+	if (type == 2 && off == 1) format = 4; // GGG1
+	if (type == 2 && off == 2) format = 5; // BBB1
+	if (type == 2 && off == 3) format = 6; // AAA1
+
+	if (context_raw.layers_destination == export_destination_t.PACKED) {
+		let image: image_t = image_from_bytes(pixels, res_x, res_y);
+		data_cached_images.set(file, image);
+		let ar: string[] = file.split(path_sep);
+		let name: string = ar[ar.length - 1];
+		let asset: asset_t = {name: name, file: file, id: project_asset_id++};
+		project_assets.push(asset);
+		if (project_raw.assets == null) project_raw.assets = [];
+		project_raw.assets.push(asset.file);
+		project_asset_names.push(asset.name);
+		project_asset_map.set(asset.id, image);
+		export_arm_pack_assets(project_raw, [asset]);
+		return;
+	}
+
+	if (bits == 8 && context_raw.format_type == texture_ldr_format_t.PNG) {
+		krom_write_png(file, pixels, res_x, res_y, format);
+	}
+	else if (bits == 8 && context_raw.format_type == texture_ldr_format_t.JPG) {
+		krom_write_jpg(file, pixels, res_x, res_y, format, math_floor(context_raw.format_quality));
+	}
+	else { // Exr
+		let b: ArrayBuffer = parser_exr_run(res_x, res_y, pixels, bits, type, off);
+		krom_file_save_bytes(file, b, b.byteLength);
+	}
+}
+
+function export_texture_copy_channel(from: DataView, from_channel: i32, to: DataView, to_channel: i32, linear: bool = true) {
+	for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
+		to.setUint8(i * 4 + to_channel, from.getUint8(i * 4 + from_channel));
+	}
+	if (!linear) export_texture_to_srgb(to, to_channel);
+}
+
+function export_texture_copy_channel_inv(from: DataView, from_channel: i32, to: DataView, to_channel: i32, linear: bool = true) {
+	for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
+		to.setUint8(i * 4 + to_channel, 255 - from.getUint8(i * 4 + from_channel));
+	}
+	if (!linear) export_texture_to_srgb(to, to_channel);
+}
+
+function export_texture_extract_channel(from: DataView, from_channel: i32, to: DataView, to_channel: i32, step: i32, mask: i32, linear: bool = true) {
+	for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
+		to.setUint8(i * 4 + to_channel, from.getUint8(i * 4 + from_channel) % step == mask ? 255 : 0);
+	}
+	if (!linear) export_texture_to_srgb(to, to_channel);
+}
+
+function export_texture_set_channel(value: i32, to: DataView, to_channel: i32, linear: bool = true) {
+	for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
+		to.setUint8(i * 4 + to_channel, value);
+	}
+	if (!linear) export_texture_to_srgb(to, to_channel);
+}
+
+function export_texture_to_srgb(to: DataView, to_channel: i32) {
+	for (let i: i32 = 0; i < math_floor(to.byteLength / 4); ++i) {
+		to.setUint8(i * 4 + to_channel, math_floor(math_pow(to.getUint8(i * 4 + to_channel) / 255, export_texture_gamma) * 255));
+	}
+}
+
+type export_preset_t = {
+	textures?: export_preset_texture_t[];
+};
+
+type export_preset_texture_t = {
+	name?: string;
+	channels?: string[];
+	color_space?: string;
+};
+
+///end

+ 1 - 1
base/Sources/gizmo.ts

@@ -255,7 +255,7 @@ function gizmo_update() {
 
 		///if is_forge
 		util_mesh_remove_merged();
-		RenderPathRaytrace.ready = false;
+		render_path_raytrace_ready = false;
 		///end
 	}
 

+ 62 - 62
base/Sources/history.ts

@@ -23,28 +23,28 @@ function history_undo() {
 		///if (is_paint || is_sculpt)
 		else if (step.name == tr("New Layer") || step.name == tr("New Black Mask") || step.name == tr("New White Mask") || step.name == tr("New Fill Mask")) {
 			context_raw.layer = project_layers[step.layer];
-			SlotLayer.delete(context_raw.layer);
+			SlotLayer.slot_layer_delete(context_raw.layer);
 			context_raw.layer = project_layers[step.layer > 0 ? step.layer - 1 : 0];
 		}
 		else if (step.name == tr("New Group")) {
 			context_raw.layer = project_layers[step.layer];
 			// The layer below is the only layer in the group. Its layer masks are automatically unparented, too.
 			project_layers[step.layer - 1].parent = null;
-			SlotLayer.delete(context_raw.layer);
+			SlotLayer.slot_layer_delete(context_raw.layer);
 			context_raw.layer = project_layers[step.layer > 0 ? step.layer - 1 : 0];
 		}
 		else if (step.name == tr("Delete Layer")) {
 			let parent: SlotLayerRaw = step.layer_parent > 0 ? project_layers[step.layer_parent - 1] : null;
-			let l: SlotLayerRaw = SlotLayer.create("", step.layer_type, parent);
+			let l: SlotLayerRaw = SlotLayer.slot_layer_create("", step.layer_type, parent);
 			project_layers.splice(step.layer, 0, l);
 			context_set_layer(l);
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
-			SlotLayer.swap(l, lay);
+			SlotLayer.slot_layer_swap(l, lay);
 			l.mask_opacity = step.layer_opacity;
 			l.blending = step.layer_blending;
 			l.object_mask = step.layer_object;
-			MakeMaterial.parse_mesh_material();
+			MakeMaterial.make_material_parse_mesh_material();
 
 			// Undo at least second time in order to avoid empty groups
 			if (step.layer_type == layer_slot_type_t.GROUP) {
@@ -63,17 +63,17 @@ function history_undo() {
 		else if (step.name == tr("Clear Layer")) {
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer_preview_dirty = true;
 		}
 		else if (step.name == tr("Duplicate Layer")) {
-			let children: SlotLayerRaw[] = SlotLayer.get_recursive_children(project_layers[step.layer]);
+			let children: SlotLayerRaw[] = SlotLayer.slot_layer_get_recursive_children(project_layers[step.layer]);
 			let position: i32 = step.layer + 1;
 			if (children != null)
 				position += children.length;
 
 			context_raw.layer = project_layers[position];
-			SlotLayer.delete(context_raw.layer);
+			SlotLayer.slot_layer_delete(context_raw.layer);
 		}
 		else if (step.name == tr("Order Layers")) {
 			let target: SlotLayerRaw = project_layers[step.prev_order];
@@ -82,44 +82,44 @@ function history_undo() {
 		}
 		else if (step.name == tr("Merge Layers")) {
 			context_raw.layer = project_layers[step.layer];
-			SlotLayer.delete(context_raw.layer);
+			SlotLayer.slot_layer_delete(context_raw.layer);
 
 			let parent: SlotLayerRaw = step.layer_parent > 0 ? project_layers[step.layer_parent - 2] : null;
-			let l: SlotLayerRaw = SlotLayer.create("", step.layer_type, parent);
+			let l: SlotLayerRaw = SlotLayer.slot_layer_create("", step.layer_type, parent);
 			project_layers.splice(step.layer, 0, l);
 			context_set_layer(l);
 
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 
-			l = SlotLayer.create("", step.layer_type, parent);
+			l = SlotLayer.slot_layer_create("", step.layer_type, parent);
 			project_layers.splice(step.layer + 1, 0, l);
 			context_set_layer(l);
 
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			lay = history_undo_layers[history_undo_i];
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 
 			context_raw.layer.mask_opacity = step.layer_opacity;
 			context_raw.layer.blending = step.layer_blending;
 			context_raw.layer.object_mask = step.layer_object;
 			context_raw.layers_preview_dirty = true;
-			MakeMaterial.parse_mesh_material();
+			MakeMaterial.make_material_parse_mesh_material();
 		}
 		else if (step.name == tr("Apply Mask")) {
 			// First restore the layer(s)
 			let mask_pos: i32 = step.layer;
 			let current_layer: SlotLayerRaw = null;
 			// The layer at the old mask position is a mask, i.e. the layer had multiple masks before.
-			if (SlotLayer.is_mask(project_layers[mask_pos])) {
+			if (SlotLayer.slot_layer_is_mask(project_layers[mask_pos])) {
 				current_layer = project_layers[mask_pos].parent;
 			}
-			else if (SlotLayer.is_layer(project_layers[mask_pos]) || SlotLayer.is_group(project_layers[mask_pos])) {
+			else if (SlotLayer.slot_layer_is_layer(project_layers[mask_pos]) || SlotLayer.slot_layer_is_group(project_layers[mask_pos])) {
 				current_layer = project_layers[mask_pos];
 			}
 
-			let layers_to_restore: SlotLayerRaw[] = SlotLayer.is_group(current_layer) ? SlotLayer.get_children(current_layer) : [current_layer];
+			let layers_to_restore: SlotLayerRaw[] = SlotLayer.slot_layer_is_group(current_layer) ? SlotLayer.slot_layer_get_children(current_layer) : [current_layer];
 			layers_to_restore.reverse();
 
 			for (let layer of layers_to_restore) {
@@ -127,21 +127,21 @@ function history_undo() {
 				context_raw.layer = layer;
 				history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 				let old_layer: SlotLayerRaw = history_undo_layers[history_undo_i];
-				SlotLayer.swap(context_raw.layer, old_layer);
+				SlotLayer.slot_layer_swap(context_raw.layer, old_layer);
 			}
 
 			// Now restore the applied mask
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			let mask: SlotLayerRaw = history_undo_layers[history_undo_i];
 			base_new_mask(false, current_layer, mask_pos);
-			SlotLayer.swap(context_raw.layer, mask);
+			SlotLayer.slot_layer_swap(context_raw.layer, mask);
 			context_raw.layers_preview_dirty = true;
 			context_set_layer(context_raw.layer);
 		}
 		else if (step.name == tr("Invert Mask")) {
 			let _next = function () {
 				context_raw.layer = project_layers[step.layer];
-				SlotLayer.invert_mask(context_raw.layer);
+				SlotLayer.slot_layer_invert_mask(context_raw.layer);
 			}
 			app_notify_on_init(_next);
 		}
@@ -149,21 +149,21 @@ function history_undo() {
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
 			context_set_layer(project_layers[step.layer]);
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			base_new_mask(false, context_raw.layer);
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer_preview_dirty = true;
 		}
 		else if (step.name == tr("To Fill Layer") || step.name == tr("To Fill Mask")) {
-			SlotLayer.to_paint_layer(context_raw.layer);
+			SlotLayer.slot_layer_to_paint_layer(context_raw.layer);
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 		}
 		else if (step.name == tr("To Paint Layer") || step.name == tr("To Paint Mask")) {
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer.fill_layer = project_materials[step.material];
 		}
 		else if (step.name == tr("Layer Opacity")) {
@@ -171,14 +171,14 @@ function history_undo() {
 			let t: f32 = context_raw.layer.mask_opacity;
 			context_raw.layer.mask_opacity = step.layer_opacity;
 			step.layer_opacity = t;
-			MakeMaterial.parse_mesh_material();
+			MakeMaterial.make_material_parse_mesh_material();
 		}
 		else if (step.name == tr("Layer Blending")) {
 			context_set_layer(project_layers[step.layer]);
 			let t: blend_type_t = context_raw.layer.blending;
 			context_raw.layer.blending = step.layer_blending;
 			step.layer_blending = t;
-			MakeMaterial.parse_mesh_material();
+			MakeMaterial.make_material_parse_mesh_material();
 		}
 		else if (step.name == tr("Delete Node Group")) {
 			project_material_groups.splice(step.canvas_group, 0, { canvas: null, nodes: zui_nodes_create() });
@@ -187,10 +187,10 @@ function history_undo() {
 		else if (step.name == tr("New Material")) {
 			context_raw.material = project_materials[step.material];
 			step.canvas = context_raw.material.canvas;
-			SlotMaterial.delete(context_raw.material);
+			SlotMaterial.slot_material_delete(context_raw.material);
 		}
 		else if (step.name == tr("Delete Material")) {
-			context_raw.material = SlotMaterial.create(project_materials[0].data);
+			context_raw.material = SlotMaterial.slot_material_create(project_materials[0].data);
 			project_materials.splice(step.material, 0, context_raw.material);
 			context_raw.material.canvas = step.canvas;
 			ui_nodes_canvas_changed();
@@ -199,14 +199,14 @@ function history_undo() {
 		else if (step.name == tr("Duplicate Material")) {
 			context_raw.material = project_materials[step.material];
 			step.canvas = context_raw.material.canvas;
-			SlotMaterial.delete(context_raw.material);
+			SlotMaterial.slot_material_delete(context_raw.material);
 		}
 		else { // Paint operation
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
 			context_select_paint_object(project_paint_objects[step.object]);
 			context_set_layer(project_layers[step.layer]);
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer_preview_dirty = true;
 		}
 		///end
@@ -242,22 +242,22 @@ function history_redo() {
 		///if (is_paint || is_sculpt)
 		else if (step.name == tr("New Layer") || step.name == tr("New Black Mask") || step.name == tr("New White Mask") || step.name == tr("New Fill Mask")) {
 			let parent: SlotLayerRaw = step.layer_parent > 0 ? project_layers[step.layer_parent - 1] : null;
-			let l: SlotLayerRaw = SlotLayer.create("", step.layer_type, parent);
+			let l: SlotLayerRaw = SlotLayer.slot_layer_create("", step.layer_type, parent);
 			project_layers.splice(step.layer, 0, l);
 			if (step.name == tr("New Black Mask")) {
 				base_notify_on_next_frame(function () {
-					SlotLayer.clear(l, 0x00000000);
+					SlotLayer.slot_layer_clear(l, 0x00000000);
 				});
 			}
 			else if (step.name == tr("New White Mask")) {
 				base_notify_on_next_frame(function () {
-					SlotLayer.clear(l, 0xffffffff);
+					SlotLayer.slot_layer_clear(l, 0xffffffff);
 				});
 			}
 			else if (step.name == tr("New Fill Mask")) {
 				base_notify_on_next_frame(function () {
 					context_raw.material = project_materials[step.material];
-					SlotLayer.to_fill_layer(l);
+					SlotLayer.slot_layer_to_fill_layer(l);
 				});
 			}
 			context_raw.layer_preview_dirty = true;
@@ -274,7 +274,7 @@ function history_redo() {
 		else if (step.name == tr("Delete Layer")) {
 			context_raw.layer = project_layers[step.layer];
 			history_swap_active();
-			SlotLayer.delete(context_raw.layer);
+			SlotLayer.slot_layer_delete(context_raw.layer);
 
 			// Redoing the last delete would result in an empty group
 			// Redo deleting all group masks + the group itself
@@ -291,7 +291,7 @@ function history_redo() {
 		else if (step.name == tr("Clear Layer")) {
 			context_raw.layer = project_layers[step.layer];
 			history_swap_active();
-			SlotLayer.clear(context_raw.layer);
+			SlotLayer.slot_layer_clear(context_raw.layer);
 			context_raw.layer_preview_dirty = true;
 		}
 		else if (step.name == tr("Duplicate Layer")) {
@@ -313,16 +313,16 @@ function history_redo() {
 		}
 		else if (step.name == tr("Apply Mask")) {
 			context_raw.layer = project_layers[step.layer];
-				if (SlotLayer.is_group_mask(context_raw.layer)) {
+				if (SlotLayer.slot_layer_is_group_mask(context_raw.layer)) {
 					let group: SlotLayerRaw = context_raw.layer.parent;
-					let layers: SlotLayerRaw[] = SlotLayer.get_children(group);
+					let layers: SlotLayerRaw[] = SlotLayer.slot_layer_get_children(group);
 					layers.splice(0, 0, context_raw.layer);
 					history_copy_merging_layers2(layers);
 				}
 				else history_copy_merging_layers2([context_raw.layer, context_raw.layer.parent]);
 
 			let _next = function() {
-				SlotLayer.apply_mask(context_raw.layer);
+				SlotLayer.slot_layer_apply_mask(context_raw.layer);
 				context_set_layer(context_raw.layer);
 				context_raw.layers_preview_dirty = true;
 			}
@@ -331,29 +331,29 @@ function history_redo() {
 		else if (step.name == tr("Invert Mask")) {
 			let _next = function() {
 				context_raw.layer = project_layers[step.layer];
-				SlotLayer.invert_mask(context_raw.layer);
+				SlotLayer.slot_layer_invert_mask(context_raw.layer);
 			}
 			app_notify_on_init(_next);
 		}
 		else if (step.name == tr("Apply Filter")) {
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
 			context_set_layer(project_layers[step.layer]);
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			base_new_mask(false, lay);
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer_preview_dirty = true;
 			history_undo_i = (history_undo_i + 1) % config_raw.undo_steps;
 		}
 		else if (step.name == tr("To Fill Layer") || step.name == tr("To Fill Mask")) {
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer.fill_layer = project_materials[step.material];
 			history_undo_i = (history_undo_i + 1) % config_raw.undo_steps;
 		}
 		else if (step.name == tr("To Paint Layer") || step.name == tr("To Paint Mask")) {
-			SlotLayer.to_paint_layer(context_raw.layer);
+			SlotLayer.slot_layer_to_paint_layer(context_raw.layer);
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			history_undo_i = (history_undo_i + 1) % config_raw.undo_steps;
 		}
 		else if (step.name == tr("Layer Opacity")) {
@@ -361,21 +361,21 @@ function history_redo() {
 			let t: f32 = context_raw.layer.mask_opacity;
 			context_raw.layer.mask_opacity = step.layer_opacity;
 			step.layer_opacity = t;
-			MakeMaterial.parse_mesh_material();
+			MakeMaterial.make_material_parse_mesh_material();
 		}
 		else if (step.name == tr("Layer Blending")) {
 			context_set_layer(project_layers[step.layer]);
 			let t: blend_type_t = context_raw.layer.blending;
 			context_raw.layer.blending = step.layer_blending;
 			step.layer_blending = t;
-			MakeMaterial.parse_mesh_material();
+			MakeMaterial.make_material_parse_mesh_material();
 		}
 		else if (step.name == tr("Delete Node Group")) {
 			history_swap_canvas(step);
 			array_remove(project_material_groups, project_material_groups[step.canvas_group]);
 		}
 		else if (step.name == tr("New Material")) {
-			context_raw.material = SlotMaterial.create(project_materials[0].data);
+			context_raw.material = SlotMaterial.slot_material_create(project_materials[0].data);
 			project_materials.splice(step.material, 0, context_raw.material);
 			context_raw.material.canvas = step.canvas;
 			ui_nodes_canvas_changed();
@@ -384,10 +384,10 @@ function history_redo() {
 		else if (step.name == tr("Delete Material")) {
 			context_raw.material = project_materials[step.material];
 			step.canvas = context_raw.material.canvas;
-			SlotMaterial.delete(context_raw.material);
+			SlotMaterial.slot_material_delete(context_raw.material);
 		}
 		else if (step.name == tr("Duplicate Material")) {
-			context_raw.material = SlotMaterial.create(project_materials[0].data);
+			context_raw.material = SlotMaterial.slot_material_create(project_materials[0].data);
 			project_materials.splice(step.material, 0, context_raw.material);
 			context_raw.material.canvas = step.canvas;
 			ui_nodes_canvas_changed();
@@ -397,7 +397,7 @@ function history_redo() {
 			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
 			context_select_paint_object(project_paint_objects[step.object]);
 			context_set_layer(project_layers[step.layer]);
-			SlotLayer.swap(context_raw.layer, lay);
+			SlotLayer.slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer_preview_dirty = true;
 			history_undo_i = (history_undo_i + 1) % config_raw.undo_steps;
 		}
@@ -449,7 +449,7 @@ function history_edit_nodes(canvas: zui_node_canvas_t, canvas_group: Null<i32> =
 
 ///if (is_paint || is_sculpt)
 function history_paint() {
-	let is_mask: bool = SlotLayer.is_mask(context_raw.layer);
+	let is_mask: bool = SlotLayer.slot_layer_is_mask(context_raw.layer);
 	history_copy_to_undo(context_raw.layer.id, history_undo_i, is_mask);
 
 	history_push_undo = false;
@@ -500,8 +500,8 @@ function history_merge_layers() {
 
 	let step: step_t = history_push(tr("Merge Layers"));
 	step.layer -= 1; // Merge down
-	if (SlotLayer.has_masks(context_raw.layer)) {
-		step.layer -= SlotLayer.get_masks(context_raw.layer).length;
+	if (SlotLayer.slot_layer_has_masks(context_raw.layer)) {
+		step.layer -= SlotLayer.slot_layer_get_masks(context_raw.layer).length;
 	}
 	history_steps.shift(); // Merge consumes 2 steps
 	history_undos--;
@@ -509,9 +509,9 @@ function history_merge_layers() {
 }
 
 function history_apply_mask() {
-	if (SlotLayer.is_group_mask(context_raw.layer)) {
+	if (SlotLayer.slot_layer_is_group_mask(context_raw.layer)) {
 		let group: SlotLayerRaw = context_raw.layer.parent;
-		let layers: SlotLayerRaw[] = SlotLayer.get_children(group);
+		let layers: SlotLayerRaw[] = SlotLayer.slot_layer_get_children(group);
 		layers.splice(0, 0, context_raw.layer);
 		history_copy_merging_layers2(layers);
 	}
@@ -613,7 +613,7 @@ function history_push(name: string): step_t {
 	history_steps.push({
 		name: name,
 		layer: lpos,
-		layer_type: SlotLayer.is_mask(context_raw.layer) ? layer_slot_type_t.MASK : SlotLayer.is_group(context_raw.layer) ? layer_slot_type_t.GROUP : layer_slot_type_t.LAYER,
+		layer_type: SlotLayer.slot_layer_is_mask(context_raw.layer) ? layer_slot_type_t.MASK : SlotLayer.slot_layer_is_group(context_raw.layer) ? layer_slot_type_t.GROUP : layer_slot_type_t.LAYER,
 		layer_parent: context_raw.layer.parent == null ? -1 : project_layers.indexOf(context_raw.layer.parent),
 		object: opos,
 		material: mpos,
@@ -641,21 +641,21 @@ function history_redo_merge_layers() {
 
 function history_copy_merging_layers() {
 	let lay: SlotLayerRaw = context_raw.layer;
-	history_copy_to_undo(lay.id, history_undo_i, SlotLayer.is_mask(context_raw.layer));
+	history_copy_to_undo(lay.id, history_undo_i, SlotLayer.slot_layer_is_mask(context_raw.layer));
 
 	let below: i32 = project_layers.indexOf(lay) - 1;
 	lay = project_layers[below];
-	history_copy_to_undo(lay.id, history_undo_i, SlotLayer.is_mask(context_raw.layer));
+	history_copy_to_undo(lay.id, history_undo_i, SlotLayer.slot_layer_is_mask(context_raw.layer));
 }
 
 function history_copy_merging_layers2(layers: SlotLayerRaw[]) {
 	for (let layer of layers)
-	history_copy_to_undo(layer.id, history_undo_i, SlotLayer.is_mask(layer));
+	history_copy_to_undo(layer.id, history_undo_i, SlotLayer.slot_layer_is_mask(layer));
 }
 
 function history_swap_active() {
 	let undo_layer: SlotLayerRaw = history_undo_layers[history_undo_i];
-	SlotLayer.swap(undo_layer, context_raw.layer);
+	SlotLayer.slot_layer_swap(undo_layer, context_raw.layer);
 	history_undo_i = (history_undo_i + 1) % config_raw.undo_steps;
 }
 

+ 587 - 0
base/Sources/import_arm.ts

@@ -0,0 +1,587 @@
+
+function import_arm_run_project(path: string) {
+	let b: ArrayBuffer = data_get_blob(path);
+	let project: project_format_t = armpack_decode(b);
+
+	///if (is_paint || is_sculpt)
+	if (project.version != null && project.layer_datas == null) {
+		// Import as material
+		if (project.material_nodes != null) {
+			import_arm_run_material_from_project(project, path);
+		}
+		// Import as brush
+		else if (project.brush_nodes != null) {
+			import_arm_run_brush_from_project(project, path);
+		}
+		// Import as swatches
+		else if (project.swatches != null) {
+			import_arm_run_swatches_from_project(project, path);
+		}
+		return;
+	}
+
+	let import_as_mesh: bool = project.version == null;
+	context_raw.layers_preview_dirty = true;
+	context_raw.layer_filter = 0;
+	///end
+
+	///if is_lab
+	let import_as_mesh: bool = true;
+	///end
+
+	project_new(import_as_mesh);
+	project_filepath = path;
+	ui_files_filename = path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf("."));
+	///if (krom_android || krom_ios)
+	sys_title_set(ui_files_filename);
+	///else
+	sys_title_set(ui_files_filename + " - " + manifest_title);
+	///end
+
+	///if (is_paint || is_sculpt)
+	// Import as mesh instead
+	if (import_as_mesh) {
+		import_arm_run_mesh(project);
+		return;
+	}
+	///end
+
+	// Save to recent
+	///if krom_ios
+	let recent_path: string = path.substr(path.lastIndexOf("/") + 1);
+	///else
+	let recent_path: string = path;
+	///end
+	let recent: string[] = config_raw.recent_projects;
+	array_remove(recent, recent_path);
+	recent.unshift(recent_path);
+	config_save();
+
+	project_raw = project;
+
+	///if (is_paint || is_sculpt)
+	let l0: layer_data_t = project.layer_datas[0];
+	base_res_handle.position = config_get_texture_res_pos(l0.res);
+	let bits_pos: texture_bits_t = l0.bpp == 8 ? texture_bits_t.BITS8 : l0.bpp == 16 ? texture_bits_t.BITS16 : texture_bits_t.BITS32;
+	base_bits_handle.position = bits_pos;
+	let bytes_per_pixel: i32 = math_floor(l0.bpp / 8);
+	let format: tex_format_t = l0.bpp == 8 ? tex_format_t.RGBA32 : l0.bpp == 16 ? tex_format_t.RGBA64 : tex_format_t.RGBA128;
+	///end
+
+	let base: string = path_base_dir(path);
+	if (project_raw.envmap != null) {
+		project_raw.envmap = data_is_abs(project_raw.envmap) ? project_raw.envmap : base + project_raw.envmap;
+	}
+	if (project_raw.envmap_strength != null) {
+		scene_world.strength = project_raw.envmap_strength;
+	}
+	if (project_raw.camera_world != null) {
+		scene_camera.base.transform.local = mat4_from_f32_array(project_raw.camera_world);
+		transform_decompose(scene_camera.base.transform);
+		scene_camera.data.fov = project_raw.camera_fov;
+		camera_object_build_proj(scene_camera);
+		let origin: Float32Array = project_raw.camera_origin;
+		camera_origins[0].x = origin[0];
+		camera_origins[0].y = origin[1];
+		camera_origins[0].z = origin[2];
+	}
+
+	for (let file of project.assets) {
+		///if krom_windows
+		file = string_replace_all(file, "/", "\\");
+		///else
+		file = string_replace_all(file, "\\", "/");
+		///end
+		// Convert image path from relative to absolute
+		let abs: string = data_is_abs(file) ? file : base + file;
+		if (project.packed_assets != null) {
+			abs = path_normalize(abs);
+			import_arm_unpack_asset(project, abs, file);
+		}
+		if (data_cached_images.get(abs) == null && !file_exists(abs)) {
+			import_arm_make_pink(abs);
+		}
+		let hdr_as_envmap: bool = abs.endsWith(".hdr") && project_raw.envmap == abs;
+		import_texture_run(abs, hdr_as_envmap);
+	}
+
+	///if (is_paint || is_sculpt)
+	if (project.font_assets != null) {
+		for (let file of project.font_assets) {
+			///if krom_windows
+			file = string_replace_all(file, "/", "\\");
+			///else
+			file = string_replace_all(file, "\\", "/");
+			///end
+			// Convert font path from relative to absolute
+			let abs: string = data_is_abs(file) ? file : base + file;
+			if (file_exists(abs)) {
+				import_font_run(abs);
+			}
+		}
+	}
+	///end
+
+	///if (is_paint || is_sculpt)
+	let md: mesh_data_t = mesh_data_create(project.mesh_datas[0]);
+	///end
+
+	///if is_lab
+	let md: mesh_data_t = mesh_data_create(project.mesh_data);
+	///end
+
+	mesh_object_set_data(context_raw.paint_object, md);
+	vec4_set(context_raw.paint_object.base.transform.scale, 1, 1, 1);
+	transform_build_matrix(context_raw.paint_object.base.transform);
+	context_raw.paint_object.base.name = md.name;
+	project_paint_objects = [context_raw.paint_object];
+
+	///if (is_paint || is_sculpt)
+	for (let i: i32 = 1; i < project.mesh_datas.length; ++i) {
+		let raw: mesh_data_t = project.mesh_datas[i];
+		let md: mesh_data_t = mesh_data_create(raw);
+		let object: mesh_object_t = scene_add_mesh_object(md, context_raw.paint_object.materials, context_raw.paint_object.base);
+		object.base.name = md.name;
+		object.skip_context = "paint";
+		project_paint_objects.push(object);
+	}
+
+	if (project.mesh_assets != null && project.mesh_assets.length > 0) {
+		let file: string = project.mesh_assets[0];
+		let abs: string = data_is_abs(file) ? file : base + file;
+		project_mesh_assets = [abs];
+	}
+
+	///if is_paint
+	if (project.atlas_objects != null) project_atlas_objects = project.atlas_objects;
+	if (project.atlas_names != null) project_atlas_names = project.atlas_names;
+	///end
+
+	// No mask by default
+	if (context_raw.merged_object == null) util_mesh_merge();
+	///end
+
+	context_select_paint_object(context_main_object());
+	viewport_scale_to_bounds();
+	context_raw.paint_object.skip_context = "paint";
+	context_raw.merged_object.base.visible = true;
+
+	///if (is_paint || is_sculpt)
+	let tex: image_t = project_layers[0].texpaint;
+	if (tex.width != config_get_texture_res_x() || tex.height != config_get_texture_res_y()) {
+		if (history_undo_layers != null) for (let l of history_undo_layers) SlotLayer.slot_layer_resize_and_set_bits(l);
+		let rts: map_t<string, render_target_t> = render_path_render_targets;
+		let _texpaint_blend0: image_t = rts.get("texpaint_blend0")._image;
+		base_notify_on_next_frame(() => {
+			image_unload(_texpaint_blend0);
+		});
+		rts.get("texpaint_blend0").width = config_get_texture_res_x();
+		rts.get("texpaint_blend0").height = config_get_texture_res_y();
+		rts.get("texpaint_blend0")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8, depth_format_t.NO_DEPTH);
+		let _texpaint_blend1: image_t = rts.get("texpaint_blend1")._image;
+		base_notify_on_next_frame(() => {
+			image_unload(_texpaint_blend1);
+		});
+		rts.get("texpaint_blend1").width = config_get_texture_res_x();
+		rts.get("texpaint_blend1").height = config_get_texture_res_y();
+		rts.get("texpaint_blend1")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8, depth_format_t.NO_DEPTH);
+		context_raw.brush_blend_dirty = true;
+	}
+
+	for (let l of project_layers) SlotLayer.slot_layer_unload(l);
+	project_layers = [];
+	for (let i: i32 = 0; i < project.layer_datas.length; ++i) {
+		let ld: layer_data_t = project.layer_datas[i];
+		let is_group: bool = ld.texpaint == null;
+
+		///if is_paint
+		let is_mask: bool = ld.texpaint != null && ld.texpaint_nor == null;
+		///end
+		///if is_sculpt
+		let is_mask: bool = false;
+		///end
+
+		let l: SlotLayerRaw = SlotLayer.slot_layer_create("", is_group ? layer_slot_type_t.GROUP : is_mask ? layer_slot_type_t.MASK : layer_slot_type_t.LAYER);
+		if (ld.name != null) l.name = ld.name;
+		l.visible = ld.visible;
+		project_layers.push(l);
+
+		if (!is_group) {
+			if (base_pipe_merge == null) base_make_pipe();
+
+			let _texpaint: image_t = null;
+
+			///if is_paint
+			let _texpaint_nor: image_t = null;
+			let _texpaint_pack: image_t = null;
+			///end
+
+			if (is_mask) {
+				_texpaint = image_from_bytes(lz4_decode(ld.texpaint, ld.res * ld.res * 4), ld.res, ld.res, tex_format_t.RGBA32);
+				g2_begin(l.texpaint);
+				// g2_set_pipeline(base_pipe_copy8);
+				g2_set_pipeline(project.is_bgra ? base_pipe_copy_bgra : base_pipe_copy); // Full bits for undo support, R8 is used
+				g2_draw_image(_texpaint, 0, 0);
+				g2_set_pipeline(null);
+				g2_end();
+			}
+			else { // Layer
+				// TODO: create render target from bytes
+				_texpaint = image_from_bytes(lz4_decode(ld.texpaint, ld.res * ld.res * 4 * bytes_per_pixel), ld.res, ld.res, format);
+				g2_begin(l.texpaint);
+				g2_set_pipeline(project.is_bgra ? base_pipe_copy_bgra : base_pipe_copy);
+				g2_draw_image(_texpaint, 0, 0);
+				g2_set_pipeline(null);
+				g2_end();
+
+				///if is_paint
+				_texpaint_nor = image_from_bytes(lz4_decode(ld.texpaint_nor, ld.res * ld.res * 4 * bytes_per_pixel), ld.res, ld.res, format);
+				g2_begin(l.texpaint_nor);
+				g2_set_pipeline(project.is_bgra ? base_pipe_copy_bgra : base_pipe_copy);
+				g2_draw_image(_texpaint_nor, 0, 0);
+				g2_set_pipeline(null);
+				g2_end();
+
+				_texpaint_pack = image_from_bytes(lz4_decode(ld.texpaint_pack, ld.res * ld.res * 4 * bytes_per_pixel), ld.res, ld.res, format);
+				g2_begin(l.texpaint_pack);
+				g2_set_pipeline(project.is_bgra ? base_pipe_copy_bgra : base_pipe_copy);
+				g2_draw_image(_texpaint_pack, 0, 0);
+				g2_set_pipeline(null);
+				g2_end();
+				///end
+			}
+
+			l.scale = ld.uv_scale;
+			l.angle = ld.uv_rot;
+			l.uv_type = ld.uv_type;
+			if (ld.decal_mat != null) l.decal_mat = mat4_from_f32_array(ld.decal_mat);
+			l.mask_opacity = ld.opacity_mask;
+			l.object_mask = ld.object_mask;
+			l.blending = ld.blending;
+
+			///if is_paint
+			l.paint_base = ld.paint_base;
+			l.paint_opac = ld.paint_opac;
+			l.paint_occ = ld.paint_occ;
+			l.paint_rough = ld.paint_rough;
+			l.paint_met = ld.paint_met;
+			l.paint_nor = ld.paint_nor;
+			l.paint_nor_blend = ld.paint_nor_blend != null ? ld.paint_nor_blend : true; // TODO: deprecated
+			l.paint_height = ld.paint_height;
+			l.paint_height_blend = ld.paint_height_blend != null ? ld.paint_height_blend : true; // TODO: deprecated
+			l.paint_emis = ld.paint_emis;
+			l.paint_subs = ld.paint_subs;
+			///end
+
+			base_notify_on_next_frame(() => {
+				image_unload(_texpaint);
+				///if is_paint
+				if (_texpaint_nor != null) image_unload(_texpaint_nor);
+				if (_texpaint_pack != null) image_unload(_texpaint_pack);
+				///end
+			});
+		}
+	}
+
+	// Assign parents to groups and masks
+	for (let i: i32 = 0; i < project.layer_datas.length; ++i) {
+		let ld: layer_data_t = project.layer_datas[i];
+		if (ld.parent >= 0) {
+			project_layers[i].parent = project_layers[ld.parent];
+		}
+	}
+
+	context_set_layer(project_layers[0]);
+
+	// Materials
+	let m0: material_data_t = data_get_material("Scene", "Material");
+
+	project_materials = [];
+	for (let n of project.material_nodes) {
+		import_arm_init_nodes(n.nodes);
+		context_raw.material = SlotMaterial.slot_material_create(m0, n);
+		project_materials.push(context_raw.material);
+	}
+	///end
+
+	ui_nodes_hwnd.redraws = 2;
+	ui_nodes_group_stack = [];
+	project_material_groups = [];
+	if (project.material_groups != null) {
+		for (let g of project.material_groups) project_material_groups.push({ canvas: g, nodes: zui_nodes_create() });
+	}
+
+	///if (is_paint || is_sculpt)
+	for (let m of project_materials) {
+		context_raw.material = m;
+		MakeMaterial.make_material_parse_paint_material();
+		util_render_make_material_preview();
+	}
+
+	project_brushes = [];
+	for (let n of project.brush_nodes) {
+		import_arm_init_nodes(n.nodes);
+		context_raw.brush = SlotBrush.slot_brush_create(n);
+		project_brushes.push(context_raw.brush);
+		MakeMaterial.make_material_parse_brush();
+		util_render_make_brush_preview();
+	}
+
+	// Fill layers
+	for (let i: i32 = 0; i < project.layer_datas.length; ++i) {
+		let ld: layer_data_t = project.layer_datas[i];
+		let l: SlotLayerRaw = project_layers[i];
+		let is_group: bool = ld.texpaint == null;
+		if (!is_group) {
+			l.fill_layer = ld.fill_layer > -1 ? project_materials[ld.fill_layer] : null;
+		}
+	}
+
+	ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
+	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
+	///end
+
+	///if is_lab
+	import_arm_init_nodes(project.material.nodes);
+	project_canvas = project.material;
+	parser_logic_parse(project_canvas);
+	///end
+
+	context_raw.ddirty = 4;
+	data_delete_blob(path);
+}
+
+///if (is_paint || is_sculpt)
+function import_arm_run_mesh(raw: scene_t) {
+	project_paint_objects = [];
+	for (let i: i32 = 0; i < raw.mesh_datas.length; ++i) {
+		let md: mesh_data_t = mesh_data_create(raw.mesh_datas[i]);
+		let object: mesh_object_t = null;
+		if (i == 0) {
+			mesh_object_set_data(context_raw.paint_object, md);
+			object = context_raw.paint_object;
+		}
+		else {
+			object = scene_add_mesh_object(md, context_raw.paint_object.materials, context_raw.paint_object.base);
+			object.base.name = md.name;
+			object.skip_context = "paint";
+			md._.handle = md.name;
+			data_cached_meshes.set(md._.handle, md);
+		}
+		vec4_set(object.base.transform.scale, 1, 1, 1);
+		transform_build_matrix(object.base.transform);
+		object.base.name = md.name;
+		project_paint_objects.push(object);
+		util_mesh_merge();
+		viewport_scale_to_bounds();
+	}
+	app_notify_on_init(base_init_layers);
+	history_reset();
+}
+
+function import_arm_run_material(path: string) {
+	let b: ArrayBuffer = data_get_blob(path);
+	let project: project_format_t = armpack_decode(b);
+	if (project.version == null) { data_delete_blob(path); return; }
+	import_arm_run_material_from_project(project, path);
+}
+
+function import_arm_run_material_from_project(project: project_format_t, path: string) {
+	let base: string = path_base_dir(path);
+	for (let file of project.assets) {
+		///if krom_windows
+		file = string_replace_all(file, "/", "\\");
+		///else
+		file = string_replace_all(file, "\\", "/");
+		///end
+		// Convert image path from relative to absolute
+		let abs: string = data_is_abs(file) ? file : base + file;
+		if (project.packed_assets != null) {
+			abs = path_normalize(abs);
+			import_arm_unpack_asset(project, abs, file);
+		}
+		if (data_cached_images.get(abs) == null && !file_exists(abs)) {
+			import_arm_make_pink(abs);
+		}
+		import_texture_run(abs);
+	}
+
+	let m0: material_data_t = data_get_material("Scene", "Material");
+
+	let imported: SlotMaterialRaw[] = [];
+
+	for (let c of project.material_nodes) {
+		import_arm_init_nodes(c.nodes);
+		context_raw.material = SlotMaterial.slot_material_create(m0, c);
+		project_materials.push(context_raw.material);
+		imported.push(context_raw.material);
+		history_new_material();
+	}
+
+	if (project.material_groups != null) {
+		for (let c of project.material_groups) {
+			while (import_arm_group_exists(c)) import_arm_rename_group(c.name, imported, project.material_groups); // Ensure unique group name
+			import_arm_init_nodes(c.nodes);
+			project_material_groups.push({ canvas: c, nodes: zui_nodes_create() });
+		}
+	}
+
+	let _init = () => {
+		for (let m of imported) {
+			context_set_material(m);
+			MakeMaterial.make_material_parse_paint_material();
+			util_render_make_material_preview();
+		}
+	}
+	app_notify_on_init(_init);
+
+	ui_nodes_group_stack = [];
+	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
+	data_delete_blob(path);
+}
+
+function import_arm_group_exists(c: zui_node_canvas_t): bool {
+	for (let g of project_material_groups) {
+		if (g.canvas.name == c.name) return true;
+	}
+	return false;
+}
+
+function import_arm_rename_group(name: string, materials: SlotMaterialRaw[], groups: zui_node_canvas_t[]) {
+	for (let m of materials) {
+		for (let n of m.canvas.nodes) {
+			if (n.type == "GROUP" && n.name == name) n.name += ".1";
+		}
+	}
+	for (let c of groups) {
+		if (c.name == name) c.name += ".1";
+		for (let n of c.nodes) {
+			if (n.type == "GROUP" && n.name == name) n.name += ".1";
+		}
+	}
+}
+
+function import_arm_run_brush(path: string) {
+	let b: ArrayBuffer = data_get_blob(path);
+	let project: project_format_t = armpack_decode(b);
+	if (project.version == null) { data_delete_blob(path); return; }
+	import_arm_run_brush_from_project(project, path);
+}
+
+function import_arm_run_brush_from_project(project: project_format_t, path: string) {
+	let base: string = path_base_dir(path);
+	for (let file of project.assets) {
+		///if krom_windows
+		file = string_replace_all(file, "/", "\\");
+		///else
+		file = string_replace_all(file, "\\", "/");
+		///end
+		// Convert image path from relative to absolute
+		let abs: string = data_is_abs(file) ? file : base + file;
+		if (project.packed_assets != null) {
+			abs = path_normalize(abs);
+			import_arm_unpack_asset(project, abs, file);
+		}
+		if (data_cached_images.get(abs) == null && !file_exists(abs)) {
+			import_arm_make_pink(abs);
+		}
+		import_texture_run(abs);
+	}
+
+	let imported: SlotBrushRaw[] = [];
+
+	for (let n of project.brush_nodes) {
+		import_arm_init_nodes(n.nodes);
+		context_raw.brush = SlotBrush.slot_brush_create(n);
+		project_brushes.push(context_raw.brush);
+		imported.push(context_raw.brush);
+	}
+
+	let _init = () => {
+		for (let b of imported) {
+			context_set_brush(b);
+			util_render_make_brush_preview();
+		}
+	}
+	app_notify_on_init(_init);
+
+	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
+	data_delete_blob(path);
+}
+///end
+
+function import_arm_run_swatches(path: string, replace_existing: bool = false) {
+	let b: ArrayBuffer = data_get_blob(path);
+	let project: project_format_t = armpack_decode(b);
+	if (project.version == null) { data_delete_blob(path); return; }
+	import_arm_run_swatches_from_project(project, path, replace_existing);
+}
+
+function import_arm_run_swatches_from_project(project: project_format_t, path: string, replace_existing: bool = false) {
+	if (replace_existing) {
+		project_raw.swatches = [];
+
+		if (project.swatches == null) { // No swatches contained
+			project_raw.swatches.push(make_swatch());
+		}
+	}
+
+	if (project.swatches != null) {
+		for (let s of project.swatches) {
+			project_raw.swatches.push(s);
+		}
+	}
+	ui_base_hwnds[tab_area_t.STATUS].redraws = 2;
+	data_delete_blob(path);
+}
+
+function import_arm_make_pink(abs: string) {
+	console_error(strings_error2() + " " + abs);
+	let b: Uint8Array = new Uint8Array(4);
+	b[0] = 255;
+	b[1] = 0;
+	b[2] = 255;
+	b[3] = 255;
+	let pink: image_t = image_from_bytes(b.buffer, 1, 1);
+	data_cached_images.set(abs, pink);
+}
+
+function import_arm_texture_node_name(): string {
+	///if (is_paint || is_sculpt)
+	return "TEX_IMAGE";
+	///else
+	return "ImageTextureNode";
+	///end
+}
+
+function import_arm_init_nodes(nodes: zui_node_t[]) {
+	for (let node of nodes) {
+		if (node.type == import_arm_texture_node_name()) {
+			node.buttons[0].default_value = base_get_asset_index(node.buttons[0].data);
+			node.buttons[0].data = "";
+		}
+	}
+}
+
+function import_arm_unpack_asset(project: project_format_t, abs: string, file: string) {
+	if (project_raw.packed_assets == null) {
+		project_raw.packed_assets = [];
+	}
+	for (let pa of project.packed_assets) {
+		///if krom_windows
+		pa.name = string_replace_all(pa.name, "/", "\\");
+		///else
+		pa.name = string_replace_all(pa.name, "\\", "/");
+		///end
+		pa.name = path_normalize(pa.name);
+		if (pa.name == file) pa.name = abs; // From relative to absolute
+		if (pa.name == abs) {
+			if (!project_packed_asset_exists(project_raw.packed_assets, pa.name)) {
+				project_raw.packed_assets.push(pa);
+			}
+			let image: image_t = image_from_encoded_bytes(pa.bytes, pa.name.endsWith(".jpg") ? ".jpg" : ".png");
+			data_cached_images.set(abs, image);
+			break;
+		}
+	}
+}

+ 80 - 0
base/Sources/import_asset.ts

@@ -0,0 +1,80 @@
+
+function import_asset_run(path: string, drop_x: f32 = -1.0, drop_y: f32 = -1.0, show_box: bool = true, hdr_as_envmap: bool = true, done: ()=>void = null) {
+
+	if (path.startsWith("cloud")) {
+		let do_cache_cloud = function () {
+			file_cache_cloud(path, function (abs: string) {
+				if (abs == null) return;
+				import_asset_run(abs, drop_x, drop_y, show_box, hdr_as_envmap, done);
+			});
+		}
+
+		///if (krom_android || krom_ios)
+		base_notify_on_next_frame(function () {
+			console_toast(tr("Downloading"));
+			base_notify_on_next_frame(do_cache_cloud);
+		});
+		///else
+		do_cache_cloud();
+		///end
+
+		return;
+	}
+
+	if (path_is_mesh(path)) {
+		show_box ? project_import_mesh_box(path) : import_mesh_run(path);
+		if (drop_x > 0) ui_box_click_to_hide = false; // Prevent closing when going back to window after drag and drop
+	}
+	else if (path_is_texture(path)) {
+		import_texture_run(path, hdr_as_envmap);
+		// Place image node
+		let x0: i32 = ui_nodes_wx;
+		let x1: i32 = ui_nodes_wx + ui_nodes_ww;
+		if (ui_nodes_show && drop_x > x0 && drop_x < x1) {
+			let asset_index: i32 = 0;
+			for (let i: i32 = 0; i < project_assets.length; ++i) {
+				if (project_assets[i].file == path) {
+					asset_index = i;
+					break;
+				}
+			}
+			ui_nodes_accept_asset_drag(asset_index);
+			ui_nodes_get_nodes().nodesDrag = false;
+			ui_nodes_hwnd.redraws = 2;
+		}
+
+		///if is_paint
+		if (context_raw.tool == workspace_tool_t.COLORID && project_asset_names.length == 1) {
+			ui_header_handle.redraws = 2;
+			context_raw.ddirty = 2;
+		}
+		///end
+	}
+	else if (path_is_project(path)) {
+		import_arm_run_project(path);
+	}
+	else if (path_is_plugin(path)) {
+		import_plugin_run(path);
+	}
+	else if (path_is_gimp_color_palette(path)) {
+		import_gpl_run(path, false);
+	}
+	///if is_paint
+	else if (path_is_font(path)) {
+		import_font_run(path);
+	}
+	else if (path_is_folder(path)) {
+		ImportFolder.import_folder_run(path);
+	}
+	///end
+	else {
+		if (context_enable_import_plugin(path)) {
+			import_asset_run(path, drop_x, drop_y, show_box);
+		}
+		else {
+			console_error(strings_error1());
+		}
+	}
+
+	if (done != null) done();
+}

+ 291 - 0
base/Sources/import_blend_material.ts

@@ -0,0 +1,291 @@
+
+///if (is_paint || is_sculpt)
+
+function import_blend_material_run(path: string) {
+	let b: ArrayBuffer = data_get_blob(path);
+	let bl: BlendRaw = parser_blend_init(b);
+	if (bl.dna == null) {
+		console_error(strings_error3());
+		return;
+	}
+
+	let mats: BlHandleRaw[] = parser_blend_get(bl, "Material");
+	if (mats.length == 0) {
+		console_error("Error: No materials found");
+		return;
+	}
+
+	let imported: SlotMaterialRaw[] = [];
+
+	for (let mat of mats) {
+		// Material slot
+		context_raw.material = SlotMaterial.slot_material_create(project_materials[0].data);
+		project_materials.push(context_raw.material);
+		imported.push(context_raw.material);
+		let nodes: zui_nodes_t = context_raw.material.nodes;
+		let canvas: zui_node_canvas_t = context_raw.material.canvas;
+		canvas.name = bl_handle_get(bl_handle_get(mat, "id"), "name").substr(2); // MAWood
+		let nout: zui_node_t = null;
+		for (let n of canvas.nodes) {
+			if (n.type == "OUTPUT_MATERIAL_PBR") {
+				nout = n;
+				break;
+			}
+		}
+		for (let n of canvas.nodes) {
+			if (n.name == "RGB") {
+				zui_remove_node(n, canvas);
+				break;
+			}
+		}
+
+		// Parse nodetree
+		let nodetree: any = bl_handle_get(mat, "nodetree"); // bNodeTree
+		let blnodes: any = bl_handle_get(nodetree, "nodes"); // ListBase
+		let bllinks: any = bl_handle_get(nodetree, "links"); // bNodeLink
+
+		// Look for Principled BSDF node
+		let node: any = bl_handle_get(blnodes, "first", 0, "bNode");
+		let last: any = bl_handle_get(blnodes, "last", 0, "bNode");
+		while (true) {
+			if (bl_handle_get(node, "idname") == "ShaderNodeBsdfPrincipled") break;
+			if (bl_handle_get(node, "name") == bl_handle_get(last, "name")) break;
+			node = bl_handle_get(node, "next");
+		}
+		if (bl_handle_get(node, "idname") != "ShaderNodeBsdfPrincipled") {
+			console_error("Error: No Principled BSDF node found");
+			continue;
+		}
+
+		// Use Principled BSDF as material output
+		nout.name = bl_handle_get(node, "name");
+		nout.x = bl_handle_get(node, "locx") + 400;
+		nout.y = -bl_handle_get(node, "locy") + 400;
+
+		// Place nodes
+		node = bl_handle_get(blnodes, "first", 0, "bNode");
+		while (true) {
+			// Search for node in list
+			let search: string = bl_handle_get(node, "idname").substr(10).toLowerCase();
+			let base: zui_node_t = null;
+			for (let list of nodes_material_list) {
+				let found: bool = false;
+				for (let n of list) {
+					let s: string = string_replace_all(n.type, "_", "").toLowerCase();
+					if (search == s) {
+						base = n;
+						found = true;
+						break;
+					}
+				}
+				if (found) break;
+			}
+
+			if (base != null) {
+				let n: zui_node_t = ui_nodes_make_node(base, nodes, canvas);
+				n.x = bl_handle_get(node, "locx") + 400;
+				n.y = -bl_handle_get(node, "locy") + 400;
+				n.name = bl_handle_get(node, "name");
+
+				// Fill input socket values
+				let inputs: any = bl_handle_get(node, "inputs");
+				let sock: any = bl_handle_get(inputs, "first", 0, "bNodeSocket");
+				let pos: i32 = 0;
+				while (true) {
+					if (pos >= n.inputs.length) break;
+					n.inputs[pos].default_value = import_blend_material_read_blend_socket(sock);
+
+					let last: any = sock;
+					sock = bl_handle_get(sock, "next");
+					if (last.block == sock.block) break;
+					pos++;
+				}
+
+				// Fill button values
+				if (search == "teximage") {
+					let img: any = bl_handle_get(node, "id", 0, "Image");
+					let file: string = bl_handle_get(img, "name").substr(2); // '//desktop\logo.png'
+					file = path_base_dir(path) + file;
+					import_texture_run(file);
+					let ar: string[] = file.split(path_sep);
+					let filename: string = ar[ar.length - 1];
+					n.buttons[0].default_value = base_get_asset_index(filename);
+				}
+				else if (search == "valtorgb") {
+					let ramp: any = bl_handle_get(node, "storage", 0, "ColorBand");
+					n.buttons[0].data = bl_handle_get(ramp, "ipotype") == 0 ? 0 : 1; // Linear / Constant
+					let elems: f32[][] = n.buttons[0].default_value;
+					for (let i: i32 = 0; i < bl_handle_get(ramp, "tot"); ++i) {
+						if (i >= elems.length) elems.push([1.0, 1.0, 1.0, 1.0, 0.0]);
+						let cbdata: any = bl_handle_get(ramp, "data", i, "CBData");
+						elems[i][0] = math_floor(bl_handle_get(cbdata, "r") * 100) / 100;
+						elems[i][1] = math_floor(bl_handle_get(cbdata, "g") * 100) / 100;
+						elems[i][2] = math_floor(bl_handle_get(cbdata, "b") * 100) / 100;
+						elems[i][3] = math_floor(bl_handle_get(cbdata, "a") * 100) / 100;
+						elems[i][4] = math_floor(bl_handle_get(cbdata, "pos") * 100) / 100;
+					}
+				}
+				else if (search == "mixrgb" || search == "math") {
+					n.buttons[0].default_value = bl_handle_get(node, "custom1");
+					n.buttons[1].default_value = bl_handle_get(node, "custom2") & 2;
+				}
+				else if (search == "mapping") {
+					let storage: any = bl_handle_get(node, "storage", 0, "TexMapping");
+					n.buttons[0].default_value = bl_handle_get(storage, "loc");
+					n.buttons[1].default_value = bl_handle_get(storage, "rot");
+					n.buttons[2].default_value = bl_handle_get(storage, "size");
+					// let mat: any = get(storage, "mat"); float[4][4]
+					// storage.flag & 1 // use_min
+					// storage.flag & 2 // use_max
+					// storage.min[0]
+					// storage.min[1]
+					// storage.min[2]
+					// storage.max[0]
+					// storage.max[1]
+					// storage.max[2]
+				}
+
+				// Fill output socket values
+				let outputs: any = bl_handle_get(node, "outputs");
+				sock = bl_handle_get(outputs, "first", 0, "bNodeSocket");
+				pos = 0;
+				while (true) {
+					if (pos >= n.outputs.length) break;
+					n.outputs[pos].default_value = import_blend_material_read_blend_socket(sock);
+
+					let last: any = sock;
+					sock = bl_handle_get(sock, "next");
+					if (last.block == sock.block) break;
+					pos++;
+				}
+
+				canvas.nodes.push(n);
+			}
+
+			if (bl_handle_get(node, "name") == bl_handle_get(last, "name")) break;
+			node = bl_handle_get(node, "next");
+		}
+
+		// Place links
+		let link: any = bl_handle_get(bllinks, "first", 0, "bNodeLink");
+		while (true) {
+			let fromnode: any = bl_handle_get(bl_handle_get(link, "fromnode"), "name");
+			let tonode: any = bl_handle_get(bl_handle_get(link, "tonode"), "name");
+			let fromsock: any = bl_handle_get(link, "fromsock");
+			let tosock: any = bl_handle_get(link, "tosock");
+
+			let from_id: i32 = -1;
+			let to_id: i32 = -1;
+			for (let n of canvas.nodes) {
+				if (n.name == fromnode) {
+					from_id = n.id;
+					break;
+				}
+			}
+			for (let n of canvas.nodes) {
+				if (n.name == tonode) {
+					to_id = n.id;
+					break;
+				}
+			}
+
+			if (from_id >= 0 && to_id >= 0) {
+				let from_socket: i32 = 0;
+				let sock: any = fromsock;
+				while (true) {
+					let last: any = sock;
+					sock = bl_handle_get(sock, "prev");
+					if (last.block == sock.block) break;
+					from_socket++;
+				}
+
+				let to_socket: i32 = 0;
+				sock = tosock;
+				while (true) {
+					let last: any = sock;
+					sock = bl_handle_get(sock, "prev");
+					if (last.block == sock.block) break;
+					to_socket++;
+				}
+
+				let valid: bool = true;
+
+				// Remap principled
+				if (tonode == nout.name) {
+					if (to_socket == 0) to_socket = 0; // Base
+					else if (to_socket == 18) to_socket = 1; // Opac
+					else if (to_socket == 7) to_socket = 3; // Rough
+					else if (to_socket == 4) to_socket = 4; // Met
+					else if (to_socket == 19) to_socket = 5; // TODO: auto-remove normal_map node
+					else if (to_socket == 17) to_socket = 6; // Emis
+					else if (to_socket == 1) to_socket = 8; // Subs
+					else valid = false;
+				}
+
+				if (valid) {
+					let raw: zui_node_link_t = {
+						id: zui_get_link_id(canvas.links),
+						from_id: from_id,
+						from_socket: from_socket,
+						to_id: to_id,
+						to_socket: to_socket
+					};
+					canvas.links.push(raw);
+				}
+			}
+
+			let last: any = link;
+			link = bl_handle_get(link, "next");
+			if (last.block == link.block) break;
+		}
+		history_new_material();
+	}
+
+	let _init = () => {
+		for (let m of imported) {
+			context_set_material(m);
+			MakeMaterial.make_material_parse_paint_material();
+			util_render_make_material_preview();
+		}
+	}
+	app_notify_on_init(_init);
+
+	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
+	data_delete_blob(path);
+}
+
+function import_blend_material_read_blend_socket(sock: any): any {
+	let idname: any = bl_handle_get(sock, "idname");
+	if (idname.startsWith("NodeSocketVector")) {
+		let v: any = bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueVector"), "value");
+		v[0] = math_floor(v[0] * 100) / 100;
+		v[1] = math_floor(v[1] * 100) / 100;
+		v[2] = math_floor(v[2] * 100) / 100;
+		return v;
+	}
+	else if (idname.startsWith("NodeSocketColor")) {
+		let v: any = bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueRGBA"), "value");
+		v[0] = math_floor(v[0] * 100) / 100;
+		v[1] = math_floor(v[1] * 100) / 100;
+		v[2] = math_floor(v[2] * 100) / 100;
+		v[3] = math_floor(v[3] * 100) / 100;
+		return v;
+	}
+	else if (idname.startsWith("NodeSocketFloat")) {
+		let v: any = bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueFloat"), "value");
+		v = math_floor(v * 100) / 100;
+		return v;
+	}
+	else if (idname.startsWith("NodeSocketInt")) {
+		return bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueInt"), "value");
+	}
+	else if (idname.startsWith("NodeSocketBoolean")) {
+		return bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueBoolean"), "value");
+	}
+	else if (idname.startsWith("NodeSocketString")) {
+		return bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueString"), "value");
+	}
+	return null;
+}
+
+///end

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác