2023-02-08 14:51:54 +01:00
|
|
|
|
|
|
|
|
class TabMeshes {
|
|
|
|
|
|
2024-01-17 18:53:31 +01:00
|
|
|
static draw = (htab: Handle) => {
|
2024-01-21 15:18:44 +01:00
|
|
|
let ui = UIBase.ui;
|
2024-01-17 18:53:31 +01:00
|
|
|
let statush = Config.raw.layout[LayoutSize.LayoutStatusH];
|
2023-03-27 16:44:48 +02:00
|
|
|
if (ui.tab(htab, tr("Meshes")) && statush > UIStatus.defaultStatusH * ui.SCALE()) {
|
2023-02-08 14:51:54 +01:00
|
|
|
|
|
|
|
|
ui.beginSticky();
|
2023-04-20 00:38:27 +02:00
|
|
|
|
2024-01-17 18:53:31 +01:00
|
|
|
///if (is_paint || is_sculpt)
|
2023-04-20 00:38:27 +02:00
|
|
|
if (Config.raw.touch_ui) {
|
|
|
|
|
ui.row([1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6, 1 / 6]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ui.row([1 / 14, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 14]);
|
|
|
|
|
}
|
2024-01-17 18:53:31 +01:00
|
|
|
///end
|
2023-04-20 00:38:27 +02:00
|
|
|
|
2024-01-17 18:53:31 +01:00
|
|
|
///if is_lab
|
2023-02-08 14:51:54 +01:00
|
|
|
if (Config.raw.touch_ui) {
|
|
|
|
|
ui.row([1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7]);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ui.row([1 / 14, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 14]);
|
|
|
|
|
}
|
2024-01-17 18:53:31 +01:00
|
|
|
///end
|
2023-02-08 14:51:54 +01:00
|
|
|
|
|
|
|
|
if (ui.button(tr("Import"))) {
|
2024-01-17 18:53:31 +01:00
|
|
|
UIMenu.draw((ui: Zui) => {
|
|
|
|
|
if (UIMenu.menuButton(ui, tr("Replace Existing"), `${Config.keymap.file_import_assets}`)) {
|
2023-02-08 14:51:54 +01:00
|
|
|
Project.importMesh(true);
|
|
|
|
|
}
|
2023-05-18 22:53:58 +02:00
|
|
|
if (UIMenu.menuButton(ui, tr("Append"))) {
|
2023-02-08 14:51:54 +01:00
|
|
|
Project.importMesh(false);
|
|
|
|
|
}
|
2023-05-18 22:53:58 +02:00
|
|
|
}, 2);
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
if (ui.isHovered) ui.tooltip(tr("Import mesh file"));
|
|
|
|
|
|
2024-01-17 18:53:31 +01:00
|
|
|
///if is_lab
|
2023-02-08 14:51:54 +01:00
|
|
|
if (ui.button(tr("Set Default"))) {
|
2024-01-17 18:53:31 +01:00
|
|
|
UIMenu.draw((ui: Zui) => {
|
|
|
|
|
if (UIMenu.menuButton(ui, tr("Cube"))) TabMeshes.setDefaultMesh(".Cube");
|
|
|
|
|
if (UIMenu.menuButton(ui, tr("Plane"))) TabMeshes.setDefaultMesh(".Plane");
|
|
|
|
|
if (UIMenu.menuButton(ui, tr("Sphere"))) TabMeshes.setDefaultMesh(".Sphere");
|
|
|
|
|
if (UIMenu.menuButton(ui, tr("Cylinder"))) TabMeshes.setDefaultMesh(".Cylinder");
|
2023-05-18 22:53:58 +02:00
|
|
|
}, 4);
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
2024-01-17 18:53:31 +01:00
|
|
|
///end
|
2023-02-08 14:51:54 +01:00
|
|
|
|
|
|
|
|
if (ui.button(tr("Flip Normals"))) {
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.flipNormals();
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ui.button(tr("Calculate Normals"))) {
|
2024-01-17 18:53:31 +01:00
|
|
|
UIMenu.draw((ui: Zui) => {
|
2023-12-13 15:52:41 +01:00
|
|
|
if (UIMenu.menuButton(ui, tr("Smooth"))) { UtilMesh.calcNormals(true); Context.raw.ddirty = 2; }
|
|
|
|
|
if (UIMenu.menuButton(ui, tr("Flat"))) { UtilMesh.calcNormals(false); Context.raw.ddirty = 2; }
|
2023-05-18 22:53:58 +02:00
|
|
|
}, 2);
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ui.button(tr("Geometry to Origin"))) {
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.toOrigin();
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ui.button(tr("Apply Displacement"))) {
|
2024-01-17 18:53:31 +01:00
|
|
|
///if is_paint
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.applyDisplacement(Project.layers[0].texpaint_pack);
|
2024-01-17 18:53:31 +01:00
|
|
|
///end
|
|
|
|
|
///if is_lab
|
|
|
|
|
let displace_strength = Config.raw.displace_strength > 0 ? Config.raw.displace_strength : 1.0;
|
|
|
|
|
let uv_scale = Scene.active.meshes[0].data.scaleTex * Context.raw.brushScale;
|
|
|
|
|
UtilMesh.applyDisplacement(BrushOutputNode.inst.texpaint_pack, 0.05 * displace_strength, uv_scale);
|
|
|
|
|
///end
|
2023-04-20 00:38:27 +02:00
|
|
|
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.calcNormals();
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ui.button(tr("Rotate"))) {
|
2024-01-17 18:53:31 +01:00
|
|
|
UIMenu.draw((ui: Zui) => {
|
2023-05-18 22:53:58 +02:00
|
|
|
if (UIMenu.menuButton(ui, tr("Rotate X"))) {
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.swapAxis(1, 2);
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-18 22:53:58 +02:00
|
|
|
if (UIMenu.menuButton(ui, tr("Rotate Y"))) {
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.swapAxis(2, 0);
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-18 22:53:58 +02:00
|
|
|
if (UIMenu.menuButton(ui, tr("Rotate Z"))) {
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.swapAxis(0, 1);
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
2023-05-18 22:53:58 +02:00
|
|
|
}, 3);
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ui.endSticky();
|
|
|
|
|
|
2024-01-17 18:53:31 +01:00
|
|
|
for (let i = 0; i < Project.paintObjects.length; ++i) {
|
|
|
|
|
let o = Project.paintObjects[i];
|
|
|
|
|
let h = Zui.handle("tabmeshes_0");
|
2023-02-08 14:51:54 +01:00
|
|
|
h.selected = o.visible;
|
|
|
|
|
o.visible = ui.check(h, o.name);
|
|
|
|
|
if (ui.isHovered && ui.inputReleasedR) {
|
2024-01-17 18:53:31 +01:00
|
|
|
UIMenu.draw((ui: Zui) => {
|
2023-05-18 22:53:58 +02:00
|
|
|
if (UIMenu.menuButton(ui, tr("Export"))) {
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.exportMeshIndex = i + 1;
|
2023-02-08 14:51:54 +01:00
|
|
|
BoxExport.showMesh();
|
|
|
|
|
}
|
2023-05-18 22:53:58 +02:00
|
|
|
if (Project.paintObjects.length > 1 && UIMenu.menuButton(ui, tr("Delete"))) {
|
2024-01-17 18:53:31 +01:00
|
|
|
array_remove(Project.paintObjects, o);
|
2023-02-08 14:51:54 +01:00
|
|
|
while (o.children.length > 0) {
|
2024-01-17 18:53:31 +01:00
|
|
|
let child = o.children[0];
|
2023-02-08 14:51:54 +01:00
|
|
|
child.setParent(null);
|
|
|
|
|
if (Project.paintObjects[0] != child) {
|
|
|
|
|
child.setParent(Project.paintObjects[0]);
|
|
|
|
|
}
|
|
|
|
|
if (o.children.length == 0) {
|
|
|
|
|
Project.paintObjects[0].transform.scale.setFrom(o.transform.scale);
|
|
|
|
|
Project.paintObjects[0].transform.buildMatrix();
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-12 14:57:44 +01:00
|
|
|
Data.deleteMesh(o.data.handle);
|
2023-02-08 14:51:54 +01:00
|
|
|
o.remove();
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.paintObject = Context.mainObject();
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.mergeMesh();
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
2023-05-18 22:53:58 +02:00
|
|
|
}, Project.paintObjects.length > 1 ? 2 : 1);
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
if (h.changed) {
|
2024-01-17 18:53:31 +01:00
|
|
|
let visibles: MeshObject[] = [];
|
|
|
|
|
for (let p of Project.paintObjects) if (p.visible) visibles.push(p);
|
2023-12-13 15:52:41 +01:00
|
|
|
UtilMesh.mergeMesh(visibles);
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-17 18:53:31 +01:00
|
|
|
///if is_lab
|
|
|
|
|
static setDefaultMesh = (name: string) => {
|
|
|
|
|
let mo: MeshObject = null;
|
2023-09-14 17:45:53 +02:00
|
|
|
if (name == ".Plane" || name == ".Sphere") {
|
2024-01-17 18:53:31 +01:00
|
|
|
let res = Config.raw.rp_supersample > 1.0 ? 2048 : 1024;
|
2024-01-21 15:18:44 +01:00
|
|
|
let mesh: any = name == ".Plane" ? Geom.make_plane(1, 1, res, res) : Geom.make_uv_sphere(1.0, res, Math.floor(res / 2), false, 2.0);
|
2024-01-17 18:53:31 +01:00
|
|
|
let raw = {
|
2023-09-14 17:45:53 +02:00
|
|
|
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
|
|
|
|
|
};
|
2024-01-17 18:53:31 +01:00
|
|
|
let md = new MeshData(raw, (md: MeshData) => {});
|
2023-09-14 17:45:53 +02:00
|
|
|
mo = new MeshObject(md, Context.raw.paintObject.materials);
|
2024-01-17 18:53:31 +01:00
|
|
|
array_remove(Scene.active.meshes, mo);
|
2023-09-14 17:45:53 +02:00
|
|
|
mo.name = "Tessellated";
|
|
|
|
|
}
|
|
|
|
|
else {
|
2024-01-17 18:53:31 +01:00
|
|
|
mo = Scene.active.getChild(name) as MeshObject;
|
2023-09-14 17:45:53 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-08 14:51:54 +01:00
|
|
|
mo.visible = true;
|
2023-02-27 21:13:25 +01:00
|
|
|
Context.raw.ddirty = 2;
|
|
|
|
|
Context.raw.paintObject = mo;
|
2023-09-14 17:45:53 +02:00
|
|
|
Project.paintObjects[0] = mo;
|
2024-01-21 15:18:44 +01:00
|
|
|
if (UIHeader.worktab.position == SpaceType.Space3D) {
|
2023-12-12 14:57:44 +01:00
|
|
|
Scene.active.meshes = [mo];
|
2023-09-14 17:45:53 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-17 18:53:31 +01:00
|
|
|
///if (krom_direct3d12 || krom_vulkan || krom_metal)
|
2023-12-13 15:52:41 +01:00
|
|
|
RenderPathRaytrace.ready = false;
|
2024-01-17 18:53:31 +01:00
|
|
|
///end
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|
2024-01-17 18:53:31 +01:00
|
|
|
///end
|
2023-02-08 14:51:54 +01:00
|
|
|
}
|