2
0
luboslenco 1 жил өмнө
parent
commit
1b93b5dcda

+ 0 - 4
base/Sources/arm/ui/TabLayers.hx → armorpaint/Sources/arm/ui/TabLayers.hx

@@ -1,7 +1,5 @@
 package arm.ui;
 
-#if (is_paint || is_sculpt)
-
 import zui.Zui;
 import zui.Id;
 import zui.Nodes;
@@ -1103,5 +1101,3 @@ class TabLayers {
 		return true;
 	}
 }
-
-#end

+ 3 - 3
armorsculpt/Sources/arm/io/ImportMesh.hx

@@ -147,8 +147,8 @@ class ImportMesh {
 
 				arm.App.notifyOnNextFrame(function() {
 					var f32 = new kha.arrays.Float32Array(Config.getTextureResX() * Config.getTextureResY() * 4);
-					for (i in 0...raw.index_arrays[0].values.length) {
-						var index = raw.index_arrays[0].values[i];
+					for (i in 0...Std.int(mesh.inda.length)) {
+						var index = mesh.inda[i];
 						f32[i * 4]     = mesh.posa[index * 4]     / 32767;
 						f32[i * 4 + 1] = mesh.posa[index * 4 + 1] / 32767;
 						f32[i * 4 + 2] = mesh.posa[index * 4 + 2] / 32767;
@@ -203,7 +203,7 @@ class ImportMesh {
 		_addMesh();
 	}
 
-	static function rawMesh(mesh: Dynamic): TMeshData {
+	public static function rawMesh(mesh: Dynamic): TMeshData {
 		var posa = new kha.arrays.Int16Array(Std.int(mesh.inda.length * 4));
 		for (i in 0...posa.length) posa[i] = 32767;
 		var inda = new kha.arrays.Uint32Array(mesh.inda.length);

+ 412 - 0
armorsculpt/Sources/arm/ui/TabLayers.hx

@@ -0,0 +1,412 @@
+package arm.ui;
+
+import zui.Zui;
+import zui.Id;
+import zui.Nodes;
+import iron.system.Time;
+import iron.system.Input;
+import iron.object.MeshObject;
+import arm.data.LayerSlot;
+import arm.shader.MakeMaterial;
+import arm.util.UVUtil;
+import arm.util.MeshUtil;
+import arm.util.RenderUtil;
+import arm.sys.Path;
+
+@:access(zui.Zui)
+class TabLayers {
+
+	static var layerNameEdit = -1;
+	static var layerNameHandle = Id.handle();
+	static var showContextMenu = false;
+
+	public static function draw(htab: Handle) {
+		var mini = Config.raw.layout[LayoutSidebarW] <= UIBase.sidebarMiniW;
+		mini ? drawMini(htab) : drawFull(htab);
+	}
+
+	static function drawMini(htab: Handle) {
+		var ui = UIBase.inst.ui;
+		@:privateAccess ui.setHoveredTabName(tr("Layers"));
+
+		var _ELEMENT_H = ui.t.ELEMENT_H;
+		ui.t.ELEMENT_H = Std.int(UIBase.sidebarMiniW / 2 / ui.SCALE());
+
+		ui.beginSticky();
+		ui.separator(5);
+
+		comboFilter();
+		buttonNew("+");
+
+		ui.endSticky();
+		ui._y += 2;
+
+		highlightOddLines();
+		drawSlots(true);
+
+		ui.t.ELEMENT_H = _ELEMENT_H;
+	}
+
+	static function drawFull(htab: Handle) {
+		var ui = UIBase.inst.ui;
+		if (ui.tab(htab, tr("Layers"))) {
+			ui.beginSticky();
+			ui.row([1 / 4, 3 / 4]);
+
+			buttonNew(tr("New"));
+			comboFilter();
+
+			ui.endSticky();
+			ui._y += 2;
+
+			highlightOddLines();
+			drawSlots(false);
+		}
+	}
+
+	static function drawSlots(mini: Bool) {
+		for (i in 0...Project.layers.length) {
+			if (i >= Project.layers.length) break; // Layer was deleted
+			var j = Project.layers.length - 1 - i;
+			var l = Project.layers[j];
+			drawLayerSlot(l, j, mini);
+		}
+	}
+
+	static function highlightOddLines() {
+		var ui = UIBase.inst.ui;
+		var step = ui.t.ELEMENT_H * 2;
+		var fullH = ui._windowH - UIBase.inst.hwnds[0].scrollOffset;
+		for (i in 0...Std.int(fullH / step)) {
+			if (i % 2 == 0) {
+				ui.fill(0, i * step, (ui._w / ui.SCALE() - 2), step, ui.t.WINDOW_BG_COL - 0x00040404);
+			}
+		}
+	}
+
+	static function buttonNew(text: String) {
+		var ui = UIBase.inst.ui;
+		if (ui.button(text)) {
+			UIMenu.draw(function(ui: Zui) {
+				var l = Context.raw.layer;
+				if (UIMenu.menuButton(ui, tr("Paint Layer"))) {
+					App.newLayer();
+					History.newLayer();
+				}
+			}, 1);
+		}
+	}
+
+	static function comboFilter() {
+		var ui = UIBase.inst.ui;
+		var ar = [tr("All")];
+		var filterHandle = Id.handle();
+		filterHandle.position = Context.raw.layerFilter;
+		Context.raw.layerFilter = ui.combo(filterHandle, ar, tr("Filter"), false, Left);
+	}
+
+	public static function remapLayerPointers(nodes: Array<TNode>, pointerMap: Map<Int, Int>) {
+		for (n in nodes) {
+			if (n.type == "LAYER" || n.type == "LAYER_MASK") {
+				var i = n.buttons[0].default_value;
+				if (pointerMap.exists(i)) {
+					n.buttons[0].default_value = pointerMap.get(i);
+				}
+			}
+		}
+	}
+
+	public static function initLayerMap(): Map<LayerSlot, Int> {
+		var res: Map<LayerSlot, Int> = [];
+		for (i in 0...Project.layers.length) res.set(Project.layers[i], i);
+		return res;
+	}
+
+	public static function fillLayerMap(map: Map<LayerSlot, Int>): Map<Int, Int> {
+		var res: Map<Int, Int> = [];
+		for (l in map.keys()) res.set(map.get(l), Project.layers.indexOf(l) > -1 ? Project.layers.indexOf(l) : 9999);
+		return res;
+	}
+
+	static function setDragLayer(layer: LayerSlot, offX: Float, offY: Float) {
+		App.dragOffX = offX;
+		App.dragOffY = offY;
+		App.dragLayer = layer;
+		Context.raw.dragDestination = Project.layers.indexOf(layer);
+	}
+
+	static function drawLayerSlot(l: LayerSlot, i: Int, mini: Bool) {
+		var ui = UIBase.inst.ui;
+
+		if (Context.raw.layerFilter > 0 &&
+			l.getObjectMask() > 0 &&
+			l.getObjectMask() != Context.raw.layerFilter) {
+			return;
+		}
+
+		if (l.parent != null && !l.parent.show_panel) { // Group closed
+			return;
+		}
+		if (l.parent != null && l.parent.parent != null && !l.parent.parent.show_panel) {
+			return;
+		}
+
+		var step = ui.t.ELEMENT_H;
+		var checkw = (ui._windowW / 100 * 8) / ui.SCALE();
+
+		// Highlight drag destination
+		var mouse = Input.getMouse();
+		var absy = ui._windowY + ui._y;
+		if (App.isDragging && App.dragLayer != null && Context.inLayers()) {
+			if (mouse.y > absy + step && mouse.y < absy + step * 3) {
+				var down = Project.layers.indexOf(App.dragLayer) >= i;
+				Context.raw.dragDestination = down ? i : i - 1;
+
+				var ls = Project.layers;
+				var dest = Context.raw.dragDestination;
+				var toGroup = down ? dest > 0 && ls[dest - 1].parent != null && ls[dest - 1].parent.show_panel : dest < ls.length && ls[dest].parent != null && ls[dest].parent.show_panel;
+				var nestedGroup = App.dragLayer.isGroup() && toGroup;
+				if (!nestedGroup) {
+					if (Context.raw.layer.canMove(Context.raw.dragDestination)) {
+						ui.fill(checkw, step * 2, (ui._windowW / ui.SCALE() - 2) - checkw, 2 * ui.SCALE(), ui.t.HIGHLIGHT_COL);
+					}
+				}
+			}
+			else if (i == Project.layers.length - 1 && mouse.y < absy + step) {
+				Context.raw.dragDestination = Project.layers.length - 1;
+				if (Context.raw.layer.canMove(Context.raw.dragDestination)) {
+					ui.fill(checkw, 0, (ui._windowW / ui.SCALE() - 2) - checkw, 2 * ui.SCALE(), ui.t.HIGHLIGHT_COL);
+				}
+			}
+		}
+		if (App.isDragging && (App.dragMaterial != null || App.dragSwatch != null) && Context.inLayers()) {
+			if (mouse.y > absy + step && mouse.y < absy + step * 3) {
+				Context.raw.dragDestination = i;
+				if (canDropNewLayer(i))
+					ui.fill(checkw, 2 * step, (ui._windowW / ui.SCALE() - 2) - checkw, 2 * ui.SCALE(), ui.t.HIGHLIGHT_COL);
+			}
+			else if (i == Project.layers.length - 1 && mouse.y < absy + step) {
+				Context.raw.dragDestination = Project.layers.length;
+				if (canDropNewLayer(Project.layers.length))
+					ui.fill(checkw, 0, (ui._windowW / ui.SCALE() - 2) - checkw, 2 * ui.SCALE(), ui.t.HIGHLIGHT_COL);
+			}
+		}
+
+		mini ? drawLayerSlotMini(l, i) : drawLayerSlotFull(l, i);
+
+		drawLayerHighlight(l, mini);
+
+		if (showContextMenu) {
+			drawLayerContextMenu(l, mini);
+		}
+	}
+
+	static function drawLayerSlotMini(l: LayerSlot, i: Int) {
+		var ui = UIBase.inst.ui;
+
+		ui.row([1, 1]);
+		var uix = ui._x;
+		var uiy = ui._y;
+		@:privateAccess ui.endElement();
+		@:privateAccess ui.endElement();
+
+		ui._y += ui.ELEMENT_H();
+		ui._y -= ui.ELEMENT_OFFSET();
+	}
+
+	static function drawLayerSlotFull(l: LayerSlot, i: Int) {
+		var ui = UIBase.inst.ui;
+
+		var step = ui.t.ELEMENT_H;
+
+		var hasPanel = l.isGroup() || (l.isLayer() && l.getMasks(false) != null);
+		if (hasPanel) {
+			ui.row([8 / 100, 52 / 100, 30 / 100, 10 / 100]);
+		}
+		else {
+			ui.row([8 / 100, 52 / 100, 30 / 100]);
+		}
+
+		// Draw eye icon
+		var icons = Res.get("icons.k");
+		var r = Res.tile18(icons, l.visible ? 0 : 1, 0);
+		var center = (step / 2) * ui.SCALE();
+		ui._x += 2;
+		ui._y += 3;
+		ui._y += center;
+		var col = ui.t.ACCENT_SELECT_COL;
+		var parentHidden = l.parent != null && (!l.parent.visible || (l.parent.parent != null && !l.parent.parent.visible));
+		if (parentHidden) col -= 0x99000000;
+
+		if (ui.image(icons, col, null, r.x, r.y, r.w, r.h) == Released) {
+			layerToggleVisible(l);
+		}
+		ui._x -= 2;
+		ui._y -= 3;
+		ui._y -= center;
+
+		var uix = ui._x;
+		var uiy = ui._y;
+
+		// Draw layer name
+		ui._y += center;
+		if (layerNameEdit == l.id) {
+			layerNameHandle.text = l.name;
+			l.name = ui.textInput(layerNameHandle);
+			if (ui.textSelectedHandle != layerNameHandle) layerNameEdit = -1;
+		}
+		else {
+			if (ui.enabled && ui.inputEnabled && ui.comboSelectedHandle == null &&
+				ui.inputX > ui._windowX + ui._x && ui.inputX < ui._windowX + ui._windowW &&
+				ui.inputY > ui._windowY + ui._y - center && ui.inputY < ui._windowY + ui._y - center + (step * ui.SCALE()) * 2) {
+				if (ui.inputStarted) {
+					Context.setLayer(l);
+					var mouse = Input.getMouse();
+					setDragLayer(Context.raw.layer, -(mouse.x - uix - ui._windowX - 3), -(mouse.y - uiy - ui._windowY + 1));
+				}
+				else if (ui.inputReleased) {
+					if (Time.time() - Context.raw.selectTime > 0.2) {
+						Context.raw.selectTime = Time.time();
+					}
+				}
+				else if (ui.inputReleasedR) {
+					Context.setLayer(l);
+					showContextMenu = true;
+				}
+			}
+
+			var state = ui.text(l.name);
+			if (state == State.Released) {
+				var td = Time.time() - Context.raw.selectTime;
+				if (td < 0.2 && td > 0.0) {
+					layerNameEdit = l.id;
+					layerNameHandle.text = l.name;
+					ui.startTextEdit(layerNameHandle);
+				}
+			}
+
+			// var inFocus = 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;
+			// 	function _init() {
+			// 		deleteLayer(Context.raw.layer);
+			// 	}
+			// 	iron.App.notifyOnInit(_init);
+			// }
+		}
+		ui._y -= center;
+
+		if (l.parent != null) {
+			ui._x -= 10 * ui.SCALE();
+			if (l.parent.parent != null) ui._x -= 10 * ui.SCALE();
+		}
+
+		if (l.isGroup()) {
+			@:privateAccess ui.endElement();
+		}
+		else {
+			if (l.isMask()) {
+				ui._y += center;
+			}
+
+			// comboBlending(ui, l);
+			@:privateAccess ui.endElement();
+
+			if (l.isMask()) {
+				ui._y -= center;
+			}
+		}
+
+		if (hasPanel) {
+			ui._y += center;
+			var layerPanel = Id.handle().nest(l.id);
+			layerPanel.selected = l.show_panel;
+			l.show_panel = ui.panel(layerPanel, "", true, false, false);
+			ui._y -= center;
+		}
+
+		if (l.isGroup() || l.isMask()) {
+			ui._y -= ui.ELEMENT_OFFSET();
+			@:privateAccess ui.endElement();
+		}
+		else {
+			ui._y -= ui.ELEMENT_OFFSET();
+
+			ui.row([8 / 100, 16 / 100, 36 / 100, 30 / 100, 10 / 100]);
+			@:privateAccess ui.endElement();
+			@:privateAccess ui.endElement();
+			@:privateAccess ui.endElement();
+
+			if (Config.raw.touch_ui) {
+				ui._x += 12 * ui.SCALE();
+			}
+
+			ui._y -= center;
+			comboObject(ui, l);
+			ui._y += center;
+
+			@:privateAccess ui.endElement();
+		}
+
+		ui._y -= ui.ELEMENT_OFFSET();
+	}
+
+	static function comboObject(ui: Zui, l: LayerSlot, label = false): Handle {
+		var ar = [tr("Shared")];
+		var objectHandle = Id.handle().nest(l.id);
+		objectHandle.position = l.objectMask;
+		l.objectMask = ui.combo(objectHandle, ar, tr("Object"), label, Left);
+		return objectHandle;
+	}
+
+	static function layerToggleVisible(l: LayerSlot) {
+		l.visible = !l.visible;
+		UIView2D.inst.hwnd.redraws = 2;
+		MakeMaterial.parseMeshMaterial();
+	}
+
+	static function drawLayerHighlight(l: LayerSlot, mini: Bool) {
+		var ui = UIBase.inst.ui;
+		var step = ui.t.ELEMENT_H;
+
+		// Separator line
+		ui.fill(0, 0, (ui._w / ui.SCALE() - 2), 1 * ui.SCALE(), ui.t.SEPARATOR_COL);
+
+		// Highlight selected
+		if (Context.raw.layer == l) {
+			if (mini) {
+				ui.rect(1, -step * 2, ui._w / ui.SCALE() - 1, step * 2 + (mini ? -1 : 1), ui.t.HIGHLIGHT_COL, 3);
+			}
+			else {
+				ui.rect(1, -step * 2 - 1, ui._w / ui.SCALE() - 2, step * 2 + (mini ? -2 : 1), ui.t.HIGHLIGHT_COL, 2);
+			}
+		}
+	}
+
+	static function canMergeDown(l: LayerSlot) : Bool {
+		var index = Project.layers.indexOf(l);
+		// Lowest layer
+		if (index == 0) return false;
+		// Lowest layer that has masks
+		if (l.isLayer() && Project.layers[0].isMask() && Project.layers[0].parent == l) return false;
+		// The lowest toplevel layer is a group
+		if (l.isGroup() && Project.layers[0].isInGroup() && Project.layers[0].getContainingGroup() == l) return false;
+		// Masks must be merged down to masks
+		if (l.isMask() && !Project.layers[index - 1].isMask()) return false;
+		return true;
+	}
+
+	static function drawLayerContextMenu(l: LayerSlot, mini: Bool) {
+
+	}
+
+	public static function canDropNewLayer(position: Int) {
+		if (position > 0 && position < Project.layers.length && Project.layers[position - 1].isMask()) {
+			// 1. The layer to insert is inserted in the middle
+			// 2. The layer below is a mask, i.e. the layer would have to be a (group) mask, too.
+			return false;
+		}
+		return true;
+	}
+}

+ 13 - 0
base/Sources/arm/App.hx

@@ -759,6 +759,15 @@ class App {
 				});
 			});
 			#end
+
+			#if is_sculpt
+			arm.App.notifyOnNextFrame(function() {
+				arm.App.notifyOnNextFrame(function() {
+					Context.raw.projectType = ModelSphere;
+					Project.projectNew();
+				});
+			});
+			#end
 		}
 		else if (Context.raw.frame == 3) {
 			Context.raw.ddirty = 3;
@@ -1988,6 +1997,10 @@ class App {
 	}
 
 	public static function setObjectMask() {
+		#if is_sculpt
+		return;
+		#end
+
 		var ar = [tr("None")];
 		for (p in Project.paintObjects) ar.push(p.name);
 

+ 1 - 1
base/Sources/arm/Enums.hx

@@ -276,7 +276,7 @@ package arm;
 	var ToolBlur = 6;
 	var ToolSmudge = 7;
 	var ToolParticle = 8;
-	var ToolPicker = 9;
+	var ToolPicker = 9; // Unused
 	var ToolGizmo = 10;
 	var ToolMaterial = 11;
 	var ToolBake = 12; // Unused

+ 24 - 13
base/Sources/arm/Project.hx

@@ -207,19 +207,30 @@ class Project {
 				var mesh: Dynamic = Context.raw.projectType == ModelSphere ?
 					new arm.geom.UVSphere(1, 512, 256) :
 					new arm.geom.Plane(1, 1, 512, 512);
-				raw = {
-					name: "Tessellated",
-					vertex_arrays: [
-						{ values: mesh.posa, attrib: "pos", data: "short4norm" },
-						{ values: mesh.nora, attrib: "nor", data: "short2norm" },
-						{ values: mesh.texa, attrib: "tex", data: "short2norm" }
-					],
-					index_arrays: [
-						{ values: mesh.inda, material: 0 }
-					],
-					scale_pos: mesh.scalePos,
-					scale_tex: mesh.scaleTex
-				};
+				mesh.name = "Tessellated";
+				raw = ImportMesh.rawMesh(mesh);
+
+				#if is_sculpt
+				arm.App.notifyOnNextFrame(function() {
+					var f32 = new kha.arrays.Float32Array(Config.getTextureResX() * Config.getTextureResY() * 4);
+					for (i in 0...Std.int(mesh.inda.length)) {
+						var index = mesh.inda[i];
+						f32[i * 4]     = mesh.posa[index * 4]     / 32767;
+						f32[i * 4 + 1] = mesh.posa[index * 4 + 1] / 32767;
+						f32[i * 4 + 2] = mesh.posa[index * 4 + 2] / 32767;
+						f32[i * 4 + 3] = 1.0;
+					}
+
+					var bytes = haxe.io.Bytes.ofData(f32.buffer);
+					var imgmesh = kha.Image.fromBytes(bytes, Config.getTextureResX(), Config.getTextureResY(), kha.graphics4.TextureFormat.RGBA128);
+					var texpaint = Project.layers[0].texpaint;
+					texpaint.g2.begin(false);
+					texpaint.g2.pipeline = App.pipeCopy128;
+					texpaint.g2.drawScaledImage(imgmesh, 0, 0, Config.getTextureResX(), Config.getTextureResY());
+					texpaint.g2.pipeline = null;
+					texpaint.g2.end();
+				});
+				#end
 			}
 			else {
 				Data.getBlob("meshes/" + meshList[Context.raw.projectType] + ".arm", function(b: kha.Blob) {

+ 1 - 1
base/Sources/arm/io/ImportMesh.hx

@@ -236,7 +236,7 @@ class ImportMesh {
 		}
 	}
 
-	static function rawMesh(mesh: Dynamic): TMeshData {
+	public static function rawMesh(mesh: Dynamic): TMeshData {
 		return {
 			name: mesh.name,
 			vertex_arrays: [

+ 2 - 1
base/Sources/arm/ui/BoxPreferences.hx

@@ -326,13 +326,14 @@ class BoxPreferences {
 
 				var layerResHandle = Id.handle({ position: Config.raw.layer_res });
 
-				#if (is_paint || is_sculpt)
+				#if is_paint
 				#if (krom_android || krom_ios)
 				ui.combo(layerResHandle, ["128", "256", "512", "1K", "2K", "4K"], tr("Default Layer Resolution"), true);
 				#else
 				ui.combo(layerResHandle, ["128", "256", "512", "1K", "2K", "4K", "8K"], tr("Default Layer Resolution"), true);
 				#end
 				#end
+
 				#if is_lab
 				#if (krom_android || krom_ios)
 				ui.combo(layerResHandle, ["2K", "4K"], tr("Default Layer Resolution"), true);

+ 10 - 1
base/Sources/arm/ui/UIBase.hx

@@ -45,7 +45,7 @@ class UIBase {
 	var undoTapTime = 0.0;
 	var redoTapTime = 0.0;
 
-	#if (is_paint || is_sculpt)
+	#if is_paint
 	public var hwnds = [Id.handle(), Id.handle(), Id.handle()];
 	public var htabs = [Id.handle(), Id.handle(), Id.handle()];
 	public var hwndTabs = [
@@ -54,6 +54,15 @@ class UIBase {
 		[TabBrowser.draw, TabTextures.draw, TabMeshes.draw, TabFonts.draw, TabSwatches.draw, TabScript.draw, TabConsole.draw, UIStatus.drawVersionTab]
 	];
 	#end
+	#if is_sculpt
+	public var hwnds = [Id.handle(), Id.handle(), Id.handle()];
+	public var htabs = [Id.handle(), Id.handle(), Id.handle()];
+	public var hwndTabs = [
+		[TabLayers.draw, TabHistory.draw, TabPlugins.draw #if is_forge , TabObjects.draw #end],
+		[TabMaterials.draw, TabBrushes.draw, TabParticles.draw],
+		[TabBrowser.draw, TabTextures.draw, TabMeshes.draw, TabFonts.draw, TabScript.draw, TabConsole.draw, UIStatus.drawVersionTab]
+	];
+	#end
 	#if is_lab
 	public var hwnds = [Id.handle()];
 	public var htabs = [Id.handle()];

+ 6 - 1
base/Sources/arm/ui/UIHeader.hx

@@ -485,7 +485,12 @@ class UIHeader {
 
 	#if is_sculpt
 
-	public function drawToolProperties(ui: Zui) {}
+	public function drawToolProperties(ui: Zui) {
+		if (Context.raw.tool == ToolBrush) {
+			Context.raw.brushRadius = ui.slider(Context.raw.brushRadiusHandle, tr("Radius"), 0.01, 2.0, true);
+			if (ui.isHovered) ui.tooltip(tr("Hold {brush_radius} and move mouse to the left or press {brush_radius_decrease} to decrease the radius\nHold {brush_radius} and move mouse to the right or press {brush_radius_increase} to increase the radius", ["brush_radius" => Config.keymap.brush_radius, "brush_radius_decrease" => Config.keymap.brush_radius_decrease, "brush_radius_increase" => Config.keymap.brush_radius_increase]));
+		}
+	}
 
 	#end
 

+ 10 - 2
base/Sources/arm/ui/UIMenu.hx

@@ -80,7 +80,9 @@ class UIMenu {
 				if (menuButton(ui, tr("Import Brush..."))) Project.importBrush();
 				#end
 
+				#if (is_paint || is_lab)
 				if (menuButton(ui, tr("Import Swatches..."))) Project.importSwatches();
+				#end
 				if (menuButton(ui, tr("Import Mesh..."))) Project.importMesh();
 				if (menuButton(ui, tr("Reimport Mesh"), Config.keymap.file_reimport_mesh)) Project.reimportMesh();
 				if (menuButton(ui, tr("Reimport Textures"), Config.keymap.file_reimport_textures)) Project.reimportTextures();
@@ -92,8 +94,8 @@ class UIMenu {
 					#end
 					BoxExport.showTextures();
 				}
-				#end
 				if (menuButton(ui, tr("Export Swatches..."))) Project.exportSwatches();
+				#end
 				if (menuButton(ui, tr("Export Mesh..."))) {
 					Context.raw.exportMeshIndex = 0; // All
 					BoxExport.showMesh();
@@ -245,7 +247,9 @@ class UIMenu {
 					ui.g.begin(false);
 					MakeMaterial.parseMeshMaterial();
 				}
+				#end
 
+				#if is_paint
 				menuFill(ui);
 				Context.raw.drawTexels = ui.check(Context.raw.texelsHandle, " " + tr("Texels"));
 				if (Context.raw.texelsHandle.changed) {
@@ -279,15 +283,19 @@ class UIMenu {
 				var modes = [
 					tr("Lit"),
 					tr("Base Color"),
+					#if (is_paint || is_lab)
 					tr("Normal"),
 					tr("Occlusion"),
 					tr("Roughness"),
 					tr("Metallic"),
 					tr("Opacity"),
 					tr("Height"),
-					#if (is_paint || is_sculpt)
+					#end
+					#if (is_paint)
 					tr("Emission"),
 					tr("Subsurface"),
+					#end
+					#if (is_paint || is_sculpt)
 					tr("TexCoord"),
 					tr("Object Normal"),
 					tr("Material ID"),

+ 4 - 4
base/Sources/arm/ui/UIToolbar.hx

@@ -95,8 +95,6 @@ class UIToolbar {
 			if (ui.isHovered) ui.tooltip(tr("Toggle header"));
 			ui._y -= 4 * ui.SCALE();
 
-			#if is_paint
-
 			var keys = [
 				"(" + Config.keymap.tool_brush + ") - " + tr("Hold {action_paint} to paint\nHold {key} and press {action_paint} to paint a straight line (ruler mode)", ["key" => Config.keymap.brush_ruler, "action_paint" => Config.keymap.action_paint]),
 				"(" + Config.keymap.tool_eraser + ") - " + tr("Hold {action_paint} to erase\nHold {key} and press {action_paint} to erase a straight line (ruler mode)", ["key" => Config.keymap.brush_ruler, "action_paint" => Config.keymap.action_paint]),
@@ -133,9 +131,11 @@ class UIToolbar {
 					lastTool = i;
 				}
 
+				#if is_paint
 				if (i == ToolColorId && Context.raw.colorIdPicked) {
 					ui.g.drawScaledSubImage(RenderPath.active.renderTargets.get("texpaint_colorid").image, 0, 0, 1, 1, 0, _y + 1.5 * ui.SCALE(), 5 * ui.SCALE(), 34 * ui.SCALE());
 				}
+				#end
 
 				if (ui.isHovered) ui.tooltip(tr(toolNames[i]) + " " + keys[i]);
 				ui._x -= 2;
@@ -143,6 +143,7 @@ class UIToolbar {
 			}
 
 			drawTool(ToolBrush);
+			#if is_paint
 			drawTool(ToolEraser);
 			drawTool(ToolFill);
 			drawTool(ToolDecal);
@@ -155,13 +156,12 @@ class UIToolbar {
 			drawTool(ToolPicker);
 			drawTool(ToolBake);
 			drawTool(ToolMaterial);
+			#end
 
 			#if is_forge
 			drawTool(ToolGizmo);
 			#end
 
-			#end
-
 			ui.imageScrollAlign = true;
 		}