luboslenco 1 year ago
parent
commit
1eb6727466
100 changed files with 3904 additions and 2523 deletions
  1. 78 53
      armorforge/Sources/tab_objects.ts
  2. 20 12
      armorlab/Sources/make_material.ts
  3. 6 4
      armorlab/Sources/nodes/image_texture_node.ts
  4. 30 24
      armorlab/Sources/nodes/inpaint_node.ts
  5. 25 19
      armorlab/Sources/nodes/photo_to_pbr_node.ts
  6. 5 5
      armorlab/Sources/nodes/rgb_node.ts
  7. 51 47
      armorlab/Sources/nodes/text_to_photo_node.ts
  8. 13 9
      armorlab/Sources/nodes/tiling_node.ts
  9. 18 12
      armorlab/Sources/nodes/upscale_node.ts
  10. 13 11
      armorlab/Sources/nodes/variance_node.ts
  11. 17 17
      armorlab/Sources/nodes_brush.ts
  12. 23 15
      armorlab/Sources/render_path_paint.ts
  13. 30 24
      armorlab/Sources/ui_nodes_ext.ts
  14. 7 5
      armorpaint/Sources/import_folder.ts
  15. 3 3
      armorpaint/Sources/make_bake.ts
  16. 1 1
      armorpaint/Sources/make_blur.ts
  17. 10 4
      armorpaint/Sources/make_brush.ts
  18. 1 1
      armorpaint/Sources/make_clone.ts
  19. 1 1
      armorpaint/Sources/make_colorid_picker.ts
  20. 4 4
      armorpaint/Sources/make_discard.ts
  21. 83 53
      armorpaint/Sources/make_material.ts
  22. 40 20
      armorpaint/Sources/make_mesh.ts
  23. 4 4
      armorpaint/Sources/make_mesh_preview.ts
  24. 5 5
      armorpaint/Sources/make_node_preview.ts
  25. 19 9
      armorpaint/Sources/make_paint.ts
  26. 5 5
      armorpaint/Sources/make_particle.ts
  27. 7 7
      armorpaint/Sources/make_texcoord.ts
  28. 9 7
      armorpaint/Sources/nodes/brush_output_node.ts
  29. 8 4
      armorpaint/Sources/nodes/input_node.ts
  30. 8 4
      armorpaint/Sources/nodes/tex_image_node.ts
  31. 1 1
      armorpaint/Sources/nodes_brush.ts
  32. 105 77
      armorpaint/Sources/render_path_paint.ts
  33. 4 4
      armorpaint/Sources/render_path_preview.ts
  34. 10 6
      armorpaint/Sources/slot_brush.ts
  35. 8 4
      armorpaint/Sources/slot_font.ts
  36. 220 138
      armorpaint/Sources/slot_layer.ts
  37. 16 12
      armorpaint/Sources/slot_material.ts
  38. 176 96
      armorpaint/Sources/tab_layers.ts
  39. 21 19
      armorsculpt/Sources/export_obj.ts
  40. 53 29
      armorsculpt/Sources/import_mesh.ts
  41. 89 49
      armorsculpt/Sources/make_material.ts
  42. 20 12
      armorsculpt/Sources/make_mesh.ts
  43. 1 1
      armorsculpt/Sources/make_sculpt.ts
  44. 14 12
      armorsculpt/Sources/nodes/brush_output_node.ts
  45. 46 24
      armorsculpt/Sources/tab_layers.ts
  46. 15 9
      base/Sources/args.ts
  47. 261 151
      base/Sources/base.ts
  48. 73 49
      base/Sources/box_export.ts
  49. 124 52
      base/Sources/box_preferences.ts
  50. 42 22
      base/Sources/box_projects.ts
  51. 34 18
      base/Sources/camera.ts
  52. 56 38
      base/Sources/config.ts
  53. 9 5
      base/Sources/console.ts
  54. 89 43
      base/Sources/context.ts
  55. 74 64
      base/Sources/export_arm.ts
  56. 1 1
      base/Sources/export_gpl.ts
  57. 24 22
      base/Sources/export_obj.ts
  58. 178 83
      base/Sources/export_texture.ts
  59. 40 36
      base/Sources/file.ts
  60. 15 13
      base/Sources/geom.ts
  61. 45 15
      base/Sources/gizmo.ts
  62. 90 74
      base/Sources/history.ts
  63. 112 67
      base/Sources/import_arm.ts
  64. 7 3
      base/Sources/import_asset.ts
  65. 81 38
      base/Sources/import_blend_material.ts
  66. 86 38
      base/Sources/import_blend_mesh.ts
  67. 11 9
      base/Sources/import_envmap.ts
  68. 5 5
      base/Sources/import_font.ts
  69. 12 12
      base/Sources/import_gpl.ts
  70. 1 1
      base/Sources/import_keymap.ts
  71. 52 26
      base/Sources/import_mesh.ts
  72. 38 26
      base/Sources/import_obj.ts
  73. 1 1
      base/Sources/import_plugin.ts
  74. 16 12
      base/Sources/import_texture.ts
  75. 1 1
      base/Sources/import_theme.ts
  76. 3 3
      base/Sources/line_draw.ts
  77. 2 2
      base/Sources/logic_node.ts
  78. 6 2
      base/Sources/main.ts
  79. 2 2
      base/Sources/make_voxel.ts
  80. 129 103
      base/Sources/node_shader.ts
  81. 18 16
      base/Sources/node_shader_context.ts
  82. 12 4
      base/Sources/nodes/boolean_node.ts
  83. 25 12
      base/Sources/nodes/color_node.ts
  84. 25 12
      base/Sources/nodes/float_node.ts
  85. 13 5
      base/Sources/nodes/integer_node.ts
  86. 5 3
      base/Sources/nodes/math_node.ts
  87. 2 2
      base/Sources/nodes/random_node.ts
  88. 11 5
      base/Sources/nodes/separate_vector_node.ts
  89. 12 4
      base/Sources/nodes/string_node.ts
  90. 9 3
      base/Sources/nodes/time_node.ts
  91. 11 7
      base/Sources/nodes/vector_math_node.ts
  92. 16 14
      base/Sources/nodes/vector_node.ts
  93. 134 117
      base/Sources/nodes_material.ts
  94. 8 8
      base/Sources/operator.ts
  95. 102 56
      base/Sources/parser_blend.ts
  96. 209 209
      base/Sources/parser_exr.ts
  97. 49 23
      base/Sources/parser_logic.ts
  98. 123 61
      base/Sources/parser_material.ts
  99. 44 30
      base/Sources/path.ts
  100. 13 13
      base/Sources/physics_body.ts

+ 78 - 53
armorforge/Sources/tab_objects.ts

@@ -1,7 +1,7 @@
 
-let tab_objects_material_id = 0;
+let tab_objects_material_id: i32 = 0;
 
-function tab_objects_roundfp(f: f32, precision = 2): f32 {
+function tab_objects_roundfp(f: f32, precision: i32 = 2): f32 {
 	f *= math_pow(10, precision);
 	return math_round(f) / math_pow(10, precision);
 }
@@ -12,7 +12,7 @@ function tab_objects_draw(htab: zui_handle_t) {
 		zui_begin_sticky();
 		zui_row([1 / 4]);
 		if (zui_button("Import")) {
-			project_import_mesh(false, () => {
+			project_import_mesh(false, function () {
 				object_set_parent(project_paint_objects.pop().base, null);
 			});
 		}
@@ -22,32 +22,31 @@ function tab_objects_draw(htab: zui_handle_t) {
 			// ui.indent();
 			ui._y -= zui_ELEMENT_OFFSET(ui);
 
-			let listX = ui._x;
-			let listW = ui._w;
-
-			let lineCounter = 0;
-			let drawList = (listHandle: zui_handle_t, currentObject: object_t) => {
-				if (currentObject.name.charAt(0) == ".") return; // Hidden
-				let b = false;
+			let line_counter = 0;
+			let draw_list = function (list_handle: zui_handle_t, current_object: object_t) {
+				if (char_at(current_object.name, 0) == ".") {
+					return; // Hidden
+				}
+				let b: bool = false;
 
 				// Highlight every other line
-				if (lineCounter % 2 == 0) {
+				if (line_counter % 2 == 0) {
 					g2_set_color(ui.t.SEPARATOR_COL);
 					g2_fill_rect(0, ui._y, ui._window_w, zui_ELEMENT_H(ui));
 					g2_set_color(0xffffffff);
 				}
 
 				// Highlight selected line
-				if (currentObject == context_context_raw.selected_object) {
+				if (current_object == context_context_raw.selected_object) {
 					g2_set_color(0xff205d9c);
 					g2_fill_rect(0, ui._y, ui._window_w, zui_ELEMENT_H(ui));
 					g2_set_color(0xffffffff);
 				}
 
-				if (currentObject.children.length > 0) {
+				if (current_object.children.length > 0) {
 					zui_row([1 / 13, 12 / 13]);
-					b = zui_panel(zui_nest(listHandle, lineCounter, {selected: true}), "", true, false, false);
-					zui_text(currentObject.name);
+					b = zui_panel(zui_nest(list_handle, line_counter, {selected: true}), "", true, false, false);
+					zui_text(current_object.name);
 				}
 				else {
 					ui._x += 18; // Sign offset
@@ -57,20 +56,20 @@ function tab_objects_draw(htab: zui_handle_t) {
 					g2_draw_line(ui._x - 10, ui._y + zui_ELEMENT_H(ui) / 2, ui._x, ui._y + zui_ELEMENT_H(ui) / 2);
 					g2_set_color(0xffffffff);
 
-					zui_text(currentObject.name);
+					zui_text(current_object.name);
 					ui._x -= 18;
 				}
 
-				lineCounter++;
+				line_counter++;
 				// Undo applied offset for row drawing caused by endElement() in Zui.hx
 				ui._y -= zui_ELEMENT_OFFSET(ui);
 
 				if (ui.is_released) {
-					context_context_raw.selected_object = currentObject;
+					context_context_raw.selected_object = current_object;
 				}
 
 				if (ui.is_hovered && ui.input_released_r) {
-					ui_menu_draw((ui: zui_t) => {
+					ui_menu_draw(function (ui: zui_t) {
 						if (ui_menu_button(ui, "Assign Material")) {
 							tab_objects_material_id++;
 
@@ -78,7 +77,7 @@ function tab_objects_draw(htab: zui_handle_t) {
 								if (sh.name == "Material_data") {
 									let s: shader_data_t = json_parse(json_stringify(sh));
 									s.name = "TempMaterial_data" + tab_objects_material_id;
-									_scene_raw.shader_datas.push(s);
+									array_push(_scene_raw.shader_datas, s);
 									break;
 								}
 							}
@@ -88,35 +87,35 @@ function tab_objects_draw(htab: zui_handle_t) {
 									let m: material_data_t = json_parse(json_stringify(mat));
 									m.name = "TempMaterial" + tab_objects_material_id;
 									m.shader = "TempMaterial_data" + tab_objects_material_id;
-									_scene_raw.material_datas.push(m);
+									array_push(_scene_raw.material_datas, m);
 									break;
 								}
 							}
 
 							let md: material_data_t = data_get_material("Scene", "TempMaterial" + tab_objects_material_id);
-							let mo: mesh_object_t = currentObject.ext;
+							let mo: mesh_object_t = current_object.ext;
 							mo.materials = [md];
-							MakeMaterial.make_material_parse_mesh_preview_material(md);
+							make_material_parse_mesh_preview_material(md);
 						}
 					}, 1);
 				}
 
 				if (b) {
-					let currentY = ui._y;
-					for (let child of currentObject.children) {
+					let current_y = ui._y;
+					for (let child of current_object.children) {
 						// ui.indent();
-						drawList(listHandle, child);
+						draw_list(list_handle, child);
 						// ui.unindent();
 					}
 
 					// Draw line that shows parent relations
 					g2_set_color(ui.t.ACCENT_COL);
-					g2_draw_line(ui._x + 14, currentY, ui._x + 14, ui._y - zui_ELEMENT_H(ui) / 2);
+					g2_draw_line(ui._x + 14, current_y, ui._x + 14, ui._y - zui_ELEMENT_H(ui) / 2);
 					g2_set_color(0xffffffff);
 				}
 			}
 			for (let c of _scene_root.children) {
-				drawList(zui_handle("tabobjects_1"), c);
+				draw_list(zui_handle("tabobjects_1"), c);
 			}
 
 			// ui.unindent();
@@ -131,31 +130,36 @@ function tab_objects_draw(htab: zui_handle_t) {
 				context_context_raw.selected_object.visible = zui_check(h, "Visible");
 
 				let t = context_context_raw.selected_object.transform;
-				let localPos = t.loc;
-				let worldPos = vec4_create(transform_world_x(t), transform_world_y(t), transform_world_z(t), 1.0);
+				let local_pos = t.loc;
 				let scale = t.scale;
 				let rot = quat_get_euler(t.rot);
 				let dim = t.dim;
 				vec4_mult(rot, 180 / 3.141592);
-				let f = 0.0;
+				let f: f32 = 0.0;
 
 				zui_row([1 / 4, 1 / 4, 1 / 4, 1 / 4]);
 				zui_text("Loc");
 
 				h = zui_handle("tabobjects_4");
-				h.text = roundfp(localPos.x) + "";
+				h.text = roundfp(local_pos.x) + "";
 				f = parseFloat(zui_text_input(h, "X"));
-				if (h.changed) localPos.x = f;
+				if (h.changed) {
+					local_pos.x = f;
+				}
 
 				h = zui_handle("tabobjects_5");
-				h.text = roundfp(localPos.y) + "";
+				h.text = roundfp(local_pos.y) + "";
 				f = parseFloat(zui_text_input(h, "Y"));
-				if (h.changed) localPos.y = f;
+				if (h.changed) {
+					local_pos.y = f;
+				}
 
 				h = zui_handle("tabobjects_6");
-				h.text = roundfp(localPos.z) + "";
+				h.text = roundfp(local_pos.z) + "";
 				f = parseFloat(zui_text_input(h, "Z"));
-				if (h.changed) localPos.z = f;
+				if (h.changed) {
+					local_pos.z = f;
+				}
 
 				zui_row([1 / 4, 1 / 4, 1 / 4, 1 / 4]);
 				zui_text("Rotation");
@@ -164,17 +168,26 @@ function tab_objects_draw(htab: zui_handle_t) {
 				h.text = roundfp(rot.x) + "";
 				f = parseFloat(zui_text_input(h, "X"));
 				let changed = false;
-				if (h.changed) { changed = true; rot.x = f; }
+				if (h.changed) {
+					changed = true;
+					rot.x = f;
+				}
 
 				h = zui_handle("tabobjects_8");
 				h.text = roundfp(rot.y) + "";
 				f = parseFloat(zui_text_input(h, "Y"));
-				if (h.changed) { changed = true; rot.y = f; }
+				if (h.changed) {
+					changed = true;
+					rot.y = f;
+				}
 
 				h = zui_handle("tabobjects_9");
 				h.text = roundfp(rot.z) + "";
 				f = parseFloat(zui_text_input(h, "Z"));
-				if (h.changed) { changed = true; rot.z = f; }
+				if (h.changed) {
+					changed = true;
+					rot.z = f;
+				}
 
 				if (changed && context_context_raw.selected_object.name != "Scene") {
 					vec4_mult(rot, 3.141592 / 180);
@@ -191,17 +204,23 @@ function tab_objects_draw(htab: zui_handle_t) {
 				h = zui_handle("tabobjects_10");
 				h.text = roundfp(scale.x) + "";
 				f = parseFloat(zui_text_input(h, "X"));
-				if (h.changed) scale.x = f;
+				if (h.changed) {
+					scale.x = f;
+				}
 
 				h = zui_handle("tabobjects_11");
 				h.text = roundfp(scale.y) + "";
 				f = parseFloat(zui_text_input(h, "Y"));
-				if (h.changed) scale.y = f;
+				if (h.changed) {
+					scale.y = f;
+				}
 
 				h = zui_handle("tabobjects_12");
 				h.text = roundfp(scale.z) + "";
 				f = parseFloat(zui_text_input(h, "Z"));
-				if (h.changed) scale.z = f;
+				if (h.changed) {
+					scale.z = f;
+				}
 
 				zui_row([1 / 4, 1 / 4, 1 / 4, 1 / 4]);
 				zui_text("Dimensions");
@@ -209,17 +228,23 @@ function tab_objects_draw(htab: zui_handle_t) {
 				h = zui_handle("tabobjects_13");
 				h.text = roundfp(dim.x) + "";
 				f = parseFloat(zui_text_input(h, "X"));
-				if (h.changed) dim.x = f;
+				if (h.changed) {
+					dim.x = f;
+				}
 
 				h = zui_handle("tabobjects_14");
 				h.text = roundfp(dim.y) + "";
 				f = parseFloat(zui_text_input(h, "Y"));
-				if (h.changed) dim.y = f;
+				if (h.changed) {
+					dim.y = f;
+				}
 
 				h = zui_handle("tabobjects_15");
 				h.text = roundfp(dim.z) + "";
 				f = parseFloat(zui_text_input(h, "Z"));
-				if (h.changed) dim.z = f;
+				if (h.changed) {
+					dim.z = f;
+				}
 
 				context_context_raw.selected_object.transform.dirty = true;
 
@@ -229,16 +254,16 @@ function tab_objects_draw(htab: zui_handle_t) {
 				}
 				else if (context_context_raw.selected_object.ext_type == "light_object_t") {
 					let light = context_context_raw.selected_object.ext;
-					let lightHandle = zui_handle("tabobjects_17");
-					lightHandle.value = light.data.strength / 10;
-					light.data.strength = zui_slider(lightHandle, "Strength", 0.0, 5.0, true) * 10;
+					let light_handle = zui_handle("tabobjects_17");
+					light_handle.value = light.data.strength / 10;
+					light.data.strength = zui_slider(light_handle, "Strength", 0.0, 5.0, true) * 10;
 				}
 				else if (context_context_raw.selected_object.ext_type == "camera_object_t") {
 					let cam = context_context_raw.selected_object.ext;
-					let fovHandle = zui_handle("tabobjects_18");
-					fovHandle.value = math_floor(cam.data.fov * 100) / 100;
-					cam.data.fov = zui_slider(fovHandle, "FoV", 0.3, 2.0, true);
-					if (fovHandle.changed) {
+					let fov_handle = zui_handle("tabobjects_18");
+					fov_handle.value = math_floor(cam.data.fov * 100) / 100;
+					cam.data.fov = zui_slider(fov_handle, "FoV", 0.3, 2.0, true);
+					if (fov_handle.changed) {
 						camera_object_build_proj(cam);
 					}
 				}

+ 20 - 12
armorlab/Sources/make_material.ts

@@ -20,14 +20,14 @@ function make_material_parse_mesh_material() {
 	scon._.override_context = {};
 	if (con.frag.shared_samplers.length > 0) {
 		let sampler = con.frag.shared_samplers[0];
-		scon._.override_context.shared_sampler = sampler.substr(sampler.lastIndexOf(" ") + 1);
+		scon._.override_context.shared_sampler = substring(sampler, string_last_index_of(sampler, " ") + 1, sampler.length);
 	}
 	if (!context_raw.texture_filter) {
 		scon._.override_context.filter = "point";
 	}
 	scon._.override_context.addressing = "repeat";
-	m._.shader.contexts.push(scon);
-	m._.shader._.contexts.push(scon);
+	array_push(m._.shader.contexts, scon);
+	array_push(m._.shader._.contexts, scon);
 
 	context_raw.ddirty = 2;
 
@@ -83,21 +83,29 @@ function make_material_parse_paint_material() {
 	let compileError = false;
 	let scon2: shader_context_t;
 	let _scon: shader_context_t = shader_context_create(con.data);
-	if (_scon == null) compileError = true;
+	if (_scon == null) {
+		compileError = true;
+	}
 	scon2 = _scon;
 
-	if (compileError) return;
+	if (compileError) {
+		return;
+	}
 	scon2._.override_context = {};
 	scon2._.override_context.addressing = "repeat";
 	let mcon3: material_context_t = material_context_create(mcon2);
 
-	m._.shader.contexts.push(scon2);
-	m._.shader._.contexts.push(scon2);
-	m.contexts.push(mcon3);
-	m._.contexts.push(mcon3);
+	array_push(m._.shader.contexts, scon2);
+	array_push(m._.shader._.contexts, scon2);
+	array_push(m.contexts, mcon3);
+	array_push(m._.contexts, mcon3);
 
-	if (make_material_default_scon == null) make_material_default_scon = scon2;
-	if (make_material_default_mcon == null) make_material_default_mcon = mcon3;
+	if (make_material_default_scon == null) {
+		make_material_default_scon = scon2;
+	}
+	if (make_material_default_mcon == null) {
+		make_material_default_mcon = mcon3;
+	}
 }
 
 function make_material_get_displace_strength(): f32 {
@@ -111,7 +119,7 @@ function make_material_voxelgi_half_extents(): string {
 }
 
 function make_material_delete_context(c: shader_context_t) {
-	base_notify_on_next_frame(() => { // Ensure pipeline is no longer in use
+	base_notify_on_next_frame(function () { // Ensure pipeline is no longer in use
 		shader_context_delete(c);
 	});
 }

+ 6 - 4
armorlab/Sources/nodes/image_texture_node.ts

@@ -14,14 +14,16 @@ function image_texture_node_create(): image_texture_node_t {
 }
 
 function image_texture_node_get_as_image(self: image_texture_node_t, from: i32, done: (img: image_t)=>void) {
-	let index = project_asset_names.indexOf(self.file);
+	let index = array_index_of(project_asset_names, self.file);
 	let asset = project_assets[index];
 	done(project_get_image(asset));
 }
 
 function image_texture_node_get_cached_image(self: image_texture_node_t): image_t {
 	let image: image_t;
-	self.base.get_as_image(self, 0, (img: image_t) => { image = img; });
+	self.base.get_as_image(self, 0, function (img: image_t) {
+		image = img;
+	});
 	return image;
 }
 
@@ -39,7 +41,7 @@ let image_texture_node_def: zui_node_t = {
 			name: _tr("Vector"),
 			type: "VECTOR",
 			color: 0xff6363c7,
-			default_value: new Float32Array([0.0, 0.0, 0.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0])
 		}
 	],
 	outputs: [
@@ -49,7 +51,7 @@ let image_texture_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		},
 		{
 			id: 0,

+ 30 - 24
armorlab/Sources/nodes/inpaint_node.ts

@@ -32,7 +32,7 @@ function inpaint_node_init() {
 
 	if (inpaint_node_mask == null) {
 		inpaint_node_mask = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8);
-		base_notify_on_next_frame(() => {
+		base_notify_on_next_frame(function () {
 			g4_begin(inpaint_node_mask);
 			g4_clear(color_from_floats(1.0, 1.0, 1.0, 1.0));
 			g4_end();
@@ -53,16 +53,18 @@ function inpaint_node_buttons(ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) {
 	if (!inpaint_node_auto) {
 		inpaint_node_strength = zui_slider(zui_handle("inpaintnode_0", { value: inpaint_node_strength }), tr("strength"), 0, 1, true);
 		inpaint_node_prompt = zui_text_area(zui_handle("inpaintnode_1"), zui_align_t.LEFT, true, tr("prompt"), true);
-		node.buttons[1].height = 1 + inpaint_node_prompt.split("\n").length;
+		node.buttons[1].height = 1 + string_split(inpaint_node_prompt, "\n").length;
+	}
+	else {
+		node.buttons[1].height = 0;
 	}
-	else node.buttons[1].height = 0;
 }
 
 function inpaint_node_get_as_image(self: inpaint_node_t, from: i32, done: (img: image_t)=>void) {
-	self.base.inputs[0].get_as_image((source: image_t) => {
+	self.base.inputs[0].get_as_image(function (source: image_t) {
 
 		console_progress(tr("Processing") + " - " + tr("Inpaint"));
-		base_notify_on_next_frame(() => {
+		base_notify_on_next_frame(function () {
 			g2_begin(inpaint_node_image);
 			g2_draw_scaled_image(source, 0, 0, config_get_texture_res_x(), config_get_texture_res_y());
 			g2_end();
@@ -73,10 +75,14 @@ function inpaint_node_get_as_image(self: inpaint_node_t, from: i32, done: (img:
 }
 
 function inpaint_node_get_cached_image(self: inpaint_node_t): image_t {
-	base_notify_on_next_frame(() => {
-		self.base.inputs[0].get_as_image((source: image_t) => {
-			if (base_pipe_copy == null) base_make_pipe();
-			if (const_data_screen_aligned_vb == null) const_data_create_screen_aligned_data();
+	base_notify_on_next_frame(function () {
+		self.base.inputs[0].get_as_image(function (source: image_t) {
+			if (base_pipe_copy == null) {
+				base_make_pipe();
+			}
+			if (const_data_screen_aligned_vb == null) {
+				const_data_create_screen_aligned_data();
+			}
 			g4_begin(inpaint_node_image);
 			g4_set_pipeline(base_pipe_inpaint_preview);
 			g4_set_tex(base_tex0_inpaint_preview, source);
@@ -94,13 +100,13 @@ function inpaint_node_get_target(): image_t {
 	return inpaint_node_mask;
 }
 
-function inpaint_node_texsynth_inpaint(image: image_t, tiling: bool, mask: image_t/* = null*/, done: (img: image_t)=>void) {
+function inpaint_node_texsynth_inpaint(image: image_t, tiling: bool, mask: image_t, done: (img: image_t)=>void) {
 	let w = config_get_texture_res_x();
 	let h = config_get_texture_res_y();
 
 	let bytes_img = image_get_pixels(image);
-	let bytes_mask = mask != null ? image_get_pixels(mask) : new ArrayBuffer(w * h);
-	let bytes_out = new ArrayBuffer(w * h * 4);
+	let bytes_mask = mask != null ? image_get_pixels(mask) : buffer_create(w * h);
+	let bytes_out = buffer_create(w * h * 4);
 	Krom_texsynth.inpaint(w, h, bytes_out, bytes_img, bytes_mask, tiling);
 
 	inpaint_node_result = image_from_bytes(bytes_out, w, h);
@@ -111,10 +117,10 @@ function inpaint_node_sd_inpaint(image: image_t, mask: image_t, done: (img: imag
 	inpaint_node_init();
 
 	let bytes_img = image_get_pixels(mask);
-	let u8 = new Uint8Array(bytes_img);
-	let f32mask = new Float32Array(4 * 64 * 64);
+	let u8 = new u8_array_t(bytes_img);
+	let f32mask = f32_array_create(4 * 64 * 64);
 
-	let vae_encoder_blob: ArrayBuffer = data_get_blob("models/sd_vae_encoder.quant.onnx");
+	let vae_encoder_blob: buffer_t = data_get_blob("models/sd_vae_encoder.quant.onnx");
 	// for (let x = 0; x < math_floor(image.width / 512); ++x) {
 		// for (let y = 0; y < math_floor(image.height / 512); ++y) {
 			let x = 0;
@@ -141,8 +147,8 @@ function inpaint_node_sd_inpaint(image: image_t, mask: image_t, done: (img: imag
 			g2_end();
 
 			bytes_img = image_get_pixels(inpaint_node_temp);
-			let u8a = new Uint8Array(bytes_img);
-			let f32a = new Float32Array(3 * 512 * 512);
+			let u8a = new u8_array_t(bytes_img);
+			let f32a = f32_array_create(3 * 512 * 512);
 			for (let i = 0; i < (512 * 512); ++i) {
 				f32a[i                ] = (u8a[i * 4    ] / 255.0) * 2.0 - 1.0;
 				f32a[i + 512 * 512    ] = (u8a[i * 4 + 1] / 255.0) * 2.0 - 1.0;
@@ -150,14 +156,14 @@ function inpaint_node_sd_inpaint(image: image_t, mask: image_t, done: (img: imag
 			}
 
 			let latents_buf = krom_ml_inference(vae_encoder_blob, [f32a.buffer], [[1, 3, 512, 512]], [1, 4, 64, 64], config_raw.gpu_inference);
-			let latents = new Float32Array(latents_buf);
+			let latents = new f32_array_t(latents_buf);
 			for (let i = 0; i < latents.length; ++i) {
 				latents[i] = 0.18215 * latents[i];
 			}
-			let latents_orig = latents.slice(0);
+			let latents_orig = array_slice(latents, 0, latents.length);
 
-			let noise = new Float32Array(latents.length);
-			for (let i = 0; i < noise.length; ++i) noise[i] = math_cos(2.0 * 3.14 * RandomNode.getFloat()) * math_sqrt(-2.0 * math_log(RandomNode.getFloat()));
+			let noise = f32_array_create(latents.length);
+			for (let i = 0; i < noise.length; ++i) noise[i] = math_cos(2.0 * 3.14 * random_node_get_float()) * math_sqrt(-2.0 * math_log(random_node_get_float()));
 
 			let num_inference_steps = 50;
 			let init_timestep = math_floor(num_inference_steps * inpaint_node_strength);
@@ -171,7 +177,7 @@ function inpaint_node_sd_inpaint(image: image_t, mask: image_t, done: (img: imag
 
 			let start = num_inference_steps - init_timestep;
 
-			TextToPhotoNode.stable_diffusion(inpaint_node_prompt, (img: image_t) => {
+			text_to_photo_node_stable_diffusion(inpaint_node_prompt, function (img: image_t) {
 				// result.g2_begin();
 				// result.g2_draw_image(img, x * 512, y * 512);
 				// result.g2_end();
@@ -196,7 +202,7 @@ let inpaint_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([1.0, 1.0, 1.0, 1.0])
+			default_value: new f32_array_t([1.0, 1.0, 1.0, 1.0])
 		}
 	],
 	outputs: [
@@ -206,7 +212,7 @@ let inpaint_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		}
 	],
 	buttons: [

+ 25 - 19
armorlab/Sources/nodes/photo_to_pbr_node.ts

@@ -30,23 +30,27 @@ function photo_to_pbr_node_init() {
 	if (photo_to_pbr_node_images == null) {
 		photo_to_pbr_node_images = [];
 		for (let i = 0; i < photo_to_pbr_node_model_names.length; ++i) {
-			photo_to_pbr_node_images.push(image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y()));
+			array_push(photo_to_pbr_node_images, image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y()));
 		}
 	}
 }
 
 function photo_to_pbr_node_get_as_image(self: photo_to_pbr_node_t, from: i32, done: (img: image_t)=>void) {
 	let get_source = function (done: (img: image_t)=>void) {
-		if (photo_to_pbr_node_cached_source != null) done(photo_to_pbr_node_cached_source);
-		else self.base.inputs[0].get_as_image(done);
+		if (photo_to_pbr_node_cached_source != null) {
+			done(photo_to_pbr_node_cached_source);
+		}
+		else {
+			self.base.inputs[0].get_as_image(done);
+		}
 	}
 
 	get_source(function (source: image_t) {
 		photo_to_pbr_node_cached_source = source;
 
 		console_progress(tr("Processing") + " - " + tr("Photo to PBR"));
-		base_notify_on_next_frame(() => {
-			let tile_floats: Float32Array[] = [];
+		base_notify_on_next_frame(function () {
+			let tile_floats: f32_array_t[] = [];
 			let tiles_x = math_floor(config_get_texture_res_x() / photo_to_pbr_node_tile_w);
 			let tiles_y = math_floor(config_get_texture_res_y() / photo_to_pbr_node_tile_w);
 			let num_tiles = tiles_x * tiles_y;
@@ -65,18 +69,18 @@ function photo_to_pbr_node_get_as_image(self: photo_to_pbr_node_t, from: i32, do
 				g2_end();
 
 				let bytes_img = image_get_pixels(photo_to_pbr_node_temp);
-				let u8a = new Uint8Array(bytes_img);
-				let f32a = new Float32Array(3 * photo_to_pbr_node_tile_with_border_w * photo_to_pbr_node_tile_with_border_w);
+				let u8a = new u8_array_t(bytes_img);
+				let f32a = f32_array_create(3 * photo_to_pbr_node_tile_with_border_w * photo_to_pbr_node_tile_with_border_w);
 				for (let i = 0; i < (photo_to_pbr_node_tile_with_border_w * photo_to_pbr_node_tile_with_border_w); ++i) {
 					f32a[i                                        ] = (u8a[i * 4    ] / 255 - 0.5) / 0.5;
 					f32a[i + photo_to_pbr_node_tile_with_border_w * photo_to_pbr_node_tile_with_border_w    ] = (u8a[i * 4 + 1] / 255 - 0.5) / 0.5;
 					f32a[i + photo_to_pbr_node_tile_with_border_w * photo_to_pbr_node_tile_with_border_w * 2] = (u8a[i * 4 + 2] / 255 - 0.5) / 0.5;
 				}
 
-				let model_blob: ArrayBuffer = data_get_blob("models/photo_to_" + photo_to_pbr_node_model_names[from] + ".quant.onnx");
+				let model_blob: buffer_t = data_get_blob("models/photo_to_" + photo_to_pbr_node_model_names[from] + ".quant.onnx");
 				let buf = krom_ml_inference(model_blob, [f32a.buffer], null, null, config_raw.gpu_inference);
-				let ar = new Float32Array(buf);
-				u8a = new Uint8Array(4 * photo_to_pbr_node_tile_w * photo_to_pbr_node_tile_w);
+				let ar = new f32_array_t(buf);
+				u8a = u8_array_create(4 * photo_to_pbr_node_tile_w * photo_to_pbr_node_tile_w);
 				let offset_g = (from == channel_type_t.BASE_COLOR || from == channel_type_t.NORMAL_MAP) ? photo_to_pbr_node_tile_with_border_w * photo_to_pbr_node_tile_with_border_w : 0;
 				let offset_b = (from == channel_type_t.BASE_COLOR || from == channel_type_t.NORMAL_MAP) ? photo_to_pbr_node_tile_with_border_w * photo_to_pbr_node_tile_with_border_w * 2 : 0;
 				for (let i = 0; i < (photo_to_pbr_node_tile_w * photo_to_pbr_node_tile_w); ++i) {
@@ -87,7 +91,7 @@ function photo_to_pbr_node_get_as_image(self: photo_to_pbr_node_t, from: i32, do
 					u8a[i * 4 + 2] = math_floor((ar[y * photo_to_pbr_node_tile_with_border_w + x + offset_b] * 0.5 + 0.5) * 255);
 					u8a[i * 4 + 3] = 255;
 				}
-				tile_floats.push(ar);
+				array_push(tile_floats, ar);
 
 				// Use border pixels to blend seams
 				if (i > 0) {
@@ -144,14 +148,16 @@ function photo_to_pbr_node_get_as_image(self: photo_to_pbr_node_t, from: i32, do
 				}
 
 				///if (krom_metal || krom_vulkan)
-				if (from == channel_type_t.BASE_COLOR) photo_to_pbr_node_bgra_swap(u8a.buffer);
+				if (from == channel_type_t.BASE_COLOR) {
+					photo_to_pbr_node_bgra_swap(u8a.buffer);
+				}
 				///end
 
 				let temp2 = image_from_bytes(u8a.buffer, photo_to_pbr_node_tile_w, photo_to_pbr_node_tile_w);
 				g2_begin(photo_to_pbr_node_images[from]);
 				g2_draw_image(temp2, x * photo_to_pbr_node_tile_w, y * photo_to_pbr_node_tile_w);
 				g2_end();
-				base_notify_on_next_frame(() => {
+				base_notify_on_next_frame(function () {
 					image_unload(temp2);
 				});
 			}
@@ -162,9 +168,9 @@ function photo_to_pbr_node_get_as_image(self: photo_to_pbr_node_t, from: i32, do
 }
 
 ///if (krom_metal || krom_vulkan)
-function photo_to_pbr_node_bgra_swap(buffer: ArrayBuffer) {
-	let u8a = new Uint8Array(buffer);
-	for (let i = 0; i < math_floor(buffer.byteLength / 4); ++i) {
+function photo_to_pbr_node_bgra_swap(buffer: buffer_t) {
+	let u8a = new u8_array_t(buffer);
+	for (let i = 0; i < math_floor(buffer_size(buffer) / 4); ++i) {
 		let r = u8a[i * 4];
 		u8a[i * 4] = u8a[i * 4 + 2];
 		u8a[i * 4 + 2] = r;
@@ -187,7 +193,7 @@ let photo_to_pbr_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		}
 	],
 	outputs: [
@@ -197,7 +203,7 @@ let photo_to_pbr_node_def: zui_node_t = {
 			name: _tr("Base Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		},
 		{
 			id: 0,
@@ -229,7 +235,7 @@ let photo_to_pbr_node_def: zui_node_t = {
 			name: _tr("Normal Map"),
 			type: "VECTOR",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		},
 		{
 			id: 0,

+ 5 - 5
armorlab/Sources/nodes/rgb_node.ts

@@ -14,12 +14,12 @@ function rgb_node_create(): rgb_node_t {
 
 function rgb_node_get_as_image(self: rgb_node_t, from: i32, done: (img: image_t)=>void) {
 	if (self.image != null) {
-		base_notify_on_next_frame(() => {
+		base_notify_on_next_frame(function () {
 			image_unload(self.image);
 		});
 	}
 
-	let f32a = new Float32Array(4);
+	let f32a = f32_array_create(4);
 	let raw = parser_logic_get_raw_node(self);
 	let default_value = raw.outputs[0].default_value;
 	f32a[0] = default_value[0];
@@ -31,7 +31,7 @@ function rgb_node_get_as_image(self: rgb_node_t, from: i32, done: (img: image_t)
 }
 
 function rgb_node_get_cached_image(self: rgb_node_t): image_t {
-	self.base.get_as_image(self, 0, (img: image_t) => {});
+	self.base.get_as_image(self, 0, function (img: image_t) {});
 	return self.image;
 }
 
@@ -50,7 +50,7 @@ let rgb_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
+			default_value: new f32_array_t([0.8, 0.8, 0.8, 1.0])
 		}
 	],
 	buttons: [
@@ -58,7 +58,7 @@ let rgb_node_def: zui_node_t = {
 			name: _tr("default_value"),
 			type: "RGBA",
 			output: 0,
-			default_value: new Float32Array([0.8, 0.8, 0.8, 1.0])
+			default_value: new f32_array_t([0.8, 0.8, 0.8, 1.0])
 		}
 	]
 };

+ 51 - 47
armorlab/Sources/nodes/text_to_photo_node.ts

@@ -6,9 +6,9 @@ type text_to_photo_node_t = {
 let text_to_photo_node_prompt: string = "";
 let text_to_photo_node_image: image_t = null;
 let text_to_photo_node_tiling: bool = false;
-let text_to_photo_node_text_encoder_blob : ArrayBuffer;
-let text_to_photo_node_unet_blob : ArrayBuffer;
-let text_to_photo_node_vae_decoder_blob : ArrayBuffer;
+let text_to_photo_node_text_encoder_blob : buffer_t;
+let text_to_photo_node_unet_blob : buffer_t;
+let text_to_photo_node_vae_decoder_blob : buffer_t;
 
 function text_to_photo_node_create(): text_to_photo_node_t {
 	let n: text_to_photo_node_t = {};
@@ -19,7 +19,7 @@ function text_to_photo_node_create(): text_to_photo_node_t {
 }
 
 function text_to_photo_node_get_as_image(self: text_to_photo_node_t, from: i32, done: (img: image_t)=>void) {
-	text_to_photo_node_stable_diffusion(text_to_photo_node_prompt, (_image: image_t) => {
+	text_to_photo_node_stable_diffusion(text_to_photo_node_prompt, function (_image: image_t) {
 		text_to_photo_node_image = _image;
 		done(text_to_photo_node_image);
 	});
@@ -32,52 +32,52 @@ function text_to_photo_node_get_cached_image(self: text_to_photo_node_t): image_
 function text_to_photo_node_buttons(ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) {
 	text_to_photo_node_tiling = node.buttons[0].default_value == 0 ? false : true;
 	text_to_photo_node_prompt = zui_text_area(zui_handle("texttophotonode_0"), zui_align_t.LEFT, true, tr("prompt"), true);
-	node.buttons[1].height = text_to_photo_node_prompt.split("\n").length;
+	node.buttons[1].height = string_split(text_to_photo_node_prompt, "\n").length;
 }
 
-function stable_diffusion(prompt: string, done: (img: image_t)=>void, inpaint_latents: Float32Array = null, offset: i32 = 0, upscale: bool = true, mask: Float32Array = null, latents_orig: Float32Array = null) {
-	let _text_encoder_blob: ArrayBuffer = data_get_blob("models/sd_text_encoder.quant.onnx");
-	let _unet_blob: ArrayBuffer = data_get_blob("models/sd_unet.quant.onnx");
-	let _vae_decoder_blob: ArrayBuffer = data_get_blob("models/sd_vae_decoder.quant.onnx");
+function stable_diffusion(prompt: string, done: (img: image_t)=>void, inpaint_latents: f32_array_t = null, offset: i32 = 0, upscale: bool = true, mask: f32_array_t = null, latents_orig: f32_array_t = null) {
+	let _text_encoder_blob: buffer_t = data_get_blob("models/sd_text_encoder.quant.onnx");
+	let _unet_blob: buffer_t = data_get_blob("models/sd_unet.quant.onnx");
+	let _vae_decoder_blob: buffer_t = data_get_blob("models/sd_vae_decoder.quant.onnx");
 	text_to_photo_node_text_encoder_blob = _text_encoder_blob;
 	text_to_photo_node_unet_blob = _unet_blob;
 	text_to_photo_node_vae_decoder_blob = _vae_decoder_blob;
-	text_to_photo_node_text_encoder(prompt, inpaint_latents, (latents: Float32Array, text_embeddings: Float32Array) => {
-		text_to_photo_node_unet(latents, text_embeddings, mask, latents_orig, offset, (latents: Float32Array) => {
+	text_to_photo_node_text_encoder(prompt, inpaint_latents, function (latents: f32_array_t, text_embeddings: f32_array_t) {
+		text_to_photo_node_unet(latents, text_embeddings, mask, latents_orig, offset, function (latents: f32_array_t) {
 			text_to_photo_node_vae_decoder(latents, upscale, done);
 		});
 	});
 }
 
-function text_to_photo_node_text_encoder(prompt: string, inpaint_latents: Float32Array, done: (a: Float32Array, b: Float32Array)=>void) {
+function text_to_photo_node_text_encoder(prompt: string, inpaint_latents: f32_array_t, done: (a: f32_array_t, b: f32_array_t)=>void) {
 	console_progress(tr("Processing") + " - " + tr("Text to Photo"));
-	base_notify_on_next_frame(() => {
-		let words = string_replace_all(string_replace_all(string_replace_all(prompt, "\n", " "), ",", " , "), "  ", " ").trim().split(" ");
+	base_notify_on_next_frame(function () {
+		let words = string_split(string_replace_all(string_replace_all(string_replace_all(prompt, "\n", " "), ",", " , "), "  ", " ").trim(), " ");
 		for (let i = 0; i < words.length; ++i) {
-			text_to_photo_node_text_input_ids[i + 1] = text_to_photo_node_vocab[words[i].toLowerCase() + "</w>"];
+			text_to_photo_node_text_input_ids[i + 1] = to_lower_case(text_to_photo_node_vocab[words[i]) + "</w>"];
 		}
 		for (let i = words.length; i < (text_to_photo_node_text_input_ids.length - 1); ++i) {
 			text_to_photo_node_text_input_ids[i + 1] = 49407; // <|endoftext|>
 		}
 
-		let i32a = new Int32Array(text_to_photo_node_text_input_ids);
+		let i32a = new i32_array_t(text_to_photo_node_text_input_ids);
 		let text_embeddings_buf = krom_ml_inference(text_to_photo_node_text_encoder_blob, [i32a.buffer], [[1, 77]], [1, 77, 768], config_raw.gpu_inference);
-		let text_embeddings = new Float32Array(text_embeddings_buf);
+		let text_embeddings = new f32_array_t(text_embeddings_buf);
 
-		i32a = new Int32Array(text_to_photo_node_uncond_input_ids);
+		i32a = new i32_array_t(text_to_photo_node_uncond_input_ids);
 		let uncond_embeddings_buf = krom_ml_inference(text_to_photo_node_text_encoder_blob, [i32a.buffer], [[1, 77]], [1, 77, 768], config_raw.gpu_inference);
-		let uncond_embeddings = new Float32Array(uncond_embeddings_buf);
+		let uncond_embeddings = new f32_array_t(uncond_embeddings_buf);
 
-		let f32a = new Float32Array(uncond_embeddings.length + text_embeddings.length);
+		let f32a = f32_array_create(uncond_embeddings.length + text_embeddings.length);
 		for (let i = 0; i < uncond_embeddings.length; ++i) f32a[i] = uncond_embeddings[i];
 		for (let i = 0; i < text_embeddings.length; ++i) f32a[i + uncond_embeddings.length] = text_embeddings[i];
 		text_embeddings = f32a;
 
 		let width = 512;
 		let height = 512;
-		let latents = new Float32Array(1 * 4 * math_floor(height / 8) * math_floor(width / 8));
+		let latents = f32_array_create(1 * 4 * math_floor(height / 8) * math_floor(width / 8));
 		if (inpaint_latents == null) {
-			for (let i = 0; i < latents.length; ++i) latents[i] = math_cos(2.0 * 3.14 * RandomNode.getFloat()) * math_sqrt(-2.0 * math_log(RandomNode.getFloat()));
+			for (let i = 0; i < latents.length; ++i) latents[i] = math_cos(2.0 * 3.14 * random_node_get_float()) * math_sqrt(-2.0 * math_log(random_node_get_float()));
 		}
 		else {
 			for (let i = 0; i < latents.length; ++i) latents[i] = inpaint_latents[i];
@@ -87,34 +87,34 @@ function text_to_photo_node_text_encoder(prompt: string, inpaint_latents: Float3
 	});
 }
 
-function text_to_photo_node_unet(latents: Float32Array, text_embeddings: Float32Array, mask: Float32Array, latents_orig: Float32Array, offset: i32, done: (ar: Float32Array)=>void) {
-	let latent_model_input = new Float32Array(latents.length * 2);
-	let noise_pred_uncond = new Float32Array(latents.length);
-	let noise_pred_text = new Float32Array(latents.length);
+function text_to_photo_node_unet(latents: f32_array_t, text_embeddings: f32_array_t, mask: f32_array_t, latents_orig: f32_array_t, offset: i32, done: (ar: f32_array_t)=>void) {
+	let latent_model_input = f32_array_create(latents.length * 2);
+	let noise_pred_uncond = f32_array_create(latents.length);
+	let noise_pred_text = f32_array_create(latents.length);
 
-	let cur_latents: Float32Array = null;
+	let cur_latents: f32_array_t = null;
 	let num_train_timesteps = 1000;
 	let num_inference_steps = 50;
-	let ets: Float32Array[] = [];
+	let ets: f32_array_t[] = [];
 	let counter = 0;
 
-	let processing = () => {
+	let processing = function () {
 		console_progress(tr("Processing") + " - " + tr("Text to Photo") + " (" + (counter + 1) + "/" + (50 - offset) + ")");
 
 		let timestep = text_to_photo_node_timesteps[counter + offset];
 		for (let i = 0; i < latents.length; ++i) latent_model_input[i] = latents[i];
 		for (let i = 0; i < latents.length; ++i) latent_model_input[i + latents.length] = latents[i];
 
-		let t32 = new Int32Array(2);
+		let t32 = i32_array_create(2);
 		t32[0] = timestep;
 		let noise_pred_buf = krom_ml_inference(text_to_photo_node_unet_blob, [latent_model_input.buffer, t32.buffer, text_embeddings.buffer], [[2, 4, 64, 64], [1], [2, 77, 768]], [2, 4, 64, 64], config_raw.gpu_inference);
-		let noise_pred = new Float32Array(noise_pred_buf);
+		let noise_pred = new f32_array_t(noise_pred_buf);
 
 		for (let i = 0; i < noise_pred_uncond.length; ++i) noise_pred_uncond[i] = noise_pred[i];
 		for (let i = 0; i < noise_pred_text.length; ++i) noise_pred_text[i] = noise_pred[noise_pred_uncond.length + i];
 
 		let guidance_scale = 7.5;
-		noise_pred = new Float32Array(noise_pred_uncond.length);
+		noise_pred = f32_array_create(noise_pred_uncond.length);
 		for (let i = 0; i < noise_pred_uncond.length; ++i) {
 			noise_pred[i] = noise_pred_uncond[i] + guidance_scale * (noise_pred_text[i] - noise_pred_uncond[i]);
 		}
@@ -122,7 +122,7 @@ function text_to_photo_node_unet(latents: Float32Array, text_embeddings: Float32
 		let prev_timestep = math_floor(math_max(timestep - math_floor(num_train_timesteps / num_inference_steps), 0));
 
 		if (counter != 1) {
-			ets.push(noise_pred);
+			array_push(ets, noise_pred);
 		}
 		else {
 			prev_timestep = timestep;
@@ -133,7 +133,7 @@ function text_to_photo_node_unet(latents: Float32Array, text_embeddings: Float32
 			cur_latents = latents;
 		}
 		else if (ets.length == 1 && counter == 1) {
-			let _noise_pred = new Float32Array(noise_pred.length);
+			let _noise_pred = f32_array_create(noise_pred.length);
 			for (let i = 0; i < noise_pred.length; ++i) {
 				_noise_pred[i] = (noise_pred[i] + ets[ets.length - 1][i]) / 2;
 			}
@@ -142,21 +142,21 @@ function text_to_photo_node_unet(latents: Float32Array, text_embeddings: Float32
 			cur_latents = null;
 		}
 		else if (ets.length == 2) {
-			let _noise_pred = new Float32Array(noise_pred.length);
+			let _noise_pred = f32_array_create(noise_pred.length);
 			for (let i = 0; i < noise_pred.length; ++i) {
 				_noise_pred[i] = (3 * ets[ets.length - 1][i] - ets[ets.length - 2][i]) / 2;
 			}
 			noise_pred = _noise_pred;
 		}
 		else if (ets.length == 3) {
-			let _noise_pred = new Float32Array(noise_pred.length);
+			let _noise_pred = f32_array_create(noise_pred.length);
 			for (let i = 0; i < noise_pred.length; ++i) {
 				_noise_pred[i] = (23 * ets[ets.length - 1][i] - 16 * ets[ets.length - 2][i] + 5 * ets[ets.length - 3][i]) / 12;
 			}
 			noise_pred = _noise_pred;
 		}
 		else {
-			let _noise_pred = new Float32Array(noise_pred.length);
+			let _noise_pred = f32_array_create(noise_pred.length);
 			for (let i = 0; i < noise_pred.length; ++i) {
 				_noise_pred[i] = (1 / 24) * (55 * ets[ets.length - 1][i] - 59 * ets[ets.length - 2][i] + 37 * ets[ets.length - 3][i] - 9 * ets[ets.length - 4][i]);
 			}
@@ -175,12 +175,14 @@ function text_to_photo_node_unet(latents: Float32Array, text_embeddings: Float32
 		counter += 1;
 
 		if (mask != null) {
-			let noise = new Float32Array(latents.length);
-			for (let i = 0; i < noise.length; ++i) noise[i] = math_cos(2.0 * 3.14 * RandomNode.getFloat()) * math_sqrt(-2.0 * math_log(RandomNode.getFloat()));
+			let noise = f32_array_create(latents.length);
+			for (let i = 0; i < noise.length; ++i) {
+				noise[i] = math_cos(2.0 * 3.14 * random_node_get_float()) * math_sqrt(-2.0 * math_log(random_node_get_float()));
+			}
 			let sqrt_alpha_prod = math_pow(text_to_photo_node_alphas_cumprod[timestep], 0.5);
 			let sqrt_one_minus_alpha_prod = math_pow(1.0 - text_to_photo_node_alphas_cumprod[timestep], 0.5);
 
-			let init_latents_proper = new Float32Array(latents.length);
+			let init_latents_proper = f32_array_create(latents.length);
 			for (let i = 0; i < init_latents_proper.length; ++i) {
 				init_latents_proper[i] = sqrt_alpha_prod * latents_orig[i] + sqrt_one_minus_alpha_prod * noise[i];
 			}
@@ -198,15 +200,15 @@ function text_to_photo_node_unet(latents: Float32Array, text_embeddings: Float32
 	app_notify_on_render_2d(processing);
 }
 
-function text_to_photo_node_vae_decoder(latents: Float32Array, upscale: bool, done: (img: image_t)=>void) {
+function text_to_photo_node_vae_decoder(latents: f32_array_t, upscale: bool, done: (img: image_t)=>void) {
 	console_progress(tr("Processing") + " - " + tr("Text to Photo"));
-	base_notify_on_next_frame(() => {
+	base_notify_on_next_frame(function () {
 		for (let i = 0; i < latents.length; ++i) {
 			latents[i] = 1.0 / 0.18215 * latents[i];
 		}
 
 		let pyimage_buf = krom_ml_inference(text_to_photo_node_vae_decoder_blob, [latents.buffer], [[1, 4, 64, 64]], [1, 3, 512, 512], config_raw.gpu_inference);
-		let pyimage = new Float32Array(pyimage_buf);
+		let pyimage = new f32_array_t(pyimage_buf);
 
 		for (let i = 0; i < pyimage.length; ++i) {
 			pyimage[i] = pyimage[i] / 2.0 + 0.5;
@@ -214,7 +216,7 @@ function text_to_photo_node_vae_decoder(latents: Float32Array, upscale: bool, do
 			else if (pyimage[i] > 1) pyimage[i] = 1;
 		}
 
-		let u8a = new Uint8Array(4 * 512 * 512);
+		let u8a = u8_array_create(4 * 512 * 512);
 		for (let i = 0; i < (512 * 512); ++i) {
 			u8a[i * 4    ] = math_floor(pyimage[i                ] * 255);
 			u8a[i * 4 + 1] = math_floor(pyimage[i + 512 * 512    ] * 255);
@@ -230,7 +232,7 @@ function text_to_photo_node_vae_decoder(latents: Float32Array, upscale: bool, do
 		}
 		else {
 			if (upscale) {
-				UpscaleNode.load_blob(() => {
+				UpscaleNode.load_blob(function () {
 					while (image.width < config_get_texture_res_x()) {
 						let lastImage = image;
 						image = UpscaleNode.esrgan(image);
@@ -239,7 +241,9 @@ function text_to_photo_node_vae_decoder(latents: Float32Array, upscale: bool, do
 					done(image);
 				});
 			}
-			else done(image);
+			else {
+				done(image);
+			}
 		}
 	});
 }
@@ -259,7 +263,7 @@ let text_to_photo_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		}
 	],
 	buttons: [

+ 13 - 9
armorlab/Sources/nodes/tiling_node.ts

@@ -29,13 +29,15 @@ function tiling_node_buttons(ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) {
 	if (!tiling_node_auto) {
 		tiling_node_strength = zui_slider(zui_handle("tilingnode_0", { value: tiling_node_strength }), tr("strength"), 0, 1, true);
 		tiling_node_prompt = zui_text_area(zui_handle("tilingnode_1"), zui_align_t.LEFT, true, tr("prompt"), true);
-		node.buttons[1].height = 1 + tiling_node_prompt.split("\n").length;
+		node.buttons[1].height = 1 + string_split(tiling_node_prompt, "\n").length;
+	}
+	else {
+		node.buttons[1].height = 0;
 	}
-	else node.buttons[1].height = 0;
 }
 
 function tiling_node_get_as_image(self: tiling_node_t, from: i32, done: (img: image_t)=>void) {
-	self.base.inputs[0].get_as_image((source: image_t) => {
+	self.base.inputs[0].get_as_image(function (source: image_t) {
 		g2_begin(tiling_node_image);
 		g2_draw_scaled_image(source, 0, 0, config_get_texture_res_x(), config_get_texture_res_y());
 		g2_end();
@@ -51,11 +53,11 @@ function tiling_node_get_as_image(self: tiling_node_t, from: i32, done: (img: im
 	});
 }
 
-function tiling_node_get_cached_image(self: tiling_node_t): image_t => {
+function tiling_node_get_cached_image(self: tiling_node_t): image_t {
 	return self.result;
 }
 
-function tiling_node_sd_tiling(image: image_t, seed: i32/* = -1*/, done: (img: image_t)=>void) {
+function tiling_node_sd_tiling(image: image_t, seed: i32, done: (img: image_t)=>void) {
 	text_to_photo_node_tiling = false;
 	let tile = image_create_render_target(512, 512);
 	g2_begin(tile);
@@ -65,7 +67,7 @@ function tiling_node_sd_tiling(image: image_t, seed: i32/* = -1*/, done: (img: i
 	g2_draw_scaled_image(image, 256, 256, 512, 512);
 	g2_end();
 
-	let u8a = new Uint8Array(512 * 512);
+	let u8a = u8_array_create(512 * 512);
 	for (let i = 0; i < 512 * 512; ++i) {
 		let x = i % 512;
 		let y = math_floor(i / 512);
@@ -87,7 +89,9 @@ function tiling_node_sd_tiling(image: image_t, seed: i32/* = -1*/, done: (img: i
 
 	inpaint_node_prompt = tiling_node_prompt;
 	inpaint_node_strength = tiling_node_strength;
-	if (seed >= 0) random_node_set_seed(seed);
+	if (seed >= 0) {
+		random_node_set_seed(seed);
+	}
 	inpaint_node_sd_inpaint(tile, mask, done);
 }
 
@@ -105,7 +109,7 @@ let tiling_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		}
 	],
 	outputs: [
@@ -115,7 +119,7 @@ let tiling_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		}
 	],
 	buttons: [

+ 18 - 12
armorlab/Sources/nodes/upscale_node.ts

@@ -5,7 +5,7 @@ type upscale_node_t = {
 
 let upscale_node_temp: image_t = null;
 let upscale_node_image: image_t = null;
-let upscale_node_esrgan_blob: ArrayBuffer;
+let upscale_node_esrgan_blob: buffer_t;
 
 function upscale_node_create(): upscale_node_t {
 	let n: float_node_t = {};
@@ -16,7 +16,7 @@ function upscale_node_create(): upscale_node_t {
 }
 
 function upscale_node_get_as_image(self: upscale_node_t, from: i32, done: (img: image_t)=>void) {
-	self.base.inputs[0].get_as_image((_image: image_t) => {
+	self.base.inputs[0].get_as_image(function (_image: image_t) {
 		upscale_node_image = _image;
 
 		console_progress(tr("Processing") + " - " + tr("Upscale"));
@@ -37,7 +37,7 @@ function upscale_node_get_as_image(self: upscale_node_t, from: i32, done: (img:
 }
 
 function upscale_node_load_blob(done: ()=>void) {
-	let _esrgan_blob: ArrayBuffer = data_get_blob("models/esrgan.quant.onnx");
+	let _esrgan_blob: buffer_t = data_get_blob("models/esrgan.quant.onnx");
 	upscale_node_esrgan_blob = _esrgan_blob;
 	done();
 }
@@ -61,8 +61,8 @@ function upscale_node_do_tile(source: image_t) {
 	g2_end();
 
 	let bytes_img = image_get_pixels(upscale_node_temp);
-	let u8a = new Uint8Array(bytes_img);
-	let f32a = new Float32Array(3 * size1w * size1h);
+	let u8a = new u8_array_t(bytes_img);
+	let f32a = f32_array_create(3 * size1w * size1h);
 	for (let i = 0; i < (size1w * size1h); ++i) {
 		f32a[i                      ] = (u8a[i * 4    ] / 255);
 		f32a[i + size1w * size1w    ] = (u8a[i * 4 + 1] / 255);
@@ -70,13 +70,17 @@ function upscale_node_do_tile(source: image_t) {
 	}
 
 	let esrgan2x_buf = krom_ml_inference(upscale_node_esrgan_blob, [f32a.buffer], [[1, 3, size1w, size1h]], [1, 3, size2w, size2h], config_raw.gpu_inference);
-	let esrgan2x = new Float32Array(esrgan2x_buf);
+	let esrgan2x = new f32_array_t(esrgan2x_buf);
 	for (let i = 0; i < esrgan2x.length; ++i) {
-		if (esrgan2x[i] < 0) esrgan2x[i] = 0;
-		else if (esrgan2x[i] > 1) esrgan2x[i] = 1;
+		if (esrgan2x[i] < 0) {
+			esrgan2x[i] = 0;
+		}
+		else if (esrgan2x[i] > 1) {
+			esrgan2x[i] = 1;
+		}
 	}
 
-	u8a = new Uint8Array(4 * size2w * size2h);
+	u8a = u8_array_create(4 * size2w * size2h);
 	for (let i = 0; i < (size2w * size2h); ++i) {
 		u8a[i * 4    ] = math_floor(esrgan2x[i                      ] * 255);
 		u8a[i * 4 + 1] = math_floor(esrgan2x[i + size2w * size2w    ] * 255);
@@ -120,7 +124,9 @@ function upscale_node_esrgan(source: image_t): image_t {
 		}
 		image_unload(tile_source);
 	}
-	else result = upscale_node_do_tile(source); // Single tile
+	else {
+		result = upscale_node_do_tile(source); // Single tile
+	}
 	return result;
 }
 
@@ -138,7 +144,7 @@ let upscale_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		}
 	],
 	outputs: [
@@ -148,7 +154,7 @@ let upscale_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		}
 	],
 	buttons: []

+ 13 - 11
armorlab/Sources/nodes/variance_node.ts

@@ -28,20 +28,20 @@ function variance_node_init() {
 
 function variance_node_buttons(ui: zui_t, nodes: zui_nodes_t, node: zui_node_t) {
 	variance_node_prompt = zui_text_area(zui_handle("variancenode_0"), zui_align_t.LEFT, true, tr("prompt"), true);
-	node.buttons[0].height = variance_node_prompt.split("\n").length;
+	node.buttons[0].height = string_split(variance_node_prompt, "\n").length;
 }
 
 function variance_node_get_as_image(self: variance_node_t, from: i32, done: (img: image_t)=>void) {
 	let strength = (variance_node_inst.inputs[1].node as any).value;
 
-	variance_node_inst.inputs[0].get_as_image((source: image_t) => {
+	variance_node_inst.inputs[0].get_as_image(function (source: image_t) {
 		g2_begin(variance_node_temp);
 		g2_draw_scaled_image(source, 0, 0, 512, 512);
 		g2_end();
 
 		let bytes_img = image_get_pixels(variance_node_temp);
-		let u8a = new Uint8Array(bytes_img);
-		let f32a = new Float32Array(3 * 512 * 512);
+		let u8a = new u8_array_t(bytes_img);
+		let f32a = f32_array_create(3 * 512 * 512);
 		for (let i = 0; i < (512 * 512); ++i) {
 			f32a[i                ] = (u8a[i * 4    ] / 255) * 2.0 - 1.0;
 			f32a[i + 512 * 512    ] = (u8a[i * 4 + 1] / 255) * 2.0 - 1.0;
@@ -50,15 +50,17 @@ function variance_node_get_as_image(self: variance_node_t, from: i32, done: (img
 
 		console_progress(tr("Processing") + " - " + tr("Variance"));
 		base_notify_on_next_frame(function () {
-			let vae_encoder_blob: ArrayBuffer = data_get_blob("models/sd_vae_encoder.quant.onnx");
+			let vae_encoder_blob: buffer_t = data_get_blob("models/sd_vae_encoder.quant.onnx");
 			let latents_buf = krom_ml_inference(vae_encoder_blob, [f32a.buffer], [[1, 3, 512, 512]], [1, 4, 64, 64], config_raw.gpu_inference);
-			let latents = new Float32Array(latents_buf);
+			let latents = new f32_array_t(latents_buf);
 			for (let i = 0; i < latents.length; ++i) {
 				latents[i] = 0.18215 * latents[i];
 			}
 
-			let noise = new Float32Array(latents.length);
-			for (let i = 0; i < noise.length; ++i) noise[i] = math_cos(2.0 * 3.14 * random_node_get_float()) * math_sqrt(-2.0 * math_log(random_node_get_float()));
+			let noise = f32_array_create(latents.length);
+			for (let i = 0; i < noise.length; ++i) {
+				noise[i] = math_cos(2.0 * 3.14 * random_node_get_float()) * math_sqrt(-2.0 * math_log(random_node_get_float()));
+			}
 			let num_inference_steps = 50;
 			let init_timestep = math_floor(num_inference_steps * strength);
 			let timesteps = text_to_photo_node_timesteps[num_inference_steps - init_timestep];
@@ -70,7 +72,7 @@ function variance_node_get_as_image(self: variance_node_t, from: i32, done: (img
 			}
 			let t_start = num_inference_steps - init_timestep;
 
-			text_to_photo_node_stable_diffusion(variance_node_prompt, (_image: image_t) => {
+			text_to_photo_node_stable_diffusion(variance_node_prompt, function (_image: image_t) {
 				variance_node_image = _image;
 				done(variance_node_image);
 			}, latents, t_start);
@@ -96,7 +98,7 @@ let variance_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		},
 		{
 			id: 0,
@@ -114,7 +116,7 @@ let variance_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "RGBA",
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		}
 	],
 	buttons: [

+ 17 - 17
armorlab/Sources/nodes_brush.ts

@@ -1,26 +1,26 @@
-/// <reference path='./nodes/ImageTextureNode.ts'/>
-/// <reference path='./nodes/RGBNode.ts'/>
-/// <reference path='./nodes/InpaintNode.ts'/>
-/// <reference path='./nodes/PhotoToPBRNode.ts'/>
-/// <reference path='./nodes/TextToPhotoNode.ts'/>
-/// <reference path='./nodes/TilingNode.ts'/>
-/// <reference path='./nodes/UpscaleNode.ts'/>
-/// <reference path='./nodes/VarianceNode.ts'/>
+/// <reference path='./nodes/image_texture_node.ts'/>
+/// <reference path='./nodes/rgb_node.ts'/>
+/// <reference path='./nodes/inpaint_node.ts'/>
+/// <reference path='./nodes/photo_to_pbr_node.ts'/>
+/// <reference path='./nodes/text_to_photo_node.ts'/>
+/// <reference path='./nodes/tiling_node.ts'/>
+/// <reference path='./nodes/upscale_node.ts'/>
+/// <reference path='./nodes/variance_node.ts'/>
 
 let nodes_brush_categories: string[] = [_tr("Input"), _tr("Model")];
 
 let nodes_brush_list: zui_node_t[][] = [
 	[ // Input
-		ImageTextureNode.def,
-		RGBNode.def,
+		image_texture_node.def,
+		rgb_node.def,
 	],
 	[ // Model
-		InpaintNode.def,
-		PhotoToPBRNode.def,
-		TextToPhotoNode.def,
-		TilingNode.def,
-		UpscaleNode.def,
-		VarianceNode.def,
+		inpaint_node.def,
+		photo_to_pbr_node.def,
+		text_to_photo_node.def,
+		tiling_node.def,
+		upscale_node.def,
+		variance_node.def,
 	]
 ];
 
@@ -31,7 +31,7 @@ function nodes_brush_create_node(nodeType: string): zui_node_t {
 				let canvas = project_canvas;
 				let nodes = project_nodes;
 				let node = ui_nodes_make_node(n, nodes, canvas);
-				canvas.nodes.push(node);
+				array_push(canvas.nodes, node);
 				return node;
 			}
 		}

+ 23 - 15
armorlab/Sources/render_path_paint.ts

@@ -82,10 +82,10 @@ function render_path_paint_commands_paint(dilation: bool = true) {
 				render_path_draw_meshes("paint");
 				ui_header_handle.redraws = 2;
 
-				let texpaint_picker = render_path_render_targets.get("texpaint_picker")._image;
-				let texpaint_nor_picker = render_path_render_targets.get("texpaint_nor_picker")._image;
-				let texpaint_pack_picker = render_path_render_targets.get("texpaint_pack_picker")._image;
-				let texpaint_uv_picker = render_path_render_targets.get("texpaint_uv_picker")._image;
+				let texpaint_picker = map_get(render_path_render_targets, "texpaint_picker")._image;
+				let texpaint_nor_picker = map_get(render_path_render_targets, "texpaint_nor_picker")._image;
+				let texpaint_pack_picker = map_get(render_path_render_targets, "texpaint_pack_picker")._image;
+				let texpaint_uv_picker = map_get(render_path_render_targets, "texpaint_uv_picker")._image;
 				let a = image_get_pixels(texpaint_picker);
 				let b = image_get_pixels(texpaint_nor_picker);
 				let c = image_get_pixels(texpaint_pack_picker);
@@ -182,13 +182,15 @@ function render_path_paint_commands_cursor() {
 function 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 = scene_get_child(".Plane").ext;
 	let geom = plane.data;
-	if (base_pipe_cursor == null) base_make_cursor_pipe();
+	if (base_pipe_cursor == null) {
+		base_make_cursor_pipe();
+	}
 
 	render_path_set_target("");
 	g4_set_pipeline(base_pipe_cursor);
 	let img = resource_get("cursor.k");
 	g4_set_tex(base_cursor_tex, img);
-	let gbuffer0 = render_path_render_targets.get("gbuffer0")._image;
+	let gbuffer0 = map_get(render_path_render_targets, "gbuffer0")._image;
 	g4_set_tex_depth(base_cursor_gbufferd, gbuffer0);
 	g4_set_float2(base_cursor_mouse, mx, my);
 	g4_set_float2(base_cursor_tex_step, 1 / gbuffer0.width, 1 / gbuffer0.height);
@@ -217,7 +219,9 @@ function render_path_paint_paint_enabled(): bool {
 }
 
 function render_path_paint_begin() {
-	if (!render_path_paint_paint_enabled()) return;
+	if (!render_path_paint_paint_enabled()) {
+		return;
+	}
 }
 
 function render_path_paint_end() {
@@ -225,12 +229,16 @@ function render_path_paint_end() {
 	context_raw.ddirty--;
 	context_raw.rdirty--;
 
-	if (!render_path_paint_paint_enabled()) return;
+	if (!render_path_paint_paint_enabled()) {
+		return;
+	}
 	context_raw.pdirty--;
 }
 
 function render_path_paint_draw() {
-	if (!render_path_paint_paint_enabled()) return;
+	if (!render_path_paint_paint_enabled()) {
+		return;
+	}
 
 	render_path_paint_commands_paint();
 
@@ -260,23 +268,23 @@ function render_path_paint_bind_layers() {
 		}
 	}
 	if (image != null) {
-		if (render_path_render_targets.get("texpaint_node") == null) {
+		if (map_get(render_path_render_targets, "texpaint_node") == null) {
 			let t = render_target_create();
 			t.name = "texpaint_node";
 			t.width = config_get_texture_res_x();
 			t.height = config_get_texture_res_y();
 			t.format = "RGBA32";
-			render_path_render_targets.set(t.name, t);
+			map_set(render_path_render_targets, t.name, t);
 		}
-		if (render_path_render_targets.get("texpaint_node_target") == null) {
+		if (map_get(render_path_render_targets, "texpaint_node_target") == null) {
 			let t = render_target_create();
 			t.name = "texpaint_node_target";
 			t.width = config_get_texture_res_x();
 			t.height = config_get_texture_res_y();
 			t.format = "RGBA32";
-			render_path_render_targets.set(t.name, t);
+			map_set(render_path_render_targets, t.name, t);
 		}
-		render_path_render_targets.get("texpaint_node")._image = image;
+		map_get(render_path_render_targets, "texpaint_node")._image = image;
 		render_path_bind_target("texpaint_node", "texpaint");
 		render_path_bind_target("texpaint_nor_empty", "texpaint_nor");
 		render_path_bind_target("texpaint_pack_empty", "texpaint_pack");
@@ -287,7 +295,7 @@ function render_path_paint_bind_layers() {
 		let inpaint = node.type == "InpaintNode";
 		if (inpaint) {
 			let brushNode = parser_logic_get_logic_node(node);
-			render_path_render_targets.get("texpaint_node_target")._image = (brushNode as InpaintNode).getTarget();
+			map_get(render_path_render_targets, "texpaint_node_target")._image = (brushNode as InpaintNode).getTarget();
 		}
 	}
 	else {

+ 30 - 24
armorlab/Sources/ui_nodes_ext.ts

@@ -1,19 +1,19 @@
 
-let ui_nodes_ext_last_vertices: DataView = null; // Before displacement
+let ui_nodes_ext_last_vertices: buffer_view_t = null; // Before displacement
 
 function ui_nodes_ext_draw_buttons(ew: f32, start_y: f32) {
 	let ui = ui_nodes_ui;
 	if (zui_button(tr("Run"))) {
 		console_progress(tr("Processing"));
 
-		let delay_idle_sleep = () => {
+		let delay_idle_sleep = function () {
 			krom_delay_idle_sleep();
 		}
 		app_notify_on_render_2d(delay_idle_sleep);
 
 		let tasks: i32 = 1;
 
-		let task_done = () => {
+		let task_done = function () {
 			tasks--;
 			if (tasks == 0) {
 				console_progress(null);
@@ -26,36 +26,42 @@ function ui_nodes_ext_draw_buttons(ew: f32, start_y: f32) {
 			}
 		}
 
-		base_notify_on_next_frame(() => {
+		base_notify_on_next_frame(function () {
 			let timer = time_time();
 			parser_logic_parse(project_canvas);
 
-			PhotoToPBRNode.cached_source = null;
-			BrushOutputNode.inst.get_as_image(channel_type_t.BASE_COLOR, (texbase: image_t) => {
-			BrushOutputNode.inst.get_as_image(channel_type_t.OCCLUSION, (texocc: image_t) => {
-			BrushOutputNode.inst.get_as_image(channel_type_t.ROUGHNESS, (texrough: image_t) => {
-			BrushOutputNode.inst.get_as_image(channel_type_t.NORMAL_MAP, (texnor: image_t) => {
-			BrushOutputNode.inst.get_as_image(channel_type_t.HEIGHT, (texheight: image_t) => {
+			photo_to_pbr_node_cached_source = null;
+			brush_output_node_inst.get_as_image(channel_type_t.BASE_COLOR, function (texbase: image_t) {
+			brush_output_node_inst.get_as_image(channel_type_t.OCCLUSION, function (texocc: image_t) {
+			brush_output_node_inst.get_as_image(channel_type_t.ROUGHNESS, function (texrough: image_t) {
+			brush_output_node_inst.get_as_image(channel_type_t.NORMAL_MAP, function (texnor: image_t) {
+			brush_output_node_inst.get_as_image(channel_type_t.HEIGHT, function (texheight: image_t) {
 
 				if (texbase != null) {
-					let texpaint = render_path_render_targets.get("texpaint")._image;
+					let texpaint = map_get(render_path_render_targets, "texpaint")._image;
 					g2_begin(texpaint);
 					g2_draw_scaled_image(texbase, 0, 0, config_get_texture_res_x(), config_get_texture_res_y());
 					g2_end();
 				}
 
 				if (texnor != null) {
-					let texpaint_nor = render_path_render_targets.get("texpaint_nor")._image;
+					let texpaint_nor = map_get(render_path_render_targets, "texpaint_nor")._image;
 					g2_begin(texpaint_nor);
 					g2_draw_scaled_image(texnor, 0, 0, config_get_texture_res_x(), config_get_texture_res_y());
 					g2_end();
 				}
 
-				if (base_pipe_copy == null) base_make_pipe();
-				if (base_pipe_copy_a == null) base_make_pipe_copy_a();
-				if (const_data_screen_aligned_vb == null) const_data_create_screen_aligned_data();
+				if (base_pipe_copy == null) {
+					base_make_pipe();
+				}
+				if (base_pipe_copy_a == null) {
+					base_make_pipe_copy_a();
+				}
+				if (const_data_screen_aligned_vb == null) {
+					const_data_create_screen_aligned_data();
+				}
 
-				let texpaint_pack = render_path_render_targets.get("texpaint_pack")._image;
+				let texpaint_pack = map_get(render_path_render_targets, "texpaint_pack")._image;
 
 				if (texocc != null) {
 					g2_begin(texpaint_pack);
@@ -89,15 +95,15 @@ function ui_nodes_ext_draw_buttons(ew: f32, start_y: f32) {
 						let o = project_paint_objects[0];
 						let g = o.data;
 						let vertices = g4_vertex_buffer_lock(g._.vertex_buffer);
-						if (ui_nodes_ext_last_vertices == null || ui_nodes_ext_last_vertices.byteLength != vertices.byteLength) {
-							ui_nodes_ext_last_vertices = new DataView(new ArrayBuffer(vertices.byteLength));
-							for (let i = 0; i < math_floor(vertices.byteLength / 2); ++i) {
-								ui_nodes_ext_last_vertices.setInt16(i * 2, vertices.getInt16(i * 2, true), true);
+						if (ui_nodes_ext_last_vertices == null || buffer_view_size(ui_nodes_ext_last_vertices) != buffer_view_size(vertices)) {
+							ui_nodes_ext_last_vertices = buffer_view_create(buffer_create(buffer_view_size(vertices)));
+							for (let i = 0; i < math_floor(buffer_view_size(vertices) / 2); ++i) {
+								buffer_view_set_i16(ui_nodes_ext_last_vertices, i * 2, buffer_view_get_i16(vertices, i * 2));
 							}
 						}
 						else {
-							for (let i = 0; i < math_floor(vertices.byteLength / 2); ++i) {
-								vertices.setInt16(i * 2, ui_nodes_ext_last_vertices.getInt16(i * 2, true), true);
+							for (let i = 0; i < math_floor(buffer_view_size(vertices) / 2); ++i) {
+								buffer_view_set_i16(vertices, i * 2, buffer_view_get_i16(ui_nodes_ext_last_vertices, i * 2));
 							}
 						}
 						g4_vertex_buffer_unlock(g._.vertex_buffer);
@@ -105,9 +111,9 @@ function ui_nodes_ext_draw_buttons(ew: f32, start_y: f32) {
 						// Apply displacement
 						if (config_raw.displace_strength > 0) {
 							tasks++;
-							base_notify_on_next_frame(() => {
+							base_notify_on_next_frame(function () {
 								console_progress(tr("Apply Displacement"));
-								base_notify_on_next_frame(() => {
+								base_notify_on_next_frame(function () {
 									let uv_scale = scene_meshes[0].data.scale_tex * context_raw.brush_scale;
 									util_mesh_apply_displacement(texpaint_pack, 0.05 * config_raw.displace_strength, uv_scale);
 									util_mesh_calc_normals();

+ 7 - 5
armorpaint/Sources/import_folder.ts

@@ -12,11 +12,13 @@ function import_folder_run(path: string) {
 	let found_texture: bool = false;
 	// Import maps
 	for (let f of files) {
-		if (!path_is_texture(f)) continue;
+		if (!path_is_texture(f)) {
+			continue;
+		}
 
 		// TODO: handle -albedo
 
-		let base: string = f.substr(0, f.lastIndexOf(".")).toLowerCase();
+		let base: string = to_lower_case(substring(f, 0, string_last_index_of(f, ".")));
 		let valid: bool = false;
 		if (mapbase == "" && path_is_base_color_tex(base)) {
 			mapbase = f;
@@ -60,10 +62,10 @@ function import_folder_run(path: string) {
 
 	// Create material
 	context_raw.material = slot_material_create(project_materials[0].data);
-	project_materials.push(context_raw.material);
+	array_push(project_materials, context_raw.material);
 	let nodes: zui_nodes_t = context_raw.material.nodes;
 	let canvas: zui_node_canvas_t = context_raw.material.canvas;
-	let dirs: string[] = path.split(path_sep);
+	let dirs: string[] = string_split(path, path_sep);
 	canvas.name = dirs[dirs.length - 1];
 	let nout: zui_node_t = null;
 	for (let n of canvas.nodes) {
@@ -124,5 +126,5 @@ function import_folder_place_image_node(nodes: zui_nodes_t, canvas: zui_node_can
 	n.x = 72;
 	n.y = ny;
 	let l: zui_node_link_t = { id: zui_get_link_id(canvas.links), from_id: n.id, from_socket: 0, to_id: to_id, to_socket: to_socket };
-	canvas.links.push(l);
+	array_push(canvas.links, l);
 }

+ 3 - 3
armorpaint/Sources/make_bake.ts

@@ -1,5 +1,5 @@
 
-function make_bake_run(con: NodeShaderContextRaw, vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_bake_run(con: node_shader_context_t, vert: node_shader_t, frag: node_shader_t) {
 	if (context_raw.bake_type == bake_type_t.AO) { // Voxel
 		///if arm_voxels
 		// Apply normal channel
@@ -121,7 +121,7 @@ function make_bake_run(con: NodeShaderContextRaw, vert: NodeShaderRaw, frag: Nod
 	}
 }
 
-function make_bake_position_normal(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_bake_position_normal(vert: node_shader_t, frag: node_shader_t) {
 	node_shader_add_out(vert, 'vec3 position');
 	node_shader_add_out(vert, 'vec3 normal');
 	node_shader_add_uniform(vert, 'mat4 W', '_world_matrix');
@@ -134,7 +134,7 @@ function make_bake_position_normal(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 	node_shader_write(frag, 'fragColor[1] = vec4(normal, 1.0);');
 }
 
-function make_bake_set_color_writes(con_paint: NodeShaderContextRaw) {
+function make_bake_set_color_writes(con_paint: node_shader_context_t) {
 	// Bake into base color, disable other slots
 	con_paint.data.color_writes_red[1] = false;
 	con_paint.data.color_writes_green[1] = false;

+ 1 - 1
armorpaint/Sources/make_blur.ts

@@ -1,5 +1,5 @@
 
-function make_blur_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_blur_run(vert: node_shader_t, frag: node_shader_t) {
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
 	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2(sp.x * gbufferSize.x, sp.y * gbufferSize.y), 0).ba;');
 	///else

+ 10 - 4
armorpaint/Sources/make_brush.ts

@@ -1,13 +1,17 @@
 
-function make_brush_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_brush_run(vert: node_shader_t, frag: node_shader_t) {
 
 	node_shader_write(frag, 'float dist = 0.0;');
 
-	if (context_raw.tool == workspace_tool_t.PARTICLE) return;
+	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) node_shader_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)
@@ -87,5 +91,7 @@ function make_brush_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 
 	node_shader_write(frag, 'if (dist > brushRadius) discard;');
 
-	if (decal && !fill_layer) node_shader_write(frag, '}');
+	if (decal && !fill_layer) {
+		node_shader_write(frag, '}');
+	}
 }

+ 1 - 1
armorpaint/Sources/make_clone.ts

@@ -1,5 +1,5 @@
 
-function make_clone_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_clone_run(vert: node_shader_t, frag: node_shader_t) {
 	node_shader_add_uniform(frag, 'vec2 cloneDelta', '_cloneDelta');
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)
 	node_shader_write(frag, 'vec2 texCoordInp = texelFetch(gbuffer2, ivec2((sp.xy + cloneDelta) * gbufferSize), 0).ba;');

+ 1 - 1
armorpaint/Sources/make_colorid_picker.ts

@@ -1,5 +1,5 @@
 
-function make_colorid_picker_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_colorid_picker_run(vert: node_shader_t, frag: node_shader_t) {
 	// Mangle vertices to form full screen triangle
 	node_shader_write(vert, 'gl_Position = vec4(-1.0 + float((gl_VertexID & 1) << 2), -1.0 + float((gl_VertexID & 2) << 1), 0.0, 1.0);');
 

+ 4 - 4
armorpaint/Sources/make_discard.ts

@@ -1,5 +1,5 @@
 
-function make_discard_color_id(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_discard_color_id(vert: node_shader_t, frag: node_shader_t) {
 	node_shader_add_uniform(frag, 'sampler2D texpaint_colorid'); // 1x1 picker
 	node_shader_add_uniform(frag, 'sampler2D texcolorid', '_texcolorid'); // color map
 	node_shader_write(frag, 'vec3 colorid_c1 = texelFetch(texpaint_colorid, ivec2(0, 0), 0).rgb;');
@@ -11,7 +11,7 @@ function make_discard_color_id(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 	///end
 }
 
-function make_discard_face(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_discard_face(vert: node_shader_t, frag: node_shader_t) {
 	node_shader_add_uniform(frag, 'sampler2D gbuffer2');
 	node_shader_add_uniform(frag, 'sampler2D textrianglemap', '_textrianglemap');
 	node_shader_add_uniform(frag, 'vec2 textrianglemapSize', '_texpaintSize');
@@ -30,12 +30,12 @@ function make_discard_face(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 	///end
 }
 
-function make_discard_uv_island(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_discard_uv_island(vert: node_shader_t, frag: node_shader_t) {
 	node_shader_add_uniform(frag, 'sampler2D texuvislandmap', '_texuvislandmap');
 	node_shader_write(frag, 'if (textureLod(texuvislandmap, texCoordPick, 0).r == 0.0) discard;');
 }
 
-function make_discard_material_id(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_discard_material_id(vert: node_shader_t, frag: node_shader_t) {
 	frag.wvpposition = true;
 	node_shader_write(frag, 'vec2 picker_sample_tc = vec2(wvpposition.x / wvpposition.w, wvpposition.y / wvpposition.w) * 0.5 + 0.5;');
 	///if (krom_direct3d11 || krom_direct3d12 || krom_metal || krom_vulkan)

+ 83 - 53
armorpaint/Sources/make_material.ts

@@ -7,7 +7,11 @@ let make_material_emis_used = false;
 let make_material_subs_used = false;
 
 function make_material_get_mout(): bool {
-	for (let n of ui_nodes_get_canvas_material().nodes) if (n.type == "OUTPUT_MATERIAL_PBR") return true;
+	for (let n of ui_nodes_get_canvas_material().nodes) {
+		if (n.type == "OUTPUT_MATERIAL_PBR") {
+			return true;
+		}
+	}
 	return false;
 }
 
@@ -54,37 +58,37 @@ function make_material_parse_mesh_material() {
 		}
 	}
 
-	let con: NodeShaderContextRaw = make_mesh_run({ name: "Material", canvas: null });
+	let con: node_shader_context_t = 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) {
 		let sampler: string = con.frag.shared_samplers[0];
-		scon._.override_context.shared_sampler = sampler.substr(sampler.lastIndexOf(" ") + 1);
+		scon._.override_context.shared_sampler = substring(sampler, string_last_index_of(sampler, " ") + 1, sampler.length);
 	}
 	if (!context_raw.texture_filter) {
 		scon._.override_context.filter = "point";
 	}
-	m._.shader.contexts.push(scon);
-	m._.shader._.contexts.push(scon);
+	array_push(m._.shader.contexts, scon);
+	array_push(m._.shader._.contexts, scon);
 
 	for (let i: i32 = 1; i < make_mesh_layer_pass_count; ++i) {
-		let con: NodeShaderContextRaw = make_mesh_run({ name: "Material", canvas: null }, i);
+		let con: node_shader_context_t = 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) {
 			let sampler: string = con.frag.shared_samplers[0];
-			scon._.override_context.shared_sampler = sampler.substr(sampler.lastIndexOf(" ") + 1);
+			scon._.override_context.shared_sampler = substring(sampler, string_last_index_of(sampler, " ") + 1, sampler.length);
 		}
 		if (!context_raw.texture_filter) {
 			scon._.override_context.filter = "point";
 		}
-		m._.shader.contexts.push(scon);
-		m._.shader._.contexts.push(scon);
+		array_push(m._.shader.contexts, scon);
+		array_push(m._.shader._.contexts, scon);
 
 		let mcon: material_context_t;
 		mcon = material_context_create({ name: "mesh" + i, bind_textures: [] });
-		m.contexts.push(mcon);
-		m._.contexts.push(mcon);
+		array_push(m.contexts, mcon);
+		array_push(m._.contexts, mcon);
 	}
 
 	context_raw.ddirty = 2;
@@ -111,11 +115,13 @@ function make_material_parse_particle_material() {
 		array_remove(m._.shader.contexts, sc);
 		array_remove(m._.shader._.contexts, sc);
 	}
-	let con: NodeShaderContextRaw = make_particle_run({ name: "MaterialParticle", canvas: null });
-	if (sc != null) make_material_delete_context(sc);
+	let con: node_shader_context_t = make_particle_run({ name: "MaterialParticle", canvas: null });
+	if (sc != null) {
+		make_material_delete_context(sc);
+	}
 	sc = shader_context_create(con.data);
-	m._.shader.contexts.push(sc);
-	m._.shader._.contexts.push(sc);
+	array_push(m._.shader.contexts, sc);
+	array_push(m._.shader._.contexts, sc);
 }
 
 function make_material_parse_mesh_preview_material(md: material_data_t = null) {
@@ -136,7 +142,7 @@ function make_material_parse_mesh_preview_material(md: material_data_t = null) {
 	let mcon: material_context_t = { name: "mesh", bind_textures: [] };
 
 	let sd: material_t = { name: "Material", canvas: null };
-	let con: NodeShaderContextRaw = make_mesh_preview_run(sd, mcon);
+	let con: node_shader_context_t = make_mesh_preview_run(sd, mcon);
 
 	for (let i: i32 = 0; i < m._.contexts.length; ++i) {
 		if (m._.contexts[i].name == "mesh") {
@@ -145,16 +151,22 @@ function make_material_parse_mesh_preview_material(md: material_data_t = null) {
 		}
 	}
 
-	if (scon != null) make_material_delete_context(scon);
+	if (scon != null) {
+		make_material_delete_context(scon);
+	}
 
 	let compile_error: bool = false;
 	let _scon: shader_context_t = shader_context_create(con.data);
-	if (_scon == null) compile_error = true;
+	if (_scon == null) {
+		compile_error = true;
+	}
 	scon = _scon;
-	if (compile_error) return;
+	if (compile_error) {
+		return;
+	}
 
-	m._.shader.contexts.push(scon);
-	m._.shader._.contexts.push(scon);
+	array_push(m._.shader.contexts, scon);
+	array_push(m._.shader._.contexts, scon);
 }
 
 ///if arm_voxels
@@ -168,7 +180,9 @@ function make_material_make_voxel(m: material_data_t) {
 				break;
 			}
 		}
-		if (scon != null) make_voxel_run(scon);
+		if (scon != null) {
+			make_voxel_run(scon);
+		}
 	}
 }
 ///end
@@ -205,25 +219,33 @@ function make_material_parse_paint_material(bake_previews = true) {
 
 	let sdata: material_t = { name: "Material", canvas: ui_nodes_get_canvas_material() };
 	let tmcon: material_context_t = { name: "paint", bind_textures: [] };
-	let con: NodeShaderContextRaw = make_paint_run(sdata, tmcon);
+	let con: node_shader_context_t = make_paint_run(sdata, tmcon);
 
 	let compile_error: bool = false;
 	let scon: shader_context_t;
 	let _scon: shader_context_t = shader_context_create(con.data);
-	if (_scon == null) compile_error = true;
+	if (_scon == null) {
+		compile_error = true;
+	}
 	scon = _scon;
-	if (compile_error) return;
+	if (compile_error) {
+		return;
+	}
 	scon._.override_context = {};
 	scon._.override_context.addressing = "repeat";
 	let mcon: material_context_t = material_context_create(tmcon);
 
-	m._.shader.contexts.push(scon);
-	m._.shader._.contexts.push(scon);
-	m.contexts.push(mcon);
-	m._.contexts.push(mcon);
+	array_push(m._.shader.contexts, scon);
+	array_push(m._.shader._.contexts, scon);
+	array_push(m.contexts, mcon);
+	array_push(m._.contexts, mcon);
 
-	if (make_material_default_scon == null) make_material_default_scon = scon;
-	if (make_material_default_mcon == null) make_material_default_mcon = mcon;
+	if (make_material_default_scon == null) {
+		make_material_default_scon = scon;
+	}
+	if (make_material_default_mcon == null) {
+		make_material_default_mcon = mcon;
+	}
 }
 
 function make_material_bake_node_previews() {
@@ -231,10 +253,10 @@ function make_material_bake_node_previews() {
 	if (context_raw.node_previews == null) context_raw.node_previews = map_create();
 	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);
+		if (array_index_of(context_raw.node_previews_used, key) == -1) {
+			let image: image_t = map_get(context_raw.node_previews, key);
 			base_notify_on_next_frame(function() { image_unload(image); });
-			context_raw.node_previews.delete(key);
+			map_delete(context_raw.node_previews, key);
 		}
 	}
 }
@@ -245,7 +267,7 @@ function make_material_traverse_nodes(nodes: zui_node_t[], group: zui_node_canva
 		if (node.type == "GROUP") {
 			for (let g of project_material_groups) {
 				if (g.canvas.name == node.name) {
-					parents.push(node);
+					array_push(parents, node);
 					make_material_traverse_nodes(g.canvas.nodes, g.canvas, parents);
 					parents.pop();
 					break;
@@ -258,14 +280,16 @@ function make_material_traverse_nodes(nodes: zui_node_t[], group: zui_node_canva
 function 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 = parser_material_node_name(node, parents);
-		let image: image_t = context_raw.node_previews.get(id);
-		context_raw.node_previews_used.push(id);
+		let image: image_t = map_get(context_raw.node_previews, id);
+		array_push(context_raw.node_previews_used, id);
 		let resX: i32 = math_floor(config_get_texture_res_x() / 4);
 		let resY: i32 = math_floor(config_get_texture_res_y() / 4);
 		if (image == null || image.width != resX || image.height != resY) {
-			if (image != null) image_unload(image);
+			if (image != null) {
+				image_unload(image);
+			}
 			image = image_create_render_target(resX, resY);
-			context_raw.node_previews.set(id, image);
+			map_set(context_raw.node_previews, id, image);
 		}
 
 		parser_material_blur_passthrough = true;
@@ -274,14 +298,14 @@ function make_material_bake_node_preview(node: zui_node_t, group: zui_node_canva
 	}
 	else if (node.type == "DIRECT_WARP") {
 		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 image: image_t = map_get(context_raw.node_previews, id);
+		array_push(context_raw.node_previews_used, id);
 		let resX: i32 = math_floor(config_get_texture_res_x());
 		let resY: i32 = math_floor(config_get_texture_res_y());
 		if (image == null || image.width != resX || image.height != resY) {
 			if (image != null) image_unload(image);
 			image = image_create_render_target(resX, resY);
-			context_raw.node_previews.set(id, image);
+			map_set(context_raw.node_previews, id, image);
 		}
 
 		parser_material_warp_passthrough = true;
@@ -290,14 +314,14 @@ function make_material_bake_node_preview(node: zui_node_t, group: zui_node_canva
 	}
 	else if (node.type == "BAKE_CURVATURE") {
 		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 image: image_t = map_get(context_raw.node_previews, id);
+		array_push(context_raw.node_previews_used, id);
 		let resX: i32 = math_floor(config_get_texture_res_x());
 		let resY: i32 = math_floor(config_get_texture_res_y());
 		if (image == null || image.width != resX || image.height != resY) {
 			if (image != null) image_unload(image);
 			image = image_create_render_target(resX, resY, tex_format_t.R8);
-			context_raw.node_previews.set(id, image);
+			map_set(context_raw.node_previews, id, image);
 		}
 
 		if (render_path_paint_live_layer == null) {
@@ -333,7 +357,7 @@ function make_material_bake_node_preview(node: zui_node_t, group: zui_node_canva
 		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");
+		let texpaint_live: render_target_t = map_get(rts, "texpaint_live");
 
 		g2_begin(image);
 		g2_draw_image(texpaint_live._image, 0, 0);
@@ -342,16 +366,22 @@ function make_material_bake_node_preview(node: zui_node_t, group: zui_node_canva
 }
 
 function make_material_parse_node_preview_material(node: zui_node_t, group: zui_node_canvas_t = null, parents: zui_node_t[] = null): { scon: shader_context_t, mcon: material_context_t } {
-	if (node.outputs.length == 0) return null;
+	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 = make_node_preview_run(sdata, mcon_raw, node, group, parents);
+	let con: node_shader_context_t = 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);
-	if (_scon == null) compile_error = true;
+	if (_scon == null) {
+		compile_error = true;
+	}
 	scon = _scon;
-	if (compile_error) return null;
+	if (compile_error) {
+		return null;
+	}
 	let mcon: material_context_t = material_context_create(mcon_raw);
 	return { scon: scon, mcon: mcon };
 }
@@ -360,7 +390,7 @@ function make_material_parse_brush() {
 	parser_logic_parse(context_raw.brush.canvas);
 }
 
-function make_material_blend_mode(frag: NodeShaderRaw, blending: i32, cola: string, colb: string, opac: string): string {
+function make_material_blend_mode(frag: node_shader_t, blending: i32, cola: string, colb: string, opac: string): string {
 	if (blending == blend_type_t.MIX) {
 		return `mix(${cola}, ${colb}, ${opac})`;
 	}
@@ -425,7 +455,7 @@ function make_material_blend_mode(frag: NodeShaderRaw, blending: i32, cola: stri
 	}
 }
 
-function make_material_blend_mode_mask(frag: NodeShaderRaw, blending: i32, cola: string, colb: string, opac: string): string {
+function make_material_blend_mode_mask(frag: node_shader_t, blending: i32, cola: string, colb: string, opac: string): string {
 	if (blending == blend_type_t.MIX) {
 		return `mix(${cola}, ${colb}, ${opac})`;
 	}
@@ -484,7 +514,7 @@ function make_material_voxelgi_half_extents(): string {
 }
 
 function make_material_delete_context(c: shader_context_t) {
-	base_notify_on_next_frame(() => { // Ensure pipeline is no longer in use
+	base_notify_on_next_frame(function () { // Ensure pipeline is no longer in use
 		shader_context_delete(c);
 	});
 }

+ 40 - 20
armorpaint/Sources/make_mesh.ts

@@ -1,9 +1,9 @@
 
 let make_mesh_layer_pass_count = 1;
 
-function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
+function make_mesh_run(data: material_t, layerPass = 0): node_shader_context_t {
 	let context_id: string = layerPass == 0 ? "mesh" : "mesh" + layerPass;
-	let con_mesh: NodeShaderContextRaw = node_shader_context_create(data, {
+	let con_mesh: node_shader_context_t = node_shader_context_create(data, {
 		name: context_id,
 		depth_write: layerPass == 0 ? true : false,
 		compare_mode: layerPass == 0 ? "less" : "equal",
@@ -13,8 +13,8 @@ function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
 		depth_attachment: "DEPTH32"
 	});
 
-	let vert: NodeShaderRaw = node_shader_context_make_vert(con_mesh);
-	let frag: NodeShaderRaw = node_shader_context_make_frag(con_mesh);
+	let vert: node_shader_t = node_shader_context_make_vert(con_mesh);
+	let frag: node_shader_t = node_shader_context_make_frag(con_mesh);
 	frag.ins = vert.outs;
 
 	node_shader_add_out(vert, 'vec2 texCoord');
@@ -31,16 +31,22 @@ function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
 		node_shader_write(vert, 'float height = 0.0;');
 		let num_layers: i32 = 0;
 		for (let l of project_layers) {
-			if (!slot_layer_is_visible(l) || !l.paint_height || !slot_layer_is_layer(l)) continue;
-			if (num_layers > 16) break;
+			if (!slot_layer_is_visible(l) || !l.paint_height || !slot_layer_is_layer(l)) {
+				continue;
+			}
+			if (num_layers > 16) {
+				break;
+			}
 			num_layers++;
 			texture_count++;
 			node_shader_add_uniform(vert, 'sampler2D texpaint_pack_vert' + l.id, '_texpaint_pack_vert' + l.id);
 			node_shader_write(vert, 'height += textureLod(texpaint_pack_vert' + l.id + ', tex, 0.0).a;');
-			let masks: SlotLayerRaw[] = slot_layer_get_masks(l);
+			let masks: slot_layer_t[] = slot_layer_get_masks(l);
 			if (masks != null) {
 				for (let m of masks) {
-					if (!slot_layer_is_visible(m)) continue;
+					if (!slot_layer_is_visible(m)) {
+						continue;
+					}
 					texture_count++;
 					node_shader_add_uniform(vert, 'sampler2D texpaint_vert' + m.id, '_texpaint_vert' + m.id);
 					node_shader_write(vert, 'height *= textureLod(texpaint_vert' + m.id + ', tex, 0.0).r;');
@@ -123,9 +129,11 @@ function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
 
 		if (context_raw.viewport_mode == viewport_mode_t.MASK && slot_layer_get_masks(context_raw.layer) != null) {
 			for (let m of slot_layer_get_masks(context_raw.layer)) {
-				if (!slot_layer_is_visible(m)) continue;
+				if (!slot_layer_is_visible(m)) {
+					continue;
+				}
 				texture_count++;
-				node_shader_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' + array_index_of(project_layers, m));
 			}
 		}
 
@@ -139,23 +147,29 @@ function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
 
 		// Get layers for this pass
 		make_mesh_layer_pass_count = 1;
-		let layers: SlotLayerRaw[] = [];
+		let layers: slot_layer_t[] = [];
 		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 (!slot_layer_is_layer(l) || !slot_layer_is_visible(l)) continue;
+			if (is_material_tool && l != context_raw.layer) {
+				continue;
+			}
+			if (!slot_layer_is_layer(l) || !slot_layer_is_visible(l)) {
+				continue;
+			}
 
 			let count: i32 = 3;
-			let masks: SlotLayerRaw[] = slot_layer_get_masks(l);
-			if (masks != null) count += masks.length;
+			let masks: slot_layer_t[] = slot_layer_get_masks(l);
+			if (masks != null) {
+				count += masks.length;
+			}
 			texture_count += count;
 			if (texture_count >= make_mesh_get_max_textures()) {
 				texture_count = start_count + count + 3; // gbuffer0_copy, gbuffer1_copy, gbuffer2_copy
 				make_mesh_layer_pass_count++;
 			}
 			if (layerPass == make_mesh_layer_pass_count - 1) {
-				layers.push(l);
+				array_push(layers, l);
 			}
 		}
 
@@ -168,7 +182,9 @@ function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
 					let visibles: mesh_object_t[] = project_get_atlas_objects(slot_layer_get_object_mask(l));
 					node_shader_write(frag, 'if (');
 					for (let i: i32 = 0; i < visibles.length; ++i) {
-						if (i > 0) node_shader_write(frag, ' || ');
+						if (i > 0) {
+							node_shader_write(frag, ' || ');
+						}
 						node_shader_write(frag, `${visibles[i].base.uid} == uid`);
 					}
 					node_shader_write(frag, ') {');
@@ -188,7 +204,7 @@ function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
 			// }
 			// ///end
 
-			let masks: SlotLayerRaw[] = slot_layer_get_masks(l);
+			let masks: slot_layer_t[] = slot_layer_get_masks(l);
 			if (masks != null) {
 				let has_visible: bool = false;
 				for (let m of masks) {
@@ -201,7 +217,9 @@ function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
 					let texpaint_mask: string = 'texpaint_mask' + l.id;
 					node_shader_write(frag, `float ${texpaint_mask} = 0.0;`);
 					for (let m of masks) {
-						if (!slot_layer_is_visible(m)) continue;
+						if (!slot_layer_is_visible(m)) {
+							continue;
+						}
 						node_shader_add_shared_sampler(frag, 'sampler2D texpaint' + m.id);
 						node_shader_write(frag, '{'); // Group mask is sampled across multiple layers
 						node_shader_write(frag, 'float texpaint_mask_sample' + m.id + ' = textureLodShared(texpaint' + m.id + ', texCoord, 0.0).r;');
@@ -381,7 +399,9 @@ function make_mesh_run(data: material_t, layerPass = 0): NodeShaderContextRaw {
 				node_shader_write(frag, 'fragColor[1] = vec4(direct + indirect, 1.0);');
 			}
 			else { // Deferred, Pathtraced
-				if (make_material_emis_used) node_shader_write(frag, 'if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;'); // Boost for bloom
+				if (make_material_emis_used) {
+					node_shader_write(frag, 'if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;'); // Boost for bloom
+				}
 				node_shader_write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
 			}
 		}

+ 4 - 4
armorpaint/Sources/make_mesh_preview.ts

@@ -1,9 +1,9 @@
 
 let make_mesh_preview_opacity_discard_decal: f32 = 0.05;
 
-function make_mesh_preview_run(data: material_t, matcon: material_context_t): NodeShaderContextRaw {
+function make_mesh_preview_run(data: material_t, matcon: material_context_t): node_shader_context_t {
 	let context_id: string = "mesh";
-	let con_mesh: NodeShaderContextRaw = node_shader_context_create(data, {
+	let con_mesh: node_shader_context_t = node_shader_context_create(data, {
 		name: context_id,
 		depth_write: true,
 		compare_mode: "less",
@@ -13,8 +13,8 @@ function make_mesh_preview_run(data: material_t, matcon: material_context_t): No
 		depth_attachment: "DEPTH32"
 	});
 
-	let vert: NodeShaderRaw = node_shader_context_make_vert(con_mesh);
-	let frag: NodeShaderRaw = node_shader_context_make_frag(con_mesh);
+	let vert: node_shader_t = node_shader_context_make_vert(con_mesh);
+	let frag: node_shader_t = node_shader_context_make_frag(con_mesh);
 	frag.ins = vert.outs;
 	let pos: string = "pos";
 

+ 5 - 5
armorpaint/Sources/make_node_preview.ts

@@ -1,7 +1,7 @@
 
-function 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 {
+function make_node_preview_run(data: material_t, matcon: material_context_t, node: zui_node_t, group: zui_node_canvas_t, parents: zui_node_t[]): node_shader_context_t {
 	let context_id: string = "mesh";
-	let con_mesh: NodeShaderContextRaw = node_shader_context_create(data, {
+	let con_mesh: node_shader_context_t = node_shader_context_create(data, {
 		name: context_id,
 		depth_write: false,
 		compare_mode: "always",
@@ -11,8 +11,8 @@ function make_node_preview_run(data: material_t, matcon: material_context_t, nod
 	});
 
 	con_mesh.allow_vcols = true;
-	let vert: NodeShaderRaw = node_shader_context_make_vert(con_mesh);
-	let frag: NodeShaderRaw = node_shader_context_make_frag(con_mesh);
+	let vert: node_shader_t = node_shader_context_make_vert(con_mesh);
+	let frag: node_shader_t = node_shader_context_make_frag(con_mesh);
 	frag.ins = vert.outs;
 
 	node_shader_write_attrib(vert, 'gl_Position = vec4(pos.xy * 3.0, 0.0, 1.0);'); // Pos unpack
@@ -33,7 +33,7 @@ function make_node_preview_run(data: material_t, matcon: material_context_t, nod
 	}
 	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);
+	array_push(links, link);
 
 	parser_material_con = con_mesh;
 	parser_material_vert = vert;

+ 19 - 9
armorpaint/Sources/make_paint.ts

@@ -9,10 +9,10 @@ function make_paint_is_raytraced_bake(): bool {
 	///end
 }
 
-function make_paint_run(data: material_t, matcon: material_context_t): NodeShaderContextRaw {
+function make_paint_run(data: material_t, matcon: material_context_t): node_shader_context_t {
 	let context_id: string = "paint";
 
-	let con_paint: NodeShaderContextRaw = node_shader_context_create(data, {
+	let con_paint: node_shader_context_t = node_shader_context_create(data, {
 		name: context_id,
 		depth_write: false,
 		compare_mode: "always", // TODO: align texcoords winding order
@@ -33,8 +33,8 @@ function make_paint_run(data: material_t, matcon: material_context_t): NodeShade
 	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 = node_shader_context_make_vert(con_paint);
-	let frag: NodeShaderRaw = node_shader_context_make_frag(con_paint);
+	let vert: node_shader_t = node_shader_context_make_vert(con_paint);
+	let frag: node_shader_t = node_shader_context_make_frag(con_paint);
 	frag.ins = vert.outs;
 
 	///if (krom_direct3d12 || krom_vulkan || krom_metal)
@@ -88,7 +88,9 @@ function make_paint_run(data: material_t, matcon: material_context_t): NodeShade
 	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;
+	if (uv_type == uv_type_t.PROJECT) {
+		frag.ndcpos = true;
+	}
 
 	node_shader_add_uniform(frag, 'vec4 inp', '_inputBrush');
 	node_shader_add_uniform(frag, 'vec4 inplast', '_inputBrushLast');
@@ -114,12 +116,16 @@ function make_paint_run(data: material_t, matcon: material_context_t): NodeShade
 		decal) {
 
 		let depth_reject: bool = !context_raw.xray;
-		if (config_raw.brush_3d && !config_raw.brush_depth_reject) depth_reject = false;
+		if (config_raw.brush_3d && !config_raw.brush_depth_reject) {
+			depth_reject = false;
+		}
 
 		// 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 (make_material_height_used || context_raw.sym_x || context_raw.sym_y || context_raw.sym_z) depth_reject = false;
+			if (make_material_height_used || context_raw.sym_x || context_raw.sym_y || context_raw.sym_z) {
+				depth_reject = false;
+			}
 		}
 
 		if (depth_reject) {
@@ -236,8 +242,12 @@ function make_paint_run(data: material_t, matcon: material_context_t): NodeShade
 			// Height used for the first time, also rebuild vertex shader
 			return make_paint_run(data, matcon);
 		}
-		if (parseFloat(emis) != 0.0) make_material_emis_used = true;
-		if (parseFloat(subs) != 0.0) make_material_subs_used = true;
+		if (parseFloat(emis) != 0.0) {
+			make_material_emis_used = true;
+		}
+		if (parseFloat(subs) != 0.0) {
+			make_material_subs_used = true;
+		}
 	}
 
 	if (context_raw.brush_mask_image != null && context_raw.tool == workspace_tool_t.DECAL) {

+ 5 - 5
armorpaint/Sources/make_particle.ts

@@ -1,7 +1,7 @@
 
-function make_particle_run(data: material_t): NodeShaderContextRaw {
+function make_particle_run(data: material_t): node_shader_context_t {
 	let context_id: string = "mesh";
-	let con_part: NodeShaderContextRaw = node_shader_context_create(data, {
+	let con_part: node_shader_context_t = node_shader_context_create(data, {
 		name: context_id,
 		depth_write: false,
 		compare_mode: "always",
@@ -10,8 +10,8 @@ function make_particle_run(data: material_t): NodeShaderContextRaw {
 		color_attachments: ["R8"]
 	});
 
-	let vert: NodeShaderRaw = node_shader_context_make_vert(con_part);
-	let frag: NodeShaderRaw = node_shader_context_make_frag(con_part);
+	let vert: node_shader_t = node_shader_context_make_vert(con_part);
+	let frag: node_shader_t = node_shader_context_make_frag(con_part);
 	frag.ins = vert.outs;
 
 	node_shader_write_attrib(vert, 'vec4 spos = vec4(pos.xyz, 1.0);');
@@ -83,7 +83,7 @@ function make_particle_run(data: material_t): NodeShaderContextRaw {
 	return con_part;
 }
 
-function make_particle_mask(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_particle_mask(vert: node_shader_t, frag: node_shader_t) {
 	///if arm_physics
 	if (context_raw.particle_physics) {
 		node_shader_add_out(vert, 'vec4 wpos');

+ 7 - 7
armorpaint/Sources/make_texcoord.ts

@@ -1,11 +1,11 @@
 
-function make_texcoord_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
+function make_texcoord_run(vert: node_shader_t, frag: node_shader_t) {
 
 	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;
 	let decal: bool = context_raw.tool == workspace_tool_t.DECAL || context_raw.tool == workspace_tool_t.TEXT;
 	let angle: f32 = context_raw.brush_angle + context_raw.brush_nodes_angle;
-	let uvAngle: f32 = fill_layer ? context_raw.layer.angle : angle;
+	let uv_angle: f32 = fill_layer ? context_raw.layer.angle : angle;
 
 	if (uv_type == uv_type_t.PROJECT || decal) { // TexCoords - project
 		node_shader_add_uniform(frag, 'float brushScale', '_brushScale');
@@ -14,7 +14,7 @@ function make_texcoord_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 		if (fill_layer) { // Decal layer
 			node_shader_write_attrib(frag, 'if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) discard;');
 
-			if (uvAngle != 0.0) {
+			if (uv_angle != 0.0) {
 				node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
 				node_shader_write_attrib(frag, 'uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);');
 			}
@@ -41,7 +41,7 @@ function make_texcoord_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 				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) {
+			if (uv_angle != 0.0) {
 				node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
 				node_shader_write_attrib(frag, 'uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);');
 			}
@@ -56,7 +56,7 @@ function make_texcoord_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 		else {
 			node_shader_write_attrib(frag, 'uvsp.x *= aspectRatio;');
 
-			if (uvAngle != 0.0) {
+			if (uv_angle != 0.0) {
 				node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
 				node_shader_write_attrib(frag, 'uvsp = vec2(uvsp.x * brushAngle.x - uvsp.y * brushAngle.y, uvsp.x * brushAngle.y + uvsp.y * brushAngle.x);');
 			}
@@ -69,7 +69,7 @@ function make_texcoord_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 		node_shader_add_out(vert, 'vec2 texCoord');
 		node_shader_write(vert, 'texCoord = tex * brushScale;');
 
-		if (uvAngle > 0.0) {
+		if (uv_angle > 0.0) {
 			node_shader_add_uniform(vert, 'vec2 brushAngle', '_brushAngle');
 			node_shader_write(vert, 'texCoord = vec2(texCoord.x * brushAngle.x - texCoord.y * brushAngle.y, texCoord.x * brushAngle.y + texCoord.y * brushAngle.x);');
 		}
@@ -86,7 +86,7 @@ function make_texcoord_run(vert: NodeShaderRaw, frag: NodeShaderRaw) {
 		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) {
+		if (uv_angle != 0.0) {
 			node_shader_add_uniform(frag, 'vec2 brushAngle', '_brushAngle');
 			node_shader_write_attrib(frag, 'texCoord = vec2(texCoord.x * brushAngle.x - texCoord.y * brushAngle.y, texCoord.x * brushAngle.y + texCoord.y * brushAngle.x);');
 			node_shader_write_attrib(frag, 'texCoord1 = vec2(texCoord1.x * brushAngle.x - texCoord1.y * brushAngle.y, texCoord1.x * brushAngle.y + texCoord1.y * brushAngle.x);');

+ 9 - 7
armorpaint/Sources/nodes/brush_output_node.ts

@@ -47,10 +47,10 @@ function brush_output_node_parse_inputs(self: brush_output_node_t) {
 	let opac: any = input4; // Float or texture name
 	if (opac == null) opac = 1.0;
 	if (typeof opac == "string") {
-		context_raw.brush_mask_image_is_alpha = opac.endsWith(".a");
-		opac = opac.substr(0, opac.lastIndexOf("."));
+		context_raw.brush_mask_image_is_alpha = ends_with(opac, ".a");
+		opac = substring(opac, 0, string_last_index_of(opac, "."));
 		context_raw.brush_nodes_opacity = 1.0;
-		let index: i32 = project_asset_names.indexOf(opac);
+		let index: i32 = array_index_of(project_asset_names, opac);
 		let asset: asset_t = project_assets[index];
 		context_raw.brush_mask_image = project_get_image(asset);
 	}
@@ -62,11 +62,13 @@ function brush_output_node_parse_inputs(self: brush_output_node_t) {
 	context_raw.brush_nodes_hardness = input5;
 
 	let stencil: any = input6; // Float or texture name
-	if (stencil == null) stencil = 1.0;
+	if (stencil == null) {
+		stencil = 1.0;
+	}
 	if (typeof stencil == "string") {
-		context_raw.brush_stencil_image_is_alpha = stencil.endsWith(".a");
-		stencil = stencil.substr(0, stencil.lastIndexOf("."));
-		let index: i32 = project_asset_names.indexOf(stencil);
+		context_raw.brush_stencil_image_is_alpha = ends_with(stencil, ".a");
+		stencil = substring(stencil, 0, string_last_index_of(stencil, "."));
+		let index: i32 = array_index_of(project_asset_names, stencil);
 		let asset: asset_t = project_assets[index];
 		context_raw.brush_stencil_image = project_get_image(asset);
 	}

+ 8 - 4
armorpaint/Sources/nodes/input_node.ts

@@ -57,8 +57,12 @@ function input_node_update(self: float_node_t) {
 	}
 
 	if (operator_shortcut(config_keymap.brush_ruler + "+" + config_keymap.action_paint, shortcut_type_t.DOWN)) {
-		if (input_node_lock_x) paint_x = input_node_start_x;
-		if (input_node_lock_y) paint_y = input_node_start_y;
+		if (input_node_lock_x) {
+			paint_x = input_node_start_x;
+		}
+		if (input_node_lock_y) {
+			paint_y = input_node_start_y;
+		}
 	}
 
 	if (context_raw.brush_lazy_radius > 0) {
@@ -117,9 +121,9 @@ function input_node_update(self: float_node_t) {
 }
 
 function input_node_get(self: input_node_t, from: i32, done: (a: any)=>void) {
-	logic_node_input_get(self.base.inputs[0], (value) => {
+	logic_node_input_get(self.base.inputs[0], function (value) {
 		context_raw.brush_lazy_radius = value;
-		logic_node_input_get(self.base.inputs[1], (value) => {
+		logic_node_input_get(self.base.inputs[1], function (value) {
 			context_raw.brush_lazy_step = value;
 			done(input_node_coords);
 		});

+ 8 - 4
armorpaint/Sources/nodes/tex_image_node.ts

@@ -13,8 +13,12 @@ function tex_image_node_create(): tex_image_node_t {
 }
 
 function tex_image_node_get(self: tex_image_node_t, from: i32, done: (a: any)=>void) {
-	if (from == 0) done(self.file + ".rgb");
-	else done(self.file + ".a");
+	if (from == 0) {
+		done(self.file + ".rgb");
+	}
+	else {
+		done(self.file + ".a");
+	}
 }
 
 let tex_image_node_def: zui_node_t = {
@@ -31,7 +35,7 @@ let tex_image_node_def: zui_node_t = {
 			name: _tr("Vector"),
 			type: "VECTOR",
 			color: 0xff6363c7,
-			default_value: new Float32Array([0.0, 0.0, 0.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0])
 		}
 	],
 	outputs: [
@@ -41,7 +45,7 @@ let tex_image_node_def: zui_node_t = {
 			name: _tr("Color"),
 			type: "VALUE", // Match brush output socket type
 			color: 0xffc7c729,
-			default_value: new Float32Array([0.0, 0.0, 0.0, 1.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0, 1.0])
 		},
 		{
 			id: 0,

+ 1 - 1
armorpaint/Sources/nodes_brush.ts

@@ -24,7 +24,7 @@ function nodes_brush_create_node(node_type: string): zui_node_t {
 				let canvas: zui_node_canvas_t = context_raw.brush.canvas;
 				let nodes: zui_nodes_t = context_raw.brush.nodes;
 				let node: zui_node_t = ui_nodes_make_node(n, nodes, canvas);
-				canvas.nodes.push(node);
+				array_push(canvas.nodes, node);
 				return node;
 			}
 		}

+ 105 - 77
armorpaint/Sources/render_path_paint.ts

@@ -1,5 +1,5 @@
 
-let render_path_paint_live_layer: SlotLayerRaw = null;
+let render_path_paint_live_layer: slot_layer_t = null;
 let render_path_paint_live_layer_drawn: i32 = 0;
 let render_path_paint_live_layer_locked: bool = false;
 let render_path_paint_dilated: bool = true;
@@ -149,41 +149,45 @@ function render_path_paint_commands_paint(dilation = true) {
 				render_path_bind_target("gbuffer2", "gbuffer2");
 				render_path_bind_target("_main", "gbufferD");
 				render_path_draw_meshes("paint");
-				let texpaint_posnortex_picker0: image_t = render_path_render_targets.get("texpaint_posnortex_picker0")._image;
-				let texpaint_posnortex_picker1: image_t = render_path_render_targets.get("texpaint_posnortex_picker1")._image;
-				let a: DataView = new DataView(image_get_pixels(texpaint_posnortex_picker0));
-				let b: DataView = new DataView(image_get_pixels(texpaint_posnortex_picker1));
-				context_raw.posx_picked = a.getFloat32(0, true);
-				context_raw.posy_picked = a.getFloat32(4, true);
-				context_raw.posz_picked = a.getFloat32(8, true);
-				context_raw.uvx_picked = a.getFloat32(12, true);
-				context_raw.norx_picked = b.getFloat32(0, true);
-				context_raw.nory_picked = b.getFloat32(4, true);
-				context_raw.norz_picked = b.getFloat32(8, true);
-				context_raw.uvy_picked = b.getFloat32(12, true);
+				let texpaint_posnortex_picker0: image_t = map_get(render_path_render_targets, "texpaint_posnortex_picker0")._image;
+				let texpaint_posnortex_picker1: image_t = map_get(render_path_render_targets, "texpaint_posnortex_picker1")._image;
+				let a: buffer_view_t = buffer_view_create(image_get_pixels(texpaint_posnortex_picker0));
+				let b: buffer_view_t = buffer_view_create(image_get_pixels(texpaint_posnortex_picker1));
+				context_raw.posx_picked = buffer_view_get_f32(a, 0);
+				context_raw.posy_picked = buffer_view_get_f32(a, 4);
+				context_raw.posz_picked = buffer_view_get_f32(a, 8);
+				context_raw.uvx_picked = buffer_view_get_f32(a, 12);
+				context_raw.norx_picked = buffer_view_get_f32(b, 0);
+				context_raw.nory_picked = buffer_view_get_f32(b, 4);
+				context_raw.norz_picked = buffer_view_get_f32(b, 8);
+				context_raw.uvy_picked = buffer_view_get_f32(b, 12);
 			}
 			else {
 				render_path_set_target("texpaint_picker", ["texpaint_nor_picker", "texpaint_pack_picker", "texpaint_uv_picker"]);
 				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) render_path_paint_use_live_layer(true);
+				if (use_live_layer) {
+					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) render_path_paint_use_live_layer(false);
+				if (use_live_layer) {
+					render_path_paint_use_live_layer(false);
+				}
 				ui_header_handle.redraws = 2;
 				ui_base_hwnds[2].redraws = 2;
 
-				let texpaint_picker: image_t = render_path_render_targets.get("texpaint_picker")._image;
-				let texpaint_nor_picker: image_t = render_path_render_targets.get("texpaint_nor_picker")._image;
-				let texpaint_pack_picker: image_t = render_path_render_targets.get("texpaint_pack_picker")._image;
-				let texpaint_uv_picker: image_t = render_path_render_targets.get("texpaint_uv_picker")._image;
-				let a: DataView = new DataView(image_get_pixels(texpaint_picker));
-				let b: DataView = new DataView(image_get_pixels(texpaint_nor_picker));
-				let c: DataView = new DataView(image_get_pixels(texpaint_pack_picker));
-				let d: DataView = new DataView(image_get_pixels(texpaint_uv_picker));
+				let texpaint_picker: image_t = map_get(render_path_render_targets, "texpaint_picker")._image;
+				let texpaint_nor_picker: image_t = map_get(render_path_render_targets, "texpaint_nor_picker")._image;
+				let texpaint_pack_picker: image_t = map_get(render_path_render_targets, "texpaint_pack_picker")._image;
+				let texpaint_uv_picker: image_t = map_get(render_path_render_targets, "texpaint_uv_picker")._image;
+				let a: buffer_view_t = buffer_view_create(image_get_pixels(texpaint_picker));
+				let b: buffer_view_t = buffer_view_create(image_get_pixels(texpaint_nor_picker));
+				let c: buffer_view_t = buffer_view_create(image_get_pixels(texpaint_pack_picker));
+				let d: buffer_view_t = buffer_view_create(image_get_pixels(texpaint_uv_picker));
 
 				if (context_raw.color_picker_callback != null) {
 					context_raw.color_picker_callback(context_raw.picked_color);
@@ -200,23 +204,23 @@ function render_path_paint_commands_paint(dilation = true) {
 				let i2: i32 = 2;
 				///end
 				let i3: i32 = 3;
-				context_raw.picked_color.base = color_set_rb(context_raw.picked_color.base, a.getUint8(i0));
-				context_raw.picked_color.base = color_set_gb(context_raw.picked_color.base, a.getUint8(i1));
-				context_raw.picked_color.base = color_set_bb(context_raw.picked_color.base, a.getUint8(i2));
-				context_raw.picked_color.normal = color_set_rb(context_raw.picked_color.normal, b.getUint8(i0));
-				context_raw.picked_color.normal = color_set_gb(context_raw.picked_color.normal, b.getUint8(i1));
-				context_raw.picked_color.normal = color_set_bb(context_raw.picked_color.normal, b.getUint8(i2));
-				context_raw.picked_color.occlusion = c.getUint8(i0) / 255;
-				context_raw.picked_color.roughness = c.getUint8(i1) / 255;
-				context_raw.picked_color.metallic = c.getUint8(i2) / 255;
-				context_raw.picked_color.height = c.getUint8(i3) / 255;
-				context_raw.picked_color.opacity = a.getUint8(i3) / 255;
-				context_raw.uvx_picked = d.getUint8(i0) / 255;
-				context_raw.uvy_picked = d.getUint8(i1) / 255;
+				context_raw.picked_color.base = color_set_rb(context_raw.picked_color.base, buffer_view_get_u8(a, i0));
+				context_raw.picked_color.base = color_set_gb(context_raw.picked_color.base, buffer_view_get_u8(a, i1));
+				context_raw.picked_color.base = color_set_bb(context_raw.picked_color.base, buffer_view_get_u8(a, i2));
+				context_raw.picked_color.normal = color_set_rb(context_raw.picked_color.normal, buffer_view_get_u8(b, i0));
+				context_raw.picked_color.normal = color_set_gb(context_raw.picked_color.normal, buffer_view_get_u8(b, i1));
+				context_raw.picked_color.normal = color_set_bb(context_raw.picked_color.normal, buffer_view_get_u8(b, i2));
+				context_raw.picked_color.occlusion = buffer_view_get_u8(c, i0) / 255;
+				context_raw.picked_color.roughness = buffer_view_get_u8(c, i1) / 255;
+				context_raw.picked_color.metallic = buffer_view_get_u8(c, i2) / 255;
+				context_raw.picked_color.height = buffer_view_get_u8(c, i3) / 255;
+				context_raw.picked_color.opacity = buffer_view_get_u8(a, i3) / 255;
+				context_raw.uvx_picked = buffer_view_get_u8(d, i0) / 255;
+				context_raw.uvy_picked = buffer_view_get_u8(d, i1) / 255;
 				// Pick material
 				if (context_raw.picker_select_material && context_raw.color_picker_callback == null) {
 					// matid % 3 == 0 - normal, 1 - emission, 2 - subsurface
-					let matid: i32 = math_floor((b.getUint8(3) - (b.getUint8(3) % 3)) / 3);
+					let matid: i32 = math_floor((buffer_view_get_u8(b, 3) - (buffer_view_get_u8(b, 3) % 3)) / 3);
 					for (let m of project_materials) {
 						if (m.id == matid) {
 							context_set_material(m);
@@ -296,7 +300,7 @@ function render_path_paint_commands_paint(dilation = true) {
 			render_path_draw_meshes("paint");
 
 			if (context_raw.tool == workspace_tool_t.BAKE && context_raw.bake_type == bake_type_t.CURVATURE && context_raw.bake_curv_smooth > 0) {
-				if (render_path_render_targets.get("texpaint_blur") == null) {
+				if (map_get(render_path_render_targets, "texpaint_blur") == null) {
 					let t = render_target_create();
 					t.name = "texpaint_blur";
 					t.width = math_floor(config_get_texture_res_x() * 0.95);
@@ -349,7 +353,9 @@ function render_path_paint_commands_paint(dilation = true) {
 		mesh_object_get_contexts(project_paint_objects[0], "paint", mats, material_contexts, shader_contexts);
 
 		let cc_context: shader_context_t = shader_contexts[0];
-		if (const_data_screen_aligned_vb == null) const_data_create_screen_aligned_data();
+		if (const_data_screen_aligned_vb == null) {
+			const_data_create_screen_aligned_data();
+		}
 		g4_set_pipeline(cc_context._.pipe_state);
 		uniforms_set_context_consts(cc_context,_render_path_bind_params);
 		uniforms_set_obj_consts(cc_context, project_paint_objects[0].base);
@@ -366,29 +372,29 @@ function 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) {
-		_render_path_paint_texpaint = render_path_render_targets.get("texpaint" + tid);
-		_render_path_paint_texpaint_undo = render_path_render_targets.get("texpaint_undo" + hid);
-		_render_path_paint_texpaint_nor_undo = render_path_render_targets.get("texpaint_nor_undo" + hid);
-		_render_path_paint_texpaint_pack_undo = render_path_render_targets.get("texpaint_pack_undo" + hid);
-		_render_path_paint_texpaint_nor = render_path_render_targets.get("texpaint_nor" + tid);
-		_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"));
+		_render_path_paint_texpaint = map_get(render_path_render_targets, "texpaint" + tid);
+		_render_path_paint_texpaint_undo = map_get(render_path_render_targets, "texpaint_undo" + hid);
+		_render_path_paint_texpaint_nor_undo = map_get(render_path_render_targets, "texpaint_nor_undo" + hid);
+		_render_path_paint_texpaint_pack_undo = map_get(render_path_render_targets, "texpaint_pack_undo" + hid);
+		_render_path_paint_texpaint_nor = map_get(render_path_render_targets, "texpaint_nor" + tid);
+		_render_path_paint_texpaint_pack = map_get(render_path_render_targets, "texpaint_pack" + tid);
+		map_set(render_path_render_targets, "texpaint_undo" + hid,map_get(render_path_render_targets, "texpaint" + tid));
+		map_set(render_path_render_targets, "texpaint" + tid,map_get(render_path_render_targets, "texpaint_live"));
 		if (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"));
-			render_path_render_targets.set("texpaint_pack" + tid,render_path_render_targets.get("texpaint_pack_live"));
+			map_set(render_path_render_targets, "texpaint_nor_undo" + hid,map_get(render_path_render_targets, "texpaint_nor" + tid));
+			map_set(render_path_render_targets, "texpaint_pack_undo" + hid,map_get(render_path_render_targets, "texpaint_pack" + tid));
+			map_set(render_path_render_targets, "texpaint_nor" + tid,map_get(render_path_render_targets, "texpaint_nor_live"));
+			map_set(render_path_render_targets, "texpaint_pack" + tid,map_get(render_path_render_targets, "texpaint_pack_live"));
 		}
 	}
 	else {
-		render_path_render_targets.set("texpaint" + tid, _render_path_paint_texpaint);
-		render_path_render_targets.set("texpaint_undo" + hid, _render_path_paint_texpaint_undo);
+		map_set(render_path_render_targets, "texpaint" + tid, _render_path_paint_texpaint);
+		map_set(render_path_render_targets, "texpaint_undo" + hid, _render_path_paint_texpaint_undo);
 		if (slot_layer_is_layer(context_raw.layer)) {
-			render_path_render_targets.set("texpaint_nor_undo" + hid, _render_path_paint_texpaint_nor_undo);
-			render_path_render_targets.set("texpaint_pack_undo" + hid, _render_path_paint_texpaint_pack_undo);
-			render_path_render_targets.set("texpaint_nor" + tid, _render_path_paint_texpaint_nor);
-			render_path_render_targets.set("texpaint_pack" + tid, _render_path_paint_texpaint_pack);
+			map_set(render_path_render_targets, "texpaint_nor_undo" + hid, _render_path_paint_texpaint_nor_undo);
+			map_set(render_path_render_targets, "texpaint_pack_undo" + hid, _render_path_paint_texpaint_pack_undo);
+			map_set(render_path_render_targets, "texpaint_nor" + tid, _render_path_paint_texpaint_nor);
+			map_set(render_path_render_targets, "texpaint_pack" + tid, _render_path_paint_texpaint_pack);
 		}
 	}
 	render_path_paint_live_layer_locked = use;
@@ -406,7 +412,9 @@ function render_path_paint_commands_live_brush() {
 			return;
 	}
 
-	if (render_path_paint_live_layer_locked) return;
+	if (render_path_paint_live_layer_locked) {
+		return;
+	}
 
 	if (render_path_paint_live_layer == null) {
 		render_path_paint_live_layer = slot_layer_create("_live");
@@ -496,7 +504,9 @@ function render_path_paint_draw_cursor(mx: f32, my: f32, radius: f32, tint_r: f3
 	let plane: mesh_object_t = scene_get_child(".Plane").ext;
 	let geom: mesh_data_t = plane.data;
 
-	if (base_pipe_cursor == null) base_make_cursor_pipe();
+	if (base_pipe_cursor == null) {
+		base_make_cursor_pipe();
+	}
 
 	render_path_set_target("");
 	g4_set_pipeline(base_pipe_cursor);
@@ -504,7 +514,7 @@ function render_path_paint_draw_cursor(mx: f32, my: f32, radius: f32, tint_r: f3
 	let decal_mask: bool = decal && operator_shortcut(config_keymap.decal_mask, shortcut_type_t.DOWN);
 	let img: image_t = (decal && !decal_mask) ? context_raw.decal_image : resource_get("cursor.k");
 	g4_set_tex(base_cursor_tex, img);
-	let gbuffer0: image_t = render_path_render_targets.get("gbuffer0")._image;
+	let gbuffer0: image_t = map_get(render_path_render_targets, "gbuffer0")._image;
 	g4_set_tex_depth(base_cursor_gbufferd, gbuffer0);
 	g4_set_float2(base_cursor_mouse, mx, my);
 	g4_set_float2(base_cursor_tex_step, 1 / gbuffer0.width, 1 / gbuffer0.height);
@@ -610,7 +620,9 @@ function render_path_paint_begin() {
 	}
 	///end
 
-	if (!render_path_paint_paint_enabled()) return;
+	if (!render_path_paint_paint_enabled()) {
+		return;
+	}
 
 	///if is_paint
 	render_path_paint_push_undo_last = history_push_undo;
@@ -653,12 +665,16 @@ function render_path_paint_end() {
 	context_raw.ddirty--;
 	context_raw.rdirty--;
 
-	if (!render_path_paint_paint_enabled()) return;
+	if (!render_path_paint_paint_enabled()) {
+		return;
+	}
 	context_raw.pdirty--;
 }
 
 function render_path_paint_draw() {
-	if (!render_path_paint_paint_enabled()) return;
+	if (!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) {
@@ -670,7 +686,9 @@ function render_path_paint_draw() {
 	if (history_undo_layers != null) {
 		render_path_paint_commands_symmetry();
 
-		if (context_raw.pdirty > 0) render_path_paint_dilated = false;
+		if (context_raw.pdirty > 0) {
+			render_path_paint_dilated = false;
+		}
 
 		///if is_paint
 		if (context_raw.tool == workspace_tool_t.BAKE) {
@@ -695,10 +713,12 @@ function render_path_paint_draw() {
 					context_select_paint_object(high_poly);
 					render_path_paint_commands_paint();
 					high_poly.base.visible = _visible;
-					if (render_path_paint_push_undo_last) history_paint();
+					if (render_path_paint_push_undo_last) {
+						history_paint();
+					}
 					context_select_paint_object(_paint_object);
 
-					let _render_final = () => {
+					let _render_final = function () {
 						context_raw.bake_type = _bake_type;
 						make_material_parse_paint_material();
 						context_raw.pdirty = 1;
@@ -706,13 +726,15 @@ function render_path_paint_draw() {
 						context_raw.pdirty = 0;
 						render_path_paint_baking = false;
 					}
-					let _render_deriv = () => {
+					let _render_deriv = function () {
 						context_raw.bake_type = bake_type_t.HEIGHT;
 						make_material_parse_paint_material();
 						context_raw.pdirty = 1;
 						render_path_paint_commands_paint();
 						context_raw.pdirty = 0;
-						if (render_path_paint_push_undo_last) history_paint();
+						if (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;
@@ -725,7 +747,9 @@ function render_path_paint_draw() {
 				let is_merged: bool = context_raw.merged_object != null;
 				let _visible: bool = is_merged && context_raw.merged_object.base.visible;
 				context_raw.layer_filter = 1;
-				if (is_merged) context_raw.merged_object.base.visible = false;
+				if (is_merged) {
+					context_raw.merged_object.base.visible = false;
+				}
 
 				for (let p of project_paint_objects) {
 					context_select_paint_object(p);
@@ -782,7 +806,7 @@ function render_path_paint_set_plane_mesh() {
 	render_path_paint_painto = context_raw.paint_object;
 	render_path_paint_visibles = [];
 	for (let p of project_paint_objects) {
-		render_path_paint_visibles.push(p.base.visible);
+		array_push(render_path_paint_visibles, p.base.visible);
 		p.base.visible = false;
 	}
 	if (context_raw.merged_object != null) {
@@ -821,12 +845,12 @@ function render_path_paint_set_plane_mesh() {
 		let raw: mesh_data_t = {
 			name: ".PlaneTiled",
 			vertex_arrays: [
-				{ attrib: "pos", values: new Int16Array(posa), data: "short4norm" },
-				{ attrib: "nor", values: new Int16Array(nora), data: "short2norm" },
-				{ attrib: "tex", values: new Int16Array(texa), data: "short2norm" }
+				{ attrib: "pos", values: new i16_array_t(posa), data: "short4norm" },
+				{ attrib: "nor", values: new i16_array_t(nora), data: "short2norm" },
+				{ attrib: "tex", values: new i16_array_t(texa), data: "short2norm" }
 			],
 			index_arrays: [
-				{ values: new Uint32Array(inda), material: 0 }
+				{ values: new u32_array_t(inda), material: 0 }
 			],
 			scale_pos: 1.5,
 			scale_tex: 1.0
@@ -874,11 +898,13 @@ function render_path_paint_bind_layers() {
 	///if is_paint
 	let is_live: bool = config_raw.brush_live && 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) render_path_paint_use_live_layer(true);
+	if (is_live || is_material_tool) {
+		render_path_paint_use_live_layer(true);
+	}
 	///end
 
 	for (let i: i32 = 0; i < project_layers.length; ++i) {
-		let l: SlotLayerRaw = project_layers[i];
+		let l: slot_layer_t = project_layers[i];
 		render_path_bind_target("texpaint" + l.id, "texpaint" + l.id);
 
 		///if is_paint
@@ -894,7 +920,9 @@ function render_path_paint_unbind_layers() {
 	///if is_paint
 	let is_live: bool = config_raw.brush_live && 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) render_path_paint_use_live_layer(false);
+	if (is_live || is_material_tool) {
+		render_path_paint_use_live_layer(false);
+	}
 	///end
 }
 

+ 4 - 4
armorpaint/Sources/render_path_preview.ts

@@ -96,9 +96,9 @@ function render_path_preview_commands_preview() {
 	///end
 
 	let framebuffer: string = "texpreview";
-	let selected_mat: SlotMaterialRaw = context_raw.material;
-	render_path_render_targets.get("texpreview")._image = selected_mat.image;
-	render_path_render_targets.get("texpreview_icon")._image = selected_mat.image_icon;
+	let selected_mat: slot_material_t = context_raw.material;
+	map_get(render_path_render_targets, "texpreview")._image = selected_mat.image;
+	map_get(render_path_render_targets, "texpreview_icon")._image = selected_mat.image_icon;
 
 	render_path_set_target(framebuffer);
 	render_path_bind_target("mtex", "tex");
@@ -140,7 +140,7 @@ function render_path_preview_commands_decal() {
 	///end
 
 	let framebuffer: string = "texpreview";
-	render_path_render_targets.get("texpreview")._image = context_raw.decal_image;
+	map_get(render_path_render_targets, "texpreview")._image = context_raw.decal_image;
 
 	render_path_set_target(framebuffer);
 

+ 10 - 6
armorpaint/Sources/slot_brush.ts

@@ -1,5 +1,5 @@
 
-class SlotBrushRaw {
+class slot_brush_t {
 	nodes: zui_nodes_t = zui_nodes_create();
 	canvas: zui_node_canvas_t;
 	image: image_t = null; // 200px
@@ -8,15 +8,19 @@ class SlotBrushRaw {
 	id: i32 = 0;
 }
 
-let slot_brush_default_canvas: ArrayBuffer = null;
+let slot_brush_default_canvas: buffer_t = null;
 
-function 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;
+function slot_brush_create(c: zui_node_canvas_t = null): slot_brush_t {
+	let raw: slot_brush_t = new slot_brush_t();
+	for (let brush of project_brushes) {
+		if (brush.id >= raw.id) {
+			raw.id = brush.id + 1;
+		}
+	}
 
 	if (c == null) {
 		if (slot_brush_default_canvas == null) { // Synchronous
-			let b: ArrayBuffer = data_get_blob("default_brush.arm")
+			let b: buffer_t = data_get_blob("default_brush.arm")
 			slot_brush_default_canvas = b;
 		}
 		raw.canvas = armpack_decode(slot_brush_default_canvas);

+ 8 - 4
armorpaint/Sources/slot_font.ts

@@ -1,5 +1,5 @@
 
-class SlotFontRaw {
+class slot_font_t {
 	image: image_t = null; // 200px
 	preview_ready: bool = false;
 	id: i32 = 0;
@@ -8,9 +8,13 @@ class SlotFontRaw {
 	file: string;
 }
 
-function 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;
+function slot_font_create(name: string, font: g2_font_t, file = ""): slot_font_t {
+	let raw: slot_font_t = new slot_font_t();
+	for (let slot of project_fonts) {
+		if (slot.id >= raw.id) {
+			raw.id = slot.id + 1;
+		}
+	}
 	raw.name = name;
 	raw.font = font;
 	raw.file = file;

+ 220 - 138
armorpaint/Sources/slot_layer.ts

@@ -1,10 +1,10 @@
 
-class SlotLayerRaw {
+class slot_layer_t {
 	id: i32 = 0;
 	name: string;
 	ext: string = "";
 	visible: bool = true;
-	parent: SlotLayerRaw = null; // Group (for layers) or layer (for masks)
+	parent: slot_layer_t = null; // Group (for layers) or layer (for masks)
 
 	texpaint: image_t = null; // Base or mask
 	///if is_paint
@@ -14,7 +14,7 @@ class SlotLayerRaw {
 	///end
 
 	mask_opacity: f32 = 1.0; // Opacity mask
-	fill_layer: SlotMaterialRaw = null;
+	fill_layer: slot_material_t = null;
 	show_panel: bool = true;
 	blending = blend_type_t.MIX;
 	object_mask: i32 = 0;
@@ -35,11 +35,15 @@ class SlotLayerRaw {
 	decal_mat: mat4_t = mat4_identity(); // Decal layer
 }
 
-function slot_layer_create(ext: string = "", type: layer_slot_type_t = layer_slot_type_t.LAYER, parent: SlotLayerRaw = null): SlotLayerRaw {
-	let raw: SlotLayerRaw = new SlotLayerRaw();
+function slot_layer_create(ext: string = "", type: layer_slot_type_t = layer_slot_type_t.LAYER, parent: slot_layer_t = null): slot_layer_t {
+	let raw: slot_layer_t = new slot_layer_t();
 	if (ext == "") {
 		raw.id = 0;
-		for (let l of project_layers) if (l.id >= raw.id) raw.id = l.id + 1;
+		for (let l of project_layers) {
+			if (l.id >= raw.id) {
+				raw.id = l.id + 1;
+			}
+		}
 		ext = raw.id + "";
 	}
 	raw.ext = ext;
@@ -52,8 +56,8 @@ function slot_layer_create(ext: string = "", type: layer_slot_type_t = layer_slo
 		raw.name = "Layer " + (raw.id + 1);
 		///if is_paint
 		let format: string = base_bits_handle.position == texture_bits_t.BITS8  ? "RGBA32" :
-								base_bits_handle.position == texture_bits_t.BITS16 ? "RGBA64" :
-																					"RGBA128";
+							 base_bits_handle.position == texture_bits_t.BITS16 ? "RGBA64" :
+																				  "RGBA128";
 		///end
 
 		///if is_sculpt
@@ -113,21 +117,33 @@ function slot_layer_create(ext: string = "", type: layer_slot_type_t = layer_slo
 	return raw;
 }
 
-function slot_layer_delete(raw: SlotLayerRaw) {
+function slot_layer_delete(raw: slot_layer_t) {
 	slot_layer_unload(raw);
 
 	if (slot_layer_is_layer(raw)) {
-		let masks: SlotLayerRaw[] = slot_layer_get_masks(raw, false); // Prevents deleting group masks
-		if (masks != null) for (let m of masks) slot_layer_delete(m);
+		let masks: slot_layer_t[] = slot_layer_get_masks(raw, false); // Prevents deleting group masks
+		if (masks != null) {
+			for (let m of masks) {
+				slot_layer_delete(m);
+			}
+		}
 	}
 	else if (slot_layer_is_group(raw)) {
-		let children: SlotLayerRaw[] = slot_layer_get_children(raw);
-		if (children != null) for (let c of children) slot_layer_delete(c);
-		let masks: SlotLayerRaw[] = slot_layer_get_masks(raw);
-		if (masks != null) for (let m of masks) slot_layer_delete(m);
+		let children: slot_layer_t[] = slot_layer_get_children(raw);
+		if (children != null) {
+			for (let c of children) {
+				slot_layer_delete(c);
+			}
+		}
+		let masks: slot_layer_t[] = slot_layer_get_masks(raw);
+		if (masks != null) {
+			for (let m of masks) {
+				slot_layer_delete(m);
+			}
+		}
 	}
 
-	let lpos: i32 = project_layers.indexOf(raw);
+	let lpos: i32 = array_index_of(project_layers, raw);
 	array_remove(project_layers, raw);
 	// Undo can remove base layer and then restore it from undo layers
 	if (project_layers.length > 0) {
@@ -137,8 +153,10 @@ function slot_layer_delete(raw: SlotLayerRaw) {
 	// Do not remove empty groups if the last layer is deleted as this prevents redo from working properly
 }
 
-function slot_layer_unload(raw: SlotLayerRaw) {
-	if (slot_layer_is_group(raw)) return;
+function slot_layer_unload(raw: slot_layer_t) {
+	if (slot_layer_is_group(raw)) {
+		return;
+	}
 
 	let _texpaint: image_t = raw.texpaint;
 	///if is_paint
@@ -147,29 +165,33 @@ function slot_layer_unload(raw: SlotLayerRaw) {
 	let _texpaint_preview: image_t = raw.texpaint_preview;
 	///end
 
-	let _next = () => {
+	let _next = function () {
 		image_unload(_texpaint);
 		///if is_paint
-		if (_texpaint_nor != null) image_unload(_texpaint_nor);
-		if (_texpaint_pack != null) image_unload(_texpaint_pack);
+		if (_texpaint_nor != null) {
+			image_unload(_texpaint_nor);
+		}
+		if (_texpaint_pack != null) {
+			image_unload(_texpaint_pack);
+		}
 		image_unload(_texpaint_preview);
 		///end
 	}
 	base_notify_on_next_frame(_next);
 
-	render_path_render_targets.delete("texpaint" + raw.ext);
+	map_delete(render_path_render_targets, "texpaint" + raw.ext);
 	///if is_paint
 	if (slot_layer_is_layer(raw)) {
-		render_path_render_targets.delete("texpaint_nor" + raw.ext);
-		render_path_render_targets.delete("texpaint_pack" + raw.ext);
+		map_delete(render_path_render_targets, "texpaint_nor" + raw.ext);
+		map_delete(render_path_render_targets, "texpaint_pack" + raw.ext);
 	}
 	///end
 }
 
-function slot_layer_swap(raw: SlotLayerRaw, other: SlotLayerRaw) {
+function slot_layer_swap(raw: slot_layer_t, other: slot_layer_t) {
 	if ((slot_layer_is_layer(raw) || slot_layer_is_mask(raw)) && (slot_layer_is_layer(other) || 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;
+		map_get(render_path_render_targets, "texpaint" + raw.ext)._image = other.texpaint;
+		map_get(render_path_render_targets, "texpaint" + other.ext)._image = raw.texpaint;
 		let _texpaint: image_t = raw.texpaint;
 		raw.texpaint = other.texpaint;
 		other.texpaint = _texpaint;
@@ -183,10 +205,10 @@ function slot_layer_swap(raw: SlotLayerRaw, other: SlotLayerRaw) {
 
 	///if is_paint
 	if (slot_layer_is_layer(raw) && 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;
-		render_path_render_targets.get("texpaint_pack" + other.ext)._image = raw.texpaint_pack;
+		map_get(render_path_render_targets, "texpaint_nor" + raw.ext)._image = other.texpaint_nor;
+		map_get(render_path_render_targets, "texpaint_pack" + raw.ext)._image = other.texpaint_pack;
+		map_get(render_path_render_targets, "texpaint_nor" + other.ext)._image = raw.texpaint_nor;
+		map_get(render_path_render_targets, "texpaint_pack" + other.ext)._image = raw.texpaint_pack;
 		let _texpaint_nor: image_t = raw.texpaint_nor;
 		let _texpaint_pack: image_t = raw.texpaint_pack;
 		raw.texpaint_nor = other.texpaint_nor;
@@ -197,7 +219,7 @@ function slot_layer_swap(raw: SlotLayerRaw, other: SlotLayerRaw) {
 	///end
 }
 
-function slot_layer_clear(raw: SlotLayerRaw, baseColor = 0x00000000, baseImage: image_t = null, occlusion = 1.0, roughness = base_default_rough, metallic = 0.0) {
+function slot_layer_clear(raw: slot_layer_t, 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();
@@ -222,8 +244,10 @@ function slot_layer_clear(raw: SlotLayerRaw, baseColor = 0x00000000, baseImage:
 	context_raw.ddirty = 3;
 }
 
-function slot_layer_invert_mask(raw: SlotLayerRaw) {
-	if (base_pipe_invert8 == null) base_make_pipe();
+function slot_layer_invert_mask(raw: slot_layer_t) {
+	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);
 	g2_set_pipeline(base_pipe_invert8);
@@ -231,16 +255,16 @@ function slot_layer_invert_mask(raw: SlotLayerRaw) {
 	g2_set_pipeline(null);
 	g2_end();
 	let _texpaint: image_t = raw.texpaint;
-	let _next = () => {
+	let _next = function () {
 		image_unload(_texpaint);
 	}
 	base_notify_on_next_frame(_next);
-	raw.texpaint = render_path_render_targets.get("texpaint" + raw.id)._image = inverted;
+	raw.texpaint = map_get(render_path_render_targets, "texpaint" + raw.id)._image = inverted;
 	context_raw.layer_preview_dirty = true;
 	context_raw.ddirty = 3;
 }
 
-function slot_layer_apply_mask(raw: SlotLayerRaw) {
+function slot_layer_apply_mask(raw: slot_layer_t) {
 	if (raw.parent.fill_layer != null) {
 		slot_layer_to_paint_layer(raw.parent);
 	}
@@ -255,13 +279,15 @@ function slot_layer_apply_mask(raw: SlotLayerRaw) {
 	slot_layer_delete(raw);
 }
 
-function slot_layer_duplicate(raw: SlotLayerRaw): SlotLayerRaw {
-	let layers: SlotLayerRaw[] = project_layers;
-	let i: i32 = layers.indexOf(raw) + 1;
-	let l: SlotLayerRaw = slot_layer_create("", slot_layer_is_layer(raw) ? layer_slot_type_t.LAYER : slot_layer_is_mask(raw) ? layer_slot_type_t.MASK : layer_slot_type_t.GROUP, raw.parent);
-	layers.splice(i, 0, l);
+function slot_layer_duplicate(raw: slot_layer_t): slot_layer_t {
+	let layers: slot_layer_t[] = project_layers;
+	let i: i32 = array_index_of(layers, raw) + 1;
+	let l: slot_layer_t = slot_layer_create("", slot_layer_is_layer(raw) ? layer_slot_type_t.LAYER : slot_layer_is_mask(raw) ? layer_slot_type_t.MASK : layer_slot_type_t.GROUP, raw.parent);
+	array_insert(layers, i, l);
 
-	if (base_pipe_merge == null) base_make_pipe();
+	if (base_pipe_merge == null) {
+		base_make_pipe();
+	}
 	if (slot_layer_is_layer(raw)) {
 		g2_begin(l.texpaint);
 		g2_set_pipeline(base_pipe_copy);
@@ -321,11 +347,13 @@ function slot_layer_duplicate(raw: SlotLayerRaw): SlotLayerRaw {
 	return l;
 }
 
-function slot_layer_resize_and_set_bits(raw: SlotLayerRaw) {
+function slot_layer_resize_and_set_bits(raw: slot_layer_t) {
 	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 (base_pipe_merge == null) {
+		base_make_pipe();
+	}
 
 	if (slot_layer_is_layer(raw)) {
 		///if is_paint
@@ -365,7 +393,7 @@ function slot_layer_resize_and_set_bits(raw: SlotLayerRaw) {
 		g2_end();
 		///end
 
-		let _next = () => {
+		let _next = function () {
 			image_unload(_texpaint);
 			///if is_paint
 			image_unload(_texpaint_nor);
@@ -374,10 +402,10 @@ function slot_layer_resize_and_set_bits(raw: SlotLayerRaw) {
 		}
 		base_notify_on_next_frame(_next);
 
-		rts.get("texpaint" + raw.ext)._image = raw.texpaint;
+		map_get(rts, "texpaint" + raw.ext)._image = raw.texpaint;
 		///if is_paint
-		rts.get("texpaint_nor" + raw.ext)._image = raw.texpaint_nor;
-		rts.get("texpaint_pack" + raw.ext)._image = raw.texpaint_pack;
+		map_get(rts, "texpaint_nor" + raw.ext)._image = raw.texpaint_nor;
+		map_get(rts, "texpaint_pack" + raw.ext)._image = raw.texpaint_pack;
 		///end
 	}
 	else if (slot_layer_is_mask(raw)) {
@@ -390,20 +418,20 @@ function slot_layer_resize_and_set_bits(raw: SlotLayerRaw) {
 		g2_set_pipeline(null);
 		g2_end();
 
-		let _next = () => {
+		let _next = function () {
 			image_unload(_texpaint);
 		}
 		base_notify_on_next_frame(_next);
 
-		rts.get("texpaint" + raw.ext)._image = raw.texpaint;
+		map_get(rts, "texpaint" + raw.ext)._image = raw.texpaint;
 	}
 }
 
-function slot_layer_to_fill_layer(raw: SlotLayerRaw) {
+function slot_layer_to_fill_layer(raw: slot_layer_t) {
 	context_set_layer(raw);
 	raw.fill_layer = context_raw.material;
 	base_update_fill_layer();
-	let _next = () => {
+	let _next = function () {
 		make_material_parse_paint_material();
 		context_raw.layer_preview_dirty = true;
 		ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
@@ -411,7 +439,7 @@ function slot_layer_to_fill_layer(raw: SlotLayerRaw) {
 	base_notify_on_next_frame(_next);
 }
 
-function slot_layer_to_paint_layer(raw: SlotLayerRaw) {
+function slot_layer_to_paint_layer(raw: slot_layer_t) {
 	context_set_layer(raw);
 	raw.fill_layer = null;
 	make_material_parse_paint_material();
@@ -419,45 +447,55 @@ function slot_layer_to_paint_layer(raw: SlotLayerRaw) {
 	ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
 }
 
-function slot_layer_is_visible(raw: SlotLayerRaw): bool {
+function slot_layer_is_visible(raw: slot_layer_t): bool {
 	return raw.visible && (raw.parent == null || raw.parent.visible);
 }
 
-function slot_layer_get_children(raw: SlotLayerRaw): SlotLayerRaw[] {
-	let children: SlotLayerRaw[] = null; // Child layers of a group
+function slot_layer_get_children(raw: slot_layer_t): slot_layer_t[] {
+	let children: slot_layer_t[] = null; // Child layers of a group
 	for (let l of project_layers) {
 		if (l.parent == raw && slot_layer_is_layer(l)) {
-			if (children == null) children = [];
-			children.push(l);
+			if (children == null) {
+				children = [];
+			}
+			array_push(children, l);
 		}
 	}
 	return children;
 }
 
-function slot_layer_get_recursive_children(raw: SlotLayerRaw): SlotLayerRaw[] {
-	let children: SlotLayerRaw[] = null;
+function slot_layer_get_recursive_children(raw: slot_layer_t): slot_layer_t[] {
+	let children: slot_layer_t[] = null;
 	for (let l of project_layers) {
 		if (l.parent == raw) { // Child layers and group masks
-			if (children == null) children = [];
-			children.push(l);
+			if (children == null) {
+				children = [];
+			}
+			array_push(children, l);
 		}
 		if (l.parent != null && l.parent.parent == raw) { // Layer masks
-			if (children == null) children = [];
-			children.push(l);
+			if (children == null) {
+				children = [];
+			}
+			array_push(children, l);
 		}
 	}
 	return children;
 }
 
-function slot_layer_get_masks(raw: SlotLayerRaw, includeGroupMasks = true): SlotLayerRaw[] {
-	if (slot_layer_is_mask(raw)) return null;
+function slot_layer_get_masks(raw: slot_layer_t, includeGroupMasks = true): slot_layer_t[] {
+	if (slot_layer_is_mask(raw)) {
+		return null;
+	}
 
-	let children: SlotLayerRaw[] = null;
+	let children: slot_layer_t[] = null;
 	// Child masks of a layer
 	for (let l of project_layers) {
 		if (l.parent == raw && slot_layer_is_mask(l)) {
-			if (children == null) children = [];
-			children.push(l);
+			if (children == null) {
+				children = [];
+			}
+			array_push(children, l);
 		}
 	}
 	// Child masks of a parent group
@@ -465,8 +503,10 @@ function slot_layer_get_masks(raw: SlotLayerRaw, includeGroupMasks = true): Slot
 		if (raw.parent != null && slot_layer_is_group(raw.parent)) {
 			for (let l of project_layers) {
 				if (l.parent == raw.parent && slot_layer_is_mask(l)) {
-					if (children == null) children = [];
-					children.push(l);
+					if (children == null) {
+						children = [];
+					}
+					array_push(children, l);
 				}
 			}
 		}
@@ -474,7 +514,7 @@ function slot_layer_get_masks(raw: SlotLayerRaw, includeGroupMasks = true): Slot
 	return children;
 }
 
-function slot_layer_has_masks(raw: SlotLayerRaw, includeGroupMasks = true): bool {
+function slot_layer_has_masks(raw: slot_layer_t, includeGroupMasks = true): bool {
 	// Layer mask
 	for (let l of project_layers) {
 		if (l.parent == raw && slot_layer_is_mask(l)) {
@@ -492,17 +532,19 @@ function slot_layer_has_masks(raw: SlotLayerRaw, includeGroupMasks = true): bool
 	return false;
 }
 
-function slot_layer_get_opacity(raw: SlotLayerRaw): f32 {
+function slot_layer_get_opacity(raw: slot_layer_t): f32 {
 	let f: f32 = raw.mask_opacity;
-	if (slot_layer_is_layer(raw) && raw.parent != null) f *= raw.parent.mask_opacity;
+	if (slot_layer_is_layer(raw) && raw.parent != null) {
+		f *= raw.parent.mask_opacity;
+	}
 	return f;
 }
 
-function slot_layer_get_object_mask(raw: SlotLayerRaw): i32 {
+function slot_layer_get_object_mask(raw: slot_layer_t): i32 {
 	return slot_layer_is_mask(raw) ? raw.parent.object_mask : raw.object_mask;
 }
 
-function slot_layer_is_layer(raw: SlotLayerRaw): bool {
+function slot_layer_is_layer(raw: slot_layer_t): bool {
 	///if is_paint
 	return raw.texpaint != null && raw.texpaint_nor != null;
 	///end
@@ -511,19 +553,23 @@ function slot_layer_is_layer(raw: SlotLayerRaw): bool {
 	///end
 }
 
-function slot_layer_is_group(raw: SlotLayerRaw): bool {
+function slot_layer_is_group(raw: slot_layer_t): bool {
 	return raw.texpaint == null;
 }
 
-function slot_layer_get_containing_group(raw: SlotLayerRaw): SlotLayerRaw {
-	if (raw.parent != null && slot_layer_is_group(raw.parent))
+function slot_layer_get_containing_group(raw: slot_layer_t): slot_layer_t {
+	if (raw.parent != null && slot_layer_is_group(raw.parent)) {
 		return raw.parent;
-	else if (raw.parent != null && raw.parent.parent != null && slot_layer_is_group(raw.parent.parent))
+	}
+	else if (raw.parent != null && raw.parent.parent != null && slot_layer_is_group(raw.parent.parent)) {
 		return raw.parent.parent;
-	else return null;
+	}
+	else {
+		return null;
+	}
 }
 
-function slot_layer_is_mask(raw: SlotLayerRaw): bool {
+function slot_layer_is_mask(raw: slot_layer_t): bool {
 	///if is_paint
 	return raw.texpaint != null && raw.texpaint_nor == null;
 	///end
@@ -532,7 +578,7 @@ function slot_layer_is_mask(raw: SlotLayerRaw): bool {
 	///end
 }
 
-function slot_layer_is_group_mask(raw: SlotLayerRaw): bool {
+function slot_layer_is_group_mask(raw: slot_layer_t): bool {
 	///if is_paint
 	return raw.texpaint != null && raw.texpaint_nor == null && slot_layer_is_group(raw.parent);
 	///end
@@ -541,7 +587,7 @@ function slot_layer_is_group_mask(raw: SlotLayerRaw): bool {
 	///end
 }
 
-function slot_layer_is_layer_mask(raw: SlotLayerRaw): bool {
+function slot_layer_is_layer_mask(raw: slot_layer_t): bool {
 	///if is_paint
 	return raw.texpaint != null && raw.texpaint_nor == null && slot_layer_is_layer(raw.parent);
 	///end
@@ -550,78 +596,102 @@ function slot_layer_is_layer_mask(raw: SlotLayerRaw): bool {
 	///end
 }
 
-function slot_layer_is_in_group(raw: SlotLayerRaw): bool {
+function slot_layer_is_in_group(raw: slot_layer_t): bool {
 	return raw.parent != null && (slot_layer_is_group(raw.parent) || (raw.parent.parent != null && slot_layer_is_group(raw.parent.parent)));
 }
 
-function slot_layer_can_move(raw: SlotLayerRaw, to: i32): bool {
-	let old_index: i32 = project_layers.indexOf(raw);
+function slot_layer_can_move(raw: slot_layer_t, to: i32): bool {
+	let old_index: i32 = array_index_of(project_layers, raw);
 
 	let delta: i32 = to - old_index; // If delta > 0 the layer is moved up, otherwise down
-	if (to < 0 || to > project_layers.length - 1 || delta == 0) return false;
+	if (to < 0 || to > project_layers.length - 1 || delta == 0) {
+		return false;
+	}
 
 	// If the layer is moved up, all layers between the old position and the new one move one down.
 	// The layers above the new position stay where they are.
 	// If the new position is on top or on bottom no upper resp. lower layer exists.
-	let new_upper_layer: SlotLayerRaw = delta > 0 ? (to < project_layers.length - 1 ? project_layers[to + 1] : null) : project_layers[to];
+	let new_upper_layer: slot_layer_t = 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[] = slot_layer_get_recursive_children(new_upper_layer);
+		let children: slot_layer_t[] = 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];
 	}
 
-	let new_lower_layer: SlotLayerRaw = delta > 0 ? project_layers[to] : (to > 0 ? project_layers[to - 1] : null);
+	let new_lower_layer: slot_layer_t = delta > 0 ? project_layers[to] : (to > 0 ? project_layers[to - 1] : null);
 
 	if (slot_layer_is_mask(raw)) {
 		// Masks can not be on top.
-		if (new_upper_layer == null) return false;
+		if (new_upper_layer == null) {
+			return false;
+		}
 		// Masks should not be placed below a collapsed group. This condition can be savely removed.
-		if (slot_layer_is_in_group(new_upper_layer) && !slot_layer_get_containing_group(new_upper_layer).show_panel) return false;
+		if (slot_layer_is_in_group(new_upper_layer) && !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 (slot_layer_is_mask(new_upper_layer) && !new_upper_layer.parent.show_panel) return false;
+		if (slot_layer_is_mask(new_upper_layer) && !new_upper_layer.parent.show_panel) {
+			return false;
+		}
 	}
 
 	if (slot_layer_is_layer(raw)) {
 		// Layers can not be moved directly below its own mask(s).
-		if (new_upper_layer != null && slot_layer_is_mask(new_upper_layer) && new_upper_layer.parent == raw) return false;
+		if (new_upper_layer != null && 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 && slot_layer_is_mask(new_lower_layer)) return false;
+		if (new_lower_layer != null && slot_layer_is_mask(new_lower_layer)) {
+			return false;
+		}
 	}
 
 	// Currently groups can not be nested. Thus valid positions for groups are:
 	if (slot_layer_is_group(raw)) {
 		// At the top.
-		if (new_upper_layer == null) return true;
+		if (new_upper_layer == null) {
+			return true;
+		}
 		// NOT below its own children.
-		if (slot_layer_get_containing_group(new_upper_layer) == raw) return false;
+		if (slot_layer_get_containing_group(new_upper_layer) == raw) {
+			return false;
+		}
 		// At the bottom.
-		if (new_lower_layer == null) return true;
+		if (new_lower_layer == null) {
+			return true;
+		}
 		// Above a group.
-		if (slot_layer_is_group(new_lower_layer)) return true;
+		if (slot_layer_is_group(new_lower_layer)) {
+			return true;
+		}
 		// Above a non-grouped layer.
-		if (slot_layer_is_layer(new_lower_layer) && !slot_layer_is_in_group(new_lower_layer)) return true;
-		else return false;
+		if (slot_layer_is_layer(new_lower_layer) && !slot_layer_is_in_group(new_lower_layer)) {
+			return true;
+		}
+		else {
+			return false;
+		}
 	}
 
 	return true;
 }
 
-function slot_layer_move(raw: SlotLayerRaw, to: i32) {
+function slot_layer_move(raw: slot_layer_t, to: i32) {
 	if (!slot_layer_can_move(raw, to)) {
 		return;
 	}
 
-	let pointers: map_t<SlotLayerRaw, i32> = tab_layers_init_layer_map();
-	let old_index: i32 = project_layers.indexOf(raw);
+	let pointers: map_t<slot_layer_t, i32> = tab_layers_init_layer_map();
+	let old_index: i32 = array_index_of(project_layers, 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];
+	let new_upper_layer: slot_layer_t = 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[] = slot_layer_get_recursive_children(new_upper_layer);
+		let children: slot_layer_t[] = 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];
@@ -632,58 +702,70 @@ function slot_layer_move(raw: SlotLayerRaw, to: i32) {
 	ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
 
 	array_remove(project_layers, raw);
-	project_layers.splice(to, 0, raw);
+	array_insert(project_layers, to, raw);
 
 	if (slot_layer_is_layer(raw)) {
-		let old_parent: SlotLayerRaw = raw.parent;
-
-		if (new_upper_layer == null)
-			raw.parent = null; // Placed on top.
-		else if (slot_layer_is_in_group(new_upper_layer) && !slot_layer_get_containing_group(new_upper_layer).show_panel)
-			raw.parent = null; // Placed below a collapsed group.
-		else if (slot_layer_is_layer(new_upper_layer))
-			raw.parent = new_upper_layer.parent; // Placed below a layer, use the same parent.
-		else if (slot_layer_is_group(new_upper_layer))
-			raw.parent = new_upper_layer; // Placed as top layer in a group.
-		else if (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 (slot_layer_is_layer_mask(new_upper_layer))
-			raw.parent = 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[] = slot_layer_get_masks(raw, false);
+		let old_parent: slot_layer_t = raw.parent;
+
+		if (new_upper_layer == null) {
+			raw.parent = null; // Placed on top
+		}
+		else if (slot_layer_is_in_group(new_upper_layer) && !slot_layer_get_containing_group(new_upper_layer).show_panel) {
+			raw.parent = null; // Placed below a collapsed group
+		}
+		else if (slot_layer_is_layer(new_upper_layer)) {
+			raw.parent = new_upper_layer.parent; // Placed below a layer, use the same parent
+		}
+		else if (slot_layer_is_group(new_upper_layer)) {
+			raw.parent = new_upper_layer; // Placed as top layer in a group
+		}
+		else if (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 (slot_layer_is_layer_mask(new_upper_layer)) {
+			raw.parent = 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: slot_layer_t[] = 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];
+				let mask: slot_layer_t = layer_masks[idx];
 				array_remove(project_layers, mask);
 				// If the masks are moved down each step increases the index below the layer by one.
-				project_layers.splice(delta > 0 ? old_index + delta - 1 : old_index + delta + idx, 0, mask);
+				array_insert(project_layers, delta > 0 ? old_index + delta - 1 : old_index + delta + idx, mask);
 			}
 		}
 
-		// The layer is the last layer in the group, remove it. Notice that this might remove group masks.
-		if (old_parent != null && slot_layer_get_children(old_parent) == null)
+		// The layer is the last layer in the group, remove it
+		// Notice that this might remove group masks
+		if (old_parent != null && slot_layer_get_children(old_parent) == null) {
 			slot_layer_delete(old_parent);
+		}
 	}
 	else if (slot_layer_is_mask(raw)) {
-		// Precondition newUpperLayer != null, ensured in canMove.
-		if (slot_layer_is_layer(new_upper_layer) || slot_layer_is_group(new_upper_layer))
+		// Precondition new_upper_layer != null, ensured in can_move
+		if (slot_layer_is_layer(new_upper_layer) || slot_layer_is_group(new_upper_layer)) {
 			raw.parent = new_upper_layer;
-		else if (slot_layer_is_mask(new_upper_layer)) { // Group mask or layer mask.
+		}
+		else if (slot_layer_is_mask(new_upper_layer)) { // Group mask or layer mask
 			raw.parent = new_upper_layer.parent;
 		}
 	}
 	else if (slot_layer_is_group(raw)) {
-		let children: SlotLayerRaw[] = slot_layer_get_recursive_children(raw);
+		let children: slot_layer_t[] = slot_layer_get_recursive_children(raw);
 		if (children != null) {
 			for (let idx: i32 = 0; idx < children.length; ++idx) {
-				let child: SlotLayerRaw = children[idx];
+				let child: slot_layer_t = children[idx];
 				array_remove(project_layers, child);
-				// If the children are moved down each step increases the index below the layer by one.
-				project_layers.splice(delta > 0 ? old_index + delta - 1 : old_index + delta + idx, 0, child);
+				// If the children are moved down each step increases the index below the layer by one
+				array_insert(project_layers, delta > 0 ? old_index + delta - 1 : old_index + delta + idx, child);
 			}
 		}
 	}
 
-	for (let m of project_materials) tab_layers_remap_layer_pointers(m.canvas.nodes, tab_layers_fill_layer_map(pointers));
+	for (let m of project_materials) {
+		tab_layers_remap_layer_pointers(m.canvas.nodes, tab_layers_fill_layer_map(pointers));
+	}
 }

+ 16 - 12
armorpaint/Sources/slot_material.ts

@@ -1,5 +1,5 @@
 
-class SlotMaterialRaw {
+class slot_material_t {
 	nodes: zui_nodes_t = zui_nodes_create();
 	canvas: zui_node_canvas_t;
 	image: image_t = null;
@@ -19,11 +19,15 @@ class SlotMaterialRaw {
 	paint_subs: bool = true;
 }
 
-let slot_material_default_canvas: ArrayBuffer = null;
+let slot_material_default_canvas: buffer_t = null;
 
-function 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;
+function slot_material_create(m: material_data_t = null, c: zui_node_canvas_t = null): slot_material_t {
+	let raw: slot_material_t = new slot_material_t();
+	for (let mat of project_materials) {
+		if (mat.id >= raw.id) {
+			raw.id = mat.id + 1;
+		}
+	}
 	raw.data = m;
 
 	let w: i32 = util_render_material_preview_size;
@@ -33,7 +37,7 @@ function slot_material_create(m: material_data_t = null, c: zui_node_canvas_t =
 
 	if (c == null) {
 		if (slot_material_default_canvas == null) { // Synchronous
-			let b: ArrayBuffer = data_get_blob("default_material.arm");
+			let b: buffer_t = data_get_blob("default_material.arm");
 			slot_material_default_canvas = b;
 		}
 		raw.canvas = armpack_decode(slot_material_default_canvas);
@@ -44,24 +48,24 @@ function slot_material_create(m: material_data_t = null, c: zui_node_canvas_t =
 	}
 
 	///if (krom_android || krom_ios)
-	raw.nodes.panX -= 50; // Center initial position
+	raw.nodes.pan_x -= 50; // Center initial position
 	///end
 
 	return raw;
 }
 
-function slot_material_unload(raw: SlotMaterialRaw) {
-	let _next = () => {
+function slot_material_unload(raw: slot_material_t) {
+	let _next = function () {
 		image_unload(raw.image);
 		image_unload(raw.image_icon);
 	}
 	base_notify_on_next_frame(_next);
 }
 
-function slot_material_delete(raw: SlotMaterialRaw) {
+function slot_material_delete(raw: slot_material_t) {
 	slot_material_unload(raw);
-	let mpos: i32 = project_materials.indexOf(raw);
-	array_remove(project_materials, this);
+	let mpos: i32 = array_index_of(project_materials, raw);
+	array_remove(project_materials, raw);
 	if (project_materials.length > 0) {
 		context_set_material(project_materials[mpos > 0 ? mpos - 1 : 0]);
 	}

+ 176 - 96
armorpaint/Sources/tab_layers.ts

@@ -54,14 +54,18 @@ function tab_layers_button_2d_view() {
 	if (zui_button(tr("2D View"))) {
 		ui_base_show_2d_view(view_2d_type_t.LAYER);
 	}
-	else if (ui.is_hovered) zui_tooltip(tr("Show 2D View") + ` (${config_keymap.toggle_2d_view})`);
+	else if (ui.is_hovered) {
+		zui_tooltip(tr("Show 2D View") + ` (${config_keymap.toggle_2d_view})`);
+	}
 }
 
 function 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
+		if (i >= project_layers.length) {
+			break; // Layer was deleted
+		}
 		let j: i32 = project_layers.length - 1 - i;
-		let l: SlotLayerRaw = project_layers[j];
+		let l: slot_layer_t = project_layers[j];
 		tab_layers_draw_layer_slot(l, j, mini);
 	}
 }
@@ -79,8 +83,8 @@ function tab_layers_highlight_odd_lines() {
 
 function tab_layers_button_new(text: string) {
 	if (zui_button(text)) {
-		ui_menu_draw((ui: zui_t) => {
-			let l: SlotLayerRaw = context_raw.layer;
+		ui_menu_draw(function (ui: zui_t) {
+			let l: slot_layer_t = context_raw.layer;
 			if (ui_menu_button(ui, tr("Paint Layer"))) {
 				base_new_layer();
 				history_new_layer();
@@ -92,11 +96,13 @@ function tab_layers_button_new(text: string) {
 				base_create_fill_layer(uv_type_t.PROJECT);
 			}
 			if (ui_menu_button(ui, tr("Black Mask"))) {
-				if (slot_layer_is_mask(l)) context_set_layer(l.parent);
-				// let l: SlotLayerRaw = raw.layer;
+				if (slot_layer_is_mask(l)) {
+					context_set_layer(l.parent);
+				}
+				// let l: slot_layer_t = raw.layer;
 
-				let m: SlotLayerRaw = base_new_mask(false, l);
-				let _next = () => {
+				let m: slot_layer_t = base_new_mask(false, l);
+				let _next = function () {
 					slot_layer_clear(m, 0x00000000);
 				}
 				base_notify_on_next_frame(_next);
@@ -105,11 +111,13 @@ function tab_layers_button_new(text: string) {
 				base_update_fill_layers();
 			}
 			if (ui_menu_button(ui, tr("White Mask"))) {
-				if (slot_layer_is_mask(l)) context_set_layer(l.parent);
-				// let l: SlotLayerRaw = raw.layer;
+				if (slot_layer_is_mask(l)) {
+					context_set_layer(l.parent);
+				}
+				// let l: slot_layer_t = raw.layer;
 
-				let m: SlotLayerRaw = base_new_mask(false, l);
-				let _next = () => {
+				let m: slot_layer_t = base_new_mask(false, l);
+				let _next = function () {
 					slot_layer_clear(m, 0xffffffff);
 				}
 				base_notify_on_next_frame(_next);
@@ -118,11 +126,13 @@ function tab_layers_button_new(text: string) {
 				base_update_fill_layers();
 			}
 			if (ui_menu_button(ui, tr("Fill Mask"))) {
-				if (slot_layer_is_mask(l)) context_set_layer(l.parent);
-				// let l: SlotLayerRaw = raw.layer;
+				if (slot_layer_is_mask(l)) {
+					context_set_layer(l.parent);
+				}
+				// let l: slot_layer_t = raw.layer;
 
-				let m: SlotLayerRaw = base_new_mask(false, l);
-				let _init = () => {
+				let m: slot_layer_t = base_new_mask(false, l);
+				let _init = function () {
 					slot_layer_to_fill_layer(m);
 				}
 				app_notify_on_init(_init);
@@ -132,17 +142,23 @@ function tab_layers_button_new(text: string) {
 			}
 			ui.enabled = !slot_layer_is_group(context_raw.layer) && !slot_layer_is_in_group(context_raw.layer);
 			if (ui_menu_button(ui, tr("Group"))) {
-				if (slot_layer_is_group(l) || slot_layer_is_in_group(l)) return;
+				if (slot_layer_is_group(l) || slot_layer_is_in_group(l)) {
+					return;
+				}
 
-				if (slot_layer_is_layer_mask(l)) l = l.parent;
+				if (slot_layer_is_layer_mask(l)) {
+					l = l.parent;
+				}
 
-				let pointers: map_t<SlotLayerRaw, i32> = tab_layers_init_layer_map();
+				let pointers: map_t<slot_layer_t, i32> = 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);
+				array_insert(project_layers, array_index_of(project_layers, l) + 1, group);
 				l.parent = group;
-				for (let m of project_materials) tab_layers_remap_layer_pointers(m.canvas.nodes, tab_layers_fill_layer_map(pointers));
+				for (let m of project_materials) {
+					tab_layers_remap_layer_pointers(m.canvas.nodes, tab_layers_fill_layer_map(pointers));
+				}
 				context_set_layer(group);
 				history_new_group();
 			}
@@ -153,9 +169,15 @@ function tab_layers_button_new(text: string) {
 
 function tab_layers_combo_filter() {
 	let ar: string[] = [tr("All")];
-	for (let p of project_paint_objects) ar.push(p.base.name);
+	for (let p of project_paint_objects) {
+		array_push(ar, p.base.name);
+	}
 	let atlases: string[] = project_get_used_atlases();
-	if (atlases != null) for (let a of atlases) ar.push(a);
+	if (atlases != null) {
+		for (let a of atlases) {
+			array_push(ar, a);
+		}
+	}
 	let filter_handle: zui_handle_t = zui_handle("tablayers_0");
 	filter_handle.position = context_raw.layer_filter;
 	context_raw.layer_filter = zui_combo(filter_handle, ar, tr("Filter"), false, zui_align_t.LEFT);
@@ -168,7 +190,11 @@ function tab_layers_combo_filter() {
 		}
 		else if (context_raw.layer_filter > project_paint_objects.length) { // Atlas
 			let visibles: mesh_object_t[] = [];
-			for (let p of project_paint_objects) if (p.base.visible) visibles.push(p);
+			for (let p of project_paint_objects) {
+				if (p.base.visible) {
+					array_push(visibles, p);
+				}
+			}
 			util_mesh_merge(visibles);
 		}
 		base_set_object_mask();
@@ -185,32 +211,36 @@ function tab_layers_remap_layer_pointers(nodes: zui_node_t[], pointer_map: map_t
 		if (n.type == "LAYER" || n.type == "LAYER_MASK") {
 			let i: any = n.buttons[0].default_value;
 			if (pointer_map.has(i)) {
-				n.buttons[0].default_value = pointer_map.get(i);
+				n.buttons[0].default_value = map_get(pointer_map, i);
 			}
 		}
 	}
 }
 
-function 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);
+function tab_layers_init_layer_map(): map_t<slot_layer_t, i32> {
+	let res: map_t<slot_layer_t, i32> = map_create();
+	for (let i: i32 = 0; i < project_layers.length; ++i) {
+		map_set(res, project_layers[i], i);
+	}
 	return res;
 }
 
-function tab_layers_fill_layer_map(map: map_t<SlotLayerRaw, i32>): map_t<i32, i32> {
+function tab_layers_fill_layer_map(map: map_t<slot_layer_t, 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);
+	for (let l of map.keys()) {
+		map_set(res, map_get(map, l), array_index_of(project_layers, l) > -1 ? array_index_of(project_layers, l) : 9999);
+	}
 	return res;
 }
 
-function tab_layers_set_drag_layer(layer: SlotLayerRaw, off_x: f32, off_y: f32) {
+function tab_layers_set_drag_layer(layer: slot_layer_t, 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);
+	context_raw.drag_dest = array_index_of(project_layers, layer);
 }
 
-function tab_layers_draw_layer_slot(l: SlotLayerRaw, i: i32, mini: bool) {
+function tab_layers_draw_layer_slot(l: slot_layer_t, i: i32, mini: bool) {
 	let ui: zui_t = ui_base_ui;
 
 	if (context_raw.layer_filter > 0 &&
@@ -233,10 +263,10 @@ function tab_layers_draw_layer_slot(l: SlotLayerRaw, i: i32, mini: bool) {
 	let absy: f32 = ui._window_y + ui._y;
 	if (base_is_dragging && base_drag_layer != null && context_in_layers()) {
 		if (mouse_y > absy + step && mouse_y < absy + step * 3) {
-			let down: bool = project_layers.indexOf(base_drag_layer) >= i;
+			let down: bool = array_index_of(project_layers, base_drag_layer) >= i;
 			context_raw.drag_dest = down ? i : i - 1;
 
-			let ls: SlotLayerRaw[] = project_layers;
+			let ls: slot_layer_t[] = 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 = slot_layer_is_group(base_drag_layer) && to_group;
@@ -256,13 +286,15 @@ function tab_layers_draw_layer_slot(l: SlotLayerRaw, i: i32, mini: bool) {
 	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 (tab_layers_can_drop_new_layer(i))
+			if (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 (tab_layers_can_drop_new_layer(project_layers.length))
+			if (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);
+			}
 		}
 	}
 
@@ -275,7 +307,7 @@ function tab_layers_draw_layer_slot(l: SlotLayerRaw, i: i32, mini: bool) {
 	}
 }
 
-function tab_layers_draw_layer_slot_mini(l: SlotLayerRaw, i: i32) {
+function tab_layers_draw_layer_slot_mini(l: slot_layer_t, i: i32) {
 	let ui = ui_base_ui;
 
 	zui_row([1, 1]);
@@ -289,7 +321,7 @@ function tab_layers_draw_layer_slot_mini(l: SlotLayerRaw, i: i32) {
 	ui._y -= zui_ELEMENT_OFFSET(ui);
 }
 
-function tab_layers_draw_layer_slot_full(l: SlotLayerRaw, i: i32) {
+function tab_layers_draw_layer_slot_full(l: slot_layer_t, i: i32) {
 	let ui: zui_t = ui_base_ui;
 
 	let step: i32 = ui.t.ELEMENT_H;
@@ -311,7 +343,9 @@ function tab_layers_draw_layer_slot_full(l: SlotLayerRaw, i: i32) {
 	ui._y += center;
 	let col: i32 = ui.t.ACCENT_SELECT_COL;
 	let parent_hidden: bool = l.parent != null && (!l.parent.visible || (l.parent.parent != null && !l.parent.parent.visible));
-	if (parent_hidden) col -= 0x99000000;
+	if (parent_hidden) {
+		col -= 0x99000000;
+	}
 
 	if (zui_image(icons, col, -1.0, r.x, r.y, r.w, r.h) == zui_state_t.RELEASED) {
 		tab_layers_layer_toggle_visible(l);
@@ -380,10 +414,10 @@ function tab_layers_draw_layer_slot_full(l: SlotLayerRaw, i: i32) {
 		}
 
 		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;
+							 ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
 		if (in_focus && ui.is_delete_down && tab_layers_can_delete(context_raw.layer)) {
 			ui.is_delete_down = false;
-			let _init = () => {
+			let _init = function () {
 				tab_layers_delete_layer(context_raw.layer);
 			}
 			app_notify_on_init(_init);
@@ -442,11 +476,17 @@ function tab_layers_draw_layer_slot_full(l: SlotLayerRaw, i: i32) {
 	ui._y -= zui_ELEMENT_OFFSET(ui);
 }
 
-function tab_layers_combo_object(ui: zui_t, l: SlotLayerRaw, label = false): zui_handle_t {
+function tab_layers_combo_object(ui: zui_t, l: slot_layer_t, label = false): zui_handle_t {
 	let ar: string[] = [tr("Shared")];
-	for (let p of project_paint_objects) ar.push(p.base.name);
+	for (let p of project_paint_objects) {
+		array_push(ar, p.base.name);
+	}
 	let atlases: string[] = project_get_used_atlases();
-	if (atlases != null) for (let a of atlases) ar.push(a);
+	if (atlases != null) {
+		for (let a of atlases) {
+			array_push(ar, a);
+		}
+	}
 	let object_handle: zui_handle_t = zui_nest(zui_handle("tablayers_2"), l.id);
 	object_handle.position = l.object_mask;
 	l.object_mask = zui_combo(object_handle, ar, tr("Object"), label, zui_align_t.LEFT);
@@ -454,7 +494,7 @@ function tab_layers_combo_object(ui: zui_t, l: SlotLayerRaw, label = false): zui
 		context_set_layer(l);
 		make_material_parse_mesh_material();
 		if (l.fill_layer != null) { // Fill layer
-			let _init = () => {
+			let _init = function () {
 				context_raw.material = l.fill_layer;
 				slot_layer_clear(l);
 				base_update_fill_layers();
@@ -468,7 +508,7 @@ function tab_layers_combo_object(ui: zui_t, l: SlotLayerRaw, label = false): zui
 	return object_handle;
 }
 
-function tab_layers_combo_blending(ui: zui_t, l: SlotLayerRaw, label = false): zui_handle_t {
+function tab_layers_combo_blending(ui: zui_t, l: slot_layer_t, 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, [
@@ -500,13 +540,13 @@ function tab_layers_combo_blending(ui: zui_t, l: SlotLayerRaw, label = false): z
 	return blending_handle;
 }
 
-function tab_layers_layer_toggle_visible(l: SlotLayerRaw) {
+function tab_layers_layer_toggle_visible(l: slot_layer_t) {
 	l.visible = !l.visible;
 	ui_view2d_hwnd.redraws = 2;
 	make_material_parse_mesh_material();
 }
 
-function tab_layers_draw_layer_highlight(l: SlotLayerRaw, mini: bool) {
+function tab_layers_draw_layer_highlight(l: slot_layer_t, mini: bool) {
 	let ui: zui_t = ui_base_ui;
 	let step: i32 = ui.t.ELEMENT_H;
 
@@ -524,7 +564,7 @@ function tab_layers_draw_layer_highlight(l: SlotLayerRaw, mini: bool) {
 	}
 }
 
-function tab_layers_handle_layer_icon_state(l: SlotLayerRaw, i: i32, state: zui_state_t, uix: f32, uiy: f32) {
+function tab_layers_handle_layer_icon_state(l: slot_layer_t, i: i32, state: zui_state_t, uix: f32, uiy: f32) {
 	let ui: zui_t = ui_base_ui;
 
 	///if is_paint
@@ -545,8 +585,12 @@ function tab_layers_handle_layer_icon_state(l: SlotLayerRaw, i: i32, state: zui_
 		else {
 			zui_tooltip_image(texpaint_preview);
 		}
-		if (i < 9) zui_tooltip(l.name + " - (" + config_keymap.select_layer + " " + (i + 1) + ")");
-		else zui_tooltip(l.name);
+		if (i < 9) {
+			zui_tooltip(l.name + " - (" + config_keymap.select_layer + " " + (i + 1) + ")");
+		}
+		else {
+			zui_tooltip(l.name);
+		}
 	}
 
 	// Show context menu
@@ -566,11 +610,13 @@ function tab_layers_handle_layer_icon_state(l: SlotLayerRaw, i: i32, state: zui_
 		if (time_time() - context_raw.select_time > 0.2) {
 			context_raw.select_time = time_time();
 		}
-		if (l.fill_layer != null) context_set_material(l.fill_layer);
+		if (l.fill_layer != null) {
+			context_set_material(l.fill_layer);
+		}
 	}
 }
 
-function tab_layers_draw_layer_icon(l: SlotLayerRaw, i: i32, uix: f32, uiy: f32, mini: bool) {
+function tab_layers_draw_layer_icon(l: slot_layer_t, 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;
@@ -627,7 +673,7 @@ function tab_layers_draw_layer_icon(l: SlotLayerRaw, i: i32, uix: f32, uiy: f32,
 		let is_typing: bool = ui.is_typing || ui_view2d_ui.is_typing || ui_nodes_ui.is_typing;
 		if (!is_typing) {
 			if (i < 9 && operator_shortcut(config_keymap.select_layer, shortcut_type_t.DOWN)) {
-				let number: string = String(i + 1) ;
+				let number: string = any_to_string(i + 1) ;
 				let width: i32 = g2_font_width(ui.font, ui.font_size, number) + 10;
 				let height: i32 = g2_font_height(ui.font, ui.font_size);
 				g2_set_color(ui.t.TEXT_COL);
@@ -647,34 +693,54 @@ function tab_layers_draw_layer_icon(l: SlotLayerRaw, i: i32, uix: f32, uiy: f32,
 	}
 }
 
-function tab_layers_can_merge_down(l: SlotLayerRaw) : bool {
-	let index: i32 = project_layers.indexOf(l);
+function tab_layers_can_merge_down(l: slot_layer_t) : bool {
+	let index: i32 = array_index_of(project_layers, l);
 	// Lowest layer
-	if (index == 0) return false;
+	if (index == 0) {
+		return false;
+	}
 	// Lowest layer that has masks
-	if (slot_layer_is_layer(l) && slot_layer_is_mask(project_layers[0]) && project_layers[0].parent == l) return false;
+	if (slot_layer_is_layer(l) && slot_layer_is_mask(project_layers[0]) && project_layers[0].parent == l) {
+		return false;
+	}
 	// The lowest toplevel layer is a group
-	if (slot_layer_is_group(l) && slot_layer_is_in_group(project_layers[0]) && slot_layer_get_containing_group(project_layers[0]) == l) return false;
+	if (slot_layer_is_group(l) && slot_layer_is_in_group(project_layers[0]) && slot_layer_get_containing_group(project_layers[0]) == l) {
+		return false;
+	}
 	// Masks must be merged down to masks
-	if (slot_layer_is_mask(l) && !slot_layer_is_mask(project_layers[index - 1])) return false;
+	if (slot_layer_is_mask(l) && !slot_layer_is_mask(project_layers[index - 1])) {
+		return false;
+	}
 	return true;
 }
 
-function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
+function tab_layers_draw_layer_context_menu(l: slot_layer_t, mini: bool) {
 	let add: i32 = 0;
 
-	if (l.fill_layer == null) add += 1; // Clear
-	if (l.fill_layer != null && !slot_layer_is_mask(l)) add += 3;
-	if (l.fill_layer != null && slot_layer_is_mask(l)) add += 2;
-	if (slot_layer_is_mask(l)) add += 2;
+	if (l.fill_layer == null) {
+		add += 1; // Clear
+	}
+	if (l.fill_layer != null && !slot_layer_is_mask(l)) {
+		add += 3;
+	}
+	if (l.fill_layer != null && slot_layer_is_mask(l)) {
+		add += 2;
+	}
+	if (slot_layer_is_mask(l)) {
+		add += 2;
+	}
 	if (mini) {
 		add += 1;
-		if (!slot_layer_is_group(l)) add += 1;
-		if (slot_layer_is_layer(l)) add += 1;
+		if (!slot_layer_is_group(l)) {
+			add += 1;
+		}
+		if (slot_layer_is_layer(l)) {
+			add += 1;
+		}
 	}
 	let menu_elements: i32 = slot_layer_is_group(l) ? 7 : (19 + add);
 
-	ui_menu_draw((ui: zui_t) => {
+	ui_menu_draw(function (ui: zui_t) {
 
 		if (mini) {
 			let visible_handle: zui_handle_t = zui_handle("tablayers_4");
@@ -702,10 +768,14 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 
 		if (ui_menu_button(ui, tr("Export"))) {
 			if (slot_layer_is_mask(l)) {
-				ui_files_show("png", true, false, (path: string) => {
+				ui_files_show("png", true, false, function (path: string) {
 					let f: string = ui_files_filename;
-					if (f == "") f = tr("untitled");
-					if (!f.endsWith(".png")) f += ".png";
+					if (f == "") {
+						f = tr("untitled");
+					}
+					if (!ends_with(f, ".png")) {
+						f += ".png";
+					}
 					krom_write_png(path + path_sep + f, image_get_pixels(l.texpaint), l.texpaint.width, l.texpaint.height, 3); // RRR1
 				});
 			}
@@ -722,14 +792,14 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 			let to_paint_string: string = 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 = () => {
+				let _init = function () {
 					slot_layer_is_layer(l) ? history_to_fill_layer() : history_to_fill_mask();
 					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 = () => {
+				let _init = function () {
 					slot_layer_is_layer(l) ? history_to_paint_layer() : history_to_paint_mask();
 					slot_layer_to_paint_layer(l);
 				}
@@ -739,7 +809,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 
 		ui.enabled = tab_layers_can_delete(l);
 		if (ui_menu_button(ui, tr("Delete"), "delete")) {
-			let _init = () => {
+			let _init = function () {
 				tab_layers_delete_layer(context_raw.layer);
 			}
 			app_notify_on_init(_init);
@@ -748,7 +818,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 
 		if (l.fill_layer == null && ui_menu_button(ui, tr("Clear"))) {
 			context_set_layer(l);
-			let _init = () => {
+			let _init = function () {
 				if (!slot_layer_is_group(l)) {
 					history_clear_layer();
 					slot_layer_clear(l);
@@ -766,7 +836,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 			app_notify_on_init(_init);
 		}
 		if (slot_layer_is_mask(l) && l.fill_layer == null && ui_menu_button(ui, tr("Invert"))) {
-			let _init = () => {
+			let _init = function () {
 				context_set_layer(l);
 				history_invert_mask();
 				slot_layer_invert_mask(l);
@@ -774,7 +844,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 			app_notify_on_init(_init);
 		}
 		if (slot_layer_is_mask(l) && ui_menu_button(ui, tr("Apply"))) {
-			let _init = () => {
+			let _init = function () {
 				context_raw.layer = l;
 				history_apply_mask();
 				slot_layer_apply_mask(l);
@@ -785,14 +855,14 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 			app_notify_on_init(_init);
 		}
 		if (slot_layer_is_group(l) && ui_menu_button(ui, tr("Merge Group"))) {
-			let _init = () => {
+			let _init = function () {
 				base_merge_group(l);
 			}
 			app_notify_on_init(_init);
 		}
 		ui.enabled = tab_layers_can_merge_down(l);
 		if (ui_menu_button(ui, tr("Merge Down"))) {
-			let _init = () => {
+			let _init = function () {
 				context_set_layer(l);
 				history_merge_layers();
 				base_merge_down();
@@ -802,7 +872,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 		}
 		ui.enabled = true;
 		if (ui_menu_button(ui, tr("Duplicate"))) {
-			let _init = () => {
+			let _init = function () {
 				context_set_layer(l);
 				history_duplicate_layer();
 				base_duplicate_layer(l);
@@ -816,7 +886,9 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 		layer_opac_handle.value = l.mask_opacity;
 		zui_slider(layer_opac_handle, tr("Opacity"), 0.0, 1.0, true);
 		if (layer_opac_handle.changed) {
-			if (ui.input_started) history_layer_opacity();
+			if (ui.input_started) {
+				history_layer_opacity();
+			}
 			l.mask_opacity = layer_opac_handle.value;
 			make_material_parse_mesh_material();
 			ui_menu_keep_open = true;
@@ -866,7 +938,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 			if (scale_handle.changed) {
 				context_set_material(l.fill_layer);
 				context_set_layer(l);
-				let _init = () => {
+				let _init = function () {
 					base_update_fill_layers();
 				}
 				app_notify_on_init(_init);
@@ -882,7 +954,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 				context_set_material(l.fill_layer);
 				context_set_layer(l);
 				make_material_parse_paint_material();
-				let _init = () => {
+				let _init = function () {
 					base_update_fill_layers();
 				}
 				app_notify_on_init(_init);
@@ -898,7 +970,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 				context_set_material(l.fill_layer);
 				context_set_layer(l);
 				make_material_parse_paint_material();
-				let _init = () => {
+				let _init = function () {
 					base_update_fill_layers();
 				}
 				app_notify_on_init(_init);
@@ -969,7 +1041,7 @@ function tab_layers_draw_layer_context_menu(l: SlotLayerRaw, mini: bool) {
 	}, menu_elements);
 }
 
-function tab_layers_make_mask_preview_rgba32(l: SlotLayerRaw) {
+function tab_layers_make_mask_preview_rgba32(l: slot_layer_t) {
 	///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);
@@ -977,7 +1049,7 @@ function tab_layers_make_mask_preview_rgba32(l: SlotLayerRaw) {
 	// Convert from R8 to RGBA32 for tooltip display
 	if (context_raw.mask_preview_last != l) {
 		context_raw.mask_preview_last = l;
-		app_notify_on_init(() => {
+		app_notify_on_init(function () {
 			g2_begin(context_raw.mask_preview_rgba32);
 			g2_set_pipeline(ui_view2d_pipe);
 			g4_set_int(ui_view2d_channel_loc, 1);
@@ -989,8 +1061,8 @@ function tab_layers_make_mask_preview_rgba32(l: SlotLayerRaw) {
 	///end
 }
 
-function tab_layers_delete_layer(l: SlotLayerRaw) {
-	let pointers: map_t<SlotLayerRaw, i32> = tab_layers_init_layer_map();
+function tab_layers_delete_layer(l: slot_layer_t) {
+	let pointers: map_t<slot_layer_t, i32> = tab_layers_init_layer_map();
 
 	if (slot_layer_is_layer(l) && slot_layer_has_masks(l, false)) {
 		for (let m of slot_layer_get_masks(l, false)) {
@@ -1032,7 +1104,7 @@ function tab_layers_delete_layer(l: SlotLayerRaw) {
 
 	// Remove empty group
 	if (slot_layer_is_in_group(l) && slot_layer_get_children(slot_layer_get_containing_group(l)) == null) {
-		let g: SlotLayerRaw = slot_layer_get_containing_group(l);
+		let g: slot_layer_t = slot_layer_get_containing_group(l);
 		// Maybe some group masks are left
 		if (slot_layer_has_masks(g)) {
 			for (let m of slot_layer_get_masks(g)) {
@@ -1046,20 +1118,28 @@ function tab_layers_delete_layer(l: SlotLayerRaw) {
 		slot_layer_delete(l.parent);
 	}
 	context_raw.ddirty = 2;
-	for (let m of project_materials) tab_layers_remap_layer_pointers(m.canvas.nodes, tab_layers_fill_layer_map(pointers));
+	for (let m of project_materials) {
+		tab_layers_remap_layer_pointers(m.canvas.nodes, tab_layers_fill_layer_map(pointers));
+	}
 }
 
-function tab_layers_can_delete(l: SlotLayerRaw) {
+function tab_layers_can_delete(l: slot_layer_t) {
 	let num_layers: i32 = 0;
 
-	if (slot_layer_is_mask(l)) return true;
+	if (slot_layer_is_mask(l)) {
+		return true;
+	}
 
 	for (let slot of project_layers) {
-		if (slot_layer_is_layer(slot)) ++num_layers;
+		if (slot_layer_is_layer(slot)) {
+			++num_layers;
+		}
 	}
 
 	// All layers are in one group
-	if (slot_layer_is_group(l) && slot_layer_get_children(l).length == num_layers) return false;
+	if (slot_layer_is_group(l) && slot_layer_get_children(l).length == num_layers) {
+		return false;
+	}
 
 	// Do not delete last layer
 	return num_layers > 1;

+ 21 - 19
armorsculpt/Sources/export_obj.ts

@@ -1,7 +1,7 @@
 
 function export_obj_write_string(out: i32[], str: string) {
 	for (let i = 0; i < str.length; ++i) {
-		out.push(str.charCodeAt(i));
+		array_push(out, char_code_at(str, i));
 	}
 }
 
@@ -11,16 +11,16 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 
 	let texpaint = project_layers[0].texpaint;
 	let pixels = image_get_pixels(texpaint);
-	let pixelsView = new DataView(pixels);
+	let pixelsView = buffer_view_create(pixels);
 	let mesh = paint_objects[0].data;
 	let inda = mesh.index_arrays[0].values;
 
-	let posa = new Int16Array(inda.length * 4);
+	let posa: i16_array_t = i16_array_create(inda.length * 4);
 	for (let i = 0; i < inda.length; ++i) {
 		let index = inda[i];
-		posa[index * 4    ] = math_floor(pixelsView.getFloat32(i * 16    , true) * 32767);
-		posa[index * 4 + 1] = math_floor(pixelsView.getFloat32(i * 16 + 4, true) * 32767);
-		posa[index * 4 + 2] = math_floor(pixelsView.getFloat32(i * 16 + 8, true) * 32767);
+		posa[index * 4    ] = math_floor(buffer_view_get_f32(pixelsView, i * 16    ) * 32767);
+		posa[index * 4 + 1] = math_floor(buffer_view_get_f32(pixelsView, i * 16 + 4) * 32767);
+		posa[index * 4 + 2] = math_floor(buffer_view_get_f32(pixelsView, i * 16 + 8) * 32767);
 	}
 
 	let poff = 0;
@@ -34,8 +34,8 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 		// let len = math_floor(inda.length);
 
 		// Merge shared vertices and remap indices
-		let posa2 = new Int16Array(len * 3);
-		let posmap = new map_t<i32, i32>();
+		let posa2: i16_array_t = i16_array_create(len * 3);
+		let posmap: map_t<i32, i32> = map_create();
 
 		let pi = 0;
 		for (let i = 0; i < len; ++i) {
@@ -44,13 +44,13 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 				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);
+					map_set(posmap, i, j);
 					found = true;
 					break;
 				}
 			}
 			if (!found) {
-				posmap.set(i, pi);
+				map_set(posmap, i, pi);
 				posa2[pi * 3    ] = posa[i * 4    ];
 				posa2[pi * 3 + 1] = posa[i * 4 + 1];
 				posa2[pi * 3 + 2] = posa[i * 4 + 2];
@@ -62,21 +62,21 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 		for (let i = 0; i < pi; ++i) {
 			export_obj_write_string(o, "v ");
 			let vx = posa2[i * 3] * sc + "";
-			export_obj_write_string(o, vx.substr(0, vx.indexOf(".") + 7));
+			export_obj_write_string(o, substring(vx, 0, string_index_of(vx, ".") + 7));
 			export_obj_write_string(o, " ");
 			let vy = posa2[i * 3 + 2] * sc + "";
-			export_obj_write_string(o, vy.substr(0, vy.indexOf(".") + 7));
+			export_obj_write_string(o, substring(vy, 0, string_index_of(vy, ".") + 7));
 			export_obj_write_string(o, " ");
 			let vz = -posa2[i * 3 + 1] * sc + "";
-			export_obj_write_string(o, vz.substr(0, vz.indexOf(".") + 7));
+			export_obj_write_string(o, substring(vz, 0, string_index_of(vz, ".") + 7));
 			export_obj_write_string(o, "\n");
 		}
 
 		// let inda = mesh.index_arrays[0].values;
 		for (let i = 0; i < math_floor(inda.length / 3); ++i) {
-			let pi1 = posmap.get(inda[i * 3    ]) + 1 + poff;
-			let pi2 = posmap.get(inda[i * 3 + 1]) + 1 + poff;
-			let pi3 = posmap.get(inda[i * 3 + 2]) + 1 + poff;
+			let pi1 = map_get(posmap, inda[i * 3    ]) + 1 + poff;
+			let pi2 = map_get(posmap, inda[i * 3 + 1]) + 1 + poff;
+			let pi3 = map_get(posmap, inda[i * 3 + 2]) + 1 + poff;
 			export_obj_write_string(o, "f ");
 			export_obj_write_string(o, pi1 + "");
 			export_obj_write_string(o, " ");
@@ -88,8 +88,10 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 		poff += pi;
 	// }
 
-	if (!path.endsWith(".obj")) path += ".obj";
+	if (!ends_with(path, ".obj")) {
+		path += ".obj";
+	}
 
-	let b = Uint8Array.from(o).buffer;
-	krom_file_save_bytes(path, b, b.byteLength);
+	let b = u8_array_t.from(o).buffer;
+	krom_file_save_bytes(path, b, buffer_size(b));
 }

+ 53 - 29
armorsculpt/Sources/import_mesh.ts

@@ -12,13 +12,17 @@ function import_mesh_run(path: string, _clear_layers = true, replace_existing =
 	import_mesh_clear_layers = _clear_layers;
 	context_raw.layer_filter = 0;
 
-	let p = path.toLowerCase();
-	if (p.endsWith(".obj")) import_obj_run(path, replace_existing);
-	else if (p.endsWith(".blend")) import_blend_mesh_run(path, replace_existing);
+	let p = to_lower_case(path);
+	if (ends_with(p, ".obj")) {
+		import_obj_run(path, replace_existing);
+	}
+	else if (ends_with(p, ".blend")) {
+		import_blend_mesh_run(path, replace_existing);
+	}
 	else {
-		let ext = path.substr(path.lastIndexOf(".") + 1);
-		let importer = path_mesh_importers.get(ext);
-		importer(path, (mesh: any) => {
+		let ext = substring(path, string_last_index_of(path, ".") + 1, path.length);
+		let importer = map_get(path_mesh_importers, ext);
+		importer(path, function (mesh: any) {
 			replace_existing ? import_mesh_make_mesh(mesh, path) : import_mesh_add_mesh(mesh);
 		});
 	}
@@ -26,7 +30,7 @@ function import_mesh_run(path: string, _clear_layers = true, replace_existing =
 	project_mesh_assets = [path];
 
 	///if (krom_android || krom_ios)
-	sys_title_set(path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf(".")));
+	sys_title_set(substring(path, string_last_index_of(path, path_sep) + 1, string_last_index_of(path, ".")));
 	///end
 }
 
@@ -41,22 +45,32 @@ function import_mesh_finish_import() {
 
 	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;
+		array_sort(project_paint_objects, function (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();
+		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";
+	if (context_raw.paint_object.base.name == "") {
+		context_raw.paint_object.base.name = "Object";
+	}
 	make_material_parse_paint_material();
 	make_material_parse_mesh_material();
 
@@ -73,9 +87,11 @@ function import_mesh_make_mesh(mesh: any, path: string) {
 		return;
 	}
 
-	let _makeMesh = () => {
+	let _make_mesh = function() {
 		let raw = import_mesh_raw_mesh(mesh);
-		if (mesh.cola != null) raw.vertex_arrays.push({ values: mesh.cola, attrib: "col", data: "short4norm" });
+		if (mesh.cola != null) {
+			array_push(raw.vertex_arrays, { values: mesh.cola, attrib: "col", data: "short4norm" });
+		}
 
 		let md: mesh_data_t = mesh_data_create(raw);
 		context_raw.paint_object = context_main_object();
@@ -83,7 +99,9 @@ function import_mesh_make_mesh(mesh: any, path: string) {
 		context_select_paint_object(context_main_object());
 		for (let i = 0; i < project_paint_objects.length; ++i) {
 			let p = project_paint_objects[i];
-			if (p == context_raw.paint_object) continue;
+			if (p == context_raw.paint_object) {
+				continue;
+			}
 			data_delete_mesh(p.data._.handle);
 			mesh_object_remove(p);
 		}
@@ -107,7 +125,7 @@ function import_mesh_make_mesh(mesh: any, path: string) {
 		project_paint_objects = [context_raw.paint_object];
 
 		md._.handle = raw.name;
-		data_cached_meshes.set(md._.handle, md);
+		map_set(data_cached_meshes, md._.handle, md);
 
 		context_raw.ddirty = 4;
 		ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
@@ -116,8 +134,8 @@ function import_mesh_make_mesh(mesh: any, path: string) {
 		// Wait for addMesh calls to finish
 		app_notify_on_init(import_mesh_finish_import);
 
-		base_notify_on_next_frame(() => {
-			let f32 = new Float32Array(config_get_texture_res_x() * config_get_texture_res_y() * 4);
+		base_notify_on_next_frame(function () {
+			let f32 = f32_array_create(config_get_texture_res_x() * config_get_texture_res_y() * 4);
 			for (let i = 0; i < math_floor(mesh.inda.length); ++i) {
 				let index = mesh.inda[i];
 				f32[i * 4]     = mesh.posa[index * 4]     / 32767;
@@ -135,14 +153,16 @@ function import_mesh_make_mesh(mesh: any, path: string) {
 		});
 	}
 
-	_makeMesh();
+	_make_mesh();
 }
 
 function import_mesh_add_mesh(mesh: any) {
 
-	let _addMesh = () => {
+	let _addMesh = function () {
 		let raw = import_mesh_raw_mesh(mesh);
-		if (mesh.cola != null) raw.vertex_arrays.push({ values: mesh.cola, attrib: "col", data: "short4norm" });
+		if (mesh.cola != null) {
+			array_push(raw.vertex_arrays, { values: mesh.cola, attrib: "col", data: "short4norm" });
+		}
 
 		let md: mesh_data_t = mesh_data_create(raw);
 
@@ -155,14 +175,14 @@ function import_mesh_add_mesh(mesh: any) {
 			if (p.base.name == object.base.name) {
 				p.base.name += ".001";
 				p.data._.handle += ".001";
-				data_cached_meshes.set(p.data._.handle, p.data);
+				map_set(data_cached_meshes, p.data._.handle, p.data);
 			}
 		}
 
-		project_paint_objects.push(object);
+		array_push(project_paint_objects, object);
 
 		md._.handle = raw.name;
-		data_cached_meshes.set(md._.handle, md);
+		map_set(data_cached_meshes, md._.handle, md);
 
 		context_raw.ddirty = 4;
 		ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
@@ -172,10 +192,14 @@ function import_mesh_add_mesh(mesh: any) {
 }
 
 function import_mesh_raw_mesh(mesh: any): mesh_data_t {
-	let posa = new Int16Array(math_floor(mesh.inda.length * 4));
-	for (let i = 0; i < posa.length; ++i) posa[i] = 32767;
-	let inda = new Uint32Array(mesh.inda.length);
-	for (let i = 0; i < inda.length; ++i) inda[i] = i;
+	let posa: i16_array_t = i16_array_create(math_floor(mesh.inda.length * 4));
+	for (let i: i32 = 0; i < posa.length; ++i) {
+		posa[i] = 32767;
+	}
+	let inda: u32_array_t = u32_array_create(mesh.inda.length);
+	for (let i: i32 = 0; i < inda.length; ++i) {
+		inda[i] = i;
+	}
 	return {
 		name: mesh.name,
 		vertex_arrays: [

+ 89 - 49
armorsculpt/Sources/make_material.ts

@@ -7,7 +7,11 @@ let make_material_emis_used: bool = false;
 let make_material_subs_used: bool = false;
 
 function make_material_get_mout(): bool {
-	for (let n of ui_nodes_get_canvas_material().nodes) if (n.type == "OUTPUT_MATERIAL_PBR") return true;
+	for (let n of ui_nodes_get_canvas_material().nodes) {
+		if (n.type == "OUTPUT_MATERIAL_PBR") {
+			return true;
+		}
+	}
 	return false;
 }
 
@@ -59,13 +63,13 @@ function make_material_parse_mesh_material() {
 	scon._.override_context = {};
 	if (con.frag.shared_samplers.length > 0) {
 		let sampler = con.frag.shared_samplers[0];
-		scon._.override_context.shared_sampler = sampler.substr(sampler.lastIndexOf(" ") + 1);
+		scon._.override_context.shared_sampler = substring(sampler, string_last_index_of(sampler, " ") + 1, sampler.length);
 	}
 	if (!context_raw.texture_filter) {
 		scon._.override_context.filter = "point";
 	}
-	m._.shader.contexts.push(scon);
-	m._.shader._.contexts.push(scon);
+	array_push(m._.shader.contexts, scon);
+	array_push(m._.shader._.contexts, scon);
 
 	for (let i = 1; i < make_mesh_layer_pass_count; ++i) {
 		let con = make_mesh_run({ name: "Material", canvas: null }, i);
@@ -73,17 +77,17 @@ function make_material_parse_mesh_material() {
 		scon._.override_context = {};
 		if (con.frag.shared_samplers.length > 0) {
 			let sampler = con.frag.shared_samplers[0];
-			scon._.override_context.shared_sampler = sampler.substr(sampler.lastIndexOf(" ") + 1);
+			scon._.override_context.shared_sampler = substring(sampler, string_last_index_of(sampler, " ") + 1, sampler.length);
 		}
 		if (!context_raw.texture_filter) {
 			scon._.override_context.filter = "point";
 		}
-		m._.shader.contexts.push(scon);
-		m._.shader._.contexts.push(scon);
+		array_push(m._.shader.contexts, scon);
+		array_push(m._.shader._.contexts, scon);
 
 		let mcon: material_context_t = material_context_create({ name: "mesh" + i, bind_textures: [] });
-		m.contexts.push(mcon);
-		m._.contexts.push(mcon);
+		array_push(m.contexts, mcon);
+		array_push(m._.contexts, mcon);
 	}
 
 	context_raw.ddirty = 2;
@@ -107,14 +111,18 @@ function make_material_parse_particle_material() {
 		array_remove(m._.shader._.contexts, sc);
 	}
 	let con = make_particle_run({ name: "MaterialParticle", canvas: null });
-	if (sc != null) make_material_delete_context(sc);
+	if (sc != null) {
+		make_material_delete_context(sc);
+	}
 	sc = shader_context_create(con.data);
-	m._.shader.contexts.push(sc);
-	m._.shader._.contexts.push(sc);
+	array_push(m._.shader.contexts, sc);
+	array_push(m._.shader._.contexts, sc);
 }
 
 function make_material_parse_mesh_preview_material() {
-	if (!make_material_get_mout()) return;
+	if (!make_material_get_mout()) {
+		return;
+	}
 
 	let m = project_materials[0].data;
 	let scon: shader_context_t = null;
@@ -139,16 +147,22 @@ function make_material_parse_mesh_preview_material() {
 		}
 	}
 
-	if (scon != null) make_material_delete_context(scon);
+	if (scon != null) {
+		make_material_delete_context(scon);
+	}
 
-	let compileError = false;
+	let compile_error = false;
 	let _scon: shader_context_t = shader_context_create(con.data);
-	if (_scon == null) compileError = true;
+	if (_scon == null) {
+		compile_error = true;
+	}
 	scon = _scon;
-	if (compileError) return;
+	if (compile_error) {
+		return;
+	}
 
-	m._.shader.contexts.push(scon);
-	m._.shader._.contexts.push(scon);
+	array_push(m._.shader.contexts, scon);
+	array_push(m._.shader._.contexts, scon);
 }
 
 ///if arm_voxels
@@ -162,13 +176,17 @@ function make_material_make_voxel(m: material_data_t) {
 				break;
 			}
 		}
-		if (scon != null) make_voxel_run(scon);
+		if (scon != null) {
+			make_voxel_run(scon);
+		}
 	}
 }
 ///end
 
 function make_material_parse_paint_material(bake_previews: bool = true) {
-	if (!make_material_get_mout()) return;
+	if (!make_material_get_mout()) {
+		return;
+	}
 
 	if (bake_previews) {
 		let current = _g2_current;
@@ -185,7 +203,9 @@ function make_material_parse_paint_material(bake_previews: bool = true) {
 		if (c.name == "paint") {
 			array_remove(m._.shader.contexts, c);
 			array_remove(m._.shader._.contexts, c);
-			if (c != make_material_default_scon) make_material_delete_context(c);
+			if (c != make_material_default_scon) {
+				make_material_delete_context(c);
+			}
 			break;
 		}
 	}
@@ -201,24 +221,32 @@ function make_material_parse_paint_material(bake_previews: bool = true) {
 	let mcon2: material_context_t = { name: "paint", bind_textures: [] };
 	let con = make_sculpt_run(sdata, mcon2);
 
-	let compileError = false;
+	let compile_error = false;
 	let scon2: shader_context_t;
 	let _scon: shader_context_t = shader_context_create(con.data);
-	if (_scon == null) compileError = true;
+	if (_scon == null) {
+		compile_error = true;
+	}
 	scon2 = _scon;
 
-	if (compileError) return;
+	if (compile_error) {
+		return;
+	}
 	scon2._.override_context = {};
 	scon2._.override_context.addressing = "repeat";
 	let mcon3: material_context_t = material_context_create(mcon2);
 
-	m._.shader.contexts.push(scon2);
-	m._.shader._.contexts.push(scon2);
-	m.contexts.push(mcon3);
-	m._.contexts.push(mcon3);
+	array_push(m._.shader.contexts, scon2);
+	array_push(m._.shader._.contexts, scon2);
+	array_push(m.contexts, mcon3);
+	array_push(m._.contexts, mcon3);
 
-	if (make_material_default_scon == null) make_material_default_scon = scon2;
-	if (make_material_default_mcon == null) make_material_default_mcon = mcon3;
+	if (make_material_default_scon == null) {
+		make_material_default_scon = scon2;
+	}
+	if (make_material_default_mcon == null) {
+		make_material_default_mcon = mcon3;
+	}
 }
 
 function make_material_bake_node_previews() {
@@ -226,10 +254,12 @@ function make_material_bake_node_previews() {
 	if (context_raw.node_previews == null) context_raw.node_previews = map_create();
 	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 = context_raw.node_previews.get(key);
-			base_notify_on_next_frame(function() { image_unload(image); });
-			context_raw.node_previews.delete(key);
+		if (array_index_of(context_raw.node_previews_used, key) == -1) {
+			let image = map_get(context_raw.node_previews, key);
+			base_notify_on_next_frame(function() {
+				image_unload(image);
+			});
+			map_delete(context_raw.node_previews, key);
 		}
 	}
 }
@@ -240,7 +270,7 @@ function make_material_traverse_nodes(nodes: zui_node_t[], group: zui_node_canva
 		if (node.type == "GROUP") {
 			for (let g of project_material_groups) {
 				if (g.canvas.name == node.name) {
-					parents.push(node);
+					array_push(parents, node);
 					make_material_traverse_nodes(g.canvas.nodes, g.canvas, parents);
 					parents.pop();
 					break;
@@ -253,14 +283,16 @@ function make_material_traverse_nodes(nodes: zui_node_t[], group: zui_node_canva
 function make_material_bake_node_preview(node: zui_node_t, group: zui_node_canvas_t, parents: zui_node_t[]) {
 	if (node.type == "BLUR") {
 		let id = parser_material_node_name(node, parents);
-		let image = context_raw.node_previews.get(id);
-		context_raw.node_previews_used.push(id);
+		let image = map_get(context_raw.node_previews, id);
+		array_push(context_raw.node_previews_used, id);
 		let resX = math_floor(config_get_texture_res_x() / 4);
 		let resY = math_floor(config_get_texture_res_y() / 4);
 		if (image == null || image.width != resX || image.height != resY) {
-			if (image != null) image_unload(image);
+			if (image != null) {
+				image_unload(image);
+			}
 			image = image_create_render_target(resX, resY);
-			context_raw.node_previews.set(id, image);
+			map_set(context_raw.node_previews, id, image);
 		}
 
 		parser_material_blur_passthrough = true;
@@ -269,14 +301,16 @@ function make_material_bake_node_preview(node: zui_node_t, group: zui_node_canva
 	}
 	else if (node.type == "DIRECT_WARP") {
 		let id = parser_material_node_name(node, parents);
-		let image = context_raw.node_previews.get(id);
-		context_raw.node_previews_used.push(id);
+		let image = map_get(context_raw.node_previews, id);
+		array_push(context_raw.node_previews_used, id);
 		let resX = math_floor(config_get_texture_res_x());
 		let resY = math_floor(config_get_texture_res_y());
 		if (image == null || image.width != resX || image.height != resY) {
-			if (image != null) image_unload(image);
+			if (image != null) {
+				image_unload(image);
+			}
 			image = image_create_render_target(resX, resY);
-			context_raw.node_previews.set(id, image);
+			map_set(context_raw.node_previews, id, image);
 		}
 
 		parser_material_warp_passthrough = true;
@@ -286,17 +320,23 @@ function make_material_bake_node_preview(node: zui_node_t, group: zui_node_canva
 }
 
 function make_material_parse_node_preview_material(node: zui_node_t, group: zui_node_canvas_t = null, parents: zui_node_t[] = null): { scon: shader_context_t, mcon: material_context_t } {
-	if (node.outputs.length == 0) return null;
+	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 = make_node_preview_run(sdata, mcon_raw, node, group, parents);
-	let compileError = false;
+	let compile_error = false;
 	let scon: shader_context_t;
 	let _scon: shader_context_t = shader_context_create(con.data);
-	if (_scon == null) compileError = true;
+	if (_scon == null) {
+		compile_error = true;
+	}
 	scon = _scon;
 
-	if (compileError) return null;
+	if (compile_error) {
+		return null;
+	}
 	let mcon: material_context_t = material_context_create(mcon_raw);
 	return { scon: scon, mcon: mcon };
 }
@@ -316,7 +356,7 @@ function make_material_voxelgi_half_extents(): string {
 }
 
 function make_material_delete_context(c: shader_context_t) {
-	base_notify_on_next_frame(() => { // Ensure pipeline is no longer in use
+	base_notify_on_next_frame(function () { // Ensure pipeline is no longer in use
 		shader_context_delete(c);
 	});
 }

+ 20 - 12
armorsculpt/Sources/make_mesh.ts

@@ -24,7 +24,7 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 	node_shader_add_uniform(vert, 'mat4 prevWVP', '_prev_world_view_proj_matrix');
 	vert.wposition = true;
 
-	let textureCount = 0;
+	let texture_count: i32 = 0;
 
 	node_shader_add_uniform(vert, 'mat4 WVP', '_world_view_proj_matrix');
 	node_shader_add_uniform(vert, 'sampler2D texpaint_vert', '_texpaint_vert' + project_layers[0].id);
@@ -97,12 +97,12 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 	}
 
 	if (context_raw.draw_wireframe) {
-		textureCount++;
+		texture_count++;
 		node_shader_add_uniform(frag, 'sampler2D texuvmap', '_texuvmap');
 	}
 
 	if (context_raw.viewport_mode == viewport_mode_t.LIT && context_raw.render_mode == render_mode_t.FORWARD) {
-		textureCount += 4;
+		texture_count += 4;
 		node_shader_add_uniform(frag, 'sampler2D senvmapBrdf', "$brdf.k");
 		node_shader_add_uniform(frag, 'sampler2D senvmapRadiance', '_envmap_radiance');
 		node_shader_add_uniform(frag, 'sampler2D sltcMat', '_ltcMat');
@@ -112,20 +112,24 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 	// Get layers for this pass
 	make_mesh_layer_pass_count = 1;
 	let layers: SlotLayerRaw[] = [];
-	let startCount = textureCount;
+	let startCount = texture_count;
 	for (let l of project_layers) {
-		if (!slot_layer_is_layer(l) || !slot_layer_is_visible(l)) continue;
+		if (!slot_layer_is_layer(l) || !slot_layer_is_visible(l)) {
+			continue;
+		}
 
 		let count = 3;
 		let masks = slot_layer_get_masks(l);
-		if (masks != null) count += masks.length;
-		textureCount += count;
-		if (textureCount >= make_mesh_get_max_textures()) {
-			textureCount = startCount + count + 3; // gbuffer0_copy, gbuffer1_copy, gbuffer2_copy
+		if (masks != null) {
+			count += masks.length;
+		}
+		texture_count += count;
+		if (texture_count >= make_mesh_get_max_textures()) {
+			texture_count = startCount + count + 3; // gbuffer0_copy, gbuffer1_copy, gbuffer2_copy
 			make_mesh_layer_pass_count++;
 		}
 		if (layer_pass == make_mesh_layer_pass_count - 1) {
-			layers.push(l);
+			array_push(layers, l);
 		}
 	}
 
@@ -138,7 +142,9 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 				let visibles = project_get_atlas_objects(slot_layer_get_object_mask(l));
 				node_shader_write(frag, 'if (');
 				for (let i = 0; i < visibles.length; ++i) {
-					if (i > 0) node_shader_write(frag, ' || ');
+					if (i > 0) {
+						node_shader_write(frag, ' || ');
+					}
 					node_shader_write(frag, `${visibles[i].base.uid} == uid`);
 				}
 				node_shader_write(frag, ') {');
@@ -286,7 +292,9 @@ function make_mesh_run(data: material_t, layer_pass: i32 = 0): NodeShaderContext
 				node_shader_write(frag, 'fragColor[1] = vec4(direct + indirect, 1.0);');
 			}
 			else { // Deferred, Pathtraced
-				if (make_material_emis_used) node_shader_write(frag, 'if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;'); // Boost for bloom
+				if (make_material_emis_used) {
+					node_shader_write(frag, 'if (int(matid * 255.0) % 3 == 1) basecol *= 10.0;'); // Boost for bloom
+				}
 				node_shader_write(frag, 'fragColor[1] = vec4(basecol, occlusion);');
 			}
 		}

+ 1 - 1
armorsculpt/Sources/make_sculpt.ts

@@ -51,7 +51,7 @@ function make_sculpt_run(data: material_t, matcon: material_context_t): NodeShad
 		context_raw.tool == workspace_tool_t.PARTICLE ||
 		decal) {
 
-		let depthReject = !context_raw.xray;
+		let depth_reject = !context_raw.xray;
 
 		make_brush_run(vert, frag);
 	}

+ 14 - 12
armorsculpt/Sources/nodes/brush_output_node.ts

@@ -22,11 +22,11 @@ function brush_output_node_parse_inputs(self: brush_output_node_t) {
 	let input3: any;
 	let input4: any;
 	try {
-		logic_node_input_get(self.base.inputs[0], (value) => { input0 = value; });
-		logic_node_input_get(self.base.inputs[1], (value) => { input1 = value; });
-		logic_node_input_get(self.base.inputs[2], (value) => { input2 = value; });
-		logic_node_input_get(self.base.inputs[3], (value) => { input3 = value; });
-		logic_node_input_get(self.base.inputs[4], (value) => { input4 = value; });
+		logic_node_input_get(self.base.inputs[0], function (value) { input0 = value; });
+		logic_node_input_get(self.base.inputs[1], function (value) { input1 = value; });
+		logic_node_input_get(self.base.inputs[2], function (value) { input2 = value; });
+		logic_node_input_get(self.base.inputs[3], function (value) { input3 = value; });
+		logic_node_input_get(self.base.inputs[4], function (value) { input4 = value; });
 	}
 	catch (_) {
 		return;
@@ -38,10 +38,10 @@ function brush_output_node_parse_inputs(self: brush_output_node_t) {
 	let opac: any = input2; // Float or texture name
 	if (opac == null) opac = 1.0;
 	if (typeof opac == "string") {
-		context_raw.brush_mask_image_is_alpha = opac.endsWith(".a");
-		opac = opac.substr(0, opac.lastIndexOf("."));
+		context_raw.brush_mask_image_is_alpha = ends_with(opac, ".a");
+		opac = substring(opac, 0, string_last_index_of(opac, "."));
 		context_raw.brush_nodes_opacity = 1.0;
-		let index = project_asset_names.indexOf(opac);
+		let index = array_index_of(project_asset_names, opac);
 		let asset = project_assets[index];
 		context_raw.brush_mask_image = project_get_image(asset);
 	}
@@ -53,11 +53,13 @@ function brush_output_node_parse_inputs(self: brush_output_node_t) {
 	context_raw.brush_nodes_hardness = input3;
 
 	let stencil: any = input4; // Float or texture name
-	if (stencil == null) stencil = 1.0;
+	if (stencil == null) {
+		stencil = 1.0;
+	}
 	if (typeof stencil == "string") {
-		context_raw.brush_stencil_image_is_alpha = stencil.endsWith(".a");
-		stencil = stencil.substr(0, stencil.lastIndexOf("."));
-		let index = project_asset_names.indexOf(stencil);
+		context_raw.brush_stencil_image_is_alpha = ends_with(stencil, ".a");
+		stencil = substring(stencil, 0, string_last_index_of(stencil, "."));
+		let index = array_index_of(project_asset_names, stencil);
 		let asset = project_assets[index];
 		context_raw.brush_stencil_image = project_get_image(asset);
 	}

+ 46 - 24
armorsculpt/Sources/tab_layers.ts

@@ -49,7 +49,9 @@ function tab_layers_draw_full(htab: zui_handle_t) {
 
 function tab_layers_draw_slots(mini: bool) {
 	for (let i = 0; i < project_layers.length; ++i) {
-		if (i >= project_layers.length) break; // Layer was deleted
+		if (i >= project_layers.length) {
+			break; // Layer was deleted
+		}
 		let j = project_layers.length - 1 - i;
 		let l = project_layers[j];
 		tab_layers_draw_layer_slot(l, j, mini);
@@ -70,7 +72,7 @@ function tab_layers_highlight_odd_lines() {
 function tab_layers_button_new(text: string) {
 	let ui = ui_base_ui;
 	if (zui_button(text)) {
-		ui_menu_draw((ui: zui_t) => {
+		ui_menu_draw(function (ui: zui_t) {
 			let l = context_raw.layer;
 			if (ui_menu_button(ui, tr("Paint Layer"))) {
 				base_new_layer();
@@ -83,9 +85,9 @@ function tab_layers_button_new(text: string) {
 function tab_layers_combo_filter() {
 	let ui = ui_base_ui;
 	let ar = [tr("All")];
-	let filterHandle = zui_handle("tablayers_0");
-	filterHandle.position = context_raw.layer_filter;
-	context_raw.layer_filter = zui_combo(filterHandle, ar, tr("Filter"), false, zui_align_t.LEFT);
+	let filter_handle = zui_handle("tablayers_0");
+	filter_handle.position = context_raw.layer_filter;
+	context_raw.layer_filter = zui_combo(filter_handle, ar, tr("Filter"), false, zui_align_t.LEFT);
 }
 
 function tab_layers_remap_layer_pointers(nodes: zui_node_t[], pointerMap: map_t<i32, i32>) {
@@ -93,7 +95,7 @@ function tab_layers_remap_layer_pointers(nodes: zui_node_t[], pointerMap: map_t<
 		if (n.type == "LAYER" || n.type == "LAYER_MASK") {
 			let i = n.buttons[0].default_value;
 			if (pointerMap.has(i)) {
-				n.buttons[0].default_value = pointerMap.get(i);
+				n.buttons[0].default_value = map_get(pointerMap, i);
 			}
 		}
 	}
@@ -101,13 +103,17 @@ function tab_layers_remap_layer_pointers(nodes: zui_node_t[], pointerMap: map_t<
 
 function tab_layers_init_layer_map(): map_t<SlotLayerRaw, i32> {
 	let res: map_t<SlotLayerRaw, i32> = map_create();
-	for (let i = 0; i < project_layers.length; ++i) res.set(project_layers[i], i);
+	for (let i = 0; i < project_layers.length; ++i) {
+		map_set(res, project_layers[i], i);
+	}
 	return res;
 }
 
 function 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);
+	for (let l of map.keys()) {
+		map_set(res, map_get(map, l), array_index_of(project_layers, l) > -1 ? array_index_of(project_layers, l) : 9999);
+	}
 	return res;
 }
 
@@ -115,7 +121,7 @@ function 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);
+	context_raw.drag_dest = array_index_of(project_layers, layer);
 }
 
 function tab_layers_draw_layer_slot(l: SlotLayerRaw, i: i32, mini: bool) {
@@ -141,7 +147,7 @@ function tab_layers_draw_layer_slot(l: SlotLayerRaw, i: i32, mini: bool) {
 	let absy = ui._window_y + ui._y;
 	if (base_is_dragging && base_drag_layer != null && context_in_layers()) {
 		if (mouse_y > absy + step && mouse_y < absy + step * 3) {
-			let down = project_layers.indexOf(base_drag_layer) >= i;
+			let down = array_index_of(project_layers, base_drag_layer) >= i;
 			context_raw.drag_dest = down ? i : i - 1;
 
 			let ls = project_layers;
@@ -164,13 +170,15 @@ function tab_layers_draw_layer_slot(l: SlotLayerRaw, i: i32, mini: bool) {
 	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 (tab_layers_can_drop_new_layer(i))
+			if (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 (tab_layers_can_drop_new_layer(project_layers.length))
+			if (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);
+			}
 		}
 	}
 
@@ -218,7 +226,9 @@ function tab_layers_draw_layer_slot_full(l: SlotLayerRaw, i: i32) {
 	ui._y += center;
 	let col = ui.t.ACCENT_SELECT_COL;
 	let parentHidden = l.parent != null && (!l.parent.visible || (l.parent.parent != null && !l.parent.parent.visible));
-	if (parentHidden) col -= 0x99000000;
+	if (parentHidden) {
+		col -= 0x99000000;
+	}
 
 	if (zui_image(icons, col, -1.0, r.x, r.y, r.w, r.h) == zui_state_t.RELEASED) {
 		tab_layers_layer_toggle_visible(l);
@@ -235,7 +245,9 @@ function tab_layers_draw_layer_slot_full(l: SlotLayerRaw, i: i32) {
 	if (tab_layers_layer_name_edit == l.id) {
 		tab_layers_layer_name_handle.text = l.name;
 		l.name = zui_text_input(tab_layers_layer_name_handle);
-		if (ui.text_selected_handle_ptr != tab_layers_layer_name_handle.ptr) tab_layers_layer_name_edit = -1;
+		if (ui.text_selected_handle_ptr != tab_layers_layer_name_handle.ptr) {
+			tab_layers_layer_name_edit = -1;
+		}
 	}
 	else {
 		if (ui.enabled && ui.input_enabled && ui.combo_selected_handle_ptr == 0 &&
@@ -266,11 +278,11 @@ function tab_layers_draw_layer_slot_full(l: SlotLayerRaw, i: i32) {
 			}
 		}
 
-		// let inFocus = ui.inputX > ui._windowX && ui.inputX < ui._windowX + ui._windowW &&
+		// let in_focus = ui.inputX > ui._windowX && ui.inputX < ui._windowX + ui._windowW &&
 		// 			  ui.inputY > ui._windowY && ui.inputY < ui._windowY + ui._windowH;
-		// if (inFocus && ui.isDeleteDown && canDelete(context_raw.layer)) {
-		// 	ui.isDeleteDown = false;
-		// 	let _init() = () => {
+		// if (in_focus && ui.is_delete_down && can_delete(context_raw.layer)) {
+		// 	ui.is_delete_down = false;
+		// 	let _init() = function () {
 		// 		deleteLayer(context_raw.layer);
 		// 	}
 		// 	app_notify_on_init(_init);
@@ -280,7 +292,9 @@ function tab_layers_draw_layer_slot_full(l: SlotLayerRaw, i: i32) {
 
 	if (l.parent != null) {
 		ui._x -= 10 * zui_SCALE(ui);
-		if (l.parent.parent != null) ui._x -= 10 * zui_SCALE(ui);
+		if (l.parent.parent != null) {
+			ui._x -= 10 * zui_SCALE(ui);
+		}
 	}
 
 	if (slot_layer_is_group(l)) {
@@ -366,15 +380,23 @@ function tab_layers_draw_layer_highlight(l: SlotLayerRaw, mini: bool) {
 }
 
 function tab_layers_can_merge_down(l: SlotLayerRaw) : bool {
-	let index = project_layers.indexOf(l);
+	let index = array_index_of(project_layers, l);
 	// Lowest layer
-	if (index == 0) return false;
+	if (index == 0) {
+		return false;
+	}
 	// Lowest layer that has masks
-	if (slot_layer_is_layer(l) && slot_layer_is_mask(project_layers[0]) && project_layers[0].parent == l) return false;
+	if (slot_layer_is_layer(l) && slot_layer_is_mask(project_layers[0]) && project_layers[0].parent == l) {
+		return false;
+	}
 	// The lowest toplevel layer is a group
-	if (slot_layer_is_group(l) && slot_layer_is_in_group(project_layers[0]) && slot_layer_get_containing_group(project_layers[0]) == l) return false;
+	if (slot_layer_is_group(l) && slot_layer_is_in_group(project_layers[0]) && slot_layer_get_containing_group(project_layers[0]) == l) {
+		return false;
+	}
 	// Masks must be merged down to masks
-	if (slot_layer_is_mask(l) && !slot_layer_is_mask(project_layers[index - 1])) return false;
+	if (slot_layer_is_mask(l) && !slot_layer_is_mask(project_layers[index - 1])) {
+		return false;
+	}
 	return true;
 }
 

+ 15 - 9
base/Sources/args.ts

@@ -58,7 +58,7 @@ function args_parse() {
 				++i;
 				args_export_mesh_path = krom_get_arg(i);
 			}
-			else if (path_is_mesh(current_arg) || (i > 1 && !current_arg.startsWith("-") && path_is_folder(current_arg))) {
+			else if (path_is_mesh(current_arg) || (i > 1 && !starts_with(current_arg, "-") && path_is_folder(current_arg))) {
 				args_asset_path = current_arg;
 			}
 			///end
@@ -78,7 +78,7 @@ function args_parse() {
 
 function args_run() {
 	if (args_use) {
-		app_notify_on_init(() => {
+		app_notify_on_init(function () {
 			if (project_filepath != "") {
 				import_arm_run_project(project_filepath);
 			}
@@ -134,20 +134,22 @@ function args_run() {
 						// Get export preset and apply the correct one from args
 						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
+							box_export_files[i] = substring(box_export_files[i], 0, box_export_files[i].length - 5); // Strip .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";
+						for (let f of box_export_files) {
+							if (f == args_export_textures_preset) {
+								file = "export_presets/" + box_export_files[array_index_of(box_export_files, f)] + ".json";
+							}
 						}
 
-						let blob: ArrayBuffer = data_get_blob(file);
+						let blob: buffer_t = data_get_blob(file);
 						box_export_preset = json_parse(sys_buffer_to_string(blob));
 						data_delete_blob("export_presets/" + file);
 
 						// Export queue
-						app_notify_on_init(() => {
+						app_notify_on_init(function () {
 							export_texture_run(args_export_textures_path);
 						});
 					}
@@ -165,7 +167,9 @@ function args_run() {
 			else if (args_export_mesh) {
 				if (path_is_folder(args_export_mesh_path)) {
 					let f: string = ui_files_filename;
-					if (f == "") f = tr("untitled");
+					if (f == "") {
+						f = tr("untitled");
+					}
 					export_mesh_run(args_export_mesh_path + path_sep + f, null, false);
 				}
 				else {
@@ -181,7 +185,9 @@ function args_run() {
 			}
 			///end
 
-			if (args_background) sys_stop();
+			if (args_background) {
+				sys_stop();
+			}
 		});
 	}
 }

+ 261 - 151
base/Sources/base.ts

@@ -6,7 +6,7 @@ let base_drag_asset: asset_t = null;
 let base_drag_swatch: swatch_color_t = null;
 let base_drag_file: string = null;
 let base_drag_file_icon: image_t = null;
-let base_drag_tint = 0xffffffff;
+let base_drag_tint: i32 = 0xffffffff;
 let base_drag_size: i32 = -1;
 let base_drag_rect: rect_t = null;
 let base_drag_off_x: f32 = 0.0;
@@ -31,8 +31,8 @@ let base_appy: i32 = 0;
 let base_last_window_width: i32 = 0;
 let base_last_window_height: i32 = 0;
 ///if (is_paint || is_sculpt)
-let base_drag_material: SlotMaterialRaw = null;
-let base_drag_layer: SlotLayerRaw = null;
+let base_drag_material: slot_material_t = null;
+let base_drag_layer: slot_layer_t = null;
 ///end
 
 let base_pipe_copy: pipeline_t;
@@ -184,7 +184,7 @@ function base_init() {
 		drop_path = decodeURIComponent(drop_path);
 		///end
 		drop_path = trim_end(drop_path);
-		base_drop_paths.push(drop_path);
+		array_push(base_drop_paths, drop_path);
 	});
 
 	sys_notify_on_app_state(
@@ -228,7 +228,9 @@ function base_init() {
 		base_font.font_ = krom_g2_font_13(base_font.blob);
 		base_font.glyphs = _g2_font_glyphs;
 	}
-	else g2_font_init(base_font);
+	else {
+		g2_font_init(base_font);
+	}
 
 	base_color_wheel = image_color_wheel;
 	base_color_wheel_gradient = image_color_wheel_gradient;
@@ -297,8 +299,12 @@ function base_init() {
 
 function base_save_and_quit_callback(save: bool) {
 	base_save_window_rect();
-	if (save) project_save(true);
-	else sys_stop();
+	if (save) {
+		project_save(true);
+	}
+	else {
+		sys_stop();
+	}
 }
 
 ///if (is_paint || is_sculpt)
@@ -413,7 +419,9 @@ function base_y(): i32 {
 }
 
 function base_on_resize() {
-	if (sys_width() == 0 || sys_height() == 0) return;
+	if (sys_width() == 0 || sys_height() == 0) {
+		return;
+	}
 
 	let ratio_w: f32 = sys_width() / base_last_window_width;
 	base_last_window_width = sys_width();
@@ -444,7 +452,9 @@ function base_save_window_rect() {
 }
 
 function base_resize() {
-	if (sys_width() == 0 || sys_height() == 0) return;
+	if (sys_width() == 0 || sys_height() == 0) {
+		return;
+	}
 
 	let cam: camera_object_t = scene_camera;
 	if (cam.data.ortho != null) {
@@ -496,12 +506,16 @@ function base_redraw_ui() {
 	ui_nodes_hwnd.redraws = 2;
 	ui_box_hwnd.redraws = 2;
 	ui_view2d_hwnd.redraws = 2;
-	if (context_raw.ddirty < 0) context_raw.ddirty = 0; // Redraw viewport
+	if (context_raw.ddirty < 0) {
+		context_raw.ddirty = 0; // Redraw viewport
+	}
 	///if (is_paint || is_sculpt)
 	ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
 	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
 	ui_toolbar_handle.redraws = 2;
-	if (context_raw.split_view) context_raw.ddirty = 1;
+	if (context_raw.split_view) {
+		context_raw.ddirty = 1;
+	}
 	///end
 }
 
@@ -520,8 +534,12 @@ function base_update() {
 	if (config_raw.touch_ui) {
 		// Touch and hold to activate dragging
 		if (base_drag_start < 0.2) {
-			if (has_drag && mouse_down()) base_drag_start += time_real_delta();
-			else base_drag_start = 0;
+			if (has_drag && mouse_down()) {
+				base_drag_start += time_real_delta();
+			}
+			else {
+				base_drag_start = 0;
+			}
 			has_drag = false;
 		}
 		if (mouse_released()) {
@@ -549,10 +567,10 @@ function base_update() {
 	if (mouse_released() && has_drag) {
 		if (base_drag_asset != null) {
 			if (context_in_nodes()) { // Create image texture
-				ui_nodes_accept_asset_drag(project_assets.indexOf(base_drag_asset));
+				ui_nodes_accept_asset_drag(array_index_of(project_assets, base_drag_asset));
 			}
 			else if (context_in_viewport()) {
-				if (base_drag_asset.file.toLowerCase().endsWith(".hdr")) {
+				if (ends_with(to_lower_case(base_drag_asset.file), ".hdr")) {
 					let image: image_t = project_get_image(base_drag_asset);
 					import_envmap_run(base_drag_asset.file, image);
 				}
@@ -618,7 +636,7 @@ function base_update() {
 		}
 		else if (base_drag_layer != null) {
 			if (context_in_nodes()) {
-				ui_nodes_accept_layer_drag(project_layers.indexOf(base_drag_layer));
+				ui_nodes_accept_layer_drag(array_index_of(project_layers, base_drag_layer));
 			}
 			else if (context_in_layers() && base_is_dragging) {
 				slot_layer_move(base_drag_layer, context_raw.drag_dest);
@@ -671,7 +689,7 @@ function base_material_dropped() {
 		base_create_fill_layer(uv_type, decal_mat, context_raw.drag_dest);
 	}
 	else if (context_in_nodes()) {
-		ui_nodes_accept_material_drag(project_materials.indexOf(base_drag_material));
+		ui_nodes_accept_material_drag(array_index_of(project_materials, base_drag_material));
 	}
 	base_drag_material = null;
 }
@@ -718,7 +736,7 @@ function base_get_drag_image(): image_t {
 	if (base_drag_file != null) {
 		if (base_drag_file_icon != null) return base_drag_file_icon;
 		let icons: image_t = resource_get("icons.k");
-		base_drag_rect = base_drag_file.indexOf(".") > 0 ? resource_tile50(icons, 3, 1) : resource_tile50(icons, 2, 1);
+		base_drag_rect = string_index_of(base_drag_file, ".") > 0 ? resource_tile50(icons, 3, 1) : resource_tile50(icons, 2, 1);
 		base_drag_tint = ui_base_ui.t.HIGHLIGHT_COL;
 		return icons;
 	}
@@ -764,8 +782,8 @@ function base_render() {
 		if (history_undo_layers == null) {
 			history_undo_layers = [];
 			for (let i: i32 = 0; i < config_raw.undo_steps; ++i) {
-				let l: SlotLayerRaw = slot_layer_create("_undo" + history_undo_layers.length);
-				history_undo_layers.push(l);
+				let l: slot_layer_t = slot_layer_create("_undo" + history_undo_layers.length);
+				array_push(history_undo_layers, l);
 			}
 		}
 		///end
@@ -863,12 +881,16 @@ function base_enum_texts(node_type: string): string[] {
 	}
 	if (node_type == "LAYER" || node_type == "LAYER_MASK") {
 		let layer_names: string[] = [];
-		for (let l of project_layers) layer_names.push(l.name);
+		for (let l of project_layers) {
+			array_push(layer_names, l.name);
+		}
 		return layer_names;
 	}
 	if (node_type == "MATERIAL") {
 		let material_names: string[] = [];
-		for (let m of project_materials) material_names.push(m.canvas.name);
+		for (let m of project_materials) {
+			array_push(material_names, m.canvas.name);
+		}
 		return material_names;
 	}
 	///end
@@ -882,8 +904,8 @@ function base_enum_texts(node_type: string): string[] {
 	return null;
 }
 
-function base_get_asset_index(fileName: string): i32 {
-	let i: i32 = project_asset_names.indexOf(fileName);
+function base_get_asset_index(file_name: string): i32 {
+	let i: i32 = array_index_of(project_asset_names, file_name);
 	return i >= 0 ? i : 0;
 }
 
@@ -919,12 +941,20 @@ function base_toggle_fullscreen() {
 }
 
 function base_is_scrolling(): bool {
-	for (let ui of base_get_uis()) if (ui.is_scrolling) return true;
+	for (let ui of base_get_uis()) {
+		if (ui.is_scrolling) {
+			return true;
+		}
+	}
 	return false;
 }
 
 function base_is_combo_selected(): bool {
-	for (let ui of base_get_uis()) if (ui.combo_selected_handle_ptr != 0) return true;
+	for (let ui of base_get_uis()) {
+		if (ui.combo_selected_handle_ptr != 0) {
+			return true;
+		}
+	}
 	return false;
 }
 
@@ -1077,9 +1107,9 @@ function base_init_layers() {
 	///end
 
 	///if is_lab
-	let texpaint: image_t = render_path_render_targets.get("texpaint")._image;
-	let texpaint_nor: image_t = render_path_render_targets.get("texpaint_nor")._image;
-	let texpaint_pack: image_t = render_path_render_targets.get("texpaint_pack")._image;
+	let texpaint: image_t = map_get(render_path_render_targets, "texpaint")._image;
+	let texpaint_nor: image_t = map_get(render_path_render_targets, "texpaint_nor")._image;
+	let texpaint_pack: image_t = map_get(render_path_render_targets, "texpaint_pack")._image;
 	g2_begin(texpaint);
 	g2_draw_scaled_image(resource_get("placeholder.k"), 0, 0, config_get_texture_res_x(), config_get_texture_res_y()); // Base
 	g2_end();
@@ -1089,8 +1119,8 @@ function base_init_layers() {
 	g4_begin(texpaint_pack);
 	g4_clear(color_from_floats(1.0, 0.4, 0.0, 0.0)); // Occ, rough, met
 	g4_end();
-	let texpaint_nor_empty: image_t = render_path_render_targets.get("texpaint_nor_empty")._image;
-	let texpaint_pack_empty: image_t = render_path_render_targets.get("texpaint_pack_empty")._image;
+	let texpaint_nor_empty: image_t = map_get(render_path_render_targets, "texpaint_nor_empty")._image;
+	let texpaint_pack_empty: image_t = map_get(render_path_render_targets, "texpaint_pack_empty")._image;
 	g4_begin(texpaint_nor_empty);
 	g4_clear(color_from_floats(0.5, 0.5, 1.0, 0.0)); // Nor
 	g4_end();
@@ -1109,7 +1139,7 @@ function base_resize_layers() {
 			context_raw.undo_handle.value = conf.undo_steps;
 		}
 		while (history_undo_layers.length > conf.undo_steps) {
-			let l: SlotLayerRaw = history_undo_layers.pop();
+			let l: slot_layer_t = history_undo_layers.pop();
 			base_notify_on_next_frame(function() {
 				slot_layer_unload(l);
 			});
@@ -1118,31 +1148,31 @@ function base_resize_layers() {
 	for (let l of project_layers) slot_layer_resize_and_set_bits(l);
 	for (let l of history_undo_layers) 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;
+	let _texpaint_blend0: image_t = map_get(rts, "texpaint_blend0")._image;
 	base_notify_on_next_frame(function() {
 		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);
-	let _texpaint_blend1: image_t = rts.get("texpaint_blend1")._image;
+	map_get(rts, "texpaint_blend0").width = config_get_texture_res_x();
+	map_get(rts, "texpaint_blend0").height = config_get_texture_res_y();
+	map_get(rts, "texpaint_blend0")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8);
+	let _texpaint_blend1: image_t = map_get(rts, "texpaint_blend1")._image;
 	base_notify_on_next_frame(function() {
 		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);
+	map_get(rts, "texpaint_blend1").width = config_get_texture_res_x();
+	map_get(rts, "texpaint_blend1").height = config_get_texture_res_y();
+	map_get(rts, "texpaint_blend1")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8);
 	context_raw.brush_blend_dirty = true;
-	if (rts.get("texpaint_blur") != null) {
-		let _texpaint_blur: image_t = rts.get("texpaint_blur")._image;
+	if (map_get(rts, "texpaint_blur") != null) {
+		let _texpaint_blur: image_t = map_get(rts, "texpaint_blur")._image;
 		base_notify_on_next_frame(function() {
 			image_unload(_texpaint_blur);
 		});
 		let size_x: f32 = math_floor(config_get_texture_res_x() * 0.95);
 		let size_y: f32 = math_floor(config_get_texture_res_y() * 0.95);
-		rts.get("texpaint_blur").width = size_x;
-		rts.get("texpaint_blur").height = size_y;
-		rts.get("texpaint_blur")._image = image_create_render_target(size_x, size_y);
+		map_get(rts, "texpaint_blur").width = size_x;
+		map_get(rts, "texpaint_blur").height = size_y;
+		map_get(rts, "texpaint_blur")._image = image_create_render_target(size_x, size_y);
 	}
 	if (render_path_paint_live_layer != null) slot_layer_resize_and_set_bits(render_path_paint_live_layer);
 	///if (krom_direct3d12 || krom_vulkan || krom_metal)
@@ -1152,8 +1182,12 @@ function base_resize_layers() {
 }
 
 function base_set_layer_bits() {
-	for (let l of project_layers) slot_layer_resize_and_set_bits(l);
-	for (let l of history_undo_layers) slot_layer_resize_and_set_bits(l);
+	for (let l of project_layers) {
+		slot_layer_resize_and_set_bits(l);
+	}
+	for (let l of history_undo_layers) {
+		slot_layer_resize_and_set_bits(l);
+	}
 }
 
 function base_make_merge_pipe(red: bool, green: bool, blue: bool, alpha: bool): pipeline_t {
@@ -1418,18 +1452,18 @@ function base_make_cursor_pipe() {
 
 function base_make_temp_img() {
 	///if (is_paint || is_sculpt)
-	let l: SlotLayerRaw = project_layers[0];
+	let l: slot_layer_t = project_layers[0];
 	///end
 	///if is_lab
 	let l: any = brush_output_node_inst;
 	///end
 
 	if (base_temp_image != null && (base_temp_image.width != l.texpaint.width || base_temp_image.height != l.texpaint.height || base_temp_image.format != l.texpaint.format)) {
-		let _temptex0: render_target_t = render_path_render_targets.get("temptex0");
+		let _temptex0: render_target_t = map_get(render_path_render_targets, "temptex0");
 		base_notify_on_next_frame(function() {
 			render_target_unload(_temptex0);
 		});
-		render_path_render_targets.delete("temptex0");
+		map_delete(render_path_render_targets, "temptex0");
 		base_temp_image = null;
 	}
 	if (base_temp_image == null) {
@@ -1469,7 +1503,7 @@ function base_make_temp_mask_img() {
 
 function base_make_export_img() {
 	///if (is_paint || is_sculpt)
-	let l: SlotLayerRaw = project_layers[0];
+	let l: slot_layer_t = project_layers[0];
 	///end
 	///if is_lab
 	let l: any = brush_output_node_inst;
@@ -1487,15 +1521,15 @@ function base_make_export_img() {
 		base_expa = null;
 		base_expb = null;
 		base_expc = null;
-		render_path_render_targets.delete("expa");
-		render_path_render_targets.delete("expb");
-		render_path_render_targets.delete("expc");
+		map_delete(render_path_render_targets, "expa");
+		map_delete(render_path_render_targets, "expb");
+		map_delete(render_path_render_targets, "expc");
 	}
 	if (base_expa == null) {
 		///if (is_paint || is_sculpt)
 		let format: string = base_bits_handle.position == texture_bits_t.BITS8  ? "RGBA32" :
 						base_bits_handle.position == texture_bits_t.BITS16 		? "RGBA64" :
-																				"RGBA128";
+																				  "RGBA128";
 		///end
 		///if is_lab
 		let format: string = "RGBA32";
@@ -1534,56 +1568,56 @@ function base_make_export_img() {
 }
 
 ///if (is_paint || is_sculpt)
-function base_duplicate_layer(l: SlotLayerRaw) {
+function base_duplicate_layer(l: slot_layer_t) {
 	if (!slot_layer_is_group(l)) {
-		let new_layer: SlotLayerRaw = slot_layer_duplicate(l);
+		let new_layer: slot_layer_t = slot_layer_duplicate(l);
 		context_set_layer(new_layer);
-		let masks: SlotLayerRaw[] = slot_layer_get_masks(l, false);
+		let masks: slot_layer_t[] = slot_layer_get_masks(l, false);
 		if (masks != null) {
 			for (let m of masks) {
 				m = slot_layer_duplicate(m);
 				m.parent = new_layer;
 				array_remove(project_layers, m);
-				project_layers.splice(project_layers.indexOf(new_layer), 0, m);
+				array_insert(project_layers, array_index_of(project_layers, new_layer), m);
 			}
 		}
 		context_set_layer(new_layer);
 	}
 	else {
-		let new_group: SlotLayerRaw = base_new_group();
+		let new_group: slot_layer_t = base_new_group();
 		array_remove(project_layers, new_group);
-		project_layers.splice(project_layers.indexOf(l) + 1, 0, new_group);
+		array_insert(project_layers, array_index_of(project_layers, l) + 1, new_group);
 		// group.show_panel = true;
 		for (let c of slot_layer_get_children(l)) {
-			let masks: SlotLayerRaw[] = slot_layer_get_masks(c, false);
-			let new_layer: SlotLayerRaw = slot_layer_duplicate(c);
+			let masks: slot_layer_t[] = slot_layer_get_masks(c, false);
+			let new_layer: slot_layer_t = 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);
+			array_insert(project_layers, array_index_of(project_layers, new_group), new_layer);
 			if (masks != null) {
 				for (let m of masks) {
-					let new_mask: SlotLayerRaw = slot_layer_duplicate(m);
+					let new_mask: slot_layer_t = 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);
+					array_insert(project_layers, array_index_of(project_layers, new_layer), new_mask);
 				}
 			}
 		}
-		let group_masks: SlotLayerRaw[] = slot_layer_get_masks(l);
+		let group_masks: slot_layer_t[] = slot_layer_get_masks(l);
 		if (group_masks != null) {
 			for (let m of group_masks) {
-				let new_mask: SlotLayerRaw = slot_layer_duplicate(m);
+				let new_mask: slot_layer_t = 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);
+				array_insert(project_layers, array_index_of(project_layers, new_group), new_mask);
 			}
 		}
 		context_set_layer(new_group);
 	}
 }
 
-function base_apply_masks(l: SlotLayerRaw) {
-	let masks: SlotLayerRaw[] = slot_layer_get_masks(l);
+function base_apply_masks(l: slot_layer_t) {
+	let masks: slot_layer_t[] = slot_layer_get_masks(l);
 
 	if (masks != null) {
 		for (let i: i32 = 0; i < masks.length - 1; ++i) {
@@ -1596,7 +1630,7 @@ function base_apply_masks(l: SlotLayerRaw) {
 }
 
 function base_merge_down() {
-	let l1: SlotLayerRaw = context_raw.layer;
+	let l1: slot_layer_t = context_raw.layer;
 
 	if (slot_layer_is_group(l1)) {
 		l1 = base_merge_group(l1);
@@ -1606,7 +1640,7 @@ function base_merge_down() {
 		context_set_layer(l1);
 	}
 
-	let l0: SlotLayerRaw = project_layers[project_layers.indexOf(l1) - 1];
+	let l0: slot_layer_t = project_layers[array_index_of(project_layers, l1) - 1];
 
 	if (slot_layer_is_group(l0)) {
 		l0 = base_merge_group(l0);
@@ -1622,10 +1656,12 @@ function base_merge_down() {
 	context_raw.layer_preview_dirty = true;
 }
 
-function base_merge_group(l: SlotLayerRaw) {
-	if (!slot_layer_is_group(l)) return null;
+function base_merge_group(l: slot_layer_t) {
+	if (!slot_layer_is_group(l)) {
+		return null;
+	}
 
-	let children: SlotLayerRaw[] = slot_layer_get_children(l);
+	let children: slot_layer_t[] = slot_layer_get_children(l);
 
 	if (children.length == 1 && slot_layer_has_masks(children[0], false)) {
 		base_apply_masks(children[0]);
@@ -1638,7 +1674,7 @@ function base_merge_group(l: SlotLayerRaw) {
 	}
 
 	// Now apply the group masks
-	let masks: SlotLayerRaw[] = slot_layer_get_masks(l);
+	let masks: slot_layer_t[] = 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]);
@@ -1649,17 +1685,25 @@ function base_merge_group(l: SlotLayerRaw) {
 
 	children[0].parent = null;
 	children[0].name = l.name;
-	if (children[0].fill_layer != null) slot_layer_to_paint_layer(children[0]);
+	if (children[0].fill_layer != null) {
+		slot_layer_to_paint_layer(children[0]);
+	}
 	slot_layer_delete(l);
 	return children[0];
 }
 
-function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool = false) {
-	if (!l1.visible || slot_layer_is_group(l1)) return;
+function base_merge_layer(l0 : slot_layer_t, l1: slot_layer_t, use_mask: bool = false) {
+	if (!l1.visible || slot_layer_is_group(l1)) {
+		return;
+	}
 
-	if (base_pipe_merge == null) base_make_pipe();
+	if (base_pipe_merge == null) {
+		base_make_pipe();
+	}
 	base_make_temp_img();
-	if (const_data_screen_aligned_vb == null) const_data_create_screen_aligned_data();
+	if (const_data_screen_aligned_vb == null) {
+		const_data_create_screen_aligned_data();
+	}
 
 	g2_begin(base_temp_image); // Copy to temp
 	g2_set_pipeline(base_pipe_copy);
@@ -1667,9 +1711,9 @@ function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool =
 	g2_set_pipeline(null);
 	g2_end();
 
-	let empty: image_t = render_path_render_targets.get("empty_white")._image;
+	let empty: image_t = map_get(render_path_render_targets, "empty_white")._image;
 	let mask: image_t = empty;
-	let l1masks: SlotLayerRaw[] =  use_mask ? slot_layer_get_masks(l1) : null;
+	let l1masks: slot_layer_t[] =  use_mask ? 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]);
@@ -1739,22 +1783,34 @@ function base_merge_layer(l0 : SlotLayerRaw, l1: SlotLayerRaw, use_mask: bool =
 				base_commands_merge_pack(base_pipe_merge, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, 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, 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, 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, slot_layer_get_opacity(l1), mask);
+				if (l1.paint_occ) {
+					base_commands_merge_pack(base_pipe_merge_r, l0.texpaint_pack, l1.texpaint, l1.texpaint_pack, 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, 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, slot_layer_get_opacity(l1), mask);
+				}
 			}
 		}
 		///end
 	}
 }
 
-function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = null): any {
-	if (layers == null) layers = project_layers;
+function base_flatten(height_to_normal: bool = false, layers: slot_layer_t[] = null): any {
+	if (layers == null) {
+		layers = project_layers;
+	}
 	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;
+	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 = map_get(render_path_render_targets, "empty_white")._image;
 
 	// Clear export layer
 	g4_begin(base_expa);
@@ -1769,11 +1825,15 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 
 	// Flatten layers
 	for (let l1 of layers) {
-		if (!slot_layer_is_visible(l1)) continue;
-		if (!slot_layer_is_layer(l1)) continue;
+		if (!slot_layer_is_visible(l1)) {
+			continue;
+		}
+		if (!slot_layer_is_layer(l1)) {
+			continue;
+		}
 
 		let mask: image_t = empty;
-		let l1masks: SlotLayerRaw[] = slot_layer_get_masks(l1);
+		let l1masks: slot_layer_t[] = slot_layer_get_masks(l1);
 		if (l1masks != null) {
 			if (l1masks.length > 1) {
 				base_make_temp_mask_img();
@@ -1786,7 +1846,9 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 				}
 				mask = base_temp_mask_image;
 			}
-			else mask = l1masks[0].texpaint;
+			else {
+				mask = l1masks[0].texpaint;
+			}
 		}
 
 		if (l1.paint_base) {
@@ -1843,9 +1905,15 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 				base_commands_merge_pack(base_pipe_merge, base_expc, l1.texpaint, l1.texpaint_pack, 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, 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, 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, slot_layer_get_opacity(l1), mask);
+				if (l1.paint_occ) {
+					base_commands_merge_pack(base_pipe_merge_r, base_expc, l1.texpaint, l1.texpaint_pack, 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, 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, slot_layer_get_opacity(l1), mask);
+				}
 			}
 		}
 		///end
@@ -1889,10 +1957,14 @@ function base_flatten(height_to_normal: bool = false, layers: SlotLayerRaw[] = n
 	return l0;
 }
 
-function base_apply_mask(l: SlotLayerRaw, m: SlotLayerRaw) {
-	if (!slot_layer_is_layer(l) || !slot_layer_is_mask(m)) return;
+function base_apply_mask(l: slot_layer_t, m: slot_layer_t) {
+	if (!slot_layer_is_layer(l) || !slot_layer_is_mask(m)) {
+		return;
+	}
 
-	if (base_pipe_merge == null) base_make_pipe();
+	if (base_pipe_merge == null) {
+		base_make_pipe();
+	}
 	base_make_temp_img();
 
 	// Copy layer to temp
@@ -1903,7 +1975,9 @@ function base_apply_mask(l: SlotLayerRaw, m: SlotLayerRaw) {
 	g2_end();
 
 	// Apply mask
-	if (const_data_screen_aligned_vb == null) const_data_create_screen_aligned_data();
+	if (const_data_screen_aligned_vb == null) {
+		const_data_create_screen_aligned_data();
+	}
 	g4_begin(l.texpaint);
 	g4_set_pipeline(base_pipe_apply_mask);
 	g4_set_tex(base_tex0_mask, base_temp_image);
@@ -1931,16 +2005,22 @@ function base_commands_merge_pack(pipe: pipeline_t, i0: image_t, i1: image_t, i1
 
 function base_is_fill_material(): bool {
 	///if is_paint
-	if (context_raw.tool == workspace_tool_t.MATERIAL) return true;
+	if (context_raw.tool == workspace_tool_t.MATERIAL) {
+		return true;
+	}
 	///end
 
-	let m: SlotMaterialRaw = context_raw.material;
-	for (let l of project_layers) if (l.fill_layer == m) return true;
+	let m: slot_material_t = context_raw.material;
+	for (let l of project_layers) {
+		if (l.fill_layer == m) {
+			return true;
+		}
+	}
 	return false;
 }
 
 function base_update_fill_layers() {
-	let _layer: SlotLayerRaw = context_raw.layer;
+	let _layer: slot_layer_t = context_raw.layer;
 	let _tool: workspace_tool_t = context_raw.tool;
 	let _fill_type: i32 = context_raw.fill_type_handle.position;
 	let current: image_t = null;
@@ -1974,12 +2054,22 @@ function base_update_fill_layers() {
 
 	let has_fill_layer: bool = false;
 	let has_fill_mask: bool = false;
-	for (let l of project_layers) if (slot_layer_is_layer(l) && l.fill_layer == context_raw.material) has_fill_layer = true;
-	for (let l of project_layers) if (slot_layer_is_mask(l) && l.fill_layer == context_raw.material) has_fill_mask = true;
+	for (let l of project_layers) {
+		if (slot_layer_is_layer(l) && l.fill_layer == context_raw.material) {
+			has_fill_layer = true;
+		}
+	}
+	for (let l of project_layers) {
+		if (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;
-		if (current != null) g2_end();
+		if (current != null) {
+			g2_end();
+		}
 		context_raw.pdirty = 1;
 		context_raw.tool = workspace_tool_t.FILL;
 		context_raw.fill_type_handle.position = fill_type_t.OBJECT;
@@ -2043,7 +2133,9 @@ function base_update_fill_layer(parse_paint: bool = true) {
 
 	slot_layer_clear(context_raw.layer);
 
-	if (parse_paint) make_material_parse_paint_material(false);
+	if (parse_paint) {
+		make_material_parse_paint_material(false);
+	}
 	render_path_paint_commands_paint(false);
 	render_path_paint_dilate(true, true);
 
@@ -2059,10 +2151,14 @@ function base_set_object_mask() {
 	///end
 
 	let ar: string[] = [tr("None")];
-	for (let p of project_paint_objects) ar.push(p.base.name);
+	for (let p of project_paint_objects) {
+		array_push(ar, p.base.name);
+	}
 
 	let mask: i32 = context_object_mask_used() ? slot_layer_get_object_mask(context_raw.layer) : 0;
-	if (context_layer_filter_used()) mask = context_raw.layer_filter;
+	if (context_layer_filter_used()) {
+		mask = context_raw.layer_filter;
+	}
 	if (mask > 0) {
 		if (context_raw.merged_object != null) {
 			context_raw.merged_object.base.visible = false;
@@ -2089,53 +2185,65 @@ function base_set_object_mask() {
 	util_uv_dilatemap_cached = false;
 }
 
-function base_new_layer(clear: bool = true, position: i32 = -1): SlotLayerRaw {
-	if (project_layers.length > base_max_layers) return null;
-	let l: SlotLayerRaw = slot_layer_create();
+function base_new_layer(clear: bool = true, position: i32 = -1): slot_layer_t {
+	if (project_layers.length > base_max_layers) {
+		return null;
+	}
+	let l: slot_layer_t = slot_layer_create();
 	l.object_mask = context_raw.layer_filter;
 	if (position == -1) {
 		if (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);
+		array_insert(project_layers, array_index_of(project_layers, context_raw.layer) + 1, l);
 	}
 	else {
-		project_layers.splice(position, 0, l);
+		array_insert(project_layers, position, l);
 	}
 
 	context_set_layer(l);
-	let li: i32 = project_layers.indexOf(context_raw.layer);
+	let li: i32 = array_index_of(project_layers, context_raw.layer);
 	if (li > 0) {
-		let below: SlotLayerRaw = project_layers[li - 1];
+		let below: slot_layer_t = project_layers[li - 1];
 		if (slot_layer_is_layer(below)) {
 			context_raw.layer.parent = below.parent;
 		}
 	}
-	if (clear) app_notify_on_init(function() { slot_layer_clear(l); });
+	if (clear) {
+		app_notify_on_init(function() { 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 = slot_layer_create("", layer_slot_type_t.MASK, parent);
-	if (position == -1) position = project_layers.indexOf(parent);
-	project_layers.splice(position, 0, l);
+function base_new_mask(clear: bool = true, parent: slot_layer_t, position: i32 = -1): slot_layer_t {
+	if (project_layers.length > base_max_layers) {
+		return null;
+	}
+	let l: slot_layer_t = slot_layer_create("", layer_slot_type_t.MASK, parent);
+	if (position == -1) {
+		position = array_index_of(project_layers, parent);
+	}
+	array_insert(project_layers, position, l);
 	context_set_layer(l);
-	if (clear) app_notify_on_init(function() { slot_layer_clear(l); });
+	if (clear) {
+		app_notify_on_init(function() { 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 = slot_layer_create("", layer_slot_type_t.GROUP);
-	project_layers.push(l);
+function base_new_group(): slot_layer_t {
+	if (project_layers.length > base_max_layers) {
+		return null;
+	}
+	let l: slot_layer_t = slot_layer_create("", layer_slot_type_t.GROUP);
+	array_push(project_layers, l);
 	context_set_layer(l);
 	return l;
 }
 
 function base_create_fill_layer(uv_type: uv_type_t = uv_type_t.UVMAP, decal_mat: mat4_t = null, position: i32 = -1) {
 	let _init = function() {
-		let l: SlotLayerRaw = base_new_layer(false, position);
+		let l: slot_layer_t = base_new_layer(false, position);
 		history_new_layer();
 		l.uv_type = uv_type;
 		if (decal_mat != null) l.decal_mat = decal_mat;
@@ -2147,20 +2255,20 @@ function base_create_fill_layer(uv_type: uv_type_t = uv_type_t.UVMAP, decal_mat:
 }
 
 function base_create_image_mask(asset: asset_t) {
-	let l: SlotLayerRaw = context_raw.layer;
+	let l: slot_layer_t = context_raw.layer;
 	if (slot_layer_is_mask(l) || slot_layer_is_group(l)) {
 		return;
 	}
 
 	history_new_layer();
-	let m: SlotLayerRaw = base_new_mask(false, l);
+	let m: slot_layer_t = base_new_mask(false, l);
 	slot_layer_clear(m, 0x00000000, project_get_image(asset));
 	context_raw.layer_preview_dirty = true;
 }
 
 function base_create_color_layer(baseColor: i32, occlusion: f32 = 1.0, roughness: f32 = base_default_rough, metallic: f32 = 0.0, position: i32 = -1) {
 	let _init = function() {
-		let l: SlotLayerRaw = base_new_layer(false, position);
+		let l: slot_layer_t = base_new_layer(false, position);
 		history_new_layer();
 		l.uv_type = uv_type_t.UVMAP;
 		l.object_mask = context_raw.layer_filter;
@@ -2172,8 +2280,8 @@ function base_create_color_layer(baseColor: i32, occlusion: f32 = 1.0, roughness
 function base_on_layers_resized() {
 	app_notify_on_init(function() {
 		base_resize_layers();
-		let _layer: SlotLayerRaw = context_raw.layer;
-		let _material: SlotMaterialRaw = context_raw.material;
+		let _layer: slot_layer_t = context_raw.layer;
+		let _material: slot_material_t = context_raw.material;
 		for (let l of project_layers) {
 			if (l.fill_layer != null) {
 				context_raw.layer = l;
@@ -2209,8 +2317,8 @@ function base_flatten(heightToNormal: bool = false): any {
 		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;
-			texpaint_pack = render_path_render_targets.get("texpaint_pack_empty")._image;
+			texpaint_nor = map_get(render_path_render_targets, "texpaint_nor_empty")._image;
+			texpaint_pack = map_get(render_path_render_targets, "texpaint_pack_empty")._image;
 		}
 	}
 
@@ -2219,11 +2327,11 @@ function base_flatten(heightToNormal: bool = false): any {
 
 function base_on_layers_resized() {
 	image_unload(brush_output_node_inst.texpaint);
-	brush_output_node_inst.texpaint = render_path_render_targets.get("texpaint")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y());
+	brush_output_node_inst.texpaint = map_get(render_path_render_targets, "texpaint")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y());
 	image_unload(brush_output_node_inst.texpaint_nor);
-	brush_output_node_inst.texpaint_nor = render_path_render_targets.get("texpaint_nor")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y());
+	brush_output_node_inst.texpaint_nor = map_get(render_path_render_targets, "texpaint_nor")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y());
 	image_unload(brush_output_node_inst.texpaint_pack);
-	brush_output_node_inst.texpaint_pack = render_path_render_targets.get("texpaint_pack")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y());
+	brush_output_node_inst.texpaint_pack = map_get(render_path_render_targets, "texpaint_pack")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y());
 
 	if (InpaintNode.image != null) {
 		image_unload(InpaintNode.image);
@@ -2234,7 +2342,9 @@ function base_on_layers_resized() {
 	}
 
 	if (PhotoToPBRNode.images != null) {
-		for (let image of PhotoToPBRNode.images) image_unload(image);
+		for (let image of PhotoToPBRNode.images) {
+			image_unload(image);
+		}
 		PhotoToPBRNode.images = null;
 		PhotoToPBRNode.init();
 	}
@@ -2245,16 +2355,16 @@ function base_on_layers_resized() {
 		TilingNode.init();
 	}
 
-	image_unload(render_path_render_targets.get("texpaint_blend0")._image);
-	render_path_render_targets.get("texpaint_blend0")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8);
-	image_unload(render_path_render_targets.get("texpaint_blend1")._image);
-	render_path_render_targets.get("texpaint_blend1")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8);
+	image_unload(map_get(render_path_render_targets, "texpaint_blend0")._image);
+	map_get(render_path_render_targets, "texpaint_blend0")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8);
+	image_unload(map_get(render_path_render_targets, "texpaint_blend1")._image);
+	map_get(render_path_render_targets, "texpaint_blend1")._image = image_create_render_target(config_get_texture_res_x(), config_get_texture_res_y(), tex_format_t.R8);
 
-	if (render_path_render_targets.get("texpaint_node") != null) {
-		render_path_render_targets.delete("texpaint_node");
+	if (map_get(render_path_render_targets, "texpaint_node") != null) {
+		map_delete(render_path_render_targets, "texpaint_node");
 	}
-	if (render_path_render_targets.get("texpaint_node_target") != null) {
-		render_path_render_targets.delete("texpaint_node_target");
+	if (map_get(render_path_render_targets, "texpaint_node_target") != null) {
+		map_delete(render_path_render_targets, "texpaint_node_target");
 	}
 
 	base_notify_on_next_frame(function() {

+ 73 - 49
base/Sources/box_export.ts

@@ -16,7 +16,7 @@ function box_export_show_textures() {
 
 		if (box_export_files == null) {
 			box_export_fetch_presets();
-			box_export_hpreset.position = box_export_files.indexOf("generic");
+			box_export_hpreset.position = array_index_of(box_export_files, "generic");
 		}
 		if (box_export_preset == null) {
 			box_export_parse_preset();
@@ -43,7 +43,7 @@ function box_export_show_bake_material() {
 
 		if (box_export_files == null) {
 			box_export_fetch_presets();
-			box_export_hpreset.position = box_export_files.indexOf("generic");
+			box_export_hpreset.position = array_index_of(box_export_files, "generic");
 		}
 		if (box_export_preset == null) {
 			box_export_parse_preset();
@@ -134,7 +134,7 @@ function box_export_tab_export_textures(ui: zui_t, title: string, bake_material:
 			ui_box_hide();
 			if (context_raw.layers_destination == export_destination_t.PACKED) {
 				context_raw.texture_export_path = "/";
-				let _init = () => {
+				let _init = function () {
 					///if is_paint
 					export_texture_run(context_raw.texture_export_path, bake_material);
 					///end
@@ -146,10 +146,10 @@ function box_export_tab_export_textures(ui: zui_t, title: string, bake_material:
 			}
 			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) => {
+				ui_files_show(filters, true, false, function (path: string) {
 					context_raw.texture_export_path = path;
-					let doExport = () => {
-						let _init = () => {
+					let do_export = function () {
+						let _init = function () {
 							///if is_paint
 							export_texture_run(context_raw.texture_export_path, bake_material);
 							///end
@@ -160,17 +160,19 @@ function box_export_tab_export_textures(ui: zui_t, title: string, bake_material:
 						app_notify_on_init(_init);
 					}
 					///if (krom_android || krom_ios)
-					base_notify_on_next_frame(() => {
+					base_notify_on_next_frame(function () {
 						console_toast(tr("Exporting textures"));
-						base_notify_on_next_frame(doExport);
+						base_notify_on_next_frame(do_export);
 					});
 					///else
-					doExport();
+					do_export();
 					///end
 				});
 			}
 		}
-		if (ui.is_hovered) zui_tooltip(tr("Export texture files") + ` (${config_keymap.file_export_textures})`);
+		if (ui.is_hovered) {
+			zui_tooltip(tr("Export texture files") + ` (${config_keymap.file_export_textures})`);
+		}
 	}
 }
 
@@ -180,10 +182,12 @@ function box_export_tab_presets(ui: zui_t) {
 		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 (box_export_hpreset.changed) {
+			box_export_preset = null;
+		}
 
 		if (zui_button(tr("New"))) {
-			ui_box_show_custom((ui: zui_t) => {
+			ui_box_show_custom(function (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]);
@@ -192,7 +196,7 @@ function box_export_tab_presets(ui: zui_t) {
 						box_export_new_preset(preset_name);
 						box_export_fetch_presets();
 						box_export_preset = null;
-						box_export_hpreset.position = box_export_files.indexOf(preset_name);
+						box_export_hpreset.position = array_index_of(box_export_files, preset_name);
 						ui_box_hide();
 						box_export_htab.position = 1; // Presets
 						box_export_show_textures();
@@ -202,18 +206,20 @@ function box_export_tab_presets(ui: zui_t) {
 		}
 
 		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);
+			ui_files_show("json", false, false, function (path: string) {
+				path = to_lower_case(path);
+				if (ends_with(path, ".json")) {
+					let filename: string = substring(path, string_last_index_of(path, path_sep) + 1, path.length);
 					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
+					box_export_hpreset.position = array_index_of(box_export_files, substring(filename, 0, filename.length - 5)); // Strip .json
 					console_info(tr("Preset imported:") + " " + filename);
 				}
-				else console_error(strings_error1());
+				else {
+					console_error(strings_error1());
+				}
 			});
 		}
 
@@ -240,7 +246,7 @@ function box_export_tab_presets(ui: zui_t) {
 			t.name = zui_text_input(htex);
 
 			if (ui.is_hovered && ui.input_released_r) {
-				ui_menu_draw((ui: zui_t) => {
+				ui_menu_draw(function (ui: zui_t) {
 					if (ui_menu_button(ui, tr("Delete"))) {
 						array_remove(box_export_preset.textures, t);
 						box_export_save_preset();
@@ -249,27 +255,37 @@ function box_export_tab_presets(ui: zui_t) {
 			}
 
 			let hr: zui_handle_t = zui_nest(htex, 0);
-			hr.position = box_export_channels.indexOf(t.channels[0]);
+			hr.position = array_index_of(box_export_channels, t.channels[0]);
 			let hg: zui_handle_t = zui_nest(htex, 1);
-			hg.position = box_export_channels.indexOf(t.channels[1]);
+			hg.position = array_index_of(box_export_channels, t.channels[1]);
 			let hb: zui_handle_t = zui_nest(htex, 2);
-			hb.position = box_export_channels.indexOf(t.channels[2]);
+			hb.position = array_index_of(box_export_channels, t.channels[2]);
 			let ha: zui_handle_t = zui_nest(htex, 3);
-			ha.position = box_export_channels.indexOf(t.channels[3]);
+			ha.position = array_index_of(box_export_channels, t.channels[3]);
 
 			zui_combo(hr, box_export_channels, tr("R"));
-			if (hr.changed) t.channels[0] = box_export_channels[hr.position];
+			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];
+			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];
+			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];
+			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);
+			hspace.position = array_index_of(box_export_color_spaces, 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 (hspace.changed) {
+				t.color_space = box_export_color_spaces[hspace.position];
+			}
 		}
 
 		if (ui.changed) {
@@ -278,7 +294,7 @@ function box_export_tab_presets(ui: zui_t) {
 
 		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" });
+			array_push(box_export_preset.textures, { name: "base", channels: ["base_r", "base_g", "base_b", "1.0"], color_space: "linear" });
 			box_export_hpreset.children = null;
 			box_export_save_preset();
 		}
@@ -294,8 +310,8 @@ function box_export_tab_atlases(ui: zui_t) {
 			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));
+				array_push(project_atlas_objects, 0);
+				array_push(project_atlas_names, tr("Atlas") + " " + (i + 1));
 			}
 		}
 		for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
@@ -311,7 +327,7 @@ function box_export_tab_atlases(ui: zui_t) {
 
 function box_export_show_mesh() {
 	box_export_mesh_handle.position = context_raw.export_mesh_index;
-	ui_box_show_custom((ui: zui_t) => {
+	ui_box_show_custom(function (ui: zui_t) {
 		let htab: zui_handle_t = zui_handle("boxexport_8");
 		box_export_tab_export_mesh(ui, htab);
 	});
@@ -326,7 +342,9 @@ function box_export_tab_export_mesh(ui: zui_t, htab: zui_handle_t) {
 		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);
+		for (let p of project_paint_objects) {
+			array_push(ar, 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"));
@@ -347,23 +365,23 @@ function box_export_tab_export_mesh(ui: zui_t, htab: zui_handle_t) {
 		}
 		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) => {
+			ui_files_show(context_raw.export_mesh_format == mesh_format_t.OBJ ? "obj" : "arm", true, false, function (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 = () => {
+				let do_export = function () {
 					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(() => {
+				base_notify_on_next_frame(function () {
 					console_toast(tr("Exporting mesh"));
-					base_notify_on_next_frame(doExport);
+					base_notify_on_next_frame(do_export);
 				});
 				///else
-				doExport();
+				do_export();
 				///end
 			});
 		}
@@ -388,10 +406,12 @@ function box_export_show_material() {
 			}
 			if (zui_button(tr("Export"))) {
 				ui_box_hide();
-				ui_files_show("arm", true, false, (path: string) => {
+				ui_files_show("arm", true, false, function (path: string) {
 					let f: string = ui_files_filename;
-					if (f == "") f = tr("untitled");
-					app_notify_on_init(() => {
+					if (f == "") {
+						f = tr("untitled");
+					}
+					app_notify_on_init(function () {
 						export_arm_run_material(path + path_sep + f);
 					});
 				});
@@ -417,10 +437,10 @@ function box_export_show_brush() {
 			}
 			if (zui_button(tr("Export"))) {
 				ui_box_hide();
-				ui_files_show("arm", true, false, (path: string) => {
+				ui_files_show("arm", true, false, function (path: string) {
 					let f: string = ui_files_filename;
 					if (f == "") f = tr("untitled");
-					app_notify_on_init(() => {
+					app_notify_on_init(function () {
 						export_arm_run_brush(path + path_sep + f);
 					});
 				});
@@ -434,13 +454,13 @@ function box_export_show_brush() {
 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
+		box_export_files[i] = substring(box_export_files[i], 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);
+	let blob: buffer_t = data_get_blob(file);
 	box_export_preset = json_parse(sys_buffer_to_string(blob));
 	data_delete_blob("export_presets/" + file);
 }
@@ -453,14 +473,18 @@ function box_export_new_preset(name: string) {
 ]
 }
 `;
-	if (!name.endsWith(".json")) name += ".json";
+	if (!ends_with(name, ".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
+	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)));
 }

+ 124 - 52
base/Sources/box_preferences.ts

@@ -16,7 +16,7 @@ function box_preferences_show() {
 				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) });
+			let locale_handle: zui_handle_t = zui_handle("boxpreferences_0", { position: array_index_of(box_preferences_locales, 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];
@@ -33,7 +33,9 @@ function box_preferences_show() {
 				config_raw.window_scale = hscale.value;
 				box_preferences_set_scale();
 			}
-			if (hscale.changed) context_raw.hscale_was_changed = true;
+			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);
@@ -51,7 +53,9 @@ function box_preferences_show() {
 			}
 
 			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"));
+			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"));
 
@@ -88,7 +92,11 @@ function box_preferences_show() {
 							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);
+							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;
 							make_material_parse_mesh_material();
@@ -97,7 +105,7 @@ function box_preferences_show() {
 					}
 					if (ui_menu_button(ui, tr("Import..."))) {
 						ui_files_show("json", false, false, function (path: string) {
-							let b: ArrayBuffer = data_get_blob(path);
+							let b: buffer_t = 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;
@@ -143,7 +151,9 @@ function box_preferences_show() {
 						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";
+							if (!ends_with(theme_name, ".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
@@ -166,7 +176,9 @@ function box_preferences_show() {
 			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";
+					if (!ends_with(path, ".json")) {
+						path += ".json";
+					}
 					krom_file_save_bytes(path, sys_string_to_buffer(json_stringify(base_theme)));
 				});
 			}
@@ -185,18 +197,22 @@ function box_preferences_show() {
 				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;
+					if (ui.changed) {
+						ui_menu_keep_open = true;
+					}
 				}, 11);
 			}
 			let val: i32 = h.color;
-			if (val < 0) val += 4294967296;
+			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);
+				let b: u8_array_t = u8_array_create(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);
@@ -210,13 +226,17 @@ function box_preferences_show() {
 
 			// Theme fields
 			for (let key of Object.getOwnPropertyNames(theme_t.prototype)) {
-				if (key == "constructor") continue;
+				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;
+				let isHex: bool = ends_with(key, "_COL");
+				if (isHex && val < 0) {
+					val += 4294967296;
+				}
 
 				if (isHex) {
 					zui_row([1 / 8, 7 / 8]);
@@ -227,7 +247,9 @@ function box_preferences_show() {
 							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;
+							if (ui.changed) {
+								ui_menu_keep_open = true;
+							}
 						}, 11);
 					}
 				}
@@ -248,8 +270,12 @@ function box_preferences_show() {
 				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 (isHex) {
+						theme[key] = parseInt(h.text, 16);
+					}
+					else {
+						theme[key] = parseInt(h.text);
+					}
 				}
 
 				if (ui.changed) {
@@ -272,11 +298,11 @@ function box_preferences_show() {
 
 				///if (is_paint || is_sculpt)
 				while (history_undo_layers.length < config_raw.undo_steps) {
-					let l: SlotLayerRaw = slot_layer_create("_undo" + history_undo_layers.length);
-					history_undo_layers.push(l);
+					let l: slot_layer_t = slot_layer_create("_undo" + history_undo_layers.length);
+					array_push(history_undo_layers, l);
 				}
 				while (history_undo_layers.length > config_raw.undo_steps) {
-					let l: SlotLayerRaw = history_undo_layers.pop();
+					let l: slot_layer_t = history_undo_layers.pop();
 					slot_layer_unload(l);
 				}
 				///end
@@ -287,7 +313,9 @@ function box_preferences_show() {
 
 			///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"));
+			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);
@@ -338,27 +366,39 @@ function box_preferences_show() {
 			///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"));
+			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;
+			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) make_material_parse_paint_material();
+			if (brush_3d_handle.changed) {
+				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) make_material_parse_paint_material();
+			if (brush_depth_reject_handle.changed) {
+				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) make_material_parse_paint_material();
+			if (brush_angle_reject_handle.changed) {
+				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 });
@@ -371,7 +411,9 @@ function box_preferences_show() {
 
 			///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"));
+			if (ui.is_hovered) {
+				zui_tooltip(tr("Use GPU to accelerate node graph processing"));
+			}
 			///end
 		}
 
@@ -427,12 +469,16 @@ function box_preferences_show() {
 			}
 
 			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.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 (ui.is_hovered) {
+					zui_tooltip(tr("Cone-traced AO and shadows"));
+				}
 				if (context_raw.hvxao.changed) {
 					config_apply();
 				}
@@ -440,28 +486,42 @@ function box_preferences_show() {
 				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;
+				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;
+				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();
+				if (context_raw.hssao.changed) {
+					config_apply();
+				}
 				zui_check(context_raw.hssr, tr("SSR"));
-				if (context_raw.hssr.changed) config_apply();
+				if (context_raw.hssr.changed) {
+					config_apply();
+				}
 				zui_check(context_raw.hbloom, tr("Bloom"));
-				if (context_raw.hbloom.changed) config_apply();
+				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;
+			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;
+			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);
@@ -510,7 +570,9 @@ function box_preferences_show() {
 						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";
+							if (!ends_with(keymap_name, ".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
@@ -531,7 +593,9 @@ function box_preferences_show() {
 			}
 			if (zui_button(tr("Export"))) {
 				ui_files_show("json", true, false, function (dest: string) {
-					if (!ui_files_filename.endsWith(".json")) ui_files_filename += ".json";
+					if (!ends_with(ui_files_filename, ".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);
 				});
@@ -574,7 +638,9 @@ if (Zui.panel(h1, 'New Plugin')) {
 }
 }
 `;
-							if (!plugin_name.endsWith(".js")) plugin_name += ".js";
+							if (!ends_with(plugin_name, ".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
@@ -586,7 +652,7 @@ if (Zui.panel(h1, 'New Plugin')) {
 				});
 			}
 			if (zui_button(tr("Import"))) {
-				ui_files_show("js,zip", false, false, (path: string) => {
+				ui_files_show("js,zip", false, false, function (path: string) {
 					import_plugin_run(path);
 				});
 			}
@@ -596,14 +662,18 @@ if (Zui.panel(h1, 'New Plugin')) {
 				box_preferences_fetch_plugins();
 			}
 
-			if (config_raw.plugins == null) config_raw.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;
+				let is_js: bool = ends_with(f, ".js");
+				if (!is_js) {
+					continue;
+				}
+				let enabled: bool = array_index_of(config_raw.plugins, f) >= 0;
 				h.selected = enabled;
-				let tag: string = is_js ? f.split(".")[0] : f;
+				let tag: string = is_js ? string_split(f, ".")[0] : f;
 				zui_check(h, tag);
 				if (h.changed && h.selected != enabled) {
 					h.selected ? config_enable_plugin(f) : config_disable_plugin(f);
@@ -616,19 +686,19 @@ if (Zui.panel(h1, 'New Plugin')) {
 							file_start(path);
 						}
 						if (ui_menu_button(ui, tr("Edit in Script Tab"))) {
-							let blob: ArrayBuffer = data_get_blob("plugins/" + f);
+							let blob: buffer_t = data_get_blob("plugins/" + f);
 							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";
+								if (!ends_with(ui_files_filename, ".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) {
+							if (array_index_of(config_raw.plugins, f) >= 0) {
 								array_remove(config_raw.plugins, f);
 								plugin_stop(f);
 							}
@@ -645,14 +715,16 @@ if (Zui.panel(h1, 'New Plugin')) {
 
 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
+	for (let i: i32 = 0; i < box_preferences_themes.length; ++i) {
+		box_preferences_themes[i] = substring(box_preferences_themes[i], 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[i] = substring(box_preferences_files_keymap[i], 0, box_preferences_files_keymap[i].length - 5); // Strip .json
 	}
 	box_preferences_files_keymap.unshift("default");
 }
@@ -662,11 +734,11 @@ function box_preferences_fetch_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
+	return array_index_of(box_preferences_themes, substring(config_raw.theme, 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
+	return array_index_of(box_preferences_files_keymap, substring(config_raw.keymap, 0, config_raw.keymap.length - 5)); // Strip .json
 }
 
 function box_preferences_set_scale() {

+ 42 - 22
base/Sources/box_projects.ts

@@ -49,7 +49,7 @@ function box_projects_tab(ui: zui_t) {
 			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("."));
+				base = substring(base, string_last_index_of(base, path_sep) + 1, string_last_index_of(base, "."));
 				j++;
 				if (title == base) {
 					i++;
@@ -70,19 +70,25 @@ function box_projects_tab(ui: zui_t) {
 		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);
+			for (let i: i32 = 0; i < num * mult; ++i) {
+				array_push(ar, 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;
+			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);
+					if (show_asset_names) {
+						zui_end_element(0);
+					}
 					continue;
 				}
 
@@ -90,17 +96,19 @@ function box_projects_tab(ui: zui_t) {
 
 				///if krom_ios
 				let document_directory: string = krom_save_dialog("", "");
-				document_directory = document_directory.substr(0, document_directory.length - 8); // Strip /'untitled'
+				document_directory = substring(document_directory, 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);
+				let icon_path: string = substring(path, 0, path.length - 4) + "_icon.png";
+				if (box_projects_icon_map == null) {
+					box_projects_icon_map = map_create();
+				}
+				let icon: image_t = map_get(box_projects_icon_map, icon_path);
 				if (icon == null) {
 					let image: image_t = data_get_image(icon_path);
 					icon = image;
-					box_projects_icon_map.set(icon_path, icon);
+					map_set(box_projects_icon_map, icon_path, icon);
 				}
 
 				let uix: i32 = ui._x;
@@ -113,7 +121,7 @@ function box_projects_tab(ui: zui_t) {
 						ui._x = uix;
 						zui_fill(0, 0, 128, 128, 0x66000000);
 						ui._x = _uix;
-						let doImport = function () {
+						let do_import = function () {
 							app_notify_on_init(function () {
 								ui_box_hide();
 								import_arm_run_project(path);
@@ -123,14 +131,14 @@ function box_projects_tab(ui: zui_t) {
 						///if (krom_android || krom_ios)
 						base_notify_on_next_frame(function () {
 							console_toast(tr("Opening project"));
-							base_notify_on_next_frame(doImport);
+							base_notify_on_next_frame(do_import);
 						});
 						///else
-						doImport();
+						do_import();
 						///end
 					}
 
-					let name: string = path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf("."));
+					let name: string = substring(path, string_last_index_of(path, path_sep) + 1, string_last_index_of(path, "."));
 					if (ui.is_hovered && ui.input_released_r) {
 						ui_menu_draw(function (ui: zui_t) {
 							// if (menuButton(ui, tr("Duplicate"))) {}
@@ -138,9 +146,9 @@ function box_projects_tab(ui: zui_t) {
 								app_notify_on_init(function () {
 									file_delete(path);
 									file_delete(icon_path);
-									let data_path: string = path.substr(0, path.length - 4);
+									let data_path: string = substring(path, 0, path.length - 4);
 									file_delete(data_path);
-									recent_projects.splice(i, 1);
+									array_splice(recent_projects, i, 1);
 								});
 							}
 						}, 1);
@@ -150,7 +158,9 @@ function box_projects_tab(ui: zui_t) {
 						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);
+						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);
@@ -159,7 +169,9 @@ function box_projects_tab(ui: zui_t) {
 				}
 				else {
 					zui_end_element(0);
-					if (show_asset_names) zui_end_element(0);
+					if (show_asset_names) {
+						zui_end_element(0);
+					}
 					ui._x = uix;
 				}
 			}
@@ -185,9 +197,11 @@ function box_projects_recent_tab(ui: zui_t) {
 			///else
 			file = string_replace_all(path, "\\", "/");
 			///end
-			file = file.substr(file.lastIndexOf(path_sep) + 1);
+			file = substring(file, string_last_index_of(file, path_sep) + 1, file.length);
 
-			if (file.toLowerCase().indexOf(box_projects_hsearch.text.toLowerCase()) < 0) continue; // Search filter
+			if (string_index_of(to_lower_case(file), to_lower_case(box_projects_hsearch.text)) < 0) {
+				continue; // Search filter
+			}
 
 			if (zui_button(file, zui_align_t.LEFT) && file_exists(path)) {
 				let current: image_t = _g2_current;
@@ -199,7 +213,9 @@ function box_projects_recent_tab(ui: zui_t) {
 				if (g2_in_use) g2_begin(current);
 				ui_box_hide();
 			}
-			if (ui.is_hovered) zui_tooltip(path);
+			if (ui.is_hovered) {
+				zui_tooltip(path);
+			}
 		}
 
 		ui.enabled = config_raw.recent_projects.length > 0;
@@ -210,8 +226,12 @@ function box_projects_recent_tab(ui: zui_t) {
 		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();
+		if (zui_button(tr("New .."), zui_align_t.LEFT)) {
+			project_new_box();
+		}
+		if (zui_button(tr("Open..."), zui_align_t.LEFT)) {
+			project_open();
+		}
 	}
 }
 

+ 34 - 18
base/Sources/camera.ts

@@ -126,18 +126,34 @@ function camera_update() {
 
 		if (move_forward || move_backward || strafe_right || strafe_left || strafe_up || strafe_down) {
 			camera_ease += time_delta() * 15;
-			if (camera_ease > 1.0) camera_ease = 1.0;
+			if (camera_ease > 1.0) {
+				camera_ease = 1.0;
+			}
 			vec4_set(camera_dir, 0, 0, 0);
-			if (move_forward) vec4_add_f(camera_dir, camera_object_look(camera).x, camera_object_look(camera).y, camera_object_look(camera).z);
-			if (move_backward) vec4_add_f(camera_dir, -camera_object_look(camera).x, -camera_object_look(camera).y, -camera_object_look(camera).z);
-			if (strafe_right) vec4_add_f(camera_dir, camera_object_right(camera).x, camera_object_right(camera).y, camera_object_right(camera).z);
-			if (strafe_left) vec4_add_f(camera_dir, -camera_object_right(camera).x, -camera_object_right(camera).y, -camera_object_right(camera).z);
-			if (strafe_up) vec4_add_f(camera_dir, 0, 0, 1);
-			if (strafe_down) vec4_add_f(camera_dir, 0, 0, -1);
+			if (move_forward) {
+				vec4_add_f(camera_dir, camera_object_look(camera).x, camera_object_look(camera).y, camera_object_look(camera).z);
+			}
+			if (move_backward) {
+				vec4_add_f(camera_dir, -camera_object_look(camera).x, -camera_object_look(camera).y, -camera_object_look(camera).z);
+			}
+			if (strafe_right) {
+				vec4_add_f(camera_dir, camera_object_right(camera).x, camera_object_right(camera).y, camera_object_right(camera).z);
+			}
+			if (strafe_left) {
+				vec4_add_f(camera_dir, -camera_object_right(camera).x, -camera_object_right(camera).y, -camera_object_right(camera).z);
+			}
+			if (strafe_up) {
+				vec4_add_f(camera_dir, 0, 0, 1);
+			}
+			if (strafe_down) {
+				vec4_add_f(camera_dir, 0, 0, -1);
+			}
 		}
 		else {
 			camera_ease -= time_delta() * 20.0 * camera_ease;
-			if (camera_ease < 0.0) camera_ease = 0.0;
+			if (camera_ease < 0.0) {
+				camera_ease = 0.0;
+			}
 		}
 
 
@@ -194,21 +210,21 @@ function camera_get_zoom_speed(): f32 {
 	return config_raw.camera_zoom_speed * sign;
 }
 
-function camera_reset(viewIndex: i32 = -1) {
+function camera_reset(view_index: i32 = -1) {
 	let camera: camera_object_t = scene_camera;
-	if (viewIndex == -1) {
+	if (view_index == -1) {
 		camera_origins = [vec4_create(0, 0, 0), vec4_create(0, 0, 0)];
 		camera_views = [mat4_clone(camera.base.transform.local), mat4_clone(camera.base.transform.local)];
 	}
 	else {
-		camera_origins[viewIndex] = vec4_create(0, 0, 0);
-		camera_views[viewIndex] = mat4_clone(camera.base.transform.local);
+		camera_origins[view_index] = vec4_create(0, 0, 0);
+		camera_views[view_index] = mat4_clone(camera.base.transform.local);
 	}
 }
 
-function camera_pan_action(modif: bool, defaultKeymap: bool) {
+function camera_pan_action(modif: bool, default_keymap: bool) {
 	let camera: camera_object_t = scene_camera;
-	if (operator_shortcut(config_keymap.action_pan, shortcut_type_t.DOWN) || (mouse_down("middle") && !modif && defaultKeymap)) {
+	if (operator_shortcut(config_keymap.action_pan, shortcut_type_t.DOWN) || (mouse_down("middle") && !modif && default_keymap)) {
 		camera_redraws = 2;
 		let look: vec4_t = vec4_mult(vec4_normalize(transform_look(camera.base.transform)), mouse_movement_y / 150 * config_raw.camera_pan_speed);
 		let right: vec4_t = vec4_mult(vec4_normalize(transform_right(camera.base.transform)), -mouse_movement_x / 150 * config_raw.camera_pan_speed);
@@ -222,8 +238,8 @@ function camera_pan_action(modif: bool, defaultKeymap: bool) {
 
 function camera_get_zoom_delta(): f32 {
 	return config_raw.zoom_direction == zoom_direction_t.VERTICAL ? -mouse_movement_y :
-			config_raw.zoom_direction == zoom_direction_t.VERTICAL_INVERTED ? -mouse_movement_y :
-			config_raw.zoom_direction == zoom_direction_t.HORIZONTAL ? mouse_movement_x :
-			config_raw.zoom_direction == zoom_direction_t.HORIZONTAL_INVERTED ? mouse_movement_x :
-			-(mouse_movement_y - mouse_movement_x);
+		   config_raw.zoom_direction == zoom_direction_t.VERTICAL_INVERTED ? -mouse_movement_y :
+		   config_raw.zoom_direction == zoom_direction_t.HORIZONTAL ? mouse_movement_x :
+		   config_raw.zoom_direction == zoom_direction_t.HORIZONTAL_INVERTED ? mouse_movement_x :
+		   -(mouse_movement_y - mouse_movement_x);
 }

+ 56 - 38
base/Sources/config.ts

@@ -8,7 +8,7 @@ let config_button_spacing: string = config_default_button_spacing;
 
 function config_load(done: ()=>void) {
 	try {
-		let blob: ArrayBuffer = data_get_blob((path_is_protected() ? krom_save_path() : "") + "config.json");
+		let blob: buffer_t = data_get_blob((path_is_protected() ? krom_save_path() : "") + "config.json");
 		config_loaded = true;
 		config_raw = json_parse(sys_buffer_to_string(blob));
 		done();
@@ -18,7 +18,7 @@ function config_load(done: ()=>void) {
 
 		///if krom_linux
 		try { // Protected directory
-			let blob: ArrayBuffer = data_get_blob(krom_save_path() + "config.json");
+			let blob: buffer_t = data_get_blob(krom_save_path() + "config.json");
 			config_loaded = true;
 			config_raw = json_parse(sys_buffer_to_string(blob));
 			done();
@@ -41,7 +41,9 @@ function config_save() {
 	krom_file_save_bytes(path, buffer);
 
 	///if krom_linux // Protected directory
-	if (!file_exists(path)) krom_file_save_bytes(krom_save_path() + "config.json", buffer);
+	if (!file_exists(path)) {
+		krom_file_save_bytes(krom_save_path() + "config.json", buffer);
+	}
 	///end
 }
 
@@ -108,14 +110,14 @@ function config_init() {
 
 function config_get_sha(): string {
 	let sha: string = "";
-	let blob: ArrayBuffer = data_get_blob("version.json");
+	let blob: buffer_t = data_get_blob("version.json");
 	sha = json_parse(sys_buffer_to_string(blob)).sha;
 	return sha;
 }
 
 function config_get_date(): string {
 	let date: string = "";
-	let blob: ArrayBuffer = data_get_blob("version.json");
+	let blob: buffer_t = data_get_blob("version.json");
 	date = json_parse(sys_buffer_to_string(blob)).date;
 	return date;
 }
@@ -123,9 +125,15 @@ function config_get_date(): string {
 function config_get_options(): kinc_sys_ops_t {
 	let window_mode: window_mode_t = config_raw.window_mode == 0 ? window_mode_t.WINDOWED : window_mode_t.FULLSCREEN;
 	let window_features: window_features_t = window_features_t.NONE;
-	if (config_raw.window_resizable) window_features |= window_features_t.RESIZABLE;
-	if (config_raw.window_maximizable) window_features |= window_features_t.MAXIMIZABLE;
-	if (config_raw.window_minimizable) window_features |= window_features_t.MINIMIZABLE;
+	if (config_raw.window_resizable) {
+		window_features |= window_features_t.RESIZABLE;
+	}
+	if (config_raw.window_maximizable) {
+		window_features |= window_features_t.MAXIMIZABLE;
+	}
+	if (config_raw.window_minimizable) {
+		window_features |= window_features_t.MINIMIZABLE;
+	}
 	let title: string = "untitled - " + manifest_title;
 	return {
 		title: title,
@@ -187,7 +195,7 @@ function config_load_keymap() {
 		config_keymap = base_default_keymap;
 	}
 	else {
-		let blob: ArrayBuffer = data_get_blob("keymap_presets/" + config_raw.keymap);
+		let blob: buffer_t = data_get_blob("keymap_presets/" + config_raw.keymap);
 		config_keymap = json_parse(sys_buffer_to_string(blob));
 		// Fill in undefined keys with defaults
 		for (let field in base_default_keymap) {
@@ -200,7 +208,9 @@ function config_load_keymap() {
 }
 
 function config_save_keymap() {
-	if (config_raw.keymap == "default.json") return;
+	if (config_raw.keymap == "default.json") {
+		return;
+	}
 	let path: string = data_path() + "keymap_presets/" + config_raw.keymap;
 	let buffer: buffer_t = sys_string_to_buffer(json_stringify(config_keymap));
 	krom_file_save_bytes(path, buffer);
@@ -208,30 +218,30 @@ function config_save_keymap() {
 
 function config_get_super_sample_quality(f: f32): i32 {
 	return f == 0.25 ? 0 :
-			f == 0.5 ? 1 :
-			f == 1.0 ? 2 :
-			f == 1.5 ? 3 :
-			f == 2.0 ? 4 : 5;
+		   f == 0.5 ? 1 :
+		   f == 1.0 ? 2 :
+		   f == 1.5 ? 3 :
+		   f == 2.0 ? 4 : 5;
 }
 
 function config_get_super_sample_size(i: i32): f32 {
 	return i == 0 ? 0.25 :
-			i == 1 ? 0.5 :
-			i == 2 ? 1.0 :
-			i == 3 ? 1.5 :
-			i == 4 ? 2.0 : 4.0;
+		   i == 1 ? 0.5 :
+		   i == 2 ? 1.0 :
+		   i == 3 ? 1.5 :
+		   i == 4 ? 2.0 : 4.0;
 }
 
 function config_get_texture_res(): i32 {
 	let res: i32 = base_res_handle.position;
 	return res == texture_res_t.RES128 ? 128 :
-			res == texture_res_t.RES256 ? 256 :
-			res == texture_res_t.RES512 ? 512 :
-			res == texture_res_t.RES1024 ? 1024 :
-			res == texture_res_t.RES2048 ? 2048 :
-			res == texture_res_t.RES4096 ? 4096 :
-			res == texture_res_t.RES8192 ? 8192 :
-			res == texture_res_t.RES16384 ? 16384 : 0;
+		   res == texture_res_t.RES256 ? 256 :
+		   res == texture_res_t.RES512 ? 512 :
+		   res == texture_res_t.RES1024 ? 1024 :
+		   res == texture_res_t.RES2048 ? 2048 :
+		   res == texture_res_t.RES4096 ? 4096 :
+		   res == texture_res_t.RES8192 ? 8192 :
+		   res == texture_res_t.RES16384 ? 16384 : 0;
 }
 
 function config_get_texture_res_x(): i32 {
@@ -244,13 +254,13 @@ function config_get_texture_res_y(): i32 {
 
 function config_get_texture_res_pos(i: i32): i32 {
 	return i == 128 ? texture_res_t.RES128 :
-			i == 256 ? texture_res_t.RES256 :
-			i == 512 ? texture_res_t.RES512 :
-			i == 1024 ? texture_res_t.RES1024 :
-			i == 2048 ? texture_res_t.RES2048 :
-			i == 4096 ? texture_res_t.RES4096 :
-			i == 8192 ? texture_res_t.RES8192 :
-			i == 16384 ? texture_res_t.RES16384 : 0;
+		   i == 256 ? texture_res_t.RES256 :
+		   i == 512 ? texture_res_t.RES512 :
+		   i == 1024 ? texture_res_t.RES1024 :
+		   i == 2048 ? texture_res_t.RES2048 :
+		   i == 4096 ? texture_res_t.RES4096 :
+		   i == 8192 ? texture_res_t.RES8192 :
+		   i == 16384 ? texture_res_t.RES16384 : 0;
 }
 
 function config_load_theme(theme: string, tagRedraw: bool = true) {
@@ -258,20 +268,28 @@ function config_load_theme(theme: string, tagRedraw: bool = true) {
 		base_theme = zui_theme_create();
 	}
 	else {
-		let b: ArrayBuffer = data_get_blob("themes/" + theme);
+		let b: buffer_t = data_get_blob("themes/" + theme);
 		let parsed: any = json_parse(sys_buffer_to_string(b));
 		base_theme = zui_theme_create();
 		for (let key in base_theme) {
-			if (key == "theme_") continue;
-			if (key.startsWith("set_")) continue;
-			if (key.startsWith("get_")) key = key.substr(4);
+			if (key == "theme_") {
+				continue;
+			}
+			if (starts_with(key, "set_")) {
+				continue;
+			}
+			if (starts_with(key, "get_")) {
+				key = substring(key, 4, key.length);
+			}
 			let atheme: any = base_theme;
 			atheme[key] = parsed[key];
 		}
 	}
 	base_theme.FILL_WINDOW_BG = true;
 	if (tagRedraw) {
-		for (let ui of base_get_uis()) ui.t = base_theme;
+		for (let ui of base_get_uis()) {
+			ui.t = base_theme;
+		}
 		ui_base_tag_ui_redraw();
 	}
 	if (config_raw.touch_ui) {
@@ -294,7 +312,7 @@ function config_load_theme(theme: string, tagRedraw: bool = true) {
 }
 
 function config_enable_plugin(f: string) {
-	config_raw.plugins.push(f);
+	array_push(config_raw.plugins, f);
 	plugin_start(f);
 }
 

+ 9 - 5
base/Sources/console.ts

@@ -20,9 +20,9 @@ function console_draw_toast(s: string) {
 
 function console_toast(s: string) {
 	// Show a popup message
-	let _render = () => {
+	let _render = function () {
 		console_draw_toast(s);
-		base_notify_on_next_frame(() => {
+		base_notify_on_next_frame(function () {
 			app_remove_render_2d(_render);
 		});
 	}
@@ -42,7 +42,9 @@ function console_progress(s: string) {
 	else if (console_progress_text == null) {
 		app_notify_on_render_2d(console_draw_progress);
 	}
-	if (s != null) console_trace(s);
+	if (s != null) {
+		console_trace(s);
+	}
 	console_progress_text = s;
 }
 
@@ -68,6 +70,8 @@ function console_log(s: string) {
 
 function console_trace(v: any) {
 	base_redraw_console();
-	console_last_traces.unshift(String(v));
-	if (console_last_traces.length > 100) console_last_traces.pop();
+	console_last_traces.unshift(any_to_string(v));
+	if (console_last_traces.length > 100) {
+		console_last_traces.pop();
+	}
 }

+ 89 - 43
base/Sources/context.ts

@@ -19,7 +19,7 @@ type context_t = {
 	picked_color?: swatch_color_t;
 	color_picker_callback?: (sc: swatch_color_t)=>void;
 
-	default_irradiance?: Float32Array;
+	default_irradiance?: f32_array_t;
 	default_radiance?: image_t;
 	default_radiance_mipmaps?: image_t[];
 	saved_envmap?: image_t;
@@ -57,7 +57,7 @@ type context_t = {
 	render_mode?: render_mode_t;
 	///end
 
-	viewport_shader?: (ns: NodeShaderRaw)=>string;
+	viewport_shader?: (ns: node_shader_t)=>string;
 	hscale_was_changed?: bool;
 	export_mesh_format?: mesh_format_t;
 	export_mesh_index?: i32;
@@ -113,10 +113,10 @@ type context_t = {
 	pen_painting_only?: bool;
 
 	///if (is_paint || is_sculpt)
-	material?: SlotMaterialRaw;
-	layer?: SlotLayerRaw;
-	brush?: SlotBrushRaw;
-	font?: SlotFontRaw;
+	material?: slot_material_t;
+	layer?: slot_layer_t;
+	brush?: slot_brush_t;
+	font?: slot_font_t;
 	tool?: workspace_tool_t;
 
 	layer_preview_dirty?: bool;
@@ -127,7 +127,7 @@ type context_t = {
 	node_previews_used?: string[];
 	node_preview_name?: string;
 	mask_preview_rgba32?: image_t;
-	mask_preview_last?: SlotLayerRaw;
+	mask_preview_last?: slot_layer_t;
 
 	colorid_picked?: bool;
 	material_preview?: bool;
@@ -541,12 +541,16 @@ function context_use_deferred(): bool {
 
 ///if (is_paint || is_sculpt)
 function context_select_material(i: i32) {
-	if (project_materials.length <= i) return;
+	if (project_materials.length <= i) {
+		return;
+	}
 	context_set_material(project_materials[i]);
 }
 
-function context_set_material(m: SlotMaterialRaw) {
-	if (project_materials.indexOf(m) == -1) return;
+function context_set_material(m: slot_material_t) {
+	if (array_index_of(project_materials, m) == -1) {
+		return;
+	}
 	context_raw.material = m;
 	make_material_parse_paint_material();
 	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
@@ -564,12 +568,16 @@ function context_set_material(m: SlotMaterialRaw) {
 }
 
 function context_select_brush(i: i32) {
-	if (project_brushes.length <= i) return;
+	if (project_brushes.length <= i) {
+		return;
+	}
 	context_set_brush(project_brushes[i]);
 }
 
-function context_set_brush(b: SlotBrushRaw) {
-	if (project_brushes.indexOf(b) == -1) return;
+function context_set_brush(b: slot_brush_t) {
+	if (array_index_of(project_brushes, b) == -1) {
+		return;
+	}
 	context_raw.brush = b;
 	make_material_parse_brush();
 	ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
@@ -577,12 +585,16 @@ function context_set_brush(b: SlotBrushRaw) {
 }
 
 function context_select_font(i: i32) {
-	if (project_fonts.length <= i) return;
+	if (project_fonts.length <= i) {
+		return;
+	}
 	context_set_font(project_fonts[i]);
 }
 
-function context_set_font(f: SlotFontRaw) {
-	if (project_fonts.indexOf(f) == -1) return;
+function context_set_font(f: slot_font_t) {
+	if (array_index_of(project_fonts, f) == -1) {
+		return;
+	}
 	context_raw.font = f;
 	util_render_make_text_preview();
 	util_render_make_decal_preview();
@@ -591,12 +603,16 @@ function context_set_font(f: SlotFontRaw) {
 }
 
 function context_select_layer(i: i32) {
-	if (project_layers.length <= i) return;
+	if (project_layers.length <= i) {
+		return;
+	}
 	context_set_layer(project_layers[i]);
 }
 
-function context_set_layer(l: SlotLayerRaw) {
-	if (l == context_raw.layer) return;
+function context_set_layer(l: slot_layer_t) {
+	if (l == context_raw.layer) {
+		return;
+	}
 	context_raw.layer = l;
 	ui_header_handle.redraws = 2;
 
@@ -670,11 +686,15 @@ function context_init_tool() {
 function context_select_paint_object(o: mesh_object_t) {
 	///if (is_paint || is_sculpt)
 	ui_header_handle.redraws = 2;
-	for (let p of project_paint_objects) p.skip_context = "paint";
+	for (let p of project_paint_objects) {
+		p.skip_context = "paint";
+	}
 	context_raw.paint_object = o;
 
 	let mask: i32 = slot_layer_get_object_mask(context_raw.layer);
-	if (context_layer_filter_used()) mask = context_raw.layer_filter;
+	if (context_layer_filter_used()) {
+		mask = context_raw.layer_filter;
+	}
 
 	if (context_raw.merged_object == null || mask > 0) {
 		context_raw.paint_object.skip_context = "";
@@ -691,7 +711,11 @@ function context_select_paint_object(o: mesh_object_t) {
 
 function context_main_object(): mesh_object_t {
 	///if (is_paint || is_sculpt)
-	for (let po of project_paint_objects) if (po.base.children.length > 0) return po;
+	for (let po of project_paint_objects) {
+		if (po.base.children.length > 0) {
+			return po;
+		}
+	}
 	return project_paint_objects[0];
 	///end
 
@@ -722,15 +746,17 @@ function context_object_mask_used(): bool {
 
 function context_in_viewport(): bool {
 	return context_raw.paint_vec.x < 1 && context_raw.paint_vec.x > 0 &&
-			context_raw.paint_vec.y < 1 && context_raw.paint_vec.y > 0;
+		   context_raw.paint_vec.y < 1 && context_raw.paint_vec.y > 0;
 }
 
 function context_in_paint_area(): bool {
 	///if (is_paint || is_sculpt)
 	let right: i32 = app_w();
-	if (ui_view2d_show) right += ui_view2d_ww;
+	if (ui_view2d_show) {
+		right += ui_view2d_ww;
+	}
 	return mouse_view_x() > 0 && mouse_view_x() < right &&
-			mouse_view_y() > 0 && mouse_view_y() < app_h();
+		   mouse_view_y() > 0 && mouse_view_y() < app_h();
 	///end
 
 	///if is_lab
@@ -749,15 +775,15 @@ function context_in_materials(): bool {
 ///if (is_paint || is_sculpt)
 function context_in_2d_view(type: view_2d_type_t = view_2d_type_t.LAYER): bool {
 	return ui_view2d_show && ui_view2d_type == type &&
-			mouse_x > ui_view2d_wx && mouse_x < ui_view2d_wx + ui_view2d_ww &&
-			mouse_y > ui_view2d_wy && mouse_y < ui_view2d_wy + ui_view2d_wh;
+		   mouse_x > ui_view2d_wx && mouse_x < ui_view2d_wx + ui_view2d_ww &&
+		   mouse_y > ui_view2d_wy && mouse_y < ui_view2d_wy + ui_view2d_wh;
 }
 ///end
 
 function context_in_nodes(): bool {
 	return ui_nodes_show &&
-			mouse_x > ui_nodes_wx && mouse_x < ui_nodes_wx + ui_nodes_ww &&
-			mouse_y > ui_nodes_wy && mouse_y < ui_nodes_wy + ui_nodes_wh;
+		   mouse_x > ui_nodes_wx && mouse_x < ui_nodes_wx + ui_nodes_ww &&
+		   mouse_y > ui_nodes_wy && mouse_y < ui_nodes_wy + ui_nodes_wh;
 }
 
 function context_in_swatches(): bool {
@@ -769,19 +795,33 @@ function context_in_browser(): bool {
 }
 
 function context_get_area_type(): area_type_t {
-	if (context_in_viewport()) return area_type_t.VIEWPORT;
-	if (context_in_nodes()) return area_type_t.NODES;
-	if (context_in_browser()) return area_type_t.BROWSER;
+	if (context_in_viewport()) {
+		return area_type_t.VIEWPORT;
+	}
+	if (context_in_nodes()) {
+		return area_type_t.NODES;
+	}
+	if (context_in_browser()) {
+		return area_type_t.BROWSER;
+	}
 	///if (is_paint || is_sculpt)
-	if (context_in_2d_view()) return area_type_t.VIEW2D;
-	if (context_in_layers()) return area_type_t.LAYERS;
-	if (context_in_materials()) return area_type_t.MATERIALS;
+	if (context_in_2d_view()) {
+		return area_type_t.VIEW2D;
+	}
+	if (context_in_layers()) {
+		return area_type_t.LAYERS;
+	}
+	if (context_in_materials()) {
+		return area_type_t.MATERIALS;
+	}
 	///end
 	return -1 as area_type_t;
 }
 
 function context_set_viewport_mode(mode: viewport_mode_t) {
-	if (mode == context_raw.viewport_mode) return;
+	if (mode == context_raw.viewport_mode) {
+		return;
+	}
 
 	context_raw.viewport_mode = mode;
 	if (context_use_deferred()) {
@@ -800,10 +840,12 @@ function context_load_envmap() {
 	if (!context_raw.envmap_loaded) {
 		// TODO: Unable to share texture for both radiance and envmap - reload image
 		context_raw.envmap_loaded = true;
-		data_cached_images.delete("World_radiance.k");
+		map_delete(data_cached_images, "World_radiance.k");
 	}
 	world_data_load_envmap(scene_world);
-	if (context_raw.saved_envmap == null) context_raw.saved_envmap = scene_world._.envmap;
+	if (context_raw.saved_envmap == null) {
+		context_raw.saved_envmap = scene_world._.envmap;
+	}
 }
 
 function context_update_envmap() {
@@ -815,7 +857,7 @@ function context_update_envmap() {
 	}
 }
 
-function context_set_viewport_shader(viewportShader: (ns: NodeShaderRaw)=>string) {
+function context_set_viewport_shader(viewportShader: (ns: node_shader_t)=>string) {
 	context_raw.viewport_shader = viewportShader;
 	context_set_render_path();
 }
@@ -837,9 +879,9 @@ function context_enable_import_plugin(file: string): bool {
 	if (box_preferences_files_plugin == null) {
 		box_preferences_fetch_plugins();
 	}
-	let ext: string = file.substr(file.lastIndexOf(".") + 1);
+	let ext: string = substring(file, string_last_index_of(file, ".") + 1, file.length);
 	for (let f of box_preferences_files_plugin) {
-		if (f.startsWith("import_") && f.indexOf(ext) >= 0) {
+		if (starts_with(f, "import_") && string_index_of(f, ext) >= 0) {
 			config_enable_plugin(f);
 			console_info(f + " " + tr("plugin enabled"));
 			return true;
@@ -929,8 +971,12 @@ function context_update() {
 	}
 
 	if (operator_shortcut(config_keymap.brush_ruler + "+" + config_keymap.action_paint, shortcut_type_t.DOWN)) {
-		if (context_raw.lock_x) paint_x = context_raw.start_x;
-		if (context_raw.lock_y) paint_y = context_raw.start_y;
+		if (context_raw.lock_x) {
+			paint_x = context_raw.start_x;
+		}
+		if (context_raw.lock_y) {
+			paint_y = context_raw.start_y;
+		}
 	}
 
 	context_raw.coords.x = paint_x;

+ 74 - 64
base/Sources/export_arm.ts

@@ -1,11 +1,11 @@
 
 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);
+	for (let p of paint_objects) array_push(mesh_datas, 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);
+	if (!ends_with(path, ".arm")) path += ".arm";
+	krom_file_save_bytes(path, b, buffer_size(b) + 1);
 }
 
 function export_arm_run_project() {
@@ -14,11 +14,11 @@ function export_arm_run_project() {
 	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);
+		array_push(mnodes, c);
 	}
 
 	let bnodes: zui_node_canvas_t[] = [];
-	for (let b of project_brushes) bnodes.push(b.canvas);
+	for (let b of project_brushes) array_push(bnodes, b.canvas);
 	///end
 
 	///if is_lab
@@ -32,13 +32,13 @@ function export_arm_run_project() {
 		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);
+			array_push(mgroups, c);
 		}
 	}
 
 	///if (is_paint || is_sculpt)
 	let md: mesh_data_t[] = [];
-	for (let p of project_paint_objects) md.push(p.data);
+	for (let p of project_paint_objects) array_push(md, p.data);
 	///end
 
 	///if is_lab
@@ -56,7 +56,7 @@ function export_arm_run_project() {
 
 	let ld: layer_data_t[] = [];
 	for (let l of project_layers) {
-		ld.push({
+		array_push(ld, {
 			name: l.name,
 			res: l.texpaint != null ? l.texpaint.width : project_layers[0].texpaint.width,
 			bpp: bpp,
@@ -66,10 +66,10 @@ function export_arm_run_project() {
 			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,
+			fill_layer: l.fill_layer != null ? array_index_of(project_materials, l.fill_layer) : -1,
 			object_mask: l.object_mask,
 			blending: l.blending,
-			parent: l.parent != null ? project_layers.indexOf(l.parent) : -1,
+			parent: l.parent != null ? array_index_of(project_layers, l.parent) : -1,
 			visible: l.visible,
 			///if is_paint
 			texpaint_nor: l.texpaint_nor != null ? lz4_encode(image_get_pixels(l.texpaint_nor)) : null,
@@ -94,7 +94,7 @@ function export_arm_run_project() {
 	///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;
+	let same_drive: bool = project_raw.envmap != null ? char_at(project_filepath, 0) == char_at(project_raw.envmap, 0) : true;
 	///end
 
 	project_raw = {
@@ -136,7 +136,7 @@ function export_arm_run_project() {
 	};
 
 	///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 tex: image_t = map_get(render_path_render_targets, 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);
@@ -152,14 +152,14 @@ function export_arm_run_project() {
 	g2_end();
 	///end
 	let mesh_icon_pixels: buffer_t = image_get_pixels(mesh_icon);
-	let u8a: Uint8Array = new Uint8Array(mesh_icon_pixels);
+	let u8a: u8_array_t = new u8_array_t(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(() => {
+	base_notify_on_next_frame(function () {
 		image_unload(mesh_icon);
 	});
 	// raw.mesh_icons =
@@ -168,22 +168,22 @@ function export_arm_run_project() {
 	// 	///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);
+	krom_write_png(substring(project_filepath, 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");
+	let is_packed: bool = ends_with(project_filepath, "_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);
+	krom_file_save_bytes(project_filepath, buffer, buffer_size(buffer) + 1);
 
 	// Save to recent
 	///if krom_ios
-	let recent_path: string = project_filepath.substr(project_filepath.lastIndexOf("/") + 1);
+	let recent_path: string = substring(project_filepath, string_last_index_of(project_filepath, "/") + 1, project_filepath.length);
 	///else
 	let recent_path: string = project_filepath;
 	///end
@@ -210,8 +210,8 @@ function export_arm_export_node(n: zui_node_t, assets: asset_t[] = null) {
 
 		if (assets != null) {
 			let asset: asset_t = project_assets[index];
-			if (assets.indexOf(asset) == -1) {
-				assets.push(asset);
+			if (array_index_of(assets, asset) == -1) {
+				array_push(assets, asset);
 			}
 		}
 	}
@@ -223,10 +223,10 @@ function export_arm_export_node(n: zui_node_t, assets: asset_t[] = null) {
 
 ///if (is_paint || is_sculpt)
 function export_arm_run_material(path: string) {
-	if (!path.endsWith(".arm")) path += ".arm";
+	if (!ends_with(path, ".arm")) path += ".arm";
 	let mnodes: zui_node_canvas_t[] = [];
 	let mgroups: zui_node_canvas_t[] = null;
-	let m: SlotMaterialRaw = context_raw.material;
+	let m: slot_material_t = 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)) {
@@ -235,10 +235,10 @@ function export_arm_run_material(path: string) {
 		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);
+	array_push(mnodes, c);
 
 	let texture_files: string[] = export_arm_assets_to_files(path, assets);
-	let is_cloud: bool = path.endsWith("_cloud_.arm");
+	let is_cloud: bool = ends_with(path, "_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) {
@@ -260,9 +260,9 @@ function export_arm_run_material(path: string) {
 	};
 
 	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);
+		krom_write_png(substring(path, 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);
+			krom_write_jpg(substring(path, 0, path.length - 4) + "_icon.jpg", image_get_pixels(m.image), m.image.width, m.image.height, 0, 50);
 		}
 	}
 
@@ -271,17 +271,17 @@ function export_arm_run_material(path: string) {
 	}
 
 	let buffer: buffer_t = armpack_encode(raw);
-	krom_file_save_bytes(path, buffer, buffer.byteLength + 1);
+	krom_file_save_bytes(path, buffer, buffer_size(buffer) + 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);
+function export_arm_bgra_swap(buffer: buffer_t) {
+	let view: buffer_view_t = buffer_view_create(buffer);
+	for (let i: i32 = 0; i < math_floor(buffer_size(buffer) / 4); ++i) {
+		let r: i32 = buffer_view_get_u8(view, i * 4);
+		buffer_view_set_u8(view, i * 4, buffer_view_get_u8(view, i * 4 + 2));
+		buffer_view_set_u8(view, i * 4 + 2, r);
 	}
 	return buffer;
 }
@@ -289,17 +289,23 @@ function export_arm_bgra_swap(buffer: ArrayBuffer) {
 
 ///if (is_paint || is_sculpt)
 function export_arm_run_brush(path: string) {
-	if (!path.endsWith(".arm")) path += ".arm";
+	if (!ends_with(path, ".arm")) {
+		path += ".arm";
+	}
 	let bnodes: zui_node_canvas_t[] = [];
-	let b: SlotBrushRaw = context_raw.brush;
+	let b: slot_brush_t = 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);
+	for (let n of c.nodes) {
+		export_arm_export_node(n, assets);
+	}
+	array_push(bnodes, 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 is_cloud: bool = ends_with(path, "_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);
@@ -319,7 +325,7 @@ function export_arm_run_brush(path: string) {
 	};
 
 	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);
+		krom_write_png(substring(path, 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
@@ -327,24 +333,24 @@ function export_arm_run_brush(path: string) {
 	}
 
 	let buffer: buffer_t = armpack_encode(raw);
-	krom_file_save_bytes(path, buffer, buffer.byteLength + 1);
+	krom_file_save_bytes(path, buffer, buffer_size(buffer) + 1);
 }
 ///end
 
-function export_arm_assets_to_files(projectPath: string, assets: asset_t[]): string[] {
+function export_arm_assets_to_files(project_path: 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);
+		let same_drive: bool = char_at(project_path, 0) == char_at(a.file, 0);
 		///end
 		// Convert image path from absolute to relative
 		if (same_drive) {
-			texture_files.push(path_to_relative(projectPath, a.file));
+			array_push(texture_files, path_to_relative(project_path, a.file));
 		}
 		else {
-			texture_files.push(a.file);
+			array_push(texture_files, a.file);
 		}
 	}
 	return texture_files;
@@ -357,34 +363,34 @@ function export_arm_meshes_to_files(project_path: string): string[] {
 		///if krom_ios
 		let same_drive: bool = false;
 		///else
-		let same_drive: bool = project_path.charAt(0) == file.charAt(0);
+		let same_drive: bool = char_at(project_path, 0) == char_at(file, 0);
 		///end
 		// Convert mesh path from absolute to relative
 		if (same_drive) {
-			mesh_files.push(path_to_relative(project_path, file));
+			array_push(mesh_files, path_to_relative(project_path, file));
 		}
 		else {
-			mesh_files.push(file);
+			array_push(mesh_files, file);
 		}
 	}
 	return mesh_files;
 }
 
-function export_arm_fonts_to_files(project_path: string, fonts: SlotFontRaw[]): string[] {
+function export_arm_fonts_to_files(project_path: string, fonts: slot_font_t[]): string[] {
 	let font_files: string[] = [];
 	for (let i = 1; i <fonts.length; ++i) {
-		let f: SlotFontRaw = fonts[i];
+		let f: slot_font_t = fonts[i];
 		///if krom_ios
 		let same_drive: bool = false;
 		///else
-		let same_drive: bool = project_path.charAt(0) == f.file.charAt(0);
+		let same_drive: bool = char_at(project_path, 0) == char_at(f.file, 0);
 		///end
 		// Convert font path from absolute to relative
 		if (same_drive) {
-			font_files.push(path_to_relative(project_path, f.file));
+			array_push(font_files, path_to_relative(project_path, f.file));
 		}
 		else {
-			font_files.push(f.file);
+			array_push(font_files, f.file);
 		}
 	}
 	return font_files;
@@ -398,7 +404,7 @@ function export_arm_get_packed_assets(project_path: string, texture_files: strin
 			///if krom_ios
 			let same_drive: bool = false;
 			///else
-			let same_drive: bool = project_path.charAt(0) == pa.name.charAt(0);
+			let same_drive: bool = char_at(project_path, 0) == char_at(pa.name, 0);
 			///end
 			// Convert path from absolute to relative
 			pa.name = same_drive ? path_to_relative(project_path, pa.name) : pa.name;
@@ -407,7 +413,7 @@ function export_arm_get_packed_assets(project_path: string, texture_files: strin
 					if (packed_assets == null) {
 						packed_assets = [];
 					}
-					packed_assets.push(pa);
+					array_push(packed_assets, pa);
 					break;
 				}
 			}
@@ -428,32 +434,36 @@ function export_arm_pack_assets(raw: project_format_t, assets: asset_t[]) {
 			g2_begin(temp);
 			g2_draw_image(image, 0, 0);
 			g2_end();
-			temp_images.push(temp);
-			raw.packed_assets.push({
+			array_push(temp_images, temp);
+			array_push(raw.packed_assets, {
 				name: assets[i].file,
-				bytes: assets[i].file.endsWith(".jpg") ?
+				bytes: ends_with(assets[i].file, ".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);
+	base_notify_on_next_frame(function () {
+		for (let image of temp_images) {
+			image_unload(image);
+		}
 	});
 }
 
 function export_arm_run_swatches(path: string) {
-	if (!path.endsWith(".arm")) path += ".arm";
+	if (!ends_with(path, ".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);
+	krom_file_save_bytes(path, buffer, buffer_size(buffer) + 1);
 }
 
-function export_arm_vec3f32(v: vec4_t): Float32Array {
-	let res: Float32Array = new Float32Array(3);
+function export_arm_vec3f32(v: vec4_t): f32_array_t {
+	let res: f32_array_t = f32_array_create(3);
 	res[0] = v.x;
 	res[1] = v.y;
 	res[2] = v.z;

+ 1 - 1
base/Sources/export_gpl.ts

@@ -7,7 +7,7 @@ function export_gpl_run(path: string, name: string, swatches: swatch_color_t[])
 	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";
+		o += any_to_string(color_get_rb(swatch.base)) + " " + any_to_string(color_get_gb(swatch.base)) + " " + any_to_string(color_get_bb(swatch.base)) + "\n";
 	}
 
 	krom_file_save_bytes(path, sys_string_to_buffer(o), o.length);

+ 24 - 22
base/Sources/export_obj.ts

@@ -1,7 +1,7 @@
 
 function export_obj_write_string(out: i32[], str: string) {
 	for (let i: i32 = 0; i < str.length; ++i) {
-		out.push(str.charCodeAt(i));
+		array_push(out, char_code_at(str, i));
 	}
 }
 
@@ -22,9 +22,9 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 		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 posa2: i16_array_t = i16_array_create(len * 3);
+		let nora2: i16_array_t = i16_array_create(len * 3);
+		let texa2: i16_array_t = i16_array_create(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();
@@ -38,13 +38,13 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 				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);
+					map_set(posmap, i, j);
 					found = true;
 					break;
 				}
 			}
 			if (!found) {
-				posmap.set(i, pi);
+				map_set(posmap, i, pi);
 				posa2[pi * 3    ] = posa[i * 4    ];
 				posa2[pi * 3 + 1] = posa[i * 4 + 1];
 				posa2[pi * 3 + 2] = posa[i * 4 + 2];
@@ -56,13 +56,13 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 				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);
+					map_set(normap, i, j);
 					found = true;
 					break;
 				}
 			}
 			if (!found) {
-				normap.set(i, ni);
+				map_set(normap, i, ni);
 				nora2[ni * 3    ] = nora[i * 2    ];
 				nora2[ni * 3 + 1] = nora[i * 2 + 1];
 				nora2[ni * 3 + 2] = posa[i * 4 + 3];
@@ -73,13 +73,13 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 			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);
+					map_set(texmap, i, j);
 					found = true;
 					break;
 				}
 			}
 			if (!found) {
-				texmap.set(i, ti);
+				map_set(texmap, i, ti);
 				texa2[ti * 2    ] = texa[i * 2    ];
 				texa2[ti * 2 + 1] = texa[i * 2 + 1];
 				ti++;
@@ -129,15 +129,15 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 
 		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;
+			let pi1: i32 = map_get(posmap, inda[i * 3    ]) + 1 + poff;
+			let pi2: i32 = map_get(posmap, inda[i * 3 + 1]) + 1 + poff;
+			let pi3: i32 = map_get(posmap, inda[i * 3 + 2]) + 1 + poff;
+			let ni1: i32 = map_get(normap, inda[i * 3    ]) + 1 + noff;
+			let ni2: i32 = map_get(normap, inda[i * 3 + 1]) + 1 + noff;
+			let ni3: i32 = map_get(normap, inda[i * 3 + 2]) + 1 + noff;
+			let ti1: i32 = map_get(texmap, inda[i * 3    ]) + 1 + toff;
+			let ti2: i32 = map_get(texmap, inda[i * 3 + 1]) + 1 + toff;
+			let ti3: i32 = map_get(texmap, inda[i * 3 + 2]) + 1 + toff;
 			export_obj_write_string(o, "f ");
 			export_obj_write_string(o, pi1 + "");
 			export_obj_write_string(o, "/");
@@ -163,8 +163,10 @@ function export_obj_run(path: string, paint_objects: mesh_object_t[], apply_disp
 		toff += ti;
 	}
 
-	if (!path.endsWith(".obj")) path += ".obj";
+	if (!ends_with(path, ".obj")) {
+		path += ".obj";
+	}
 
-	let b: ArrayBuffer = Uint8Array.from(o).buffer;
-	krom_file_save_bytes(path, b, b.byteLength);
+	let b: buffer_t = u8_array_t.from(o).buffer;
+	krom_file_save_bytes(path, b, buffer_size(b));
 }

+ 178 - 83
base/Sources/export_texture.ts

@@ -14,30 +14,38 @@ function export_texture_run(path: string, bake_material: bool = false) {
 		for (let l of project_layers) {
 			if (slot_layer_get_object_mask(l) > 0) {
 				let name: string = project_paint_objects[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 (substring(name, name.length - 5, 2) == ".1") { // tile.1001
+					array_push(udim_tiles, substring(name, name.length - 5, name.length));
 				}
 			}
 		}
 		if (udim_tiles.length > 0) {
-			for (let udim_tile of udim_tiles) export_texture_run_layers(path, project_layers, udim_tile);
+			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 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 (slot_layer_get_object_mask(l) > 0) {
 				let name: string = project_paint_objects[slot_layer_get_object_mask(l) - 1].base.name;
-				if (object_names.indexOf(name) == -1) {
-					object_names.push(name);
+				if (array_index_of(object_names, name) == -1) {
+					array_push(object_names, name);
 				}
 			}
 		}
 		if (object_names.length > 0) {
-			for (let name of object_names) export_texture_run_layers(path, project_layers, name);
+			for (let name of object_names) {
+				export_texture_run_layers(path, project_layers, name);
+			}
+		}
+		else {
+			export_texture_run_layers(path, project_layers);
 		}
-		else export_texture_run_layers(path, project_layers);
 	}
 	else { // Visible or selected
 		let atlas_export: bool = false;
@@ -51,11 +59,14 @@ function export_texture_run(path: string, bake_material: bool = false) {
 		}
 		if (atlas_export) {
 			for (let atlas_index: i32 = 0; atlas_index < project_atlas_objects.length; ++atlas_index) {
-				let layers: SlotLayerRaw[] = [];
+				let layers: slot_layer_t[] = [];
 				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 (slot_layer_get_object_mask(l) == 0 /* shared object */ || slot_layer_get_object_mask(l) - 1 == object_index) layers.push(l);
+							if (slot_layer_get_object_mask(l) == 0 || // shared object
+								slot_layer_get_object_mask(l) - 1 == object_index) {
+								array_push(layers, l);
+							}
 						}
 					}
 				}
@@ -64,7 +75,9 @@ function export_texture_run(path: string, bake_material: bool = false) {
 				}
 			}
 		}
-		else export_texture_run_layers(path, context_raw.layers_export == export_mode_t.SELECTED ? (slot_layer_is_group(context_raw.layer) ? slot_layer_get_children(context_raw.layer) : [context_raw.layer]) : project_layers);
+		else {
+			export_texture_run_layers(path, context_raw.layers_export == export_mode_t.SELECTED ? (slot_layer_is_group(context_raw.layer) ? slot_layer_get_children(context_raw.layer) : [context_raw.layer]) : project_layers);
+		}
 	}
 	///end
 
@@ -110,7 +123,7 @@ function export_texture_run_bake_material(path: string) {
 ///end
 
 ///if is_paint
-function export_texture_run_layers(path: string, layers: SlotLayerRaw[], object_name: string = "", bake_material: bool = false) {
+function export_texture_run_layers(path: string, layers: slot_layer_t[], object_name: string = "", bake_material: bool = false) {
 ///end
 
 ///if is_lab
@@ -124,21 +137,31 @@ function export_texture_run_layers(path: string, layers: any[], object_name: str
 	///else
 	let f: string = ui_files_filename;
 	///end
-	if (f == "") f = tr("untitled");
+	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 (ends_with(f, ext)) {
+		f = substring(f, 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;
+	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;
+	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 = map_get(render_path_render_targets, "empty_white")._image;
 
 	// Append object mask name
 	let export_selected: bool = context_raw.layers_export == export_mode_t.SELECTED;
@@ -162,17 +185,25 @@ function export_texture_run_layers(path: string, layers: any[], object_name: str
 
 	// Flatten layers
 	for (let l1 of layers) {
-		if (!export_selected && !slot_layer_is_visible(l1)) continue;
-		if (!slot_layer_is_layer(l1)) continue;
+		if (!export_selected && !slot_layer_is_visible(l1)) {
+			continue;
+		}
+		if (!slot_layer_is_layer(l1)) {
+			continue;
+		}
 
 		if (object_name != "" && slot_layer_get_object_mask(l1) > 0) {
-			if (is_udim && !project_paint_objects[slot_layer_get_object_mask(l1) - 1].base.name.endsWith(object_name)) continue;
+			if (is_udim && !ends_with(project_paint_objects[slot_layer_get_object_mask(l1) - 1].base.name, object_name)) {
+				continue;
+			}
 			let per_object: bool = context_raw.layers_export == export_mode_t.PER_OBJECT;
-			if (per_object && project_paint_objects[slot_layer_get_object_mask(l1) - 1].base.name != object_name) continue;
+			if (per_object && project_paint_objects[slot_layer_get_object_mask(l1) - 1].base.name != object_name) {
+				continue;
+			}
 		}
 
 		let mask: image_t = empty;
-		let l1masks: SlotLayerRaw[] = slot_layer_get_masks(l1);
+		let l1masks: slot_layer_t[] = slot_layer_get_masks(l1);
 		if (l1masks != null && !bake_material) {
 			if (l1masks.length > 1) {
 				base_make_temp_mask_img();
@@ -185,7 +216,9 @@ function export_texture_run_layers(path: string, layers: any[], object_name: str
 				}
 				mask = base_temp_mask_image;
 			}
-			else mask = l1masks[0].texpaint;
+			else {
+				mask = l1masks[0].texpaint;
+			}
 		}
 
 		if (l1.paint_base) {
@@ -271,17 +304,23 @@ function export_texture_run_layers(path: string, layers: any[], object_name: str
 	let texpaint_pack: image_t = brush_output_node_inst.texpaint_pack;
 	///end
 
-	let pixpaint: ArrayBuffer = null;
-	let pixpaint_nor: ArrayBuffer = null;
-	let pixpaint_pack: ArrayBuffer = null;
+	let pixpaint: buffer_t = null;
+	let pixpaint_nor: buffer_t = null;
+	let pixpaint_pack: buffer_t = null;
 	let preset: export_preset_t = box_export_preset;
-	let pix: ArrayBuffer = null;
+	let pix: buffer_t = 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);
+			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);
+			}
 		}
 	}
 
@@ -314,26 +353,62 @@ function export_texture_run_layers(path: string, layers: any[], object_name: str
 			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));
+			if (pix == null) {
+				pix = buffer_create(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);
+				if (c == "base_r") {
+					export_texture_copy_channel(buffer_view_create(pixpaint), 0, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "base_g") {
+					export_texture_copy_channel(buffer_view_create(pixpaint), 1, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "base_b") {
+					export_texture_copy_channel(buffer_view_create(pixpaint), 2, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "height") {
+					export_texture_copy_channel(buffer_view_create(pixpaint_pack), 3, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "metal") {
+					export_texture_copy_channel(buffer_view_create(pixpaint_pack), 2, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "nor_r") {
+					export_texture_copy_channel(buffer_view_create(pixpaint_nor), 0, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "nor_g") {
+					export_texture_copy_channel(buffer_view_create(pixpaint_nor), 1, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "nor_g_directx") {
+					export_texture_copy_channel_inv(buffer_view_create(pixpaint_nor), 1, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "nor_b") {
+					export_texture_copy_channel(buffer_view_create(pixpaint_nor), 2, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "occ") {
+					export_texture_copy_channel(buffer_view_create(pixpaint_pack), 0, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "opac") {
+					export_texture_copy_channel(buffer_view_create(pixpaint), 3, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "rough") {
+					export_texture_copy_channel(buffer_view_create(pixpaint_pack), 1, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "smooth") {
+					export_texture_copy_channel_inv(buffer_view_create(pixpaint_pack), 1, buffer_view_create(pix), i, t.color_space == "linear");
+				}
+				else if (c == "emis") {
+					export_texture_extract_channel(buffer_view_create(pixpaint_nor), 3, buffer_view_create(pix), i, 3, 1, t.color_space == "linear");
+				}
+				else if (c == "subs") {
+					export_texture_extract_channel(buffer_view_create(pixpaint_nor), 3, buffer_view_create(pix), i, 3, 2, t.color_space == "linear");
+				}
+				else if (c == "0.0") {
+					export_texture_set_channel(0, buffer_view_create(pix), i);
+				}
+				else if (c == "1.0") {
+					export_texture_set_channel(255, buffer_view_create(pix), i);
+				}
 			}
 			export_texture_write_texture(path + path_sep + f + tex_name + ext, pix, 3);
 		}
@@ -345,29 +420,41 @@ function export_texture_run_layers(path: string, layers: any[], object_name: str
 	texpaint_pack.pixels = null;
 }
 
-function export_texture_write_texture(file: string, pixels: ArrayBuffer, type: i32 = 1, off: i32 = 0) {
+function export_texture_write_texture(file: string, pixels: buffer_t, 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 (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);
+		map_set(data_cached_images, file, image);
+		let ar: string[] = string_split(file, 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);
+		array_push(project_assets, asset);
+		if (project_raw.assets == null) {
+			project_raw.assets = [];
+		}
+		array_push(project_raw.assets, asset.file);
+		array_push(project_asset_names, asset.name);
+		map_set(project_asset_map, asset.id, image);
 		export_arm_pack_assets(project_raw, [asset]);
 		return;
 	}
@@ -379,42 +466,50 @@ function export_texture_write_texture(file: string, pixels: ArrayBuffer, type: i
 		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);
+		let b: buffer_t = parser_exr_run(res_x, res_y, pixels, bits, type, off);
+		krom_file_save_bytes(file, b, buffer_size(b));
 	}
 }
 
-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));
+function export_texture_copy_channel(from: buffer_view_t, from_channel: i32, to: buffer_view_t, to_channel: i32, linear: bool = true) {
+	for (let i: i32 = 0; i < math_floor(buffer_view_size(to) / 4); ++i) {
+		buffer_view_set_u8(to, i * 4 + to_channel, buffer_view_get_u8(from, i * 4 + from_channel));
+	}
+	if (!linear) {
+		export_texture_to_srgb(to, to_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));
+function export_texture_copy_channel_inv(from: buffer_view_t, from_channel: i32, to: buffer_view_t, to_channel: i32, linear: bool = true) {
+	for (let i: i32 = 0; i < math_floor(buffer_view_size(to) / 4); ++i) {
+		buffer_view_set_u8(to, i * 4 + to_channel, 255 - buffer_view_get_u8(from, i * 4 + from_channel));
+	}
+	if (!linear) {
+		export_texture_to_srgb(to, to_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);
+function export_texture_extract_channel(from: buffer_view_t, from_channel: i32, to: buffer_view_t, to_channel: i32, step: i32, mask: i32, linear: bool = true) {
+	for (let i: i32 = 0; i < math_floor(buffer_view_size(to) / 4); ++i) {
+		buffer_view_set_u8(to, i * 4 + to_channel, buffer_view_get_u8(from, i * 4 + from_channel) % step == mask ? 255 : 0);
+	}
+	if (!linear) {
+		export_texture_to_srgb(to, to_channel);
 	}
-	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);
+function export_texture_set_channel(value: i32, to: buffer_view_t, to_channel: i32, linear: bool = true) {
+	for (let i: i32 = 0; i < math_floor(buffer_view_size(to) / 4); ++i) {
+		buffer_view_set_u8(to, i * 4 + to_channel, value);
+	}
+	if (!linear) {
+		export_texture_to_srgb(to, to_channel);
 	}
-	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));
+function export_texture_to_srgb(to: buffer_view_t, to_channel: i32) {
+	for (let i: i32 = 0; i < math_floor(buffer_view_size(to) / 4); ++i) {
+		buffer_view_set_u8(to, i * 4 + to_channel, math_floor(math_pow(buffer_view_get_u8(to, i * 4 + to_channel) / 255, export_texture_gamma) * 255));
 	}
 }
 

+ 40 - 36
base/Sources/file.ts

@@ -15,24 +15,24 @@ let file_cloud_sizes: map_t<string, i32> = null;
 // ///end
 
 function file_read_directory(path: string, folders_only: bool = false): string[] {
-	if (path.startsWith("cloud")) {
-		let files: string[] = file_cloud != null ? file_cloud.get(string_replace_all(path, "\\", "/")) : null;
+	if (starts_with(path, "cloud")) {
+		let files: string[] = file_cloud != null ? map_get(file_cloud, string_replace_all(path, "\\", "/")) : null;
 		return files != null ? files : [];
 	}
 	// ///if krom_android
 	// path = string_replace_all(path, "//", "/");
 	// if (file_internal == null) {
 	// 	file_internal = [];
-	// 	file_internal.set("/data/plugins", BuildMacros.readDirectory("krom/data/plugins"));
-	// 	file_internal.set("/data/export_presets", BuildMacros.readDirectory("krom/data/export_presets"));
-	// 	file_internal.set("/data/keymap_presets", BuildMacros.readDirectory("krom/data/keymap_presets"));
-	// 	file_internal.set("/data/locale", BuildMacros.readDirectory("krom/data/locale"));
-	// 	file_internal.set("/data/meshes", BuildMacros.readDirectory("krom/data/meshes"));
-	// 	file_internal.set("/data/themes", BuildMacros.readDirectory("krom/data/themes"));
+	// 	map_set(file_internal, "/data/plugins", BuildMacros.readDirectory("krom/data/plugins"));
+	// 	map_set(file_internal, "/data/export_presets", BuildMacros.readDirectory("krom/data/export_presets"));
+	// 	map_set(file_internal, "/data/keymap_presets", BuildMacros.readDirectory("krom/data/keymap_presets"));
+	// 	map_set(file_internal, "/data/locale", BuildMacros.readDirectory("krom/data/locale"));
+	// 	map_set(file_internal, "/data/meshes", BuildMacros.readDirectory("krom/data/meshes"));
+	// 	map_set(file_internal, "/data/themes", BuildMacros.readDirectory("krom/data/themes"));
 	// }
-	// if (file_internal.exists(path)) return file_internal.get(path);
+	// if (file_internal.exists(path)) return map_get(file_internal, path);
 	// ///end
-	return krom_read_directory(path, folders_only).split("\n");
+	return string_split(krom_read_directory(path, folders_only), "\n");
 }
 
 function file_create_directory(path: string) {
@@ -67,8 +67,10 @@ function file_exists(path: string): bool {
 
 function file_download(url: string, dstPath: string, done: ()=>void, size: i32 = 0) {
 	///if (krom_windows || krom_darwin || krom_ios || krom_android)
-	krom_http_request(url, size, function (ab: ArrayBuffer) {
-		if (ab != null) krom_file_save_bytes(dstPath, ab);
+	krom_http_request(url, size, function (ab: buffer_t) {
+		if (ab != null) {
+			krom_file_save_bytes(dstPath, ab);
+		}
 		done();
 	});
 	///elseif krom_linux
@@ -80,10 +82,10 @@ function file_download(url: string, dstPath: string, done: ()=>void, size: i32 =
 	///end
 }
 
-function file_download_bytes(url: string, done: (ab: ArrayBuffer)=>void) {
+function file_download_bytes(url: string, done: (ab: buffer_t)=>void) {
 	let save: string = (path_is_protected() ? krom_save_path() : path_data() + path_sep) + "download.bin";
 	file_download(url, save, function() {
-		let buffer: ArrayBuffer = null;
+		let buffer: buffer_t = null;
 		try {
 			buffer = krom_load_blob(save);
 		}
@@ -108,7 +110,7 @@ function file_cache_cloud(path: string, done: (s: string)=>void) {
 		return;
 	}
 
-	let file_dir: string = dest.substr(0, dest.lastIndexOf(path_sep));
+	let file_dir: string = substring(dest, 0, string_last_index_of(dest, path_sep));
 	if (file_read_directory(file_dir)[0] == "") {
 		file_create_directory(file_dir);
 	}
@@ -127,13 +129,13 @@ function file_cache_cloud(path: string, done: (s: string)=>void) {
 		///else
 		done((path_is_protected() ? krom_save_path() : path_working_dir() + path_sep) + path);
 		///end
-	}, file_cloud_sizes.get(path));
+	}, map_get(file_cloud_sizes, path));
 }
 
 function file_init_cloud_bytes(done: ()=>void, append: string = "") {
-	file_download_bytes(config_raw.server + "/?list-type=2" + append, function (buffer: ArrayBuffer) {
+	file_download_bytes(config_raw.server + "/?list-type=2" + append, function (buffer: buffer_t) {
 		if (buffer == null) {
-			file_cloud.set("cloud", []);
+			map_set(file_cloud, "cloud", []);
 			console_error(strings_error5());
 			return;
 		}
@@ -145,45 +147,47 @@ function file_init_cloud_bytes(done: ()=>void, append: string = "") {
 		let pos_end: i32 = 0;
 
 		while (true) {
-			pos_start = str.indexOf("<Key>", pos_start);
-			if (pos_start == -1) break;
+			pos_start = string_index_of_pos(str, "<Key>", pos_start);
+			if (pos_start == -1) {
+				break;
+			}
 			pos_start += 5; // <Key>
-			pos_end = str.indexOf("</Key>", pos_start);
+			pos_end = string_index_of_pos(str, "</Key>", pos_start);
 
-			files.push(str.substring(pos_start, pos_end));
+			array_push(files, substring(str, pos_start, pos_end));
 
-			pos_start = str.indexOf("<Size>", pos_end);
+			pos_start = string_index_of_pos(str, "<Size>", pos_end);
 			pos_start += 6; //<Size>
-			pos_end = str.indexOf("</Size>", pos_start);
+			pos_end = string_index_of_pos(str, "</Size>", pos_start);
 
-			sizes.push(Number(str.substring(pos_start, pos_end)));
+			array_push(sizes, Number(substring(str, pos_start, pos_end)));
 		}
 
 		for (let file of files) {
 			if (path_is_folder(file)) {
-				file_cloud.set(file.substr(0, file.length - 1), []);
+				map_set(file_cloud, substring(file, 0, file.length - 1), []);
 			}
 		}
 		for (let i: i32 = 0; i < files.length; ++i) {
 			let file: string = files[i];
-			let nested: bool = file.indexOf("/") != file.lastIndexOf("/");
+			let nested: bool = string_index_of(file, "/") != string_last_index_of(file, "/");
 			if (nested) {
-				let delim: i32 = path_is_folder(file) ? file.substr(0, file.length - 1).lastIndexOf("/") : file.lastIndexOf("/");
-				let parent: string = file.substr(0, delim);
-				let child: string = path_is_folder(file) ? file.substring(delim + 1, file.length - 1) : file.substr(delim + 1);
-				file_cloud.get(parent).push(child);
+				let delim: i32 = path_is_folder(file) ? string_last_index_of(substring(file, 0, file.length - 1), "/") : string_last_index_of(file, "/");
+				let parent: string = substring(file, 0, delim);
+				let child: string = path_is_folder(file) ? substring(file, delim + 1, file.length - 1) : substring(file, delim + 1, file.length);
+				array_push(map_get(file_cloud, parent), child);
 				if (!path_is_folder(file)) {
-					file_cloud_sizes.set(file, sizes[i]);
+					map_set(file_cloud_sizes, file, sizes[i]);
 				}
 			}
 		}
 
-		let is_truncated: bool = str.indexOf("<IsTruncated>true") > -1;
+		let is_truncated: bool = string_index_of(str, "<IsTruncated>true") > -1;
 		if (is_truncated) {
-			let pos_start: i32 = str.indexOf("<NextContinuationToken>");
+			let pos_start: i32 = string_index_of(str, "<NextContinuationToken>");
 			pos_start += 23;
-			let pos_end: i32 = str.indexOf("</NextContinuationToken>", pos_start);
-			file_init_cloud_bytes(done, "&start-after=" + str.substring(pos_start, pos_end));
+			let pos_end: i32 = string_index_of_pos(str, "</NextContinuationToken>", pos_start);
+			file_init_cloud_bytes(done, "&start-after=" + substring(str, pos_start, pos_end));
 		}
 		else done();
 	});

+ 15 - 13
base/Sources/geom.ts

@@ -13,10 +13,10 @@ function geom_make_plane(size_x: f32 = 1.0, size_y: f32 = 1.0, verts_x: i32 = 2,
 	mesh.scale_pos = math_max(half_x, half_y);
 	let inv: f32 = (1 / mesh.scale_pos) * 32767;
 
-	mesh.posa = new Int16Array(verts_x * verts_y * 4);
-	mesh.nora = new Int16Array(verts_x * verts_y * 2);
-	mesh.texa = new Int16Array(verts_x * verts_y * 2);
-	mesh.inda = new Uint32Array((verts_x - 1) * (verts_y - 1) * 6);
+	mesh.posa = i16_array_create(verts_x * verts_y * 4);
+	mesh.nora = i16_array_create(verts_x * verts_y * 2);
+	mesh.texa = i16_array_create(verts_x * verts_y * 2);
+	mesh.inda = u32_array_create((verts_x - 1) * (verts_y - 1) * 6);
 	let step_x: f32 = size_x / (verts_x - 1);
 	let step_y: f32 = size_y / (verts_y - 1);
 	for (let i: i32 = 0; i < verts_x * verts_y; ++i) {
@@ -63,17 +63,19 @@ function geom_make_uv_sphere(radius: f32 = 1.0, widthSegments: i32 = 32, heightS
 
 	let width_verts: i32 = widthSegments + 1;
 	let height_verts: i32 = heightSegments + 1;
-	mesh.posa = new Int16Array(width_verts * height_verts * 4);
-	mesh.nora = new Int16Array(width_verts * height_verts * 2);
-	mesh.texa = new Int16Array(width_verts * height_verts * 2);
-	mesh.inda = new Uint32Array(widthSegments * heightSegments * 6 - widthSegments * 6);
+	mesh.posa = i16_array_create(width_verts * height_verts * 4);
+	mesh.nora = i16_array_create(width_verts * height_verts * 2);
+	mesh.texa = i16_array_create(width_verts * height_verts * 2);
+	mesh.inda = u32_array_create(widthSegments * heightSegments * 6 - widthSegments * 6);
 
 	let nor: vec4_t = vec4_create();
 	let pos: i32 = 0;
 	for (let y: i32 = 0; y < height_verts; ++y) {
 		let v: f32 = y / heightSegments;
 		let v_flip: f32 = 1.0 - v;
-		if (!stretch_uv) v_flip /= 2;
+		if (!stretch_uv) {
+			v_flip /= 2;
+		}
 		let u_off: f32 = y == 0 ? 0.5 / widthSegments : y == heightSegments ? -0.5 / widthSegments : 0.0;
 		for (let x: i32 = 0; x < width_verts; ++x) {
 			let u: f32 = x / widthSegments;
@@ -125,10 +127,10 @@ function geom_make_uv_sphere(radius: f32 = 1.0, widthSegments: i32 = 32, heightS
 }
 
 type raw_mesh_t = {
-	posa?: Int16Array;
-	nora?: Int16Array;
-	texa?: Int16Array;
-	inda?: Uint32Array;
+	posa?: i16_array_t;
+	nora?: i16_array_t;
+	texa?: i16_array_t;
+	inda?: u32_array_t;
 	scale_pos?: f32;
 	scale_tex?: f32;
 	name?: string;

+ 45 - 15
base/Sources/gizmo.ts

@@ -13,7 +13,9 @@ function gizmo_update() {
 	let gizmo: object_t = context_raw.gizmo;
 	let hide: bool = operator_shortcut(config_keymap.stencil_hide, shortcut_type_t.DOWN);
 	gizmo.visible = (is_object || is_decal) && !hide;
-	if (!gizmo.visible) return;
+	if (!gizmo.visible) {
+		return;
+	}
 
 	let paint_object: object_t = context_raw.paint_object.base;
 	///if is_forge
@@ -81,7 +83,9 @@ function gizmo_update() {
 			transform_build_matrix(paint_object.transform);
 			///if arm_physics
 			let pb: any = (paint_object as any).physicsBody;
-			if (pb != null) pb.syncTransform();
+			if (pb != null) {
+				pb.syncTransform();
+			}
 			///end
 		}
 	}
@@ -152,12 +156,24 @@ function gizmo_update() {
 		];
 		let hit: transform_t = raycast_closest_box_intersect(trs, mouse_view_x(), mouse_view_y(), scene_camera);
 		if (hit != null) {
-			if (hit.object == context_raw.gizmo_translate_x) context_raw.translate_x = true;
-			else if (hit.object == context_raw.gizmo_translate_y) context_raw.translate_y = true;
-			else if (hit.object == context_raw.gizmo_translate_z) context_raw.translate_z = true;
-			else if (hit.object == context_raw.gizmo_scale_x) context_raw.scale_x = true;
-			else if (hit.object == context_raw.gizmo_scale_y) context_raw.scale_y = true;
-			else if (hit.object == context_raw.gizmo_scale_z) context_raw.scale_z = true;
+			if (hit.object == context_raw.gizmo_translate_x) {
+				context_raw.translate_x = true;
+			}
+			else if (hit.object == context_raw.gizmo_translate_y) {
+				context_raw.translate_y = true;
+			}
+			else if (hit.object == context_raw.gizmo_translate_z) {
+				context_raw.translate_z = true;
+			}
+			else if (hit.object == context_raw.gizmo_scale_x) {
+				context_raw.scale_x = true;
+			}
+			else if (hit.object == context_raw.gizmo_scale_y) {
+				context_raw.scale_y = true;
+			}
+			else if (hit.object == context_raw.gizmo_scale_z) {
+				context_raw.scale_z = true;
+			}
 			if (context_raw.translate_x || context_raw.translate_y || context_raw.translate_z || context_raw.scale_x || context_raw.scale_y || context_raw.scale_z) {
 				context_raw.gizmo_offset = 0.0;
 				context_raw.gizmo_started = true;
@@ -172,9 +188,15 @@ function gizmo_update() {
 			];
 			let hit: transform_t = raycast_closest_box_intersect(trs, mouse_view_x(), mouse_view_y(), scene_camera);
 			if (hit != null) {
-				if (hit.object == context_raw.gizmo_rotate_x) context_raw.rotate_x = true;
-				else if (hit.object == context_raw.gizmo_rotate_y) context_raw.rotate_y = true;
-				else if (hit.object == context_raw.gizmo_rotate_z) context_raw.rotate_z = true;
+				if (hit.object == context_raw.gizmo_rotate_x) {
+					context_raw.rotate_x = true;
+				}
+				else if (hit.object == context_raw.gizmo_rotate_y) {
+					context_raw.rotate_y = true;
+				}
+				else if (hit.object == context_raw.gizmo_rotate_z) {
+					context_raw.rotate_z = true;
+				}
 				if (context_raw.rotate_x || context_raw.rotate_y || context_raw.rotate_z) {
 					context_raw.gizmo_offset = 0.0;
 					context_raw.gizmo_started = true;
@@ -202,21 +224,27 @@ function gizmo_update() {
 		if (context_raw.translate_x || context_raw.scale_x) {
 			let hit: vec4_t = raycast_plane_intersect(vec4_y_axis(), gizmo_v, mouse_view_x(), mouse_view_y(), scene_camera);
 			if (hit != null) {
-				if (context_raw.gizmo_started) context_raw.gizmo_offset = hit.x - gizmo_v.x;
+				if (context_raw.gizmo_started) {
+					context_raw.gizmo_offset = hit.x - gizmo_v.x;
+				}
 				context_raw.gizmo_drag = hit.x - context_raw.gizmo_offset;
 			}
 		}
 		else if (context_raw.translate_y || context_raw.scale_y) {
 			let hit: vec4_t = raycast_plane_intersect(vec4_x_axis(), gizmo_v, mouse_view_x(), mouse_view_y(), scene_camera);
 			if (hit != null) {
-				if (context_raw.gizmo_started) context_raw.gizmo_offset = hit.y - gizmo_v.y;
+				if (context_raw.gizmo_started) {
+					context_raw.gizmo_offset = hit.y - gizmo_v.y;
+				}
 				context_raw.gizmo_drag = hit.y - context_raw.gizmo_offset;
 			}
 		}
 		else if (context_raw.translate_z || context_raw.scale_z) {
 			let hit: vec4_t = raycast_plane_intersect(vec4_x_axis(), gizmo_v, mouse_view_x(), mouse_view_y(), scene_camera);
 			if (hit != null) {
-				if (context_raw.gizmo_started) context_raw.gizmo_offset = hit.z - gizmo_v.z;
+				if (context_raw.gizmo_started) {
+					context_raw.gizmo_offset = hit.z - gizmo_v.z;
+				}
 				context_raw.gizmo_drag = hit.z - context_raw.gizmo_offset;
 			}
 		}
@@ -251,7 +279,9 @@ function gizmo_update() {
 			}
 		}
 
-		if (context_raw.gizmo_started) context_raw.gizmo_drag_last = context_raw.gizmo_drag;
+		if (context_raw.gizmo_started) {
+			context_raw.gizmo_drag_last = context_raw.gizmo_drag;
+		}
 
 		///if is_forge
 		util_mesh_remove_merged();

+ 90 - 74
base/Sources/history.ts

@@ -5,7 +5,7 @@ let history_undos: i32 = 0; // Undos available
 let history_redos: i32 = 0; // Redos available
 ///if (is_paint || is_sculpt)
 let history_push_undo: bool = false; // Store undo on next paint
-let history_undo_layers: SlotLayerRaw[] = null;
+let history_undo_layers: slot_layer_t[] = null;
 ///end
 ///if is_sculpt
 let history_push_undo2: bool = false;
@@ -34,12 +34,12 @@ function history_undo() {
 			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 = slot_layer_create("", step.layer_type, parent);
-			project_layers.splice(step.layer, 0, l);
+			let parent: slot_layer_t = step.layer_parent > 0 ? project_layers[step.layer_parent - 1] : null;
+			let l: slot_layer_t = slot_layer_create("", step.layer_type, parent);
+			array_insert(project_layers, step.layer, 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];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			slot_layer_swap(l, lay);
 			l.mask_opacity = step.layer_opacity;
 			l.blending = step.layer_blending;
@@ -62,21 +62,22 @@ 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];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer_preview_dirty = true;
 		}
 		else if (step.name == tr("Duplicate Layer")) {
-			let children: SlotLayerRaw[] = slot_layer_get_recursive_children(project_layers[step.layer]);
+			let children: slot_layer_t[] = slot_layer_get_recursive_children(project_layers[step.layer]);
 			let position: i32 = step.layer + 1;
-			if (children != null)
+			if (children != null) {
 				position += children.length;
+			}
 
 			context_raw.layer = project_layers[position];
 			slot_layer_delete(context_raw.layer);
 		}
 		else if (step.name == tr("Order Layers")) {
-			let target: SlotLayerRaw = project_layers[step.prev_order];
+			let target: slot_layer_t = project_layers[step.prev_order];
 			project_layers[step.prev_order] = project_layers[step.layer];
 			project_layers[step.layer] = target;
 		}
@@ -84,17 +85,17 @@ function history_undo() {
 			context_raw.layer = project_layers[step.layer];
 			slot_layer_delete(context_raw.layer);
 
-			let parent: SlotLayerRaw = step.layer_parent > 0 ? project_layers[step.layer_parent - 2] : null;
-			let l: SlotLayerRaw = slot_layer_create("", step.layer_type, parent);
-			project_layers.splice(step.layer, 0, l);
+			let parent: slot_layer_t = step.layer_parent > 0 ? project_layers[step.layer_parent - 2] : null;
+			let l: slot_layer_t = slot_layer_create("", step.layer_type, parent);
+			array_insert(project_layers, step.layer, 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];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			slot_layer_swap(context_raw.layer, lay);
 
 			l = slot_layer_create("", step.layer_type, parent);
-			project_layers.splice(step.layer + 1, 0, l);
+			array_insert(project_layers, step.layer + 1, l);
 			context_set_layer(l);
 
 			history_undo_i = history_undo_i - 1 < 0 ? config_raw.undo_steps - 1 : history_undo_i - 1;
@@ -110,7 +111,7 @@ function history_undo() {
 		else if (step.name == tr("Apply Mask")) {
 			// First restore the layer(s)
 			let mask_pos: i32 = step.layer;
-			let current_layer: SlotLayerRaw = null;
+			let current_layer: slot_layer_t = null;
 			// The layer at the old mask position is a mask, i.e. the layer had multiple masks before.
 			if (slot_layer_is_mask(project_layers[mask_pos])) {
 				current_layer = project_layers[mask_pos].parent;
@@ -119,20 +120,20 @@ function history_undo() {
 				current_layer = project_layers[mask_pos];
 			}
 
-			let layers_to_restore: SlotLayerRaw[] = slot_layer_is_group(current_layer) ? slot_layer_get_children(current_layer) : [current_layer];
+			let layers_to_restore: slot_layer_t[] = slot_layer_is_group(current_layer) ? slot_layer_get_children(current_layer) : [current_layer];
 			layers_to_restore.reverse();
 
 			for (let layer of layers_to_restore) {
 				// Replace the current layer's content with the old one
 				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];
+				let old_layer: slot_layer_t = history_undo_layers[history_undo_i];
 				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];
+			let mask: slot_layer_t = history_undo_layers[history_undo_i];
 			base_new_mask(false, current_layer, mask_pos);
 			slot_layer_swap(context_raw.layer, mask);
 			context_raw.layers_preview_dirty = true;
@@ -147,7 +148,7 @@ function history_undo() {
 		}
 		else if (step.name == "Apply Filter") {
 			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];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			context_set_layer(project_layers[step.layer]);
 			slot_layer_swap(context_raw.layer, lay);
 			base_new_mask(false, context_raw.layer);
@@ -157,12 +158,12 @@ function history_undo() {
 		else if (step.name == tr("To Fill Layer") || step.name == tr("To Fill Mask")) {
 			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];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			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];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			slot_layer_swap(context_raw.layer, lay);
 			context_raw.layer.fill_layer = project_materials[step.material];
 		}
@@ -181,7 +182,7 @@ function history_undo() {
 			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() });
+			array_insert(project_material_groups, step.canvas_group, { canvas: null, nodes: zui_nodes_create() });
 			history_swap_canvas(step);
 		}
 		else if (step.name == tr("New Material")) {
@@ -191,7 +192,7 @@ function history_undo() {
 		}
 		else if (step.name == tr("Delete Material")) {
 			context_raw.material = slot_material_create(project_materials[0].data);
-			project_materials.splice(step.material, 0, context_raw.material);
+			array_insert(project_materials, step.material, context_raw.material);
 			context_raw.material.canvas = step.canvas;
 			ui_nodes_canvas_changed();
 			ui_nodes_hwnd.redraws = 2;
@@ -203,7 +204,7 @@ function history_undo() {
 		}
 		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];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			context_select_paint_object(project_paint_objects[step.object]);
 			context_set_layer(project_layers[step.layer]);
 			slot_layer_swap(context_raw.layer, lay);
@@ -241,9 +242,9 @@ 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 = slot_layer_create("", step.layer_type, parent);
-			project_layers.splice(step.layer, 0, l);
+			let parent: slot_layer_t = step.layer_parent > 0 ? project_layers[step.layer_parent - 1] : null;
+			let l: slot_layer_t = slot_layer_create("", step.layer_type, parent);
+			array_insert(project_layers, step.layer, l);
 			if (step.name == tr("New Black Mask")) {
 				base_notify_on_next_frame(function () {
 					slot_layer_clear(l, 0x00000000);
@@ -264,10 +265,10 @@ function history_redo() {
 			context_set_layer(l);
 		}
 		else if (step.name == tr("New Group")) {
-			let l: SlotLayerRaw = project_layers[step.layer - 1];
-			let group: SlotLayerRaw = base_new_group();
+			let l: slot_layer_t = project_layers[step.layer - 1];
+			let group: slot_layer_t = base_new_group();
 			array_remove(project_layers, group);
-			project_layers.splice(step.layer, 0, group);
+			array_insert(project_layers, step.layer, group);
 			l.parent = group;
 			context_set_layer(group);
 		}
@@ -284,7 +285,9 @@ function history_redo() {
 					++n;
 				}
 				base_notify_on_next_frame(function() {
-					for (let i: i32 = 0; i < n; ++i) history_redo();
+					for (let i: i32 = 0; i < n; ++i) {
+						history_redo();
+					}
 				});
 			}
 		}
@@ -302,7 +305,7 @@ function history_redo() {
 			base_notify_on_next_frame(_next);
 		}
 		else if (step.name == tr("Order Layers")) {
-			let target: SlotLayerRaw = project_layers[step.prev_order];
+			let target: slot_layer_t = project_layers[step.prev_order];
 			project_layers[step.prev_order] = project_layers[step.layer];
 			project_layers[step.layer] = target;
 		}
@@ -314,12 +317,14 @@ function history_redo() {
 		else if (step.name == tr("Apply Mask")) {
 			context_raw.layer = project_layers[step.layer];
 				if (slot_layer_is_group_mask(context_raw.layer)) {
-					let group: SlotLayerRaw = context_raw.layer.parent;
-					let layers: SlotLayerRaw[] = slot_layer_get_children(group);
-					layers.splice(0, 0, context_raw.layer);
+					let group: slot_layer_t = context_raw.layer.parent;
+					let layers: slot_layer_t[] = slot_layer_get_children(group);
+					array_insert(layers, 0, context_raw.layer);
 					history_copy_merging_layers2(layers);
 				}
-				else history_copy_merging_layers2([context_raw.layer, context_raw.layer.parent]);
+				else {
+					history_copy_merging_layers2([context_raw.layer, context_raw.layer.parent]);
+				}
 
 			let _next = function() {
 				slot_layer_apply_mask(context_raw.layer);
@@ -336,7 +341,7 @@ function history_redo() {
 			app_notify_on_init(_next);
 		}
 		else if (step.name == tr("Apply Filter")) {
-			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			context_set_layer(project_layers[step.layer]);
 			slot_layer_swap(context_raw.layer, lay);
 			base_new_mask(false, lay);
@@ -345,14 +350,14 @@ function history_redo() {
 			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];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			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")) {
 			slot_layer_to_paint_layer(context_raw.layer);
-			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			slot_layer_swap(context_raw.layer, lay);
 			history_undo_i = (history_undo_i + 1) % config_raw.undo_steps;
 		}
@@ -376,7 +381,7 @@ function history_redo() {
 		}
 		else if (step.name == tr("New Material")) {
 			context_raw.material = slot_material_create(project_materials[0].data);
-			project_materials.splice(step.material, 0, context_raw.material);
+			array_insert(project_materials, step.material, context_raw.material);
 			context_raw.material.canvas = step.canvas;
 			ui_nodes_canvas_changed();
 			ui_nodes_hwnd.redraws = 2;
@@ -388,13 +393,13 @@ function history_redo() {
 		}
 		else if (step.name == tr("Duplicate Material")) {
 			context_raw.material = slot_material_create(project_materials[0].data);
-			project_materials.splice(step.material, 0, context_raw.material);
+			array_insert(project_materials, step.material, context_raw.material);
 			context_raw.material.canvas = step.canvas;
 			ui_nodes_canvas_changed();
 			ui_nodes_hwnd.redraws = 2;
 		}
 		else { // Paint operation
-			let lay: SlotLayerRaw = history_undo_layers[history_undo_i];
+			let lay: slot_layer_t = history_undo_layers[history_undo_i];
 			context_select_paint_object(project_paint_objects[step.object]);
 			context_set_layer(project_layers[step.layer]);
 			slot_layer_swap(context_raw.layer, lay);
@@ -410,7 +415,9 @@ function history_redo() {
 		///if (is_paint || is_sculpt)
 		ui_base_hwnds[tab_area_t.SIDEBAR0].redraws = 2;
 		ui_base_hwnds[tab_area_t.SIDEBAR1].redraws = 2;
-		if (ui_view2d_show) ui_view2d_hwnd.redraws = 2;
+		if (ui_view2d_show) {
+			ui_view2d_hwnd.redraws = 2;
+		}
 
 		if (config_raw.touch_ui) {
 			// Refresh undo & redo buttons
@@ -510,12 +517,14 @@ function history_merge_layers() {
 
 function history_apply_mask() {
 	if (slot_layer_is_group_mask(context_raw.layer)) {
-		let group: SlotLayerRaw = context_raw.layer.parent;
-		let layers: SlotLayerRaw[] = slot_layer_get_children(group);
-		layers.splice(0, 0, context_raw.layer);
+		let group: slot_layer_t = context_raw.layer.parent;
+		let layers: slot_layer_t[] = slot_layer_get_children(group);
+		array_insert(layers, 0, context_raw.layer);
 		history_copy_merging_layers2(layers);
 	}
-	else history_copy_merging_layers2([context_raw.layer, context_raw.layer.parent]);
+	else {
+		history_copy_merging_layers2([context_raw.layer, context_raw.layer.parent]);
+	}
 	history_push(tr("Apply Mask"));
 }
 
@@ -582,14 +591,14 @@ function history_duplicate_material() {
 function history_delete_material_group(group: node_group_t) {
 	let step: step_t = history_push(tr("Delete Node Group"));
 	step.canvas_type = canvas_type_t.MATERIAL;
-	step.canvas_group = project_material_groups.indexOf(group);
+	step.canvas_group = array_index_of(project_material_groups, group);
 	step.canvas = json_parse(json_stringify(group.canvas));
 }
 ///end
 
 function history_push(name: string): step_t {
 	///if (krom_windows || krom_linux || krom_darwin)
-	let filename: string = project_filepath == "" ? ui_files_filename : project_filepath.substring(project_filepath.lastIndexOf(path_sep) + 1, project_filepath.length - 4);
+	let filename: string = project_filepath == "" ? ui_files_filename : substring(project_filepath, string_last_index_of(project_filepath, path_sep) + 1, project_filepath.length - 4);
 	sys_title_set(filename + "* - " + manifest_title);
 	///end
 
@@ -598,23 +607,27 @@ function history_push(name: string): step_t {
 		ui_menubar_menu_handle.redraws = 2;
 	}
 
-	if (history_undos < config_raw.undo_steps) history_undos++;
+	if (history_undos < config_raw.undo_steps) {
+		history_undos++;
+	}
 	if (history_redos > 0) {
-		for (let i: i32 = 0; i < history_redos; ++i) history_steps.pop();
+		for (let i: i32 = 0; i < history_redos; ++i) {
+			history_steps.pop();
+		}
 		history_redos = 0;
 	}
 
 	///if (is_paint || is_sculpt)
-	let opos: i32 = project_paint_objects.indexOf(context_raw.paint_object);
-	let lpos: i32 = project_layers.indexOf(context_raw.layer);
-	let mpos: i32 = project_materials.indexOf(context_raw.material);
-	let bpos: i32 = project_brushes.indexOf(context_raw.brush);
+	let opos: i32 = array_index_of(project_paint_objects, context_raw.paint_object);
+	let lpos: i32 = array_index_of(project_layers, context_raw.layer);
+	let mpos: i32 = array_index_of(project_materials, context_raw.material);
+	let bpos: i32 = array_index_of(project_brushes, context_raw.brush);
 
-	history_steps.push({
+	array_push(history_steps, {
 		name: name,
 		layer: lpos,
 		layer_type: slot_layer_is_mask(context_raw.layer) ? layer_slot_type_t.MASK : 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),
+		layer_parent: context_raw.layer.parent == null ? -1 : array_index_of(project_layers, context_raw.layer.parent),
 		object: opos,
 		material: mpos,
 		brush: bpos,
@@ -625,12 +638,14 @@ function history_push(name: string): step_t {
 	///end
 
 	///if is_lab
-	history_steps.push({
+	array_push(history_steps, {
 		name: name
 	});
 	///end
 
-	while (history_steps.length > config_raw.undo_steps + 1) history_steps.shift();
+	while (history_steps.length > config_raw.undo_steps + 1) {
+		history_steps.shift();
+	}
 	return history_steps[history_steps.length - 1];
 }
 
@@ -640,42 +655,43 @@ function history_redo_merge_layers() {
 }
 
 function history_copy_merging_layers() {
-	let lay: SlotLayerRaw = context_raw.layer;
+	let lay: slot_layer_t = context_raw.layer;
 	history_copy_to_undo(lay.id, history_undo_i, slot_layer_is_mask(context_raw.layer));
 
-	let below: i32 = project_layers.indexOf(lay) - 1;
+	let below: i32 = array_index_of(project_layers, lay) - 1;
 	lay = project_layers[below];
 	history_copy_to_undo(lay.id, history_undo_i, 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, slot_layer_is_mask(layer));
+function history_copy_merging_layers2(layers: slot_layer_t[]) {
+	for (let layer of layers) {
+		history_copy_to_undo(layer.id, history_undo_i, slot_layer_is_mask(layer));
+	}
 }
 
 function history_swap_active() {
-	let undo_layer: SlotLayerRaw = history_undo_layers[history_undo_i];
+	let undo_layer: slot_layer_t = history_undo_layers[history_undo_i];
 	slot_layer_swap(undo_layer, context_raw.layer);
 	history_undo_i = (history_undo_i + 1) % config_raw.undo_steps;
 }
 
-function history_copy_to_undo(fromId: i32, toId: i32, isMask: bool) {
+function history_copy_to_undo(from_id: i32, to_id: i32, is_mask: bool) {
 
 	///if is_sculpt
-	isMask = true;
+	is_mask = true;
 	///end
 
-	if (isMask) {
-		render_path_set_target("texpaint_undo" + toId);
-		render_path_bind_target("texpaint" + fromId, "tex");
+	if (is_mask) {
+		render_path_set_target("texpaint_undo" + to_id);
+		render_path_bind_target("texpaint" + from_id, "tex");
 		// render_path_draw_shader("shader_datas/copy_pass/copyR8_pass");
 		render_path_draw_shader("shader_datas/copy_pass/copy_pass");
 	}
 	else {
-		render_path_set_target("texpaint_undo" + toId, ["texpaint_nor_undo" + toId, "texpaint_pack_undo" + toId]);
-		render_path_bind_target("texpaint" + fromId, "tex0");
-		render_path_bind_target("texpaint_nor" + fromId, "tex1");
-		render_path_bind_target("texpaint_pack" + fromId, "tex2");
+		render_path_set_target("texpaint_undo" + to_id, ["texpaint_nor_undo" + to_id, "texpaint_pack_undo" + to_id]);
+		render_path_bind_target("texpaint" + from_id, "tex0");
+		render_path_bind_target("texpaint_nor" + from_id, "tex1");
+		render_path_bind_target("texpaint_pack" + from_id, "tex2");
 		render_path_draw_shader("shader_datas/copy_mrt3_pass/copy_mrt3_pass");
 	}
 	history_undo_i = (history_undo_i + 1) % config_raw.undo_steps;

+ 112 - 67
base/Sources/import_arm.ts

@@ -1,6 +1,6 @@
 
 function import_arm_run_project(path: string) {
-	let b: ArrayBuffer = data_get_blob(path);
+	let b: buffer_t = data_get_blob(path);
 	let project: project_format_t = armpack_decode(b);
 
 	///if (is_paint || is_sculpt)
@@ -31,7 +31,7 @@ function import_arm_run_project(path: string) {
 
 	project_new(import_as_mesh);
 	project_filepath = path;
-	ui_files_filename = path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf("."));
+	ui_files_filename = substring(path, string_last_index_of(path, path_sep) + 1, string_last_index_of(path, "."));
 	///if (krom_android || krom_ios)
 	sys_title_set(ui_files_filename);
 	///else
@@ -48,7 +48,7 @@ function import_arm_run_project(path: string) {
 
 	// Save to recent
 	///if krom_ios
-	let recent_path: string = path.substr(path.lastIndexOf("/") + 1);
+	let recent_path: string = substring(path, string_last_index_of(path, "/") + 1);
 	///else
 	let recent_path: string = path;
 	///end
@@ -80,7 +80,7 @@ function import_arm_run_project(path: string) {
 		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;
+		let origin: f32_array_t = project_raw.camera_origin;
 		camera_origins[0].x = origin[0];
 		camera_origins[0].y = origin[1];
 		camera_origins[0].z = origin[2];
@@ -98,10 +98,10 @@ function import_arm_run_project(path: string) {
 			abs = path_normalize(abs);
 			import_arm_unpack_asset(project, abs, file);
 		}
-		if (data_cached_images.get(abs) == null && !file_exists(abs)) {
+		if (map_get(data_cached_images, abs) == null && !file_exists(abs)) {
 			import_arm_make_pink(abs);
 		}
-		let hdr_as_envmap: bool = abs.endsWith(".hdr") && project_raw.envmap == abs;
+		let hdr_as_envmap: bool = ends_with(abs, ".hdr") && project_raw.envmap == abs;
 		import_texture_run(abs, hdr_as_envmap);
 	}
 
@@ -143,7 +143,7 @@ function import_arm_run_project(path: string) {
 		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);
+		array_push(project_paint_objects, object);
 	}
 
 	if (project.mesh_assets != null && project.mesh_assets.length > 0) {
@@ -153,12 +153,18 @@ function import_arm_run_project(path: string) {
 	}
 
 	///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;
+	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();
+	if (context_raw.merged_object == null) {
+		util_mesh_merge();
+	}
 	///end
 
 	context_select_paint_object(context_main_object());
@@ -169,26 +175,32 @@ function import_arm_run_project(path: string) {
 	///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) slot_layer_resize_and_set_bits(l);
+		if (history_undo_layers != null) {
+			for (let l of history_undo_layers) {
+				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(() => {
+		let _texpaint_blend0: image_t = map_get(rts, "texpaint_blend0")._image;
+		base_notify_on_next_frame(function () {
 			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(() => {
+		map_get(rts, "texpaint_blend0").width = config_get_texture_res_x();
+		map_get(rts, "texpaint_blend0").height = config_get_texture_res_y();
+		map_get(rts, "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 = map_get(rts, "texpaint_blend1")._image;
+		base_notify_on_next_frame(function () {
 			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);
+		map_get(rts, "texpaint_blend1").width = config_get_texture_res_x();
+		map_get(rts, "texpaint_blend1").height = config_get_texture_res_y();
+		map_get(rts, "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) slot_layer_unload(l);
+	for (let l of project_layers) {
+		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];
@@ -201,13 +213,17 @@ function import_arm_run_project(path: string) {
 		let is_mask: bool = false;
 		///end
 
-		let l: SlotLayerRaw = 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;
+		let l: slot_layer_t = 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);
+		array_push(project_layers, l);
 
 		if (!is_group) {
-			if (base_pipe_merge == null) base_make_pipe();
+			if (base_pipe_merge == null) {
+				base_make_pipe();
+			}
 
 			let _texpaint: image_t = null;
 
@@ -254,7 +270,9 @@ function import_arm_run_project(path: string) {
 			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);
+			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;
@@ -273,11 +291,15 @@ function import_arm_run_project(path: string) {
 			l.paint_subs = ld.paint_subs;
 			///end
 
-			base_notify_on_next_frame(() => {
+			base_notify_on_next_frame(function () {
 				image_unload(_texpaint);
 				///if is_paint
-				if (_texpaint_nor != null) image_unload(_texpaint_nor);
-				if (_texpaint_pack != null) image_unload(_texpaint_pack);
+				if (_texpaint_nor != null) {
+					image_unload(_texpaint_nor);
+				}
+				if (_texpaint_pack != null) {
+					image_unload(_texpaint_pack);
+				}
 				///end
 			});
 		}
@@ -300,7 +322,7 @@ function import_arm_run_project(path: string) {
 	for (let n of project.material_nodes) {
 		import_arm_init_nodes(n.nodes);
 		context_raw.material = slot_material_create(m0, n);
-		project_materials.push(context_raw.material);
+		array_push(project_materials, context_raw.material);
 	}
 	///end
 
@@ -308,7 +330,9 @@ function import_arm_run_project(path: string) {
 	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() });
+		for (let g of project.material_groups) {
+			array_push(project_material_groups, { canvas: g, nodes: zui_nodes_create() });
+		}
 	}
 
 	///if (is_paint || is_sculpt)
@@ -322,7 +346,7 @@ function import_arm_run_project(path: string) {
 	for (let n of project.brush_nodes) {
 		import_arm_init_nodes(n.nodes);
 		context_raw.brush = slot_brush_create(n);
-		project_brushes.push(context_raw.brush);
+		array_push(project_brushes, context_raw.brush);
 		make_material_parse_brush();
 		util_render_make_brush_preview();
 	}
@@ -330,7 +354,7 @@ function import_arm_run_project(path: string) {
 	// 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 l: slot_layer_t = 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;
@@ -366,12 +390,12 @@ function import_arm_run_mesh(raw: scene_t) {
 			object.base.name = md.name;
 			object.skip_context = "paint";
 			md._.handle = md.name;
-			data_cached_meshes.set(md._.handle, md);
+			map_set(data_cached_meshes, 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);
+		array_push(project_paint_objects, object);
 		util_mesh_merge();
 		viewport_scale_to_bounds();
 	}
@@ -380,9 +404,12 @@ function import_arm_run_mesh(raw: scene_t) {
 }
 
 function import_arm_run_material(path: string) {
-	let b: ArrayBuffer = data_get_blob(path);
+	let b: buffer_t = data_get_blob(path);
 	let project: project_format_t = armpack_decode(b);
-	if (project.version == null) { data_delete_blob(path); return; }
+	if (project.version == null) {
+		data_delete_blob(path);
+		return;
+	}
 	import_arm_run_material_from_project(project, path);
 }
 
@@ -400,7 +427,7 @@ function import_arm_run_material_from_project(project: project_format_t, path: s
 			abs = path_normalize(abs);
 			import_arm_unpack_asset(project, abs, file);
 		}
-		if (data_cached_images.get(abs) == null && !file_exists(abs)) {
+		if (map_get(data_cached_images, abs) == null && !file_exists(abs)) {
 			import_arm_make_pink(abs);
 		}
 		import_texture_run(abs);
@@ -408,25 +435,27 @@ function import_arm_run_material_from_project(project: project_format_t, path: s
 
 	let m0: material_data_t = data_get_material("Scene", "Material");
 
-	let imported: SlotMaterialRaw[] = [];
+	let imported: slot_material_t[] = [];
 
 	for (let c of project.material_nodes) {
 		import_arm_init_nodes(c.nodes);
 		context_raw.material = slot_material_create(m0, c);
-		project_materials.push(context_raw.material);
-		imported.push(context_raw.material);
+		array_push(project_materials, context_raw.material);
+		array_push(imported, 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
+			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() });
+			array_push(project_material_groups, { canvas: c, nodes: zui_nodes_create() });
 		}
 	}
 
-	let _init = () => {
+	let _init = function () {
 		for (let m of imported) {
 			context_set_material(m);
 			make_material_parse_paint_material();
@@ -442,29 +471,40 @@ function import_arm_run_material_from_project(project: project_format_t, path: s
 
 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;
+		if (g.canvas.name == c.name) {
+			return true;
+		}
 	}
 	return false;
 }
 
-function import_arm_rename_group(name: string, materials: SlotMaterialRaw[], groups: zui_node_canvas_t[]) {
+function import_arm_rename_group(name: string, materials: slot_material_t[], 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";
+			if (n.type == "GROUP" && n.name == name) {
+				n.name += ".1";
+			}
 		}
 	}
 	for (let c of groups) {
-		if (c.name == name) c.name += ".1";
+		if (c.name == name) {
+			c.name += ".1";
+		}
 		for (let n of c.nodes) {
-			if (n.type == "GROUP" && n.name == name) n.name += ".1";
+			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 b: buffer_t = data_get_blob(path);
 	let project: project_format_t = armpack_decode(b);
-	if (project.version == null) { data_delete_blob(path); return; }
+	if (project.version == null) {
+		data_delete_blob(path);
+		return;
+	}
 	import_arm_run_brush_from_project(project, path);
 }
 
@@ -482,22 +522,22 @@ function import_arm_run_brush_from_project(project: project_format_t, path: stri
 			abs = path_normalize(abs);
 			import_arm_unpack_asset(project, abs, file);
 		}
-		if (data_cached_images.get(abs) == null && !file_exists(abs)) {
+		if (map_get(data_cached_images, abs) == null && !file_exists(abs)) {
 			import_arm_make_pink(abs);
 		}
 		import_texture_run(abs);
 	}
 
-	let imported: SlotBrushRaw[] = [];
+	let imported: slot_brush_t[] = [];
 
 	for (let n of project.brush_nodes) {
 		import_arm_init_nodes(n.nodes);
 		context_raw.brush = slot_brush_create(n);
-		project_brushes.push(context_raw.brush);
-		imported.push(context_raw.brush);
+		array_push(project_brushes, context_raw.brush);
+		array_push(imported, context_raw.brush);
 	}
 
-	let _init = () => {
+	let _init = function () {
 		for (let b of imported) {
 			context_set_brush(b);
 			util_render_make_brush_preview();
@@ -511,9 +551,12 @@ function import_arm_run_brush_from_project(project: project_format_t, path: stri
 ///end
 
 function import_arm_run_swatches(path: string, replace_existing: bool = false) {
-	let b: ArrayBuffer = data_get_blob(path);
+	let b: buffer_t = data_get_blob(path);
 	let project: project_format_t = armpack_decode(b);
-	if (project.version == null) { data_delete_blob(path); return; }
+	if (project.version == null) {
+		data_delete_blob(path);
+		return;
+	}
 	import_arm_run_swatches_from_project(project, path, replace_existing);
 }
 
@@ -522,13 +565,13 @@ function import_arm_run_swatches_from_project(project: project_format_t, path: s
 		project_raw.swatches = [];
 
 		if (project.swatches == null) { // No swatches contained
-			project_raw.swatches.push(make_swatch());
+			array_push(project_raw.swatches, make_swatch());
 		}
 	}
 
 	if (project.swatches != null) {
 		for (let s of project.swatches) {
-			project_raw.swatches.push(s);
+			array_push(project_raw.swatches, s);
 		}
 	}
 	ui_base_hwnds[tab_area_t.STATUS].redraws = 2;
@@ -537,13 +580,13 @@ function import_arm_run_swatches_from_project(project: project_format_t, path: s
 
 function import_arm_make_pink(abs: string) {
 	console_error(strings_error2() + " " + abs);
-	let b: Uint8Array = new Uint8Array(4);
+	let b: u8_array_t = u8_array_create(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);
+	map_set(data_cached_images, abs, pink);
 }
 
 function import_arm_texture_node_name(): string {
@@ -574,13 +617,15 @@ function import_arm_unpack_asset(project: project_format_t, abs: string, file: s
 		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 == 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);
+				array_push(project_raw.packed_assets, pa);
 			}
-			let image: image_t = image_from_encoded_bytes(pa.bytes, pa.name.endsWith(".jpg") ? ".jpg" : ".png");
-			data_cached_images.set(abs, image);
+			let image: image_t = image_from_encoded_bytes(pa.bytes, ends_with(pa.name, ".jpg") ? ".jpg" : ".png");
+			map_set(data_cached_images, abs, image);
 			break;
 		}
 	}

+ 7 - 3
base/Sources/import_asset.ts

@@ -1,7 +1,7 @@
 
 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")) {
+	if (starts_with(path, "cloud")) {
 		let do_cache_cloud = function () {
 			file_cache_cloud(path, function (abs: string) {
 				if (abs == null) return;
@@ -23,7 +23,9 @@ function import_asset_run(path: string, drop_x: f32 = -1.0, drop_y: f32 = -1.0,
 
 	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
+		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);
@@ -76,5 +78,7 @@ function import_asset_run(path: string, drop_x: f32 = -1.0, drop_y: f32 = -1.0,
 		}
 	}
 
-	if (done != null) done();
+	if (done != null) {
+		done();
+	}
 }

+ 81 - 38
base/Sources/import_blend_material.ts

@@ -2,7 +2,7 @@
 ///if (is_paint || is_sculpt)
 
 function import_blend_material_run(path: string) {
-	let b: ArrayBuffer = data_get_blob(path);
+	let b: buffer_t = data_get_blob(path);
 	let bl: BlendRaw = parser_blend_init(b);
 	if (bl.dna == null) {
 		console_error(strings_error3());
@@ -15,16 +15,17 @@ function import_blend_material_run(path: string) {
 		return;
 	}
 
-	let imported: SlotMaterialRaw[] = [];
+	let imported: slot_material_t[] = [];
 
 	for (let mat of mats) {
 		// Material slot
 		context_raw.material = slot_material_create(project_materials[0].data);
-		project_materials.push(context_raw.material);
-		imported.push(context_raw.material);
+		array_push(project_materials, context_raw.material);
+		array_push(imported, 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
+		canvas.name = bl_handle_get(bl_handle_get(mat, "id"), "name"); // MAWood
+		canvas.name = substring(canvas.name, 2, canvas.name.length);
 		let nout: zui_node_t = null;
 		for (let n of canvas.nodes) {
 			if (n.type == "OUTPUT_MATERIAL_PBR") {
@@ -48,8 +49,12 @@ function import_blend_material_run(path: string) {
 		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;
+			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") {
@@ -66,19 +71,22 @@ function import_blend_material_run(path: string) {
 		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 search: string = bl_handle_get(node, "idname");
+			search = to_lower_case(substring(search, 10, search.length));
 			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();
+					let s: string = to_lower_case(string_replace_all(n.type, "_", ""));
 					if (search == s) {
 						base = n;
 						found = true;
 						break;
 					}
 				}
-				if (found) break;
+				if (found) {
+					break;
+				}
 			}
 
 			if (base != null) {
@@ -92,22 +100,27 @@ function import_blend_material_run(path: string) {
 				let sock: any = bl_handle_get(inputs, "first", 0, "bNodeSocket");
 				let pos: i32 = 0;
 				while (true) {
-					if (pos >= n.inputs.length) break;
+					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;
+					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'
+					let file: string = bl_handle_get(img, "name"); // '//desktop\logo.png'
+					file = substring(file, 2, file.length);
 					file = path_base_dir(path) + file;
 					import_texture_run(file);
-					let ar: string[] = file.split(path_sep);
+					let ar: string[] = string_split(file, path_sep);
 					let filename: string = ar[ar.length - 1];
 					n.buttons[0].default_value = base_get_asset_index(filename);
 				}
@@ -116,7 +129,9 @@ function import_blend_material_run(path: string) {
 					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]);
+						if (i >= elems.length) {
+							array_push(elems, [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;
@@ -150,19 +165,25 @@ function import_blend_material_run(path: string) {
 				sock = bl_handle_get(outputs, "first", 0, "bNodeSocket");
 				pos = 0;
 				while (true) {
-					if (pos >= n.outputs.length) break;
+					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;
+					if (last.block == sock.block) {
+						break;
+					}
 					pos++;
 				}
 
-				canvas.nodes.push(n);
+				array_push(canvas.nodes, n);
 			}
 
-			if (bl_handle_get(node, "name") == bl_handle_get(last, "name")) break;
+			if (bl_handle_get(node, "name") == bl_handle_get(last, "name")) {
+				break;
+			}
 			node = bl_handle_get(node, "next");
 		}
 
@@ -195,7 +216,9 @@ function import_blend_material_run(path: string) {
 				while (true) {
 					let last: any = sock;
 					sock = bl_handle_get(sock, "prev");
-					if (last.block == sock.block) break;
+					if (last.block == sock.block) {
+						break;
+					}
 					from_socket++;
 				}
 
@@ -204,7 +227,9 @@ function import_blend_material_run(path: string) {
 				while (true) {
 					let last: any = sock;
 					sock = bl_handle_get(sock, "prev");
-					if (last.block == sock.block) break;
+					if (last.block == sock.block) {
+						break;
+					}
 					to_socket++;
 				}
 
@@ -212,14 +237,30 @@ function import_blend_material_run(path: string) {
 
 				// 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 (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) {
@@ -230,18 +271,20 @@ function import_blend_material_run(path: string) {
 						to_id: to_id,
 						to_socket: to_socket
 					};
-					canvas.links.push(raw);
+					array_push(canvas.links, raw);
 				}
 			}
 
 			let last: any = link;
 			link = bl_handle_get(link, "next");
-			if (last.block == link.block) break;
+			if (last.block == link.block) {
+				break;
+			}
 		}
 		history_new_material();
 	}
 
-	let _init = () => {
+	let _init = function () {
 		for (let m of imported) {
 			context_set_material(m);
 			make_material_parse_paint_material();
@@ -256,14 +299,14 @@ function import_blend_material_run(path: string) {
 
 function import_blend_material_read_blend_socket(sock: any): any {
 	let idname: any = bl_handle_get(sock, "idname");
-	if (idname.startsWith("NodeSocketVector")) {
+	if (starts_with(idname, "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")) {
+	else if (starts_with(idname, "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;
@@ -271,18 +314,18 @@ function import_blend_material_read_blend_socket(sock: any): any {
 		v[3] = math_floor(v[3] * 100) / 100;
 		return v;
 	}
-	else if (idname.startsWith("NodeSocketFloat")) {
+	else if (starts_with(idname, "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")) {
+	else if (starts_with(idname, "NodeSocketInt")) {
 		return bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueInt"), "value");
 	}
-	else if (idname.startsWith("NodeSocketBoolean")) {
+	else if (starts_with(idname, "NodeSocketBoolean")) {
 		return bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueBoolean"), "value");
 	}
-	else if (idname.startsWith("NodeSocketString")) {
+	else if (starts_with(idname, "NodeSocketString")) {
 		return bl_handle_get(bl_handle_get(sock, "default_value", 0, "bNodeSocketValueString"), "value");
 	}
 	return null;

+ 86 - 38
base/Sources/import_blend_mesh.ts

@@ -2,7 +2,7 @@
 let import_blend_mesh_eps: f32 = 1.0 / 32767;
 
 function import_blend_mesh_run(path: string, replace_existing: bool = true) {
-	let b: ArrayBuffer = data_get_blob(path);
+	let b: buffer_t = data_get_blob(path);
 	let bl: BlendRaw = parser_blend_init(b);
 	if (bl.dna == null) {
 		console_error(strings_error3());
@@ -10,20 +10,29 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 	}
 
 	let obs: BlHandleRaw[] = parser_blend_get(bl, "Object");
-	if (obs == null || obs.length == 0) { import_mesh_make_mesh(null, path); return; }
+	if (obs == null || obs.length == 0) {
+		import_mesh_make_mesh(null, path);
+		return;
+	}
 
 	let first: bool = true;
 	for (let ob of obs) {
-		if (bl_handle_get(ob, "type") != 1) continue;
+		if (bl_handle_get(ob, "type") != 1) {
+			continue;
+		}
 
 		let name: string = bl_handle_get(bl_handle_get(ob, "id"), "name");
-		name = name.substring(2, name.length);
+		name = substring(name, 2, name.length);
 
 		let m: any = bl_handle_get(ob, "data", 0, "Mesh");
-		if (m == null) continue;
+		if (m == null) {
+			continue;
+		}
 
 		let totpoly: i32 = bl_handle_get(m, "totpoly");
-		if (totpoly == 0) continue;
+		if (totpoly == 0) {
+			continue;
+		}
 
 		let numtri: i32 = 0;
 		for (let i: i32 = 0; i < totpoly; ++i) {
@@ -31,12 +40,14 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 			let totloop: i32 = bl_handle_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 inda: u32_array_t = u32_array_create(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);
+		let posa32: f32_array_t = f32_array_create(numtri * 3 * 4);
+		let posa: i16_array_t = i16_array_create(numtri * 3 * 4);
+		let nora: i16_array_t = i16_array_create(numtri * 3 * 2);
 
 		// pdata, 25 == CD_MPOLY
 		// let vdata: any = get(m, "vdata");
@@ -61,21 +72,21 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 			let l: any = bl_handle_get(ldata, "layers", i);
 			if (bl_handle_get(l, "type") == 16) { // CD_MLOOPUV
 				let ptr: any = bl_handle_get(l, "data");
-				uvdata_pos = bl.map.get(ptr).pos;
+				uvdata_pos = map_get(bl.map, ptr).pos;
 				uvdata = l;
 			}
 			else if (bl_handle_get(l, "type") == 17) { // CD_PROP_BYTE_COLOR
 				let ptr: any = bl_handle_get(l, "data");
-				coldata_pos = bl.map.get(ptr).pos;
+				coldata_pos = map_get(bl.map, ptr).pos;
 				coldata = l;
 			}
 			// CD_MLOOP == 26
 		}
 
 		let hasuv: bool = uvdata != null;
-		let texa: Int16Array = hasuv ? new Int16Array(numtri * 3 * 2) : null;
+		let texa: i16_array_t = hasuv ? i16_array_create(numtri * 3 * 2) : null;
 		let hascol: bool = context_raw.parse_vcols && coldata != null;
-		let cola: Int16Array = hascol ? new Int16Array(numtri * 3 * 4) : null;
+		let cola: i16_array_t = hascol ? i16_array_create(numtri * 3 * 4) : null;
 
 		let tri: i32 = 0;
 		let vec0: vec4_t = vec4_create();
@@ -98,18 +109,26 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 					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;
+				let uv0: f32_array_t = null;
+				let uv1: f32_array_t = null;
+				let uv2: f32_array_t = null;
 				if (hasuv) {
 					bl.pos = uvdata_pos + (loopstart + totloop - 1) * 4 * 3; // * 3 = x, y, flag
 					uv0 = parser_blend_read_f32array(bl, 2);
-					if (uv0[0] > 1.0 + import_blend_mesh_eps) uv0[0] = uv0[0] - math_floor(uv0[0]);
-					if (uv0[1] > 1.0 + import_blend_mesh_eps) uv0[1] = uv0[1] - math_floor(uv0[1]);
+					if (uv0[0] > 1.0 + import_blend_mesh_eps) {
+						uv0[0] = uv0[0] - math_floor(uv0[0]);
+					}
+					if (uv0[1] > 1.0 + import_blend_mesh_eps) {
+						uv0[1] = uv0[1] - math_floor(uv0[1]);
+					}
 					bl.pos = uvdata_pos + (loopstart) * 4 * 3;
 					uv1 = parser_blend_read_f32array(bl, 2);
-					if (uv1[0] > 1.0 + import_blend_mesh_eps) uv1[0] = uv1[0] - math_floor(uv1[0]);
-					if (uv1[1] > 1.0 + import_blend_mesh_eps) uv1[1] = uv1[1] - math_floor(uv1[1]);
+					if (uv1[0] > 1.0 + import_blend_mesh_eps) {
+						uv1[0] = uv1[0] - math_floor(uv1[0]);
+					}
+					if (uv1[1] > 1.0 + import_blend_mesh_eps) {
+						uv1[1] = uv1[1] - math_floor(uv1[1]);
+					}
 				}
 				let col0r: i32 = 0;
 				let col0g: i32 = 0;
@@ -170,8 +189,12 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 					if (hasuv) {
 						bl.pos = uvdata_pos + (loopstart + j + 1) * 4 * 3;
 						uv2 = parser_blend_read_f32array(bl, 2);
-						if (uv2[0] > 1.0 + import_blend_mesh_eps) uv2[0] = uv2[0] - math_floor(uv2[0]);
-						if (uv2[1] > 1.0 + import_blend_mesh_eps) uv2[1] = uv2[1] - math_floor(uv2[1]);
+						if (uv2[0] > 1.0 + import_blend_mesh_eps) {
+							uv2[0] = uv2[0] - math_floor(uv2[0]);
+						}
+						if (uv2[1] > 1.0 + import_blend_mesh_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);
@@ -203,7 +226,9 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 			}
 			else { // Convex or concave, ear clipping
 				let va: i32[] = [];
-				for (let i: i32 = 0; i < totloop; ++i) va.push(loopstart + i);
+				for (let i: i32 = 0; i < totloop; ++i) {
+					array_push(va, loopstart + i);
+				}
 				let v0: BlHandleRaw = import_blend_mesh_get_mvert_v(m, loopstart);
 				let v1: BlHandleRaw = import_blend_mesh_get_mvert_v(m, loopstart + 1);
 				let v2: BlHandleRaw = import_blend_mesh_get_mvert_v(m, loopstart + 2);
@@ -266,7 +291,9 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 					let e1x: f32 = v2x - v1x;
 					let e1y: f32 = v2y - v1y;
 					let cross: f32 = e0x * e1y - e0y * e1x;
-					if (cross <= 0) continue;
+					if (cross <= 0) {
+						continue;
+					}
 
 					let overlap: bool = false; // Other vertex found inside this triangle
 					for (let j: i32 = 0; j < vi - 3; ++j) {
@@ -281,7 +308,9 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 							break;
 						}
 					}
-					if (overlap) continue;
+					if (overlap) {
+						continue;
+					}
 
 					// Found ear
 					{
@@ -302,22 +331,34 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 							vec4_cross(vec0, vec1);
 							vec4_normalize(vec0, );
 						}
-						let uv0: Float32Array = null;
-						let uv1: Float32Array = null;
-						let uv2: Float32Array = null;
+						let uv0: f32_array_t = null;
+						let uv1: f32_array_t = null;
+						let uv2: f32_array_t = null;
 						if (hasuv) {
 							bl.pos = uvdata_pos + (va[i ]) * 4 * 3;
 							uv0 = parser_blend_read_f32array(bl, 2);
-							if (uv0[0] > 1.0 + import_blend_mesh_eps) uv0[0] = uv0[0] - math_floor(uv0[0]);
-							if (uv0[1] > 1.0 + import_blend_mesh_eps) uv0[1] = uv0[1] - math_floor(uv0[1]);
+							if (uv0[0] > 1.0 + import_blend_mesh_eps) {
+								uv0[0] = uv0[0] - math_floor(uv0[0]);
+							}
+							if (uv0[1] > 1.0 + import_blend_mesh_eps) {
+								uv0[1] = uv0[1] - math_floor(uv0[1]);
+							}
 							bl.pos = uvdata_pos + (va[i1]) * 4 * 3;
 							uv1 = parser_blend_read_f32array(bl, 2);
-							if (uv1[0] > 1.0 + import_blend_mesh_eps) uv1[0] = uv1[0] - math_floor(uv1[0]);
-							if (uv1[1] > 1.0 + import_blend_mesh_eps) uv1[1] = uv1[1] - math_floor(uv1[1]);
+							if (uv1[0] > 1.0 + import_blend_mesh_eps) {
+								uv1[0] = uv1[0] - math_floor(uv1[0]);
+							}
+							if (uv1[1] > 1.0 + import_blend_mesh_eps) {
+								uv1[1] = uv1[1] - math_floor(uv1[1]);
+							}
 							bl.pos = uvdata_pos + (va[i2]) * 4 * 3;
 							uv2 = parser_blend_read_f32array(bl, 2);
-							if (uv2[0] > 1.0 + import_blend_mesh_eps) uv2[0] = uv2[0] - math_floor(uv2[0]);
-							if (uv2[1] > 1.0 + import_blend_mesh_eps) uv2[1] = uv2[1] - math_floor(uv2[1]);
+							if (uv2[0] > 1.0 + import_blend_mesh_eps) {
+								uv2[0] = uv2[0] - math_floor(uv2[0]);
+							}
+							if (uv2[1] > 1.0 + import_blend_mesh_eps) {
+								uv2[1] = uv2[1] - math_floor(uv2[1]);
+							}
 						}
 						let col0r: i32 = 0;
 						let col0g: i32 = 0;
@@ -419,7 +460,9 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 		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;
+			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) {
@@ -439,7 +482,12 @@ function import_blend_mesh_run(path: string, replace_existing: bool = true) {
 			scale_tex: 1.0
 		};
 
-		(first && replace_existing) ? import_mesh_make_mesh(obj, path) : import_mesh_add_mesh(obj);
+		if (first && replace_existing) {
+			import_mesh_make_mesh(obj, path);
+		}
+		else {
+			import_mesh_add_mesh(obj);
+		}
 		first = false;
 	}
 

+ 11 - 9
base/Sources/import_envmap.ts

@@ -29,11 +29,13 @@ function import_envmap_run(path: string, image: image_t) {
 		import_envmap_mips = [];
 		let w: i32 = 512;
 		for (let i: i32 = 0; i < 10; ++i) {
-			import_envmap_mips.push(image_create_render_target(w, w > 1 ? math_floor(w / 2) : 1, tex_format_t.RGBA128));
+			array_push(import_envmap_mips, 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();
+		if (const_data_screen_aligned_vb == null) {
+			const_data_create_screen_aligned_data();
+		}
 	}
 
 	// Down-scale to 1024x512
@@ -46,7 +48,7 @@ function import_envmap_run(path: string, image: image_t) {
 	let radiance_pixels: buffer_t = image_get_pixels(import_envmap_radiance);
 	if (import_envmap_radiance_cpu != null) {
 		let _radiance_cpu: image_t = import_envmap_radiance_cpu;
-		base_notify_on_next_frame(() => {
+		base_notify_on_next_frame(function () {
 			image_unload(_radiance_cpu);
 		});
 	}
@@ -56,7 +58,7 @@ function import_envmap_run(path: string, image: image_t) {
 	if (import_envmap_mips_cpu != null) {
 		for (let mip of import_envmap_mips_cpu) {
 			let _mip: image_t = mip;
-			base_notify_on_next_frame(() => {
+			base_notify_on_next_frame(function () {
 				///if (!krom_direct3d12) // TODO: crashes after 50+ imports
 				image_unload(_mip);
 				///end
@@ -66,7 +68,7 @@ function import_envmap_run(path: string, image: image_t) {
 	import_envmap_mips_cpu = [];
 	for (let i: i32 = 0; i < import_envmap_mips.length; ++i) {
 		import_envmap_get_radiance_mip(import_envmap_mips[i], i, import_envmap_radiance);
-		import_envmap_mips_cpu.push(image_from_bytes(image_get_pixels(import_envmap_mips[i]), import_envmap_mips[i].width, import_envmap_mips[i].height, tex_format_t.RGBA128));
+		array_push(import_envmap_mips_cpu, image_from_bytes(image_get_pixels(import_envmap_mips[i]), import_envmap_mips[i].width, import_envmap_mips[i].height, tex_format_t.RGBA128));
 	}
 	image_set_mipmaps(import_envmap_radiance_cpu, import_envmap_mips_cpu);
 
@@ -109,8 +111,8 @@ function import_envmap_reverse_equirect(x: f32, y: f32): vec4_t {
 
 // https://ndotl.wordpress.com/2015/03/07/pbr-cubemap-filtering
 // https://seblagarde.wordpress.com/2012/06/10/amd-cubemapgen-for-physically-based-rendering
-function import_envmap_get_spherical_harmonics(source: ArrayBuffer, source_width: i32, source_height: i32): Float32Array {
-	let sh: Float32Array = new Float32Array(9 * 3 + 1); // Align to mult of 4 - 27->28
+function import_envmap_get_spherical_harmonics(source: buffer_t, source_width: i32, source_height: i32): f32_array_t {
+	let sh: f32_array_t = f32_array_create(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;
@@ -118,14 +120,14 @@ function import_envmap_get_spherical_harmonics(source: ArrayBuffer, source_width
 	let weight3: f32 = weight * 15 / 17;
 	let weight4: f32 = weight * 5 / 68;
 	let weight5: f32 = weight * 15 / 68;
-	let view: DataView = new DataView(source);
+	let view: buffer_view_t = buffer_view_create(source);
 
 	for (let x: i32 = 0; x < source_width; ++x) {
 		for (let y: i32 = 0; y < source_height; ++y) {
 			import_envmap_n = import_envmap_reverse_equirect(x / source_width, y / source_height);
 
 			for (let i: i32 = 0; i < 3; ++i) {
-				let value: f32 = view.getFloat32(((x + y * source_width) * 16 + i * 4), true);
+				let value: f32 = buffer_view_get_f32(view, ((x + y * source_width) * 16 + i * 4));
 				value = math_pow(value, 1.0 / 2.2);
 
 				sh[0 + i] += value * weight1;

+ 5 - 5
base/Sources/import_font.ts

@@ -11,20 +11,20 @@ function import_font_run(path: string) {
 	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[] = [];
+	let font_slots: slot_font_t[] = [];
 	for (let i: i32 = 0; i < count; ++i) {
-		let ar: string[] = path.split(path_sep);
+		let ar: string[] = string_split(path, 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 = slot_font_create(name, f, path);
-		font_slots.push(font_slot);
+		let font_slot: slot_font_t = slot_font_create(name, f, path);
+		array_push(font_slots, font_slot);
 	}
 
 	let _init = function () {
 		for (let f of font_slots) {
 			context_raw.font = f;
-			project_fonts.push(f);
+			array_push(project_fonts, f);
 			util_render_make_font_preview();
 		}
 	}

+ 12 - 12
base/Sources/import_gpl.ts

@@ -1,28 +1,28 @@
 
 function import_gpl_run(path: string, replace_existing: bool) {
-	let b: ArrayBuffer = data_get_blob(path);
+	let b: buffer_t = data_get_blob(path);
 	// let swatches: TSwatchColor[] = [];
 
 	// let str: string = sys_buffer_to_string(b);
-	// let lines: string[] = str.split("\n");
+	// let lines: string[] = string_split(str, "\n");
 
-	// let view: DataView = new DataView(b);
+	// let view: buffer_view_t = buffer_view_create(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")) {
+	// if (!starts_with(lines[0], "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;
+	// 	if (starts_with(line, "Name:")) continue;
+	// 	else if (starts_with(line, "Columns:")) continue;
+	// 	else if (starts_with(line, "#")) continue;
 	// 	else {
-	// 		let tokens: string[] = delimiter.split(line);
+	// 		let tokens: string[] = string_split(delimiter, line);
 	// 		if (tokens.length < 3) continue;
-	// 		let swatch: TSwatchColor = makeSwatch(Color.fromBytes(String(tokens[0]), String(tokens[1]), String(tokens[2])));
-	// 		swatches.push(swatch);
+	// 		let swatch: TSwatchColor = makeSwatch(Color.fromBytes(any_to_string(tokens[0]), any_to_string(tokens[1]), any_to_string(tokens[2])));
+	// 		array_push(swatches, swatch);
 	// 	}
 	// }
 
@@ -30,13 +30,13 @@ function import_gpl_run(path: string, replace_existing: bool) {
 	// 	raw.swatches = [];
 
 	// 	if (swatches.length == 0) { // No swatches contained
-	// 		raw.swatches.push(makeSwatch());
+	// 		array_push(raw.swatches, makeSwatch());
 	// 	}
 	// }
 
 	// if (swatches.length > 0) {
 	// 	for (let s of swatches) {
-	// 		raw.swatches.push(s);
+	// 		array_push(raw.swatches, s);
 	// 	}
 	// }
 }

+ 1 - 1
base/Sources/import_keymap.ts

@@ -5,7 +5,7 @@ function import_keymap_run(path: string) {
 		return;
 	}
 
-	let filename: string = path.substr(path.lastIndexOf(path_sep) + 1);
+	let filename: string = substring(path, string_last_index_of(path, path_sep) + 1, path.length);
 	let dst_path: string = path_data() + path_sep + "keymap_presets" + path_sep + filename;
 	file_copy(path, dst_path); // Copy to preset folder
 	box_preferences_fetch_keymaps(); // Refresh file list

+ 52 - 26
base/Sources/import_mesh.ts

@@ -27,18 +27,22 @@ function import_mesh_run(path: string, replace_existing: bool = true) {
 
 	import_mesh_meshes_to_unwrap = null;
 
-	let p: string = path.toLowerCase();
-	if (p.endsWith(".obj")) import_obj_run(path, replace_existing);
-	else if (p.endsWith(".blend")) import_blend_mesh_run(path, replace_existing);
+	let p: string = to_lower_case(path);
+	if (ends_with(p, ".obj")) {
+		import_obj_run(path, replace_existing);
+	}
+	else if (ends_with(p, ".blend")) {
+		import_blend_mesh_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) => {
+		let ext: string = substring(path, string_last_index_of(path, ".") + 1, path.length);
+		let importer: (s: string, f: (a: any)=>void)=>void = map_get(path_mesh_importers, ext);
+		importer(path, function (mesh: any) {
 			replace_existing ? import_mesh_make_mesh(mesh, path) : import_mesh_add_mesh(mesh);
 
 			let has_next: bool = mesh.has_next;
 			while (has_next) {
-				importer(path, (mesh: any) => {
+				importer(path, function (mesh: any) {
 					has_next = mesh.has_next;
 					import_mesh_add_mesh(mesh);
 
@@ -53,7 +57,7 @@ function import_mesh_run(path: string, replace_existing: bool = true) {
 	project_mesh_assets = [path];
 
 	///if (krom_android || krom_ios)
-	sys_title_set(path.substring(path.lastIndexOf(path_sep) + 1, path.lastIndexOf(".")));
+	sys_title_set(substring(path, string_last_index_of(path, path_sep) + 1, string_last_index_of(path, ".")));
 	///end
 }
 
@@ -68,22 +72,32 @@ function import_mesh_finish_import() {
 
 	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;
+		array_sort(project_paint_objects, function (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();
+		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";
+	if (context_raw.paint_object.base.name == "") {
+		context_raw.paint_object.base.name = "Object";
+	}
 	make_material_parse_paint_material();
 	make_material_parse_mesh_material();
 
@@ -102,7 +116,9 @@ function import_mesh_finish_import() {
 
 function _import_mesh_make_mesh(mesh: any) {
 	let raw: mesh_data_t = import_mesh_raw_mesh(mesh);
-	if (mesh.cola != null) raw.vertex_arrays.push({ values: mesh.cola, attrib: "col", data: "short4norm" });
+	if (mesh.cola != null) {
+		array_push(raw.vertex_arrays, { values: mesh.cola, attrib: "col", data: "short4norm" });
+	}
 
 	let md: mesh_data_t = mesh_data_create(raw);
 	context_raw.paint_object = context_main_object();
@@ -110,7 +126,9 @@ function _import_mesh_make_mesh(mesh: any) {
 	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;
+		if (p == context_raw.paint_object) {
+			continue;
+		}
 		data_delete_mesh(p.data._.handle);
 		mesh_object_remove(p);
 	}
@@ -124,7 +142,7 @@ function _import_mesh_make_mesh(mesh: any) {
 	project_paint_objects = [context_raw.paint_object];
 
 	md._.handle = raw.name;
-	data_cached_meshes.set(md._.handle, md);
+	map_set(data_cached_meshes, md._.handle, md);
 
 	context_raw.ddirty = 4;
 
@@ -139,7 +157,7 @@ function _import_mesh_make_mesh(mesh: any) {
 	///if (is_paint || is_sculpt)
 	if (import_mesh_clear_layers) {
 		while (project_layers.length > 0) {
-			let l: SlotLayerRaw = project_layers.pop();
+			let l: slot_layer_t = project_layers.pop();
 			slot_layer_unload(l);
 		}
 		base_new_layer(false);
@@ -167,9 +185,11 @@ function import_mesh_make_mesh(mesh: any, path: string) {
 		if (import_mesh_meshes_to_unwrap == null) {
 			import_mesh_meshes_to_unwrap = [];
 		}
-		let first_unwrap_done = (mesh: any) => {
+		let first_unwrap_done = function (mesh: any) {
 			_import_mesh_make_mesh(mesh);
-			for (let mesh of import_mesh_meshes_to_unwrap) project_unwrap_mesh_box(mesh, _import_mesh_add_mesh, true);
+			for (let mesh of import_mesh_meshes_to_unwrap) {
+				project_unwrap_mesh_box(mesh, _import_mesh_add_mesh, true);
+			}
 		}
 		project_unwrap_mesh_box(mesh, first_unwrap_done);
 	}
@@ -180,7 +200,9 @@ function import_mesh_make_mesh(mesh: any, path: string) {
 
 function _import_mesh_add_mesh(mesh: any) {
 	let raw: mesh_data_t = import_mesh_raw_mesh(mesh);
-	if (mesh.cola != null) raw.vertex_arrays.push({ values: mesh.cola, attrib: "col", data: "short4norm" });
+	if (mesh.cola != null) {
+		array_push(raw.vertex_arrays, { values: mesh.cola, attrib: "col", data: "short4norm" });
+	}
 
 	let md: mesh_data_t = mesh_data_create(raw);
 
@@ -193,14 +215,14 @@ function _import_mesh_add_mesh(mesh: any) {
 		if (p.base.name == object.base.name) {
 			p.base.name += ".001";
 			p.data._.handle += ".001";
-			data_cached_meshes.set(p.data._.handle, p.data);
+			map_set(data_cached_meshes, p.data._.handle, p.data);
 		}
 	}
 
-	project_paint_objects.push(object);
+	array_push(project_paint_objects, object);
 
 	md._.handle = raw.name;
-	data_cached_meshes.set(md._.handle, md);
+	map_set(data_cached_meshes, md._.handle, md);
 
 	context_raw.ddirty = 4;
 
@@ -214,8 +236,12 @@ function _import_mesh_add_mesh(mesh: any) {
 
 function import_mesh_add_mesh(mesh: any) {
 	if (mesh.texa == null) {
-		if (import_mesh_meshes_to_unwrap != null) import_mesh_meshes_to_unwrap.push(mesh);
-		else project_unwrap_mesh_box(mesh, _import_mesh_add_mesh);
+		if (import_mesh_meshes_to_unwrap != null) {
+			array_push(import_mesh_meshes_to_unwrap, mesh);
+		}
+		else {
+			project_unwrap_mesh_box(mesh, _import_mesh_add_mesh);
+		}
 	}
 	else {
 		_import_mesh_add_mesh(mesh);

+ 38 - 26
base/Sources/import_obj.ts

@@ -3,17 +3,19 @@ function import_obj_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
+		(i == split_type_t.OBJECT || is_udim) ? char_code_at("o", 0) :
+		 i == split_type_t.GROUP 		  	  ? char_code_at("g", 0) :
+		 										char_code_at("u", 0); // usemtl
 
-	let b: ArrayBuffer = data_get_blob(path);
+	let b: buffer_t = 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;
+			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);
@@ -24,24 +26,24 @@ function import_obj_run(path: string, replace_existing: bool = true) {
 	else {
 		let parts: any[] = [];
 		let part: any = krom_io_obj_parse(b, split_code, 0, false);
-		parts.push(part);
+		array_push(parts, 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);
+			array_push(parts, 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;
+			let posa0: i16_array_t;
+			let posa1: i16_array_t;
+			let nora0: i16_array_t;
+			let nora1: i16_array_t;
+			let texa0: i16_array_t;
+			let texa1: i16_array_t;
+			let inda0: u32_array_t;
+			let inda1: u32_array_t;
 			// Merge to single object per material
 			for (let i: i32 = 0; i < parts.length; ++i) {
 				let j: i32 = i + 1;
@@ -57,7 +59,7 @@ function import_obj_run(path: string, replace_existing: bool = true) {
 						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);
+						let posa32: f32_array_t = f32_array_create(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;
@@ -71,21 +73,27 @@ function import_obj_run(path: string, replace_existing: bool = true) {
 						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;
+							if (scale_pos < f) {
+								scale_pos = f;
+							}
 						}
 						let inv: f32 = 32767 * (1 / scale_pos);
-						let posa: Int16Array = new Int16Array(posa0.length + posa1.length);
+						let posa: i16_array_t = i16_array_create(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];
+						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);
+						let nora: i16_array_t = i16_array_create(nora0.length + nora1.length);
+						let texa: i16_array_t = (texa0 != null && texa1 != null) ? i16_array_create(texa0.length + texa1.length) : null;
+						let inda: u32_array_t = u32_array_create(inda0.length + inda1.length);
 						nora.set(nora0);
 						nora.set(nora1, nora0.length);
 						if (texa != null) {
@@ -93,15 +101,19 @@ function import_obj_run(path: string, replace_existing: bool = true) {
 							texa.set(texa1, texa0.length);
 						}
 						inda.set(inda0);
-						for (let k: i32 = 0; k < inda1.length; ++k) inda[k + inda0.length] = inda1[k] + voff;
+						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);
+						array_splice(parts, j, 1);
+					}
+					else {
+						j++;
 					}
-					else j++;
 				}
 			}
 		}

+ 1 - 1
base/Sources/import_plugin.ts

@@ -5,7 +5,7 @@ function import_plugin_run(path: string) {
 		return;
 	}
 
-	let filename: string = path.substr(path.lastIndexOf(path_sep) + 1);
+	let filename: string = substring(path, string_last_index_of(path, path_sep) + 1, path.length);
 	let dst_path: string = path_data() + path_sep + "plugins" + path_sep + filename;
 	file_copy(path, dst_path); // Copy to plugin folder
 	box_preferences_files_plugin = null; // Refresh file list

+ 16 - 12
base/Sources/import_texture.ts

@@ -11,7 +11,7 @@ function import_texture_run(path: string, hdr_as_envmap: bool = true) {
 		// Already imported
 		if (a.file == path) {
 			// Set as envmap
-			if (hdr_as_envmap && path.toLowerCase().endsWith(".hdr")) {
+			if (hdr_as_envmap && ends_with(to_lower_case(path), ".hdr")) {
 				let image: image_t = data_get_image(path);
 				base_notify_on_next_frame(function () { // Make sure file browser process did finish
 					import_envmap_run(path, image);
@@ -22,25 +22,29 @@ function import_texture_run(path: string, hdr_as_envmap: bool = true) {
 		}
 	}
 
-	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 = import_texture_default_importer;
+	let ext: string = substring(path, string_last_index_of(path, ".") + 1, path.length);
+	let importer: (s: string, f: (img: image_t)=>void)=>void = map_get(path_texture_importers, ext);
+	let cached: bool = map_get(data_cached_images, path) != null; // Already loaded or pink texture for missing file
+	if (importer == null || cached) {
+		importer = import_texture_default_importer;
+	}
 
 	importer(path, function (image: image_t) {
-		data_cached_images.set(path, image);
-		let ar: string[] = path.split(path_sep);
+		map_set(data_cached_images, path, image);
+		let ar: string[] = string_split(path, 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);
+		array_push(project_assets, asset);
+		if (context_raw.texture == null) {
+			context_raw.texture = asset;
+		}
+		array_push(project_asset_names, name);
+		map_set(project_asset_map, 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")) {
+		if (hdr_as_envmap && ends_with(to_lower_case(path), ".hdr")) {
 			base_notify_on_next_frame(function () { // Make sure file browser process did finish
 				import_envmap_run(path, image);
 			});

+ 1 - 1
base/Sources/import_theme.ts

@@ -5,7 +5,7 @@ function import_theme_run(path: string) {
 		return;
 	}
 
-	let filename: string = path.substr(path.lastIndexOf(path_sep) + 1);
+	let filename: string = substring(path, string_last_index_of(path, path_sep) + 1, path.length);
 	let dst_path: string = path_data() + path_sep + "themes" + path_sep + filename;
 	file_copy(path, dst_path); // Copy to preset folder
 	box_preferences_fetch_themes(); // Refresh file list

+ 3 - 3
base/Sources/line_draw.ts

@@ -11,8 +11,8 @@ let line_draw_pipeline: pipeline_t = null;
 let line_draw_vp: mat4_t;
 let line_draw_vp_loc: kinc_const_loc_t;
 
-let line_draw_vb_data: DataView;
-let line_draw_ib_data: Uint32Array;
+let line_draw_vb_data: buffer_view_t;
+let line_draw_ib_data: u32_array_t;
 
 let line_draw_max_lines: i32 = 300;
 let line_draw_max_vertices: i32 = line_draw_max_lines * 4;
@@ -185,6 +185,6 @@ function line_draw_end() {
 
 function line_draw_add_vb_data(i: i32, data: f32[]) {
 	for (let offset: i32 = 0; offset < 6; ++offset) {
-		line_draw_vb_data.setFloat32((i + offset) * 4, data[offset], true);
+		buffer_view_set_f32(line_draw_vb_data, (i + offset) * 4, data[offset]);
 	}
 }

+ 2 - 2
base/Sources/logic_node.ts

@@ -25,11 +25,11 @@ function logic_node_create(): logic_node_t {
 }
 
 function logic_node_add_input(self: logic_node_t, node: logic_node_t, from: i32) {
-	self.inputs.push(logic_node_input_create(node, from));
+	array_push(self.inputs, logic_node_input_create(node, from));
 }
 
 function logic_node_add_outputs(self: logic_node_t, nodes: logic_node_t[]) {
-	self.outputs.push(nodes);
+	array_push(self.outputs, nodes);
 }
 
 function logic_node_get(self: logic_node_t, from: i32, done: (a: any)=>void) {

+ 6 - 2
base/Sources/main.ts

@@ -39,7 +39,9 @@ function main_start() {
 	context_init();
 	config_init();
 	sys_start(config_get_options());
-	if (config_raw.layout == null) base_init_layout();
+	if (config_raw.layout == null) {
+		base_init_layout();
+	}
 	krom_set_app_name(manifest_title);
 	app_init(function() {
 		let o: object_t = scene_set_active("Scene");
@@ -105,7 +107,9 @@ function main_embed(additional: string[]) {
 		"text_coloring.json",
 		"version.json"
 	];
-	for (let add of additional) files.push(add);
+	for (let add of additional) {
+		array_push(files, add);
+	}
 	for (let file of files) {
 		resource_embed_blob(file, global["data/" + file]);
 		global["data/" + file] = null;

+ 2 - 2
base/Sources/make_voxel.ts

@@ -20,8 +20,8 @@ function make_voxel_run(data: shader_context_t) {
 	// if (skin) {
 	// 	g4_vertex_structure_add(structure, "bone", vertex_data_t.I16_4X_Normalized);
 	// 	g4_vertex_structure_add(structure, "weight", vertex_data_t.I16_4X_Normalized);
-	// 	data.raw.vertex_elements.push({ name: "bone", data: 'short4norm' });
-	// 	data.raw.vertex_elements.push({ name: "weight", data: 'short4norm' });
+	// 	array_push(data.raw.vertex_elements, { name: "bone", data: 'short4norm' });
+	// 	array_push(data.raw.vertex_elements, { name: "weight", data: 'short4norm' });
 	// }
 	// ///end
 

+ 129 - 103
base/Sources/node_shader.ts

@@ -1,6 +1,6 @@
 
-class NodeShaderRaw {
-	context: NodeShaderContextRaw;
+class node_shader_t {
+	context: node_shader_context_t;
 	shader_type: string = '';
 	includes: string[] = [];
 	ins: string[] = [];
@@ -37,55 +37,55 @@ class NodeShaderRaw {
 	inv_tbn: bool = false;
 }
 
-function node_shader_create(context: NodeShaderContextRaw, shader_type: string): NodeShaderRaw {
-	let raw: NodeShaderRaw = new NodeShaderRaw();
+function node_shader_create(context: node_shader_context_t, shader_type: string): node_shader_t {
+	let raw: node_shader_t = new node_shader_t();
 	raw.context = context;
 	raw.shader_type = shader_type;
 	return raw;
 }
 
-function node_shader_add_include(raw: NodeShaderRaw, s: string) {
-	raw.includes.push(s);
+function node_shader_add_include(raw: node_shader_t, s: string) {
+	array_push(raw.includes, s);
 }
 
-function node_shader_add_in(raw: NodeShaderRaw, s: string) {
-	raw.ins.push(s);
+function node_shader_add_in(raw: node_shader_t, s: string) {
+	array_push(raw.ins, s);
 }
 
-function node_shader_add_out(raw: NodeShaderRaw, s: string) {
-	raw.outs.push(s);
+function node_shader_add_out(raw: node_shader_t, s: string) {
+	array_push(raw.outs, s);
 }
 
-function node_shader_add_uniform(raw: NodeShaderRaw, s: string, link: string = null, included: bool = false) {
-	let ar: string[] = s.split(' ');
+function node_shader_add_uniform(raw: node_shader_t, s: string, link: string = null, included: bool = false) {
+	let ar: string[] = string_split(s, ' ');
 	// layout(RGBA8) image3D voxels
 	let utype: string = ar[ar.length - 2];
 	let uname: string = ar[ar.length - 1];
-	if (utype.startsWith('sampler') || utype.startsWith('image') || utype.startsWith('uimage')) {
-		let is_image: bool = (utype.startsWith('image') || utype.startsWith('uimage')) ? true : false;
+	if (starts_with(utype, 'sampler') || starts_with(utype, 'image') || starts_with(utype, 'uimage')) {
+		let is_image: bool = (starts_with(utype, 'image') || starts_with(utype, 'uimage')) ? true : false;
 		node_shader_context_add_texture_unit(raw.context, utype, uname, link, is_image);
 	}
 	else {
 		// Prefer vec4[] for d3d to avoid padding
-		if (ar[0] == 'float' && ar[1].indexOf('[') >= 0) {
+		if (ar[0] == 'float' && string_index_of(ar[1], '[') >= 0) {
 			ar[0] = 'floats';
-			ar[1] = ar[1].split('[')[0];
+			ar[1] = string_split(ar[1], '[')[0];
 		}
-		else if (ar[0] == 'vec4' && ar[1].indexOf('[') >= 0) {
+		else if (ar[0] == 'vec4' && string_index_of(ar[1], '[') >= 0) {
 			ar[0] = 'floats';
-			ar[1] = ar[1].split('[')[0];
+			ar[1] = string_split(ar[1], '[')[0];
 		}
 		node_shader_context_add_constant(raw.context, ar[0], ar[1], link);
 	}
-	if (included == false && raw.uniforms.indexOf(s) == -1) {
-		raw.uniforms.push(s);
+	if (included == false && array_index_of(raw.uniforms, s) == -1) {
+		array_push(raw.uniforms, s);
 	}
 }
 
-function node_shader_add_shared_sampler(raw: NodeShaderRaw, s: string) {
-	if (raw.shared_samplers.indexOf(s) == -1) {
-		raw.shared_samplers.push(s);
-		let ar: string[] = s.split(' ');
+function node_shader_add_shared_sampler(raw: node_shader_t, s: string) {
+	if (array_index_of(raw.shared_samplers, s) == -1) {
+		array_push(raw.shared_samplers, s);
+		let ar: string[] = string_split(s, ' ');
 		// layout(RGBA8) sampler2D tex
 		let utype: string = ar[ar.length - 2];
 		let uname: string = ar[ar.length - 1];
@@ -93,27 +93,31 @@ function node_shader_add_shared_sampler(raw: NodeShaderRaw, s: string) {
 	}
 }
 
-function node_shader_add_function(raw: NodeShaderRaw, s: string) {
-	let fname: string = s.split('(')[0];
-	if (raw.functions.has(fname)) return;
-	raw.functions.set(fname, s);
+function node_shader_add_function(raw: node_shader_t, s: string) {
+	let fname: string = string_split(s, '(')[0];
+	if (raw.functions.has(fname)) {
+		return;
+	}
+	map_set(raw.functions, fname, s);
 }
 
-function node_shader_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;
+function node_shader_contains(raw: node_shader_t, s: string): bool {
+	return string_index_of(raw.main, s) >= 0 ||
+		   string_index_of(raw.main_init, s) >= 0 ||
+		   string_index_of(raw.main_normal, s) >= 0 ||
+		   array_index_of(raw.ins, s) >= 0 ||
+		   string_index_of(raw.main_textures, s) >= 0 ||
+		   string_index_of(raw.main_attribs, s) >= 0;
 }
 
-function node_shader_write_init(raw: NodeShaderRaw, s: string) {
+function node_shader_write_init(raw: node_shader_t, s: string) {
 	raw.main_init = s + '\n' + raw.main_init;
 }
 
-function node_shader_write(raw: NodeShaderRaw, s: string) {
-	if (raw.lock) return;
+function node_shader_write(raw: node_shader_t, s: string) {
+	if (raw.lock) {
+		return;
+	}
 	if (raw.write_textures > 0) {
 		raw.main_textures += s + '\n';
 	}
@@ -128,29 +132,43 @@ function node_shader_write(raw: NodeShaderRaw, s: string) {
 	}
 }
 
-function node_shader_write_header(raw: NodeShaderRaw, s: string) {
+function node_shader_write_header(raw: node_shader_t, s: string) {
 	raw.header += s + '\n';
 }
 
-function node_shader_write_end(raw: NodeShaderRaw, s: string) {
+function node_shader_write_end(raw: node_shader_t, s: string) {
 	raw.main_end += s + '\n';
 }
 
-function node_shader_write_attrib(raw: NodeShaderRaw, s: string) {
+function node_shader_write_attrib(raw: node_shader_t, s: string) {
 	raw.main_attribs += s + '\n';
 }
 
-function node_shader_data_size(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';
+function node_shader_data_size(raw: node_shader_t, 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';
+	}
 }
 
-function node_shader_vstruct_to_vsin(raw: NodeShaderRaw) {
+function node_shader_vstruct_to_vsin(raw: node_shader_t) {
 	// if self.shader_type != 'vert' or self.ins != [] or not self.vstruct_as_vsin: # Vertex structure as vertex shader input
 		// return
 	let vs: vertex_element_t[] = raw.context.data.vertex_elements;
@@ -160,16 +178,16 @@ function node_shader_vstruct_to_vsin(raw: NodeShaderRaw) {
 }
 
 ///if (krom_direct3d11 || krom_direct3d12)
-function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string {
+function node_shader_get_hlsl(raw: node_shader_t, shared_sampler: string): string {
 	let s: string = '#define HLSL\n';
 	s += '#define textureArg(tex) Texture2D tex,SamplerState tex ## _sampler\n';
 	s += '#define texturePass(tex) tex,tex ## _sampler\n';
 	s += '#define sampler2D Texture2D\n';
 	s += '#define sampler3D Texture3D\n';
 	s += '#define texture(tex, coord) tex.Sample(tex ## _sampler, coord)\n';
-	s += `#define textureShared(tex, coord) tex.Sample(${sharedSampler}, coord)\n`;
+	s += `#define textureShared(tex, coord) tex.Sample(${shared_sampler}, coord)\n`;
 	s += '#define textureLod(tex, coord, lod) tex.SampleLevel(tex ## _sampler, coord, lod)\n';
-	s += `#define textureLodShared(tex, coord, lod) tex.SampleLevel(${sharedSampler}, coord, lod)\n`;
+	s += `#define textureLodShared(tex, coord, lod) tex.SampleLevel(${shared_sampler}, coord, lod)\n`;
 	s += '#define texelFetch(tex, coord, lod) tex.Load(float3(coord.xy, lod))\n';
 	s += 'uint2 _GetDimensions(Texture2D tex, uint lod) { uint x, y; tex.GetDimensions(x, y); return uint2(x, y); }\n';
 	s += '#define textureSize _GetDimensions\n';
@@ -204,22 +222,22 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 	if (raw.ins.length > 0) {
 		s += 'struct SPIRV_Cross_Input {\n';
 		index = 0;
-		raw.ins.sort((a, b): i32 => {
+		array_sort(raw.ins, function (a, b): i32 {
 			// Sort inputs by name
-			return a.substring(4) >= b.substring(4) ? 1 : -1;
+			return substring(a, 4, a.length) >= substring(b, 4, b.length) ? 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) {
+		if (raw.shader_type == 'vert' && string_index_of(raw.main, "gl_VertexID") >= 0) {
 			s += 'uint gl_VertexID : SV_VertexID;\n';
-			raw.ins.push('uint gl_VertexID');
+			array_push(raw.ins, 'uint gl_VertexID');
 		}
-		if (raw.shader_type == 'vert' && raw.main.indexOf("gl_InstanceID") >= 0) {
+		if (raw.shader_type == 'vert' && string_index_of(raw.main, "gl_InstanceID") >= 0) {
 			s += 'uint gl_InstanceID : SV_InstanceID;\n';
-			raw.ins.push('uint gl_InstanceID');
+			array_push(raw.ins, 'uint gl_InstanceID');
 		}
 		s += '};\n';
 	}
@@ -228,9 +246,9 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 	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 => {
+		array_sort(raw.outs, function (a, b): i32 {
 			// Sort outputs by name
-			return a.substring(4) >= b.substring(4) ? 1 : -1;
+			return substring(a, 4, a.length) >= substring(b, 4, b.length) ? 1 : -1;
 		});
 		index = 0;
 		if (raw.shader_type == 'vert') {
@@ -243,8 +261,8 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 		else {
 			let out: string = raw.outs[0];
 			// Multiple render targets
-			if (out.charAt(out.length - 1) == ']') {
-				num = parseInt(out.charAt(out.length - 2));
+			if (char_at(out, out.length - 1) == ']') {
+				num = parseInt(char_at(out, out.length - 2));
 				s += `vec4 fragColor[${num}] : SV_TARGET0;\n`;
 			}
 			else {
@@ -256,8 +274,8 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 
 	for (let a of raw.uniforms) {
 		s += 'uniform ' + a + ';\n';
-		if (a.startsWith('sampler')) {
-			s += 'SamplerState ' + a.split(' ')[1] + '_sampler;\n';
+		if (starts_with(a, 'sampler')) {
+			s += 'SamplerState ' + string_split(a, ' ')[1] + '_sampler;\n';
 		}
 	}
 
@@ -265,7 +283,7 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 		for (let a of raw.shared_samplers) {
 			s += 'uniform ' + a + ';\n';
 		}
-		s += `SamplerState ${sharedSampler};\n`;
+		s += `SamplerState ${shared_sampler};\n`;
 	}
 
 	for (let f of raw.functions.values()) {
@@ -292,7 +310,7 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 
 	// Declare inputs
 	for (let a of raw.ins) {
-		let b: string = a.substring(5); // Remove type 'vec4 '
+		let b: string = substring(a, 5, a.length); // Remove type 'vec4 '
 		s += `${a} = stage_input.${b};\n`;
 	}
 
@@ -304,8 +322,12 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 	}
 	else {
 		if (raw.outs.length > 0) {
-			if (num > 0) s += `vec4 fragColor[${num}];\n`;
-			else s += 'vec4 fragColor;\n';
+			if (num > 0) {
+				s += `vec4 fragColor[${num}];\n`;
+			}
+			else {
+				s += 'vec4 fragColor;\n';
+			}
 		}
 	}
 
@@ -323,7 +345,7 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 			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 '
+				let b: string = substring(a, 5, a.length); // Remove type 'vec4 '
 				s += `stage_output.${b} = ${b};\n`;
 			}
 		}
@@ -345,7 +367,7 @@ function node_shader_get_hlsl(raw: NodeShaderRaw, sharedSampler: string): string
 ///end
 
 ///if krom_metal
-function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string {
+function node_shader_get_msl(raw: node_shader_t, shared_sampler: string): string {
 	let s: string = '#define METAL\n';
 	s += '#include <metal_stdlib>\n';
 	s += '#include <simd/simd.h>\n';
@@ -356,9 +378,9 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 	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 textureShared(tex, coord) tex.sample(${shared_sampler}, coord)\n`;
 	s += '#define textureLod(tex, coord, lod) tex.sample(tex ## _sampler, coord, level(lod))\n';
-	s += `#define textureLodShared(tex, coord, lod) tex.sample(${sharedSampler}, coord, level(lod))\n`;
+	s += `#define textureLodShared(tex, coord, lod) tex.sample(${shared_sampler}, coord, level(lod))\n`;
 	s += '#define texelFetch(tex, coord, lod) tex.read(uint2(coord), uint(lod))\n';
 	s += 'float2 _getDimensions(texture2d<float> tex, uint lod) { return float2(tex.get_width(lod), tex.get_height(lod)); }\n';
 	s += '#define textureSize _getDimensions\n';
@@ -389,9 +411,9 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 	//if (ins.length > 0) {
 		s += 'struct main_in {\n';
 		index = 0;
-		raw.ins.sort((a, b): i32 => {
+		array_sort(raw.ins, function (a, b): i32 {
 			// Sort inputs by name
-			return a.substring(4) >= b.substring(4) ? 1 : -1;
+			return substring(a, 4, a.length) >= substring(b, 4, b.length) ? 1 : -1;
 		});
 		if (raw.shader_type == 'vert') {
 			for (let a of raw.ins) {
@@ -412,9 +434,9 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 	let num: i32 = 0;
 	if (raw.outs.length > 0 || raw.shader_type == 'vert') {
 		s += 'struct main_out {\n';
-		raw.outs.sort((a, b): i32 => {
+		array_sort(raw.outs, function (a, b): i32 {
 			// Sort outputs by name
-			return a.substring(4) >= b.substring(4) ? 1 : -1;
+			return substring(a, 4, a.length) >= substring(b, 4, b.length) ? 1 : -1;
 		});
 		index = 0;
 		if (raw.shader_type == 'vert') {
@@ -427,8 +449,8 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 		else {
 			let out: string = raw.outs[0];
 			// Multiple render targets
-			if (out.charAt(out.length - 1) == ']') {
-				num = parseInt(out.charAt(out.length - 2));
+			if (char_at(out, out.length - 1) == ']') {
+				num = parseInt(char_at(out, out.length - 2));
 				for (let i: i32 = 0; i < num; ++i) {
 					s += `float4 fragColor_${i} [[color(${i})]];\n`;
 				}
@@ -446,8 +468,8 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 		s += 'struct main_uniforms {\n';
 
 		for (let a of raw.uniforms) {
-			if (a.startsWith('sampler')) {
-				samplers.push(a);
+			if (starts_with(a, 'sampler')) {
+				array_push(samplers, a);
 			}
 			else {
 				s += a + ';\n';
@@ -478,7 +500,7 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 	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})]]`;
+			s += ', sampler ' + string_split(samplers[i], ' ')[1] + `_sampler [[sampler(${i})]]`;
 		}
 	}
 
@@ -487,14 +509,14 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 			let index: i32 = samplers.length + i;
 			s += `, ${raw.shared_samplers[i]} [[texture(${index})]]`;
 		}
-		s += `, sampler ${sharedSampler} [[sampler(${samplers.length})]]`;
+		s += `, sampler ${shared_sampler} [[sampler(${samplers.length})]]`;
 	}
 
 	// Built-ins
-	if (raw.shader_type == 'vert' && raw.main.indexOf("gl_VertexID") >= 0) {
+	if (raw.shader_type == 'vert' && string_index_of(raw.main, "gl_VertexID") >= 0) {
 		s += ', uint gl_VertexID [[vertex_id]]';
 	}
-	if (raw.shader_type == 'vert' && raw.main.indexOf("gl_InstanceID") >= 0) {
+	if (raw.shader_type == 'vert' && string_index_of(raw.main, "gl_InstanceID") >= 0) {
 		s += ', uint gl_InstanceID [[instance_id]]';
 	}
 
@@ -504,16 +526,16 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 
 	// Declare inputs
 	for (let a of raw.ins) {
-		let b: string = a.substring(5); // Remove type 'vec4 '
+		let b: string = substring(a, 5, a.length); // 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];
+		if (!starts_with(a, 'sampler')) {
+			let b: string = string_split(a, " ")[1]; // Remove type 'vec4 '
+			if (string_index_of(b, "[") >= 0) {
+				b = substring(b, 0, string_index_of(b, "["));
+				let type: string = string_split(a, " ")[0];
 				s += `constant ${type} *${b} = uniforms.${b};\n`;
 			}
 			else {
@@ -530,8 +552,12 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 	}
 	else {
 		if (raw.outs.length > 0) {
-			if (num > 0) s += `vec4 fragColor[${num}];\n`;
-			else s += 'vec4 fragColor;\n';
+			if (num > 0) {
+				s += `vec4 fragColor[${num}];\n`;
+			}
+			else {
+				s += 'vec4 fragColor;\n';
+			}
 		}
 	}
 
@@ -549,7 +575,7 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 			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 '
+				let b: string = string_split(a, " ")[1]; // Remove type 'vec4 '
 				s += `out.${b} = ${b};\n`;
 			}
 		}
@@ -571,7 +597,7 @@ function node_shader_get_msl(raw: NodeShaderRaw, sharedSampler: string): string
 ///end
 
 ///if (krom_opengl || krom_vulkan)
-function node_shader_get_glsl(raw: NodeShaderRaw, shared_sampler: string, version_header: string): string {
+function node_shader_get_glsl(raw: node_shader_t, shared_sampler: string, version_header: string): string {
 	let s: string = version_header;
 	s += '#define textureArg(tex) sampler2D tex\n';
 	s += '#define texturePass(tex) tex\n';
@@ -614,34 +640,34 @@ function node_shader_get_glsl(raw: NodeShaderRaw, shared_sampler: string, versio
 }
 ///end
 
-function node_shader_get(raw: NodeShaderRaw): string {
+function node_shader_get(raw: node_shader_t): string {
 
 	if (raw.shader_type == 'vert' && raw.vstruct_as_vsin) {
 		node_shader_vstruct_to_vsin(raw);
 	}
 
-	let sharedSampler: string = 'shared_sampler';
+	let shared_sampler: string = 'shared_sampler';
 	if (raw.shared_samplers.length > 0) {
-		sharedSampler = raw.shared_samplers[0].split(' ')[1] + '_sampler';
+		shared_sampler = string_split(raw.shared_samplers[0], ' ')[1] + '_sampler';
 	}
 
 	///if (krom_direct3d11 || krom_direct3d12)
-	let s: string = node_shader_get_hlsl(raw, sharedSampler);
+	let s: string = node_shader_get_hlsl(raw, shared_sampler);
 	///elseif krom_metal
-	let s: string = node_shader_get_msl(raw, sharedSampler);
+	let s: string = node_shader_get_msl(raw, shared_sampler);
 	///elseif krom_vulkan
 	let version_header: string = '#version 450\n';
-	let s: string = node_shader_get_glsl(raw, sharedSampler, version_header);
+	let s: string = node_shader_get_glsl(raw, shared_sampler, version_header);
 	///elseif krom_android
 	let version_header: string = '#version 300 es\n';
 	if (raw.shader_type == 'frag') {
 		version_header += 'precision highp float;\n';
 		version_header += 'precision mediump int;\n';
 	}
-	let s: string = node_shader_get_glsl(raw, sharedSampler, version_header);
+	let s: string = node_shader_get_glsl(raw, shared_sampler, version_header);
 	///elseif krom_opengl
 	let version_header: string = '#version 330\n';
-	let s: string = node_shader_get_glsl(raw, sharedSampler, version_header);
+	let s: string = node_shader_get_glsl(raw, shared_sampler, version_header);
 	///end
 
 	return s;

+ 18 - 16
base/Sources/node_shader_context.ts

@@ -1,7 +1,7 @@
 
-class NodeShaderContextRaw {
-	vert: NodeShaderRaw;
-	frag: NodeShaderRaw;
+class node_shader_context_t {
+	vert: node_shader_t;
+	frag: node_shader_t;
 	data: shader_context_t;
 	allow_vcols: bool = false;
 	material: material_t;
@@ -9,8 +9,8 @@ class NodeShaderContextRaw {
 	tunits: tex_unit_t[];
 }
 
-function node_shader_context_create(material: material_t, props: any): NodeShaderContextRaw {
-	let raw: NodeShaderContextRaw = new NodeShaderContextRaw();
+function node_shader_context_create(material: material_t, props: any): node_shader_context_t {
+	let raw: node_shader_context_t = new node_shader_context_t();
 	raw.material = material;
 	raw.data = {
 		name: props.name,
@@ -48,15 +48,17 @@ function node_shader_context_create(material: material_t, props: any): NodeShade
 	return raw;
 }
 
-function node_shader_context_add_elem(raw: NodeShaderContextRaw, name: string, data_type: string) {
+function node_shader_context_add_elem(raw: node_shader_context_t, name: string, data_type: string) {
 	for (let e of raw.data.vertex_elements) {
-		if (e.name == name) return;
+		if (e.name == name) {
+			return;
+		}
 	}
 	let elem: vertex_element_t = { name: name, data: data_type };
-	raw.data.vertex_elements.push(elem);
+	array_push(raw.data.vertex_elements, elem);
 }
 
-function node_shader_context_is_elem(raw: NodeShaderContextRaw, name: string): bool {
+function node_shader_context_is_elem(raw: node_shader_context_t, name: string): bool {
 	for (let elem of raw.data.vertex_elements) {
 		if (elem.name == name) {
 			return true;
@@ -65,7 +67,7 @@ function node_shader_context_is_elem(raw: NodeShaderContextRaw, name: string): b
 	return false;
 }
 
-function node_shader_context_get_elem(raw: NodeShaderContextRaw, name: string): vertex_element_t {
+function node_shader_context_get_elem(raw: node_shader_context_t, name: string): vertex_element_t {
 	for (let elem of raw.data.vertex_elements) {
 		if (elem.name == name) {
 			return elem;
@@ -74,7 +76,7 @@ function node_shader_context_get_elem(raw: NodeShaderContextRaw, name: string):
 	return null;
 }
 
-function node_shader_context_add_constant(raw: NodeShaderContextRaw, ctype: string, name: string, link: string = null) {
+function node_shader_context_add_constant(raw: node_shader_context_t, ctype: string, name: string, link: string = null) {
 	for (let c of raw.constants) {
 		if (c.name == name) {
 			return;
@@ -85,10 +87,10 @@ function node_shader_context_add_constant(raw: NodeShaderContextRaw, ctype: stri
 	if (link != null) {
 		c.link = link;
 	}
-	raw.constants.push(c);
+	array_push(raw.constants, c);
 }
 
-function node_shader_context_add_texture_unit(raw: NodeShaderContextRaw, ctype: string, name: string, link: string = null, is_image: bool = false) {
+function node_shader_context_add_texture_unit(raw: node_shader_context_t, ctype: string, name: string, link: string = null, is_image: bool = false) {
 	for (let c of raw.tunits) {
 		if (c.name == name) {
 			return;
@@ -102,16 +104,16 @@ function node_shader_context_add_texture_unit(raw: NodeShaderContextRaw, ctype:
 	if (is_image) {
 		c.image_uniform = is_image;
 	}
-	raw.tunits.push(c);
+	array_push(raw.tunits, c);
 }
 
-function node_shader_context_make_vert(raw: NodeShaderContextRaw): NodeShaderRaw {
+function node_shader_context_make_vert(raw: node_shader_context_t): node_shader_t {
 	raw.data.vertex_shader = raw.material.name + '_' + raw.data.name + '.vert';
 	raw.vert = node_shader_create(raw, 'vert');
 	return raw.vert;
 }
 
-function node_shader_context_make_frag(raw: NodeShaderContextRaw): NodeShaderRaw {
+function node_shader_context_make_frag(raw: node_shader_context_t): node_shader_t {
 	raw.data.fragment_shader = raw.material.name + '_' + raw.data.name + '.frag';
 	raw.frag = node_shader_create(raw, 'frag');
 	return raw.frag;

+ 12 - 4
base/Sources/nodes/boolean_node.ts

@@ -14,11 +14,19 @@ function boolean_node_create(value: bool = false): boolean_node_t {
 }
 
 function boolean_node_get(self: boolean_node_t, from: i32, done: (a: any)=>void) {
-	if (self.base.inputs.length > 0) logic_node_input_get(self.base.inputs[0], done);
-	else done(self.value);
+	if (self.base.inputs.length > 0) {
+		logic_node_input_get(self.base.inputs[0], done);
+	}
+	else {
+		done(self.value);
+	}
 }
 
 function boolean_node_set(self: boolean_node_t, value: any) {
-	if (self.base.inputs.length > 0) logic_node_input_set(self.base.inputs[0], value);
-	else self.value = value;
+	if (self.base.inputs.length > 0) {
+		logic_node_input_set(self.base.inputs[0], value);
+	}
+	else {
+		self.value = value;
+	}
 }

+ 25 - 12
base/Sources/nodes/color_node.ts

@@ -16,24 +16,37 @@ function color_node_create(r: f32 = 0.8, g: f32 = 0.8, b: f32 = 0.8, a: f32 = 1.
 }
 
 function color_node_get(self: color_node_t, from: i32, done: (a: any)=>void) {
-	if (self.base.inputs.length > 0) logic_node_input_get(self.base.inputs[0], done);
-	else done(self.value);
+	if (self.base.inputs.length > 0) {
+		logic_node_input_get(self.base.inputs[0], done);
+	}
+	else {
+		done(self.value);
+	}
 }
 
 function color_node_get_as_image(self: color_node_t, from: i32, done: (img: image_t)=>void) {
-	if (self.base.inputs.length > 0) { logic_node_input_get_as_image(self.base.inputs[0], done); return; }
-	if (self.image != null) image_unload(self.image);
-	let b: ArrayBuffer = new ArrayBuffer(16);
-	let v: DataView = new DataView(b);
-	v.setFloat32(0, self.value.x, true);
-	v.setFloat32(4, self.value.y, true);
-	v.setFloat32(8, self.value.z, true);
-	v.setFloat32(12, self.value.w, true);
+	if (self.base.inputs.length > 0) {
+		logic_node_input_get_as_image(self.base.inputs[0], done);
+		return;
+	}
+	if (self.image != null) {
+		image_unload(self.image);
+	}
+	let b: buffer_t = buffer_create(16);
+	let v: buffer_view_t = buffer_view_create(b);
+	buffer_view_set_f32(v, 0, self.value.x);
+	buffer_view_set_f32(v, 4, self.value.y);
+	buffer_view_set_f32(v, 8, self.value.z);
+	buffer_view_set_f32(v, 12, self.value.w);
 	self.image = image_from_bytes(b, 1, 1, tex_format_t.RGBA128);
 	done(self.image);
 }
 
 function color_node_set(self: color_node_t, value: any) {
-	if (self.base.inputs.length > 0) logic_node_input_set(self.base.inputs[0], value);
-	else self.value = value;
+	if (self.base.inputs.length > 0) {
+		logic_node_input_set(self.base.inputs[0], value);
+	}
+	else {
+		self.value = value;
+	}
 }

+ 25 - 12
base/Sources/nodes/float_node.ts

@@ -16,26 +16,39 @@ function float_node_create(value: f32 = 0.0): float_node_t {
 }
 
 function float_node_get(self: float_node_t, from: i32, done: (a: any)=>void) {
-	if (self.base.inputs.length > 0) logic_node_input_get(self.base.inputs[0], done);
-	else done(self.value);
+	if (self.base.inputs.length > 0) {
+		logic_node_input_get(self.base.inputs[0], done);
+	}
+	else {
+		done(self.value);
+	}
 }
 
 function float_node_get_as_image(self: float_node_t, from: i32, done: (img: image_t)=>void) {
-	if (self.base.inputs.length > 0) { logic_node_input_get_as_image(self.base.inputs[0], done); return; }
-	if (self.image != null) image_unload(self.image);
-	let b: ArrayBuffer = new ArrayBuffer(16);
-	let v: DataView = new DataView(b);
-	v.setFloat32(0, self.value, true);
-	v.setFloat32(4, self.value, true);
-	v.setFloat32(8, self.value, true);
-	v.setFloat32(12, 1.0, true);
+	if (self.base.inputs.length > 0) {
+		logic_node_input_get_as_image(self.base.inputs[0], done);
+		return;
+	}
+	if (self.image != null) {
+		image_unload(self.image);
+	}
+	let b: buffer_t = buffer_create(16);
+	let v: buffer_view_t = buffer_view_create(b);
+	buffer_view_set_f32(v, 0, self.value);
+	buffer_view_set_f32(v, 4, self.value);
+	buffer_view_set_f32(v, 8, self.value);
+	buffer_view_set_f32(v, 12, 1.0);
 	self.image = image_from_bytes(b, 1, 1, tex_format_t.RGBA128);
 	done(self.image);
 }
 
 function float_node_set(self: float_node_t, value: any) {
-	if (self.base.inputs.length > 0) logic_node_input_set(self.base.inputs[0], value);
-	else self.value = value;
+	if (self.base.inputs.length > 0) {
+		logic_node_input_set(self.base.inputs[0], value);
+	}
+	else {
+		self.value = value;
+	}
 }
 
 let float_node_def: zui_node_t = {

+ 13 - 5
base/Sources/nodes/integer_node.ts

@@ -9,16 +9,24 @@ function integer_node_create(value: i32 = 0): integer_node_t {
 	n.base = logic_node_create();
 	n.base.get = integer_node_get;
 	n.base.set = integer_node_set;
-	this.value = value;
+	n.value = value;
 	return n;
 }
 
 function integer_node_get(self: integer_node_t, from: i32, done: (a: any)=>void) {
-	if (self.base.inputs.length > 0) logic_node_input_get(self.base.inputs[0], done);
-	else done(self.value);
+	if (self.base.inputs.length > 0) {
+		logic_node_input_get(self.base.inputs[0], done);
+	}
+	else {
+		done(self.value);
+	}
 }
 
 function integer_node_set(self: integer_node_t, value: any) {
-	if (self.base.inputs.length > 0) logic_node_input_set(self.base.inputs[0], value);
-	else self.value = value;
+	if (self.base.inputs.length > 0) {
+		logic_node_input_set(self.base.inputs[0], value);
+	}
+	else {
+		self.value = value;
+	}
 }

+ 5 - 3
base/Sources/nodes/math_node.ts

@@ -13,8 +13,8 @@ function math_node_create(): math_node_t {
 }
 
 function math_node_get(self: math_node_t, from: i32, done: (a: any)=>void) {
-	logic_node_input_get(self.base.inputs[0], (v1: f32) => {
-		logic_node_input_get(self.base.inputs[1], (v2: f32) => {
+	logic_node_input_get(self.base.inputs[0], function (v1: f32) {
+		logic_node_input_get(self.base.inputs[1], function (v2: f32) {
 			let f: f32 = 0.0;
 			switch (self.operation) {
 				case "Add":
@@ -124,7 +124,9 @@ function math_node_get(self: math_node_t, from: i32, done: (a: any)=>void) {
 					break;
 			}
 
-			if (self.use_clamp) f = f < 0.0 ? 0.0 : (f > 1.0 ? 1.0 : f);
+			if (self.use_clamp) {
+				f = f < 0.0 ? 0.0 : (f > 1.0 ? 1.0 : f);
+			}
 
 			done(f);
 		});

+ 2 - 2
base/Sources/nodes/random_node.ts

@@ -16,8 +16,8 @@ function random_node_create(): random_node_t {
 }
 
 function random_node_get(self: random_node_t, from: i32, done: (a: any)=>void) {
-	logic_node_input_get(self.base.inputs[0], (min: f32) => {
-		logic_node_input_get(self.base.inputs[1], (max: f32) => {
+	logic_node_input_get(self.base.inputs[0], function (min: f32) {
+		logic_node_input_get(self.base.inputs[1], function (max: f32) {
 			done(min + random_node_get_float() * (max - min));
 		});
 	});

+ 11 - 5
base/Sources/nodes/separate_vector_node.ts

@@ -11,10 +11,16 @@ function separate_vector_node_create(): separate_vector_node_t {
 }
 
 function separate_vector_node_get(self: separate_vector_node_t, from: i32, done: (a: any)=>void) {
-	logic_node_input_get(self.base.inputs[0], (vector: vec4_t) => {
-		if (from == 0) done(vector.x);
-		else if (from == 1) done(vector.y);
-		else done(vector.z);
+	logic_node_input_get(self.base.inputs[0], function (vector: vec4_t) {
+		if (from == 0) {
+			done(vector.x);
+		}
+		else if (from == 1) {
+			done(vector.y);
+		}
+		else {
+			done(vector.z);
+		}
 	});
 }
 
@@ -32,7 +38,7 @@ let separate_vector_node_def: zui_node_t = {
 			name: _tr("Vector"),
 			type: "VECTOR",
 			color: 0xff6363c7,
-			default_value: new Float32Array([0.0, 0.0, 0.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0])
 		}
 	],
 	outputs: [

+ 12 - 4
base/Sources/nodes/string_node.ts

@@ -14,11 +14,19 @@ function string_node_create(value: string = ""): string_node_t {
 }
 
 function string_node_get(self: string_node_t, from: i32, done: (a: any)=>void) {
-	if (self.base.inputs.length > 0) logic_node_input_get(self.base.inputs[0], done);
-	else done(self.value);
+	if (self.base.inputs.length > 0) {
+		logic_node_input_get(self.base.inputs[0], done);
+	}
+	else {
+		done(self.value);
+	}
 }
 
 function string_node_set(self: string_node_t, value: any) {
-	if (self.base.inputs.length > 0) logic_node_input_set(self.base.inputs[0], value);
-	else self.value = value;
+	if (self.base.inputs.length > 0) {
+		logic_node_input_set(self.base.inputs[0], value);
+	}
+	else {
+		self.value = value;
+	}
 }

+ 9 - 3
base/Sources/nodes/time_node.ts

@@ -11,9 +11,15 @@ function time_node_create(): time_node_t {
 }
 
 function time_node_get(self: time_node_t, from: i32, done: (a: any)=>void) {
-	if (from == 0) done(time_time());
-	else if (from == 1) done(time_delta());
-	else done(context_raw.brush_time);
+	if (from == 0) {
+		done(time_time());
+	}
+	else if (from == 1) {
+		done(time_delta());
+	}
+	else {
+		done(context_raw.brush_time);
+	}
 }
 
 let time_node_def: zui_node_t = {

+ 11 - 7
base/Sources/nodes/vector_math_node.ts

@@ -14,8 +14,8 @@ function vector_math_node_create(): vector_math_node_t {
 }
 
 function vector_math_node_get(self: vector_math_node_t, from: i32, done: (a: any)=>void) {
-	logic_node_input_get(self.base.inputs[0], (v1: vec4_t) => {
-		logic_node_input_get(self.base.inputs[1], (v2: vec4_t) => {
+	logic_node_input_get(self.base.inputs[0], function (v1: vec4_t) {
+		logic_node_input_get(self.base.inputs[1], function (v2: vec4_t) {
 			vec4_set_from(self.v, v1);
 			let f: f32 = 0.0;
 
@@ -132,8 +132,12 @@ function vector_math_node_get(self: vector_math_node_t, from: i32, done: (a: any
 					break;
 			}
 
-			if (from == 0) done(self.v);
-			else done(f);
+			if (from == 0) {
+				done(self.v);
+			}
+			else {
+				done(f);
+			}
 		});
 	});
 }
@@ -152,7 +156,7 @@ let vector_math_node_def: zui_node_t = {
 			name: _tr("Vector"),
 			type: "VECTOR",
 			color: 0xff6363c7,
-			default_value: new Float32Array([0.0, 0.0, 0.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0])
 		},
 		{
 			id: 0,
@@ -160,7 +164,7 @@ let vector_math_node_def: zui_node_t = {
 			name: _tr("Vector"),
 			type: "VECTOR",
 			color: 0xff6363c7,
-			default_value: new Float32Array([0.0, 0.0, 0.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0])
 		}
 	],
 	outputs: [
@@ -170,7 +174,7 @@ let vector_math_node_def: zui_node_t = {
 			name: _tr("Vector"),
 			type: "VECTOR",
 			color: 0xff6363c7,
-			default_value: new Float32Array([0.0, 0.0, 0.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0])
 		},
 		{
 			id: 0,

+ 16 - 14
base/Sources/nodes/vector_node.ts

@@ -23,9 +23,9 @@ function vector_node_create(x: Null<f32> = null, y: Null<f32> = null, z: Null<f3
 }
 
 function vector_node_get(self: vector_node_t, from: i32, done: (a: any)=>void) {
-	logic_node_input_get(self.base.inputs[0], (x: f32) => {
-		logic_node_input_get(self.base.inputs[1], (y: f32) => {
-			logic_node_input_get(self.base.inputs[2], (z: f32) => {
+	logic_node_input_get(self.base.inputs[0], function (x: f32) {
+		logic_node_input_get(self.base.inputs[1], function (y: f32) {
+			logic_node_input_get(self.base.inputs[2], function (z: f32) {
 				self.value.x = x;
 				self.value.y = y;
 				self.value.z = z;
@@ -36,16 +36,18 @@ function vector_node_get(self: vector_node_t, from: i32, done: (a: any)=>void) {
 }
 
 function vector_node_get_as_image(self: vector_node_t, from: i32, done: (img: image_t)=>void) {
-	logic_node_input_get(self.base.inputs[0], (x: f32) => {
-		logic_node_input_get(self.base.inputs[1], (y: f32) => {
-			logic_node_input_get(self.base.inputs[2], (z: f32) => {
-				if (self.image != null) image_unload(self.image);
-				let b: ArrayBuffer = new ArrayBuffer(16);
-				let v: DataView = new DataView(b);
-				v.setFloat32(0, (self.base.inputs[0].node as any).value, true);
-				v.setFloat32(4, (self.base.inputs[1].node as any).value, true);
-				v.setFloat32(8, (self.base.inputs[2].node as any).value, true);
-				v.setFloat32(12, 1.0, true);
+	logic_node_input_get(self.base.inputs[0], function (x: f32) {
+		logic_node_input_get(self.base.inputs[1], function (y: f32) {
+			logic_node_input_get(self.base.inputs[2], function (z: f32) {
+				if (self.image != null) {
+					image_unload(self.image);
+				}
+				let b: buffer_t = buffer_create(16);
+				let v: buffer_view_t = buffer_view_create(b);
+				buffer_view_set_f32(v, 0, (self.base.inputs[0].node as any).value);
+				buffer_view_set_f32(v, 4, (self.base.inputs[1].node as any).value);
+				buffer_view_set_f32(v, 8, (self.base.inputs[2].node as any).value);
+				buffer_view_set_f32(v, 12, 1.0);
 				self.image = image_from_bytes(b, 1, 1, tex_format_t.RGBA128);
 				done(self.image);
 			});
@@ -99,7 +101,7 @@ let vector_node_def: zui_node_t = {
 			name: _tr("Vector"),
 			type: "VECTOR",
 			color: 0xff6363c7,
-			default_value: new Float32Array([0.0, 0.0, 0.0])
+			default_value: new f32_array_t([0.0, 0.0, 0.0])
 		}
 	],
 	buttons: []

File diff suppressed because it is too large
+ 134 - 117
base/Sources/nodes_material.ts


+ 8 - 8
base/Sources/operator.ts

@@ -2,12 +2,12 @@
 let operator_ops: map_t<string, any> = map_create();
 
 function operator_register(name: string, call: any) {
-	operator_ops.set(name, call);
+	map_set(operator_ops, name, call);
 }
 
 function operator_run(name: string) {
-	if (operator_ops.get(name) != null) {
-		operator_ops.get(name)();
+	if (map_get(operator_ops, name) != null) {
+		map_get(operator_ops, name)();
 	}
 }
 
@@ -25,13 +25,13 @@ function operator_shortcut(s: string, type = shortcut_type_t.STARTED): bool {
 	if (s == "") {
 		return false;
 	}
-	let shift: bool = s.indexOf("shift") >= 0;
-	let ctrl: bool = s.indexOf("ctrl") >= 0;
-	let alt: bool = s.indexOf("alt") >= 0;
+	let shift: bool = string_index_of(s, "shift") >= 0;
+	let ctrl: bool = string_index_of(s, "ctrl") >= 0;
+	let alt: bool = string_index_of(s, "alt") >= 0;
 	let flag: bool = shift == keyboard_down("shift") && ctrl == keyboard_down("control") && alt == keyboard_down("alt");
 
-	if (s.indexOf("+") > 0) {
-		s = s.substr(s.lastIndexOf("+") + 1);
+	if (string_index_of(s, "+") > 0) {
+		s = substring(s, string_last_index_of(s, "+") + 1, s.length);
 		if (s == "number") {
 			return flag;
 		}

+ 102 - 56
base/Sources/parser_blend.ts

@@ -3,14 +3,14 @@
 // 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 = parser_blend_init(blob: DataView);
+// let bl: BlendRaw = parser_blend_init(blob: buffer_view_t);
 // krom_log(parser_blend_dir(bl, "Scene"));
 // let scenes: any = parser_blend_get(bl, "Scene");
 // krom_log(get(get(scenes[0], "id"), "name"));
 
 class BlendRaw {
 	pos: i32;
-	view: DataView;
+	view: buffer_view_t;
 
 	// Header
 	version: string;
@@ -22,14 +22,16 @@ class BlendRaw {
 	map: map_t<any, Block> = map_create(); // Map blocks by memory address
 }
 
-function parser_blend_init(buffer: ArrayBuffer): BlendRaw {
+function parser_blend_init(buffer: buffer_t): BlendRaw {
 	let raw: BlendRaw = new BlendRaw();
-	raw.view = new DataView(buffer);
+	raw.view = buffer_view_create(buffer);
 	raw.pos = 0;
 	if (parser_blend_read_chars(raw, 7) != "BLENDER") {
-		raw.view = new DataView(krom_inflate(buffer, false));
+		raw.view = buffer_view_create(krom_inflate(buffer, false));
 		raw.pos = 0;
-		if (parser_blend_read_chars(raw, 7) != "BLENDER") return null;
+		if (parser_blend_read_chars(raw, 7) != "BLENDER") {
+			return null;
+		}
 	}
 	parser_blend_parse(raw);
 	return raw;
@@ -38,28 +40,34 @@ function parser_blend_init(buffer: ArrayBuffer): BlendRaw {
 function parser_blend_dir(raw: BlendRaw, type: string): string[] {
 	// Return structure fields
 	let type_index: i32 = parser_blend_get_type_index(raw.dna, type);
-	if (type_index == -1) return null;
+	if (type_index == -1) {
+		return null;
+	}
 	let ds: DnaStruct = parser_blend_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]);
+		array_push(fields, raw.dna.types[type_index] + " " + raw.dna.names[name_index]);
 	}
 	return fields;
 }
 
 function parser_blend_get(raw: BlendRaw, type: string): BlHandleRaw[] {
-	if (raw.dna == null) return null;
+	if (raw.dna == null) {
+		return null;
+	}
 	// Return all structures of type
 	let type_index: i32 = parser_blend_get_type_index(raw.dna, type);
-	if (type_index == -1) return null;
+	if (type_index == -1) {
+		return null;
+	}
 	let ds: DnaStruct = parser_blend_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);
+			array_push(handles, h);
 			h.block = b;
 			h.ds = ds;
 		}
@@ -68,12 +76,20 @@ function parser_blend_get(raw: BlendRaw, type: string): BlHandleRaw[] {
 }
 
 function parser_blend_get_struct(dna: Dna, typeIndex: i32): DnaStruct {
-	for (let ds of dna.structs) if (ds.type == typeIndex) return ds;
+	for (let ds of dna.structs) {
+		if (ds.type == typeIndex) {
+			return ds;
+		}
+	}
 	return null;
 }
 
 function parser_blend_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;
+	for (let i: i32 = 0; i < dna.types.length; ++i) {
+		if (type == dna.types[i]) {
+			return i;
+		}
+	}
 	return -1;
 }
 
@@ -88,15 +104,17 @@ function parser_blend_parse(raw: BlendRaw) {
 
 	// Reading file blocks
 	// Header - data
-	while (raw.pos < raw.view.byteLength) {
+	while (raw.pos < buffer_view_size(raw.view)) {
 		parser_blend_align(raw);
 		let b: Block = new Block();
 
 		// Block type
 		b.code = parser_blend_read_chars(raw, 4);
-		if (b.code == "ENDB") break;
+		if (b.code == "ENDB") {
+			break;
+		}
 
-		raw.blocks.push(b);
+		array_push(raw.blocks, b);
 		b.blend = raw;
 
 		// Total block length
@@ -104,7 +122,9 @@ function parser_blend_parse(raw: BlendRaw) {
 
 		// Memory address
 		let addr: any = parser_blend_read_pointer(raw);
-		if (!raw.map.has(addr)) raw.map.set(addr, b);
+		if (!raw.map.has(addr)) {
+			map_set(raw.map, addr, b);
+		}
 
 		// Index of dna struct contained in this block
 		b.sdna_index = parser_blend_read_i32(raw);
@@ -122,20 +142,20 @@ function parser_blend_parse(raw: BlendRaw) {
 			parser_blend_read_chars(raw, 4); // NAME
 			let names_count: i32 = parser_blend_read_i32(raw);
 			for (let i: i32 = 0; i < names_count; ++i) {
-				raw.dna.names.push(parser_blend_read_string(raw));
+				array_push(raw.dna.names, parser_blend_read_string(raw));
 			}
 			parser_blend_align(raw);
 
 			parser_blend_read_chars(raw, 4); // TYPE
 			let types_count: i32 = parser_blend_read_i32(raw);
 			for (let i: i32 = 0; i < types_count; ++i) {
-				raw.dna.types.push(parser_blend_read_string(raw));
+				array_push(raw.dna.types, parser_blend_read_string(raw));
 			}
 			parser_blend_align(raw);
 
 			parser_blend_read_chars(raw, 4); // TLEN
 			for (let i: i32 = 0; i < types_count; ++i) {
-				raw.dna.types_length.push(parser_blend_read_i16(raw));
+				array_push(raw.dna.types_length, parser_blend_read_i16(raw));
 			}
 			parser_blend_align(raw);
 
@@ -143,7 +163,7 @@ function parser_blend_parse(raw: BlendRaw) {
 			let struct_count: i32 = parser_blend_read_i32(raw);
 			for (let i: i32 = 0; i < struct_count; ++i) {
 				let ds: DnaStruct = new DnaStruct();
-				raw.dna.structs.push(ds);
+				array_push(raw.dna.structs, ds);
 				ds.dna = raw.dna;
 				ds.type = parser_blend_read_i16(raw);
 				let field_count: i32 = parser_blend_read_i16(raw);
@@ -151,8 +171,8 @@ function parser_blend_parse(raw: BlendRaw) {
 					ds.field_types = [];
 					ds.field_names = [];
 					for (let j: i32 = 0; j < field_count; ++j) {
-						ds.field_types.push(parser_blend_read_i16(raw));
-						ds.field_names.push(parser_blend_read_i16(raw));
+						array_push(ds.field_types, parser_blend_read_i16(raw));
+						array_push(ds.field_names, parser_blend_read_i16(raw));
 					}
 				}
 			}
@@ -166,23 +186,25 @@ function parser_blend_parse(raw: BlendRaw) {
 function parser_blend_align(raw: BlendRaw) {
 	// 4 bytes aligned
 	let mod: i32 = raw.pos % 4;
-	if (mod > 0) raw.pos += 4 - mod;
+	if (mod > 0) {
+		raw.pos += 4 - mod;
+	}
 }
 
 function parser_blend_read_i8(raw: BlendRaw): i32 {
-	let i: i32 = raw.view.getUint8(raw.pos);
+	let i: i32 = buffer_view_get_u8(raw.view, raw.pos);
 	raw.pos += 1;
 	return i;
 }
 
 function parser_blend_read_i16(raw: BlendRaw): i32 {
-	let i: i32 = raw.view.getInt16(raw.pos, raw.little_endian);
+	let i: i32 = buffer_view_get_i16(raw.view, raw.pos); //, raw.little_endian
 	raw.pos += 2;
 	return i;
 }
 
 function parser_blend_read_i32(raw: BlendRaw): i32 {
-	let i: i32 = raw.view.getInt32(raw.pos, raw.little_endian);
+	let i: i32 = buffer_view_get_i32(raw.view, raw.pos); //, raw.little_endian
 	raw.pos += 4;
 	return i;
 }
@@ -195,32 +217,40 @@ function parser_blend_read_i64(raw: BlendRaw): any {
 }
 
 function parser_blend_read_f32(raw: BlendRaw): f32 {
-	let f: f32 = raw.view.getFloat32(raw.pos, raw.little_endian);
+	let f: f32 = buffer_view_get_f32(raw.view, raw.pos); //, raw.little_endian
 	raw.pos += 4;
 	return f;
 }
 
-function parser_blend_read_i8array(raw: BlendRaw, len: i32): Int32Array {
-	let ar: Int32Array = new Int32Array(len);
-	for (let i: i32 = 0; i < len; ++i) ar[i] = parser_blend_read_i8(raw);
+function parser_blend_read_i8array(raw: BlendRaw, len: i32): i32_array_t {
+	let ar: i32_array_t = i32_array_create(len);
+	for (let i: i32 = 0; i < len; ++i) {
+		ar[i] = parser_blend_read_i8(raw);
+	}
 	return ar;
 }
 
-function parser_blend_read_i16array(raw: BlendRaw, len: i32): Int32Array {
-	let ar: Int32Array = new Int32Array(len);
-	for (let i: i32 = 0; i < len; ++i) ar[i] = parser_blend_read_i16(raw);
+function parser_blend_read_i16array(raw: BlendRaw, len: i32): i32_array_t {
+	let ar: i32_array_t = i32_array_create(len);
+	for (let i: i32 = 0; i < len; ++i) {
+		ar[i] = parser_blend_read_i16(raw);
+	}
 	return ar;
 }
 
-function parser_blend_read_i32array(raw: BlendRaw, len: i32): Int32Array {
-	let ar: Int32Array = new Int32Array(len);
-	for (let i: i32 = 0; i < len; ++i) ar[i] = parser_blend_read_i32(raw);
+function parser_blend_read_i32array(raw: BlendRaw, len: i32): i32_array_t {
+	let ar: i32_array_t = i32_array_create(len);
+	for (let i: i32 = 0; i < len; ++i) {
+		ar[i] = parser_blend_read_i32(raw);
+	}
 	return ar;
 }
 
-function parser_blend_read_f32array(raw: BlendRaw, len: i32): Float32Array {
-	let ar: Float32Array = new Float32Array(len);
-	for (let i: i32 = 0; i < len; ++i) ar[i] = parser_blend_read_f32(raw);
+function parser_blend_read_f32array(raw: BlendRaw, len: i32): f32_array_t {
+	let ar: f32_array_t = f32_array_create(len);
+	for (let i: i32 = 0; i < len; ++i) {
+		ar[i] = parser_blend_read_f32(raw);
+	}
 	return ar;
 }
 
@@ -228,20 +258,24 @@ function parser_blend_read_string(raw: BlendRaw): string {
 	let s: string = "";
 	while (true) {
 		let ch: i32 = parser_blend_read_i8(raw);
-		if (ch == 0) break;
-		s += String.fromCharCode(ch);
+		if (ch == 0) {
+			break;
+		}
+		s += string_from_char_code(ch);
 	}
 	return s;
 }
 
 function parser_blend_read_chars(raw: BlendRaw, len: i32): string {
 	let s: string = "";
-	for (let i: i32 = 0; i < len; ++i) s += parser_blend_read_char(raw);
+	for (let i: i32 = 0; i < len; ++i) {
+		s += parser_blend_read_char(raw);
+	}
 	return s;
 }
 
 function parser_blend_read_char(raw: BlendRaw): string {
-	return String.fromCharCode(parser_blend_read_i8(raw));
+	return string_from_char_code(parser_blend_read_i8(raw));
 }
 
 function parser_blend_read_pointer(raw: BlendRaw): any {
@@ -283,20 +317,30 @@ function bl_handle_get_size(raw: BlHandleRaw, index: i32): i32 {
 	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 *= bl_handle_get_array_len(n);
+	if (string_index_of(n, "*") >= 0) {
+		size = raw.block.blend.pointer_size;
+	}
+	else {
+		size = dna.types_length[type_index];
+	}
+	if (string_index_of(n, "[") > 0) {
+		size *= bl_handle_get_array_len(n);
+	}
 	return size;
 }
 
 function bl_handle_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("["));
+	while (char_at(s, 0) == "*") {
+		s = substring(s, 1, s.length);
+	}
+	if (char_at(s, s.length - 1) == "]") {
+		s = substring(s, 0, string_index_of(s, "["));
+	}
 	return s;
 }
 
 function bl_handle_get_array_len(s: string): i32 {
-	return parseInt(s.substring(s.indexOf("[") + 1, s.indexOf("]")));
+	return parseInt(substring(s, string_index_of(s, "[") + 1, string_index_of(s, "]")));
 }
 
 function bl_handle_get(raw: BlHandleRaw, name: string, index: i32 = 0, as_type: string = null, array_len: i32 = 0): any {
@@ -309,7 +353,9 @@ function bl_handle_get(raw: BlHandleRaw, name: string, index: i32 = 0, as_type:
 			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 += bl_handle_get_size(raw, j);
+			for (let j: i32 = 0; j < i; ++j) {
+				new_offset += bl_handle_get_size(raw, j);
+			}
 			// Cast void * to type
 			if (as_type != null) {
 				for (let i: i32 = 0; i < dna.types.length; ++i) {
@@ -323,8 +369,8 @@ function bl_handle_get(raw: BlHandleRaw, name: string, index: i32 = 0, as_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 ? (array_len > 0 ? array_len : this.bl_handle_get_array_len(dna_name)) : 1;
+				let is_array: bool = char_at(dna_name, dna_name.length - 1) == "]";
+				let len: i32 = is_array ? (array_len > 0 ? array_len : bl_handle_get_array_len(dna_name)) : 1;
 				switch (type) {
 					case "int": return is_array ? parser_blend_read_i32array(blend, len) : parser_blend_read_i32(blend);
 					case "char": return is_array ? parser_blend_read_string(blend) : parser_blend_read_i8(blend);
@@ -337,18 +383,18 @@ function bl_handle_get(raw: BlHandleRaw, name: string, index: i32 = 0, as_type:
 					case "ulong": return is_array ? parser_blend_read_i32array(blend, len) : parser_blend_read_i32(blend);
 					case "int64_t": return parser_blend_read_i64(blend);
 					case "uint64_t": return parser_blend_read_i64(blend);
-					case "void": if (dna_name.charAt(0) == "*") { return parser_blend_read_i64(blend); };
+					case "void": if (char_at(dna_name, 0) == "*") { return parser_blend_read_i64(blend); };
 				}
 			}
 			// Structure
 			let h: BlHandleRaw = new BlHandleRaw();
 			h.ds = parser_blend_get_struct(dna, type_index);
-			let is_pointer: bool = dna_name.charAt(0) == "*";
+			let is_pointer: bool = char_at(dna_name, 0) == "*";
 			if (is_pointer) {
 				raw.block.blend.pos = raw.block.pos + new_offset;
 				let addr: any = parser_blend_read_pointer(raw.block.blend);
 				if (raw.block.blend.map.has(addr)) {
-					h.block = raw.block.blend.map.get(addr);
+					h.block = map_get(raw.block.blend.map, addr);
 				}
 				else h.block = raw.block;
 				h.offset = 0;

+ 209 - 209
base/Sources/parser_exr.ts

@@ -4,241 +4,241 @@
 
 function parser_exr_write_string(out: i32[], str: string) {
 	for (let i: i32 = 0; i < str.length; ++i) {
-		out.push(str.charCodeAt(i));
+		array_push(out, char_code_at(str, i));
 	}
 }
 
-function parser_exr_run(width: i32, height: i32, src: ArrayBuffer, bits: i32 = 16, type: i32 = 1, off: i32 = 0): ArrayBuffer {
+function parser_exr_run(width: i32, height: i32, src: buffer_t, bits: i32 = 16, type: i32 = 1, off: i32 = 0): buffer_t {
 	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);
+	array_push(out, 0x76); // magic
+	array_push(out, 0x2f);
+	array_push(out, 0x31);
+	array_push(out, 0x01);
+	array_push(out, 2); // version, scanline
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 	parser_exr_write_string(out, "channels");
-	out.push(0);
+	array_push(out, 0);
 	parser_exr_write_string(out, "chlist");
-	out.push(0);
+	array_push(out, 0);
 
-	out.push(55);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 55);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 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);
+	array_push(out, char_code_at("B", 0)); // B
+	array_push(out, 0);
+
+	array_push(out, attrib);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 1);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 1);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, char_code_at("G", 0)); // G
+	array_push(out, 0);
+
+	array_push(out, attrib);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 1);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 1);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, char_code_at("R", 0)); // R
+	array_push(out, 0);
+
+	array_push(out, attrib);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 1);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 1);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+
+	array_push(out, 0);
 
 	parser_exr_write_string(out, "compression");
-	out.push(0);
+	array_push(out, 0);
 	parser_exr_write_string(out, "compression");
-	out.push(0);
+	array_push(out, 0);
 
-	out.push(1);
-	out.push(0);
-	out.push(0);
-	out.push(0);
-	out.push(0); // no compression
+	array_push(out, 1);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0); // no compression
 
 	parser_exr_write_string(out, "dataWindow");
-	out.push(0);
+	array_push(out, 0);
 	parser_exr_write_string(out, "box2i");
-	out.push(0);
+	array_push(out, 0);
 
-	out.push(16);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 16);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(0);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(0);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 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);
+	array_push(out, ww & 0xff);
+	array_push(out, (ww >> 8) & 0xff);
+	array_push(out, (ww >> 16) & 0xff);
+	array_push(out, (ww >> 24) & 0xff);
 
-	out.push(hh & 0xff);
-	out.push((hh >> 8) & 0xff);
-	out.push((hh >> 16) & 0xff);
-	out.push((hh >> 24) & 0xff);
+	array_push(out, hh & 0xff);
+	array_push(out, (hh >> 8) & 0xff);
+	array_push(out, (hh >> 16) & 0xff);
+	array_push(out, (hh >> 24) & 0xff);
 
 	parser_exr_write_string(out, "displayWindow");
-	out.push(0);
+	array_push(out, 0);
 	parser_exr_write_string(out, "box2i");
-	out.push(0);
+	array_push(out, 0);
 
-	out.push(16);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 16);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(0);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(0);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(ww & 0xff);
-	out.push((ww >> 8) & 0xff);
-	out.push((ww >> 16) & 0xff);
-	out.push((ww >> 24) & 0xff);
+	array_push(out, ww & 0xff);
+	array_push(out, (ww >> 8) & 0xff);
+	array_push(out, (ww >> 16) & 0xff);
+	array_push(out, (ww >> 24) & 0xff);
 
-	out.push(hh & 0xff);
-	out.push((hh >> 8) & 0xff);
-	out.push((hh >> 16) & 0xff);
-	out.push((hh >> 24) & 0xff);
+	array_push(out, hh & 0xff);
+	array_push(out, (hh >> 8) & 0xff);
+	array_push(out, (hh >> 16) & 0xff);
+	array_push(out, (hh >> 24) & 0xff);
 
 	parser_exr_write_string(out, "lineOrder");
-	out.push(0);
+	array_push(out, 0);
 	parser_exr_write_string(out, "lineOrder");
-	out.push(0);
+	array_push(out, 0);
 
-	out.push(1);
-	out.push(0);
-	out.push(0);
-	out.push(0);
-	out.push(0); // increasing Y
+	array_push(out, 1);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0); // increasing Y
 
 	parser_exr_write_string(out, "pixelAspectRatio");
-	out.push(0);
+	array_push(out, 0);
 	parser_exr_write_string(out, "float");
-	out.push(0);
+	array_push(out, 0);
 
-	out.push(4);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 4);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(0); // 1.0f
-	out.push(0);
-	out.push(0x80);
-	out.push(0x3f);
+	array_push(out, 0); // 1.0f
+	array_push(out, 0);
+	array_push(out, 0x80);
+	array_push(out, 0x3f);
 
 	parser_exr_write_string(out, "screenWindowCenter");
-	out.push(0);
+	array_push(out, 0);
 
 	parser_exr_write_string(out, "v2f");
-	out.push(0);
+	array_push(out, 0);
 
-	out.push(8);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 8);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(0);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(0);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
 	parser_exr_write_string(out, "screenWindowWidth");
-	out.push(0);
+	array_push(out, 0);
 
 	parser_exr_write_string(out, "float");
-	out.push(0);
+	array_push(out, 0);
 
-	out.push(4);
-	out.push(0);
-	out.push(0);
-	out.push(0);
+	array_push(out, 4);
+	array_push(out, 0);
+	array_push(out, 0);
+	array_push(out, 0);
 
-	out.push(0); // 1.0f
-	out.push(0);
-	out.push(0x80);
-	out.push(0x3f);
+	array_push(out, 0); // 1.0f
+	array_push(out, 0);
+	array_push(out, 0x80);
+	array_push(out, 0x3f);
 
-	out.push(0); // end of header
+	array_push(out, 0); // end of header
 
 	let channels: i32 = 4;
 	let byte_size: i32 = bits == 16 ? 2 : 4;
@@ -250,49 +250,49 @@ function parser_exr_run(width: i32, height: i32, src: ArrayBuffer, bits: i32 = 1
 	// 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);
+		array_push(out, ofs & 0xff);
+		array_push(out, (ofs >> 8) & 0xff);
+		array_push(out, (ofs >> 16) & 0xff);
+		array_push(out, (ofs >> 24) & 0xff);
+		array_push(out, 0);
+		array_push(out, 0);
+		array_push(out, 0);
+		array_push(out, 0);
 		ofs += full_row_size;
 	}
 
 	// scanline data
 	let stride: i32 = channels * byte_size;
 	let pos: i32 = 0;
-	let srcView: DataView = new DataView(src);
+	let src_view: buffer_view_t = buffer_view_create(src);
 
-	let write_line16 = (bytePos: i32) => {
+	let write_line16 = function (byte_pos: i32) {
 		for (let x: i32 = 0; x < width; ++x) {
-			out.push(srcView.getUint8(bytePos    ));
-			out.push(srcView.getUint8(bytePos + 1));
-			bytePos += stride;
+			array_push(out, buffer_view_get_u8(src_view, byte_pos    ));
+			array_push(out, buffer_view_get_u8(src_view, byte_pos + 1));
+			byte_pos += stride;
 		}
 	}
 
-	let write_line32 = (bytePos: i32) => {
+	let write_line32 = function (byte_pos: 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;
+			array_push(out, buffer_view_get_u8(src_view, byte_pos    ));
+			array_push(out, buffer_view_get_u8(src_view, byte_pos + 1));
+			array_push(out, buffer_view_get_u8(src_view, byte_pos + 2));
+			array_push(out, buffer_view_get_u8(src_view, byte_pos + 3));
+			byte_pos += stride;
 		}
 	}
 
 	let write_line = bits == 16 ? write_line16 : write_line32;
 
-	let write_bgr = (off: i32) => {
+	let write_bgr = function (off: i32) {
 		write_line(pos + byte_size * 2);
 		write_line(pos + byte_size);
 		write_line(pos);
 	}
 
-	let write_single = (off: i32) => {
+	let write_single = function (off: i32) {
 		write_line(pos + off * byte_size);
 		write_line(pos + off * byte_size);
 		write_line(pos + off * byte_size);
@@ -302,19 +302,19 @@ function parser_exr_run(width: i32, height: i32, src: ArrayBuffer, bits: i32 = 1
 
 	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);
+		array_push(out, y & 0xff);
+		array_push(out, (y >> 8) & 0xff);
+		array_push(out, (y >> 16) & 0xff);
+		array_push(out, (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);
+		array_push(out, pixel_row_size & 0xff);
+		array_push(out, (pixel_row_size >> 8) & 0xff);
+		array_push(out, (pixel_row_size >> 16) & 0xff);
+		array_push(out, (pixel_row_size >> 24) & 0xff);
 		// data
 		write_data(off);
 		pos += width * stride;
 	}
 
-	return Uint8Array.from(out).buffer;
+	return u8_array_t.from(out).buffer;
 }

+ 49 - 23
base/Sources/parser_logic.ts

@@ -9,20 +9,28 @@ let parser_logic_node_map: map_t<string, logic_node_t>;
 let parser_logic_raw_map: map_t<logic_node_t, zui_node_t>;
 
 function parser_logic_get_logic_node(node: zui_node_t): logic_node_t {
-	return parser_logic_node_map.get(parser_logic_node_name(node));
+	return map_get(parser_logic_node_map, parser_logic_node_name(node));
 }
 
 function parser_logic_get_raw_node(node: logic_node_t): zui_node_t {
-	return parser_logic_raw_map.get(node);
+	return map_get(parser_logic_raw_map, node);
 }
 
 function parser_logic_get_node(id: i32): zui_node_t {
-	for (let n of parser_logic_nodes) if (n.id == id) return n;
+	for (let n of parser_logic_nodes) {
+		if (n.id == id) {
+			return n;
+		}
+	}
 	return null;
 }
 
 function parser_logic_get_link(id: i32): zui_node_link_t {
-	for (let l of parser_logic_links) if (l.id == id) return l;
+	for (let l of parser_logic_links) {
+		if (l.id == id) {
+			return l;
+		}
+	}
 	return null;
 }
 
@@ -30,8 +38,12 @@ function parser_logic_get_input_link(inp: zui_node_socket_t): zui_node_link_t {
 	for (let l of parser_logic_links) {
 		if (l.to_id == inp.node_id) {
 			let node: zui_node_t = parser_logic_get_node(inp.node_id);
-			if (node.inputs.length <= l.to_socket) return null;
-			if (node.inputs[l.to_socket] == inp) return l;
+			if (node.inputs.length <= l.to_socket) {
+				return null;
+			}
+			if (node.inputs[l.to_socket] == inp) {
+				return l;
+			}
 		}
 	}
 	return null;
@@ -42,8 +54,12 @@ function parser_logic_get_output_links(out: zui_node_socket_t): zui_node_link_t[
 	for (let l of parser_logic_links) {
 		if (l.from_id == out.node_id) {
 			let node: zui_node_t = parser_logic_get_node(out.node_id);
-			if (node.outputs.length <= l.from_socket) continue;
-			if (node.outputs[l.from_socket] == out) res.push(l);
+			if (node.outputs.length <= l.from_socket) {
+				continue;
+			}
+			if (node.outputs[l.from_socket] == out) {
+				array_push(res, l);
+			}
 		}
 	}
 	return res;
@@ -68,7 +84,9 @@ function parser_logic_parse(canvas: zui_node_canvas_t) {
 	parser_logic_raw_map = map_create();
 	let root_nodes: zui_node_t[] = parser_logic_get_root_nodes(canvas);
 
-	for (let node of root_nodes) parser_logic_build_node(node);
+	for (let node of root_nodes) {
+		parser_logic_build_node(node);
+	}
 }
 
 function parser_logic_build_node(node: zui_node_t): string {
@@ -76,21 +94,21 @@ function parser_logic_build_node(node: zui_node_t): string {
 	let name: string = parser_logic_node_name(node);
 
 	// Check if node already exists
-	if (parser_logic_parsed_nodes.indexOf(name) != -1) {
+	if (array_index_of(parser_logic_parsed_nodes, name) != -1) {
 		return name;
 	}
 
-	parser_logic_parsed_nodes.push(name);
+	array_push(parser_logic_parsed_nodes, name);
 
 	// Create node
 	let v: any = parser_logic_create_node_instance(node.type, []);
-	parser_logic_node_map.set(name, v);
-	parser_logic_raw_map.set(v, node);
+	map_set(parser_logic_node_map, name, v);
+	map_set(parser_logic_raw_map, v, node);
 
 	// Expose button values in node class
 	for (let b of node.buttons) {
 		if (b.type == "ENUM") {
-			// let array_data: bool = Array.isArray(b.data);
+			// let array_data: bool = is_array(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];
@@ -108,7 +126,7 @@ function parser_logic_build_node(node: zui_node_t): string {
 		// Is linked - find node
 		let l: zui_node_link_t = parser_logic_get_input_link(inp);
 		if (l != null) {
-			inp_node = parser_logic_node_map.get(parser_logic_build_node(parser_logic_get_node(l.from_id)));
+			inp_node = map_get(parser_logic_node_map, parser_logic_build_node(parser_logic_get_node(l.from_id)));
 			inp_from = l.from_socket;
 		}
 		// Not linked - create node with default values
@@ -128,12 +146,12 @@ function parser_logic_build_node(node: zui_node_t): string {
 			for (let l of ls) {
 				let n: zui_node_t = parser_logic_get_node(l.to_id);
 				let out_name: string = parser_logic_build_node(n);
-				out_nodes.push(parser_logic_node_map.get(out_name));
+				array_push(out_nodes, map_get(parser_logic_node_map, out_name));
 			}
 		}
 		// Not linked - create node with default values
 		else {
-			out_nodes.push(parser_logic_build_default_node(out));
+			array_push(out_nodes, parser_logic_build_default_node(out));
 		}
 		// Add outputs
 		logic_node_add_outputs(v.base, out_nodes);
@@ -154,7 +172,7 @@ function parser_logic_get_root_nodes(node_group: zui_node_canvas_t): zui_node_t[
 			}
 		}
 		if (!linked) { // Assume node with no connected outputs as roots
-			roots.push(node);
+			array_push(roots, node);
 		}
 	}
 	return roots;
@@ -164,15 +182,21 @@ function parser_logic_build_default_node(inp: zui_node_socket_t): logic_node_t {
 	let v: logic_node_t = null;
 
 	if (inp.type == "VECTOR") {
-		if (inp.default_value == null) inp.default_value = [0, 0, 0]; // TODO
+		if (inp.default_value == null) {
+			inp.default_value = [0, 0, 0]; // TODO
+		}
 		v = parser_logic_create_node_instance("vector_node", [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
+		if (inp.default_value == null) {
+			inp.default_value = [0, 0, 0, 0]; // TODO
+		}
 		v = parser_logic_create_node_instance("color_node", [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
+		if (inp.default_value == null) {
+			inp.default_value = [0, 0, 0, 0]; // TODO
+		}
 		v = parser_logic_create_node_instance("color_node", [inp.default_value[0], inp.default_value[1], inp.default_value[2], inp.default_value[3]]);
 	}
 	else if (inp.type == "VALUE") {
@@ -194,9 +218,11 @@ function parser_logic_build_default_node(inp: zui_node_socket_t): logic_node_t {
 }
 
 function parser_logic_create_node_instance(node_type: string, args: any[]): any {
-	if (parser_logic_custom_nodes.get(node_type) != null) {
+	if (map_get(parser_logic_custom_nodes, node_type) != null) {
 		let node: logic_node_t = logic_node_create();
-		node.get = (from: i32) => { return parser_logic_custom_nodes.get(node_type)(node, from); }
+		node.get = function (from: i32) {
+			return map_get(parser_logic_custom_nodes, node_type)(node, from);
+		}
 		return node;
 	}
 

+ 123 - 61
base/Sources/parser_material.ts

@@ -15,10 +15,10 @@
 // limitations under the License.
 //
 
-let parser_material_con: NodeShaderContextRaw;
-let parser_material_vert: NodeShaderRaw;
-let parser_material_frag: NodeShaderRaw;
-let parser_material_curshader: NodeShaderRaw;
+let parser_material_con: node_shader_context_t;
+let parser_material_vert: node_shader_t;
+let parser_material_frag: node_shader_t;
+let parser_material_curshader: node_shader_t;
 let parser_material_matcon: material_context_t;
 let parser_material_parsed: string[];
 let parser_material_parents: zui_node_t[];
@@ -63,12 +63,20 @@ let parser_material_parsed_map: map_t<string, string> = map_create();
 let parser_material_texture_map: map_t<string, string> = map_create();
 
 function parser_material_get_node(id: i32): zui_node_t {
-	for (let n of parser_material_nodes) if (n.id == id) return n;
+	for (let n of parser_material_nodes) {
+		if (n.id == id) {
+			return n;
+		}
+	}
 	return null;
 }
 
 function parser_material_get_link(id: i32): zui_node_link_t {
-	for (let l of parser_material_links) if (l.id == id) return l;
+	for (let l of parser_material_links) {
+		if (l.id == id) {
+			return l;
+		}
+	}
 	return null;
 }
 
@@ -76,8 +84,12 @@ function parser_material_get_input_link(inp: zui_node_socket_t): zui_node_link_t
 	for (let l of parser_material_links) {
 		if (l.to_id == inp.node_id) {
 			let node: zui_node_t = parser_material_get_node(inp.node_id);
-			if (node.inputs.length <= l.to_socket) return null;
-			if (node.inputs[l.to_socket] == inp) return l;
+			if (node.inputs.length <= l.to_socket) {
+				return null;
+			}
+			if (node.inputs[l.to_socket] == inp) {
+				return l;
+			}
 		}
 	}
 	return null;
@@ -88,10 +100,14 @@ function parser_material_get_output_links(out: zui_node_socket_t): zui_node_link
 	for (let l of parser_material_links) {
 		if (l.from_id == out.node_id) {
 			let node: zui_node_t = parser_material_get_node(out.node_id);
-			if (node.outputs.length <= l.from_socket) continue;
+			if (node.outputs.length <= l.from_socket) {
+				continue;
+			}
 			if (node.outputs[l.from_socket] == out) {
-				if (ls == null) ls = [];
-				ls.push(l);
+				if (ls == null) {
+					ls = [];
+				}
+				array_push(ls, l);
 			}
 		}
 	}
@@ -107,7 +123,7 @@ function parser_material_init() {
 	parser_material_parsing_basecolor = false;
 }
 
-function parser_material_parse(canvas: zui_node_canvas_t, _con: NodeShaderContextRaw, _vert: NodeShaderRaw, _frag: NodeShaderRaw, _matcon: material_context_t): shader_out_t {
+function parser_material_parse(canvas: zui_node_canvas_t, _con: node_shader_context_t, _vert: node_shader_t, _frag: node_shader_t, _matcon: material_context_t): shader_out_t {
 	zui_nodes_update_canvas_format(canvas);
 	parser_material_init();
 	parser_material_canvases = [canvas];
@@ -150,9 +166,9 @@ function parser_material_parse(canvas: zui_node_canvas_t, _con: NodeShaderContex
 	return null;
 }
 
-function parser_material_finalize(con: NodeShaderContextRaw) {
-	let vert: NodeShaderRaw = con.vert;
-	let frag: NodeShaderRaw = con.frag;
+function parser_material_finalize(con: node_shader_context_t) {
+	let vert: node_shader_t = con.vert;
+	let frag: node_shader_t = con.frag;
 
 	if (frag.dotnv) {
 		frag.vvec = true;
@@ -266,12 +282,16 @@ function parser_material_parse_output_pbr(node: zui_node_t): shader_out_t {
 }
 
 function parser_material_get_group(name: string): zui_node_canvas_t {
-	for (let g of project_material_groups) if (g.canvas.name == name) return g.canvas;
+	for (let g of project_material_groups) {
+		if (g.canvas.name == name) {
+			return g.canvas;
+		}
+	}
 	return null;
 }
 
 function parser_material_push_group(g: zui_node_canvas_t) {
-	parser_material_canvases.push(g);
+	array_push(parser_material_canvases, g);
 	parser_material_nodes = g.nodes;
 	parser_material_links = g.links;
 }
@@ -284,10 +304,12 @@ function parser_material_pop_group() {
 }
 
 function parser_material_parse_group(node: zui_node_t, socket: zui_node_socket_t): string {
-	parser_material_parents.push(node); // Entering group
+	array_push(parser_material_parents, node); // Entering group
 	parser_material_push_group(parser_material_get_group(node.name));
 	let output_node: zui_node_t = parser_material_node_by_type(parser_material_nodes, "GROUP_OUTPUT");
-	if (output_node == null) return null;
+	if (output_node == null) {
+		return null;
+	}
 	let index: i32 = parser_material_socket_index(node, socket);
 	let inp: zui_node_socket_t = output_node.inputs[index];
 	let out_group: string = parser_material_parse_input(inp);
@@ -302,7 +324,7 @@ function parser_material_parse_group_input(node: zui_node_t, socket: zui_node_so
 	let index: i32 = parser_material_socket_index(node, socket);
 	let inp: zui_node_socket_t = parent.inputs[index];
 	let res: string = parser_material_parse_input(inp);
-	parser_material_parents.push(parent); // Return to group
+	array_push(parser_material_parents, parent); // Return to group
 	parser_material_push_group(parser_material_get_group(parent.name));
 	return res;
 }
@@ -388,9 +410,13 @@ function parser_material_parse_shader(node: zui_node_t, socket: zui_node_socket_
 
 		// Displacement / Height
 		if (node.inputs.length > 7 && parser_material_parse_height) {
-			if (!parser_material_parse_height_as_channel) parser_material_curshader = parser_material_vert;
+			if (!parser_material_parse_height_as_channel) {
+				parser_material_curshader = parser_material_vert;
+			}
 			sout.out_height = parser_material_parse_value_input(node.inputs[7]);
-			if (!parser_material_parse_height_as_channel) parser_material_curshader = parser_material_frag;
+			if (!parser_material_parse_height_as_channel) {
+				parser_material_curshader = parser_material_frag;
+			}
 		}
 	}
 
@@ -489,7 +515,7 @@ function parser_material_parse_vector(node: zui_node_t, socket: zui_node_socket_
 	}
 	else if (node.type == "TEX_IMAGE") {
 		// Already fetched
-		if (parser_material_parsed.indexOf(parser_material_res_var_name(node, node.outputs[1])) >= 0) { // TODO: node.outputs[0]
+		if (array_index_of(parser_material_parsed, parser_material_res_var_name(node, node.outputs[1])) >= 0) { // TODO: node.outputs[0]
 			let varname: string = parser_material_store_var_name(node);
 			return `${varname}.rgb`;
 		}
@@ -557,7 +583,9 @@ function parser_material_parse_vector(node: zui_node_t, socket: zui_node_socket_
 		return `pow(${out_col}, ` + parser_material_to_vec3(`${gamma}`) + ")";
 	}
 	else if (node.type == "DIRECT_WARP") {
-		if (parser_material_warp_passthrough) return parser_material_parse_vector_input(node.inputs[0]);
+		if (parser_material_warp_passthrough) {
+			return parser_material_parse_vector_input(node.inputs[0]);
+		}
 		let angle: string = parser_material_parse_value_input(node.inputs[1], true);
 		let mask: string = parser_material_parse_value_input(node.inputs[2], true);
 		let tex_name: string = "texwarp_" + parser_material_node_name(node);
@@ -569,9 +597,13 @@ function parser_material_parse_vector(node: zui_node_t, socket: zui_node_socket_
 		return `texture(${tex_name}, texCoord + vec2(${store}_x, ${store}_y) * ${mask}).rgb;`;
 	}
 	else if (node.type == "BLUR") {
-		if (parser_material_blur_passthrough) return parser_material_parse_vector_input(node.inputs[0]);
+		if (parser_material_blur_passthrough) {
+			return parser_material_parse_vector_input(node.inputs[0]);
+		}
 		let strength: string = parser_material_parse_value_input(node.inputs[1]);
-		if (strength == "0.0") return "vec3(0.0, 0.0, 0.0)";
+		if (strength == "0.0") {
+			return "vec3(0.0, 0.0, 0.0)";
+		}
 		let steps: string = `int(${strength} * 10 + 1)`;
 		let tex_name: string = "texblur_" + parser_material_node_name(node);
 		node_shader_add_uniform(parser_material_curshader, "sampler2D " + tex_name, "_" + tex_name);
@@ -674,8 +706,12 @@ function parser_material_parse_vector(node: zui_node_t, socket: zui_node_socket_
 			node_shader_add_function(parser_material_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;
+		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 = parser_material_parse_value_input(node.inputs[0]);
@@ -782,13 +818,15 @@ function parser_material_parse_vector(node: zui_node_t, socket: zui_node_socket_
 	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];
+		if (mi >= project_materials.length) {
+			return result;
+		}
+		let m: slot_material_t = project_materials[mi];
 		let _nodes: zui_node_t[] = parser_material_nodes;
 		let _links: zui_node_link_t[] = parser_material_links;
 		parser_material_nodes = m.canvas.nodes;
 		parser_material_links = m.canvas.links;
-		parser_material_parents.push(node);
+		array_push(parser_material_parents, node);
 		let output_node: zui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR");
 		if (socket == node.outputs[0]) { // Base
 			result = parser_material_parse_vector_input(output_node.inputs[0]);
@@ -1077,8 +1115,8 @@ function parser_material_parse_vector(node: zui_node_t, socket: zui_node_socket_
 		let height: string = parser_material_parse_value_input(node.inputs[0]);
 		return parser_material_to_vec3(`${height}`);
 	}
-	else if (parser_material_custom_nodes.get(node.type) != null) {
-		return parser_material_custom_nodes.get(node.type)(node, socket);
+	else if (map_get(parser_material_custom_nodes, node.type) != null) {
+		return map_get(parser_material_custom_nodes, node.type)(node, socket);
 	}
 	return "vec3(0.0, 0.0, 0.0)";
 }
@@ -1202,12 +1240,12 @@ function parser_material_parse_value(node: zui_node_t, socket: zui_node_socket_t
 		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 m: slot_material_t = project_materials[mi];
 		let _nodes: zui_node_t[] = parser_material_nodes;
 		let _links: zui_node_link_t[] = parser_material_links;
 		parser_material_nodes = m.canvas.nodes;
 		parser_material_links = m.canvas.links;
-		parser_material_parents.push(node);
+		array_push(parser_material_parents, node);
 		let output_node: zui_node_t = parser_material_node_by_type(parser_material_nodes, "OUTPUT_MATERIAL_PBR");
 		if (socket == node.outputs[1]) { // Opac
 			result = parser_material_parse_value_input(output_node.inputs[1]);
@@ -1336,7 +1374,7 @@ function parser_material_parse_value(node: zui_node_t, socket: zui_node_socket_t
 	}
 	else if (node.type == "TEX_IMAGE") {
 		// Already fetched
-		if (parser_material_parsed.indexOf(parser_material_res_var_name(node, node.outputs[0])) >= 0) { // TODO: node.outputs[1]
+		if (array_index_of(parser_material_parsed, parser_material_res_var_name(node, node.outputs[0])) >= 0) { // TODO: node.outputs[1]
 			let varname: string = parser_material_store_var_name(node);
 			return `${varname}.a`;
 		}
@@ -1540,10 +1578,12 @@ function parser_material_parse_value(node: zui_node_t, socket: zui_node_socket_t
 		}
 	}
 	else if (node.type == "SCRIPT_CPU") {
-		if (parser_material_script_links == null) parser_material_script_links = map_create();
+		if (parser_material_script_links == null) {
+			parser_material_script_links = map_create();
+		}
 		let script: any = node.buttons[0].default_value;
 		let link: string = parser_material_node_name(node);
-		parser_material_script_links.set(link, script);
+		map_set(parser_material_script_links, link, script);
 		node_shader_add_uniform(parser_material_curshader, "float " + link, "_" + link);
 		return link;
 	}
@@ -1644,8 +1684,8 @@ function parser_material_parse_value(node: zui_node_t, socket: zui_node_socket_t
 			return out_val;
 		}
 	}
-	else if (parser_material_custom_nodes.get(node.type) != null) {
-		return parser_material_custom_nodes.get(node.type)(node, socket);
+	else if (map_get(parser_material_custom_nodes, node.type) != null) {
+		return map_get(parser_material_custom_nodes, node.type)(node, socket);
 	}
 	return "0.0";
 }
@@ -1684,7 +1724,7 @@ function parser_material_get_gradient(grad: string, co: string): string {
 	}
 }
 
-function parser_material_vector_curve(name: string, fac: string, points: Float32Array[]): string {
+function parser_material_vector_curve(name: string, fac: string, points: f32_array_t[]): string {
 	// Write Ys array
 	let ys_var: string = name + "_ys";
 	let num: i32 = points.length;
@@ -1722,14 +1762,14 @@ function parser_material_write_result(l: zui_node_link_t): string {
 	let from_socket: zui_node_socket_t = from_node.outputs[l.from_socket];
 	let res_var: string = parser_material_res_var_name(from_node, from_socket);
 	let st: string = from_socket.type;
-	if (parser_material_parsed.indexOf(res_var) < 0) {
-		parser_material_parsed.push(res_var);
+	if (array_index_of(parser_material_parsed, res_var) < 0) {
+		array_push(parser_material_parsed, res_var);
 		if (st == "RGB" || st == "RGBA" || st == "VECTOR") {
 			let res: string = parser_material_parse_vector(from_node, from_socket);
 			if (res == null) {
 				return null;
 			}
-			parser_material_parsed_map.set(res_var, res);
+			map_set(parser_material_parsed_map, res_var, res);
 			node_shader_write(parser_material_curshader, `vec3 ${res_var} = ${res};`);
 		}
 		else if (st == "VALUE") {
@@ -1737,7 +1777,7 @@ function parser_material_write_result(l: zui_node_link_t): string {
 			if (res == null) {
 				return null;
 			}
-			parser_material_parsed_map.set(res_var, res);
+			map_set(parser_material_parsed_map, res_var, res);
 			node_shader_write(parser_material_curshader, `float ${res_var} = ${res};`);
 		}
 	}
@@ -1749,7 +1789,7 @@ function parser_material_store_var_name(node: zui_node_t): string {
 }
 
 function parser_material_texture_store(node: zui_node_t, tex: bind_tex_t, tex_name: string, color_space: i32): string {
-	parser_material_matcon.bind_textures.push(tex);
+	array_push(parser_material_matcon.bind_textures, tex);
 	node_shader_context_add_elem(parser_material_curshader.context, "tex", "short2norm");
 	node_shader_add_uniform(parser_material_curshader, "sampler2D " + tex_name);
 	let uv_name: string = "";
@@ -1779,14 +1819,14 @@ function parser_material_texture_store(node: zui_node_t, tex: bind_tex_t, tex_na
 	}
 	else {
 		if (parser_material_curshader == parser_material_frag) {
-			parser_material_texture_map.set(tex_store, `texture(${tex_name}, ${uv_name}.xy)`);
+			map_set(parser_material_texture_map, tex_store, `texture(${tex_name}, ${uv_name}.xy)`);
 			node_shader_write(parser_material_curshader, `vec4 ${tex_store} = texture(${tex_name}, ${uv_name}.xy);`);
 		}
 		else {
-			parser_material_texture_map.set(tex_store, `textureLod(${tex_name}, ${uv_name}.xy, 0.0)`);
+			map_set(parser_material_texture_map, tex_store, `textureLod(${tex_name}, ${uv_name}.xy, 0.0)`);
 			node_shader_write(parser_material_curshader, `vec4 ${tex_store} = textureLod(${tex_name}, ${uv_name}.xy, 0.0);`);
 		}
-		if (!tex.file.endsWith(".jpg")) { // Pre-mult alpha
+		if (!ends_with(tex.file, ".jpg")) { // Pre-mult alpha
 			node_shader_write(parser_material_curshader, `${tex_store}.rgb *= ${tex_store}.a;`);
 		}
 	}
@@ -1831,45 +1871,67 @@ function parser_material_to_vec3(s: string): string {
 }
 
 function parser_material_node_by_type(nodes: zui_node_t[], ntype: string): zui_node_t {
-	for (let n of nodes) if (n.type == ntype) return n;
+	for (let n of nodes) {
+		if (n.type == ntype) {
+			return n;
+		}
+	}
 	return null;
 }
 
 function parser_material_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;
+	for (let i: i32 = 0; i < node.outputs.length; ++i) {
+		if (node.outputs[i] == socket) {
+			return i;
+		}
+	}
 	return -1;
 }
 
 function parser_material_node_name(node: zui_node_t, _parents: zui_node_t[] = null): string {
-	if (_parents == null) _parents = parser_material_parents;
+	if (_parents == null) {
+		_parents = parser_material_parents;
+	}
 	let s: string = node.name;
-	for (let p of _parents) s = p.name + p.id + `_` + s;
+	for (let p of _parents) {
+		s = p.name + p.id + `_` + s;
+	}
 	s = parser_material_safesrc(s) + node.id;
 	return s;
 }
 
 function parser_material_safesrc(s: string): string {
 	for (let i: i32 = 0; i < s.length; ++i) {
-		let code: i32 = s.charCodeAt(i);
+		let code: i32 = char_code_at(s, 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 (!letter && !digit) {
+			s = string_replace_all(s, char_at(s, i), "_");
+		}
+		if (i == 0 && digit) {
+			s = "_" + s;
+		}
 	}
 	///if krom_opengl
-	while (s.indexOf("__") >= 0) s = string_replace_all(s, "__", "_");
+	while (string_index_of(s, "__") >= 0) {
+		s = string_replace_all(s, "__", "_");
+	}
 	///end
 	return s;
 }
 
 function parser_material_enum_data(s: string): string {
-	for (let a of project_assets) if (a.name == s) return a.file;
+	for (let a of project_assets) {
+		if (a.name == s) {
+			return a.file;
+		}
+	}
 	return "";
 }
 
 function parser_material_make_texture(image_node: zui_node_t, tex_name: string, matname: string = null): bind_tex_t {
 	let filepath: string = parser_material_enum_data(base_enum_texts(image_node.type)[image_node.buttons[0].default_value]);
-	if (filepath == "" || filepath.indexOf(".") == -1) {
+	if (filepath == "" || string_index_of(filepath, ".") == -1) {
 		return null;
 	}
 
@@ -1904,7 +1966,7 @@ function parser_material_asset_path(s: string): string {
 }
 
 function parser_material_extract_filename(s: string): string {
-	let ar: string[] = s.split(".");
+	let ar: string[] = string_split(s, ".");
 	return ar[ar.length - 2] + "." + ar[ar.length - 1];
 }
 
@@ -1931,5 +1993,5 @@ enum color_space_t {
 }
 
 ///if is_lab
-type SlotMaterialRaw = any;
+type slot_material_t = any;
 ///end

+ 44 - 30
base/Sources/path.ts

@@ -32,34 +32,40 @@ function path_data(): string {
 }
 
 function path_to_relative(from: string, to: string): string {
-	let a: string[] = from.split(path_sep);
-	let b: string[] = to.split(path_sep);
+	let a: string[] = string_split(from, path_sep);
+	let b: string[] = string_split(to, path_sep);
 	while (a[0] == b[0]) {
 		a.shift();
 		b.shift();
-		if (a.length == 0 || b.length == 0) break;
+		if (a.length == 0 || b.length == 0) {
+			break;
+		}
 	}
 	let base: string = "";
-	for (let i: i32 = 0; i < a.length - 1; ++i) base += ".." + path_sep;
+	for (let i: i32 = 0; i < a.length - 1; ++i) {
+		base += ".." + path_sep;
+	}
 	base += b.join(path_sep);
 	return base;
 }
 
 function path_normalize(path: string): string {
-	let ar: string[] = path.split(path_sep);
+	let ar: string[] = string_split(path, path_sep);
 	let i: i32 = 0;
 	while (i < ar.length) {
 		if (i > 0 && ar[i] == ".." && ar[i - 1] != "..") {
-			ar.splice(i - 1, 2);
+			array_splice(ar, i - 1, 2);
 			i--;
 		}
-		else i++;
+		else {
+			i++;
+		}
 	}
 	return ar.join(path_sep);
 }
 
 function path_base_dir(path: string): string {
-	return path.substr(0, path.lastIndexOf(path_sep) + 1);
+	return substring(path, 0, string_last_index_of(path, path_sep) + 1);
 }
 
 function path_working_dir(): string {
@@ -73,47 +79,55 @@ function path_working_dir(): string {
 }
 
 function path_is_mesh(path: string): bool {
-	let p: string = path.toLowerCase();
-	for (let s of path_mesh_formats) if (p.endsWith("." + s)) return true;
+	let p: string = to_lower_case(path);
+	for (let s of path_mesh_formats) {
+		if (ends_with(p, "." + s)) {
+			return true;
+		}
+	}
 	return false;
 }
 
 function path_is_texture(path: string): bool {
-	let p: string = path.toLowerCase();
-	for (let s of path_texture_formats) if (p.endsWith("." + s)) return true;
+	let p: string = to_lower_case(path);
+	for (let s of path_texture_formats) {
+		if (ends_with(p, "." + s)) {
+			return true;
+		}
+	}
 	return false;
 }
 
 function path_is_font(path: string): bool {
-	let p: string = path.toLowerCase();
-	return p.endsWith(".ttf") ||
-			p.endsWith(".ttc") ||
-			p.endsWith(".otf");
+	let p: string = to_lower_case(path);
+	return ends_with(p, ".ttf") ||
+		   ends_with(p, ".ttc") ||
+		   ends_with(p, ".otf");
 }
 
 function path_is_project(path: string): bool {
-	let p: string = path.toLowerCase();
-	return p.endsWith(".arm");
+	let p: string = to_lower_case(path);
+	return ends_with(p, ".arm");
 }
 
 function path_is_plugin(path: string): bool {
-	let p: string = path.toLowerCase();
-	return p.endsWith(".js");
+	let p: string = to_lower_case(path);
+	return ends_with(p, ".js");
 }
 
 function path_is_json(path: string): bool {
-	let p: string = path.toLowerCase();
-	return p.endsWith(".json");
+	let p: string = to_lower_case(path);
+	return ends_with(p, ".json");
 }
 
 function path_is_text(path: string): bool {
-	let p: string = path.toLowerCase();
-	return p.endsWith(".txt");
+	let p: string = to_lower_case(path);
+	return ends_with(p, ".txt");
 }
 
 function path_is_gimp_color_palette(path: string): bool {
-	let p: string = path.toLowerCase();
-	return p.endsWith(".gpl");
+	let p: string = to_lower_case(path);
+	return ends_with(p, ".gpl");
 }
 
 function path_is_known(path: string): bool {
@@ -123,8 +137,8 @@ function path_is_known(path: string): bool {
 function path_check_ext(p: string, exts: string[]): bool {
 	p = string_replace_all(p, "-", "_");
 	for (let ext of exts) {
-		if (p.endsWith("_" + ext) ||
-			(p.indexOf("_" + ext + "_") >= 0 && !p.endsWith("_preview") && !p.endsWith("_icon"))) {
+		if (ends_with(p, "_" + ext) ||
+			(string_index_of(p, "_" + ext + "_") >= 0 && !ends_with(p, "_preview") && !ends_with(p, "_icon"))) {
 			return true;
 		}
 	}
@@ -154,12 +168,12 @@ function path_is_displacement_tex(p: string): bool {
 }
 
 function path_is_folder(p: string): bool {
-	return string_replace_all(p, "\\", "/").split("/").pop().indexOf(".") == -1;
+	return string_index_of(string_split(string_replace_all(p, "\\", "/"), "/").pop(), ".") == -1;
 }
 
 function path_is_protected(): bool {
 	///if krom_windows
-	return krom_get_files_location().indexOf("Program Files") >= 0;
+	return string_index_of(krom_get_files_location(), "Program Files") >= 0;
 	///elseif krom_android
 	return true;
 	///elseif krom_ios

+ 13 - 13
base/Sources/physics_body.ts

@@ -47,7 +47,7 @@ class PhysicsBodyRaw {
 	btshape: Ammo.btCollisionShape;
 	ready: bool = false;
 	id: i32 = 0;
-	height_data: Uint8Array = null;
+	height_data: u8_array_t = null;
 }
 
 let physics_body_next_id: i32 = 0;
@@ -369,15 +369,15 @@ function physics_body_set_ccd(pb: PhysicsBodyRaw, sphereRadius: f32, motionThres
 function physics_body_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 = physics_body_convex_hull_cache.get(data);
+	let shape: Ammo.btConvexHullShape = map_get(physics_body_convex_hull_cache, data);
 	if (shape != null) {
-		physics_body_users_cache.set(data, physics_body_users_cache.get(data) + 1);
+		map_set(physics_body_users_cache, data, map_get(physics_body_users_cache, data) + 1);
 		return shape;
 	}
 
 	shape = new Ammo.btConvexHullShape();
-	physics_body_convex_hull_cache.set(data, shape);
-	physics_body_users_cache.set(data, 1);
+	map_set(physics_body_convex_hull_cache, data, shape);
+	map_set(physics_body_users_cache, data, 1);
 
 	let positions: i16_array_t = mesh_data_get_vertex_array(data, 'pos').values;
 
@@ -401,15 +401,15 @@ function physics_body_fill_convex_hull(pb: PhysicsBodyRaw, scale: vec4_t, margin
 function physics_body_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 = physics_body_triangle_mesh_cache.get(data);
+	let triangle_mesh: Ammo.btTriangleMesh = map_get(physics_body_triangle_mesh_cache, data);
 	if (triangle_mesh != null) {
-		physics_body_users_cache.set(data, physics_body_users_cache.get(data) + 1);
+		map_set(physics_body_users_cache, data, map_get(physics_body_users_cache, data) + 1);
 		return triangle_mesh;
 	}
 
 	triangle_mesh = new Ammo.btTriangleMesh(true, true);
-	physics_body_triangle_mesh_cache.set(data, triangle_mesh);
-	physics_body_users_cache.set(data, 1);
+	map_set(physics_body_triangle_mesh_cache, data, triangle_mesh);
+	map_set(physics_body_users_cache, data, 1);
 
 	let positions: i16_array_t = mesh_data_get_vertex_array(data, 'pos').values;
 	let indices: any = data._indices;
@@ -446,13 +446,13 @@ function physics_body_delete(pb: PhysicsBodyRaw) {
 	// 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 = physics_body_users_cache.get(data) - 1;
-		physics_body_users_cache.set(data, i);
+		let i: i32 = map_get(physics_body_users_cache, data) - 1;
+		map_set(physics_body_users_cache, data, i);
 		if (i <= 0) {
 			Ammo.destroy(pb.btshape);
 			pb.shape == shape_type_t.CONVEX_HULL ?
-				physics_body_convex_hull_cache.delete(data) :
-				physics_body_triangle_mesh_cache.delete(data);
+				map_delete(physics_body_convex_hull_cache, data) :
+				map_delete(physics_body_triangle_mesh_cache, data);
 		}
 	}
 	else Ammo.destroy(pb.btshape);

Some files were not shown because too many files changed in this diff