From 2b9d415f1671b115c1b6bf524c1d75e00d1c2004 Mon Sep 17 00:00:00 2001 From: Lubos Lenco Date: Tue, 9 Jun 2020 18:28:46 +0200 Subject: [PATCH] Begin projection layer --- Sources/arm/Context.hx | 1 + Sources/arm/Layers.hx | 33 ++++- Sources/arm/data/LayerSlot.hx | 4 + Sources/arm/node/MakePaint.hx | 9 +- Sources/arm/node/MakeTexcoord.hx | 10 +- Sources/arm/plugin/Gizmo.hx | 227 ++++++++++++++++++------------- Sources/arm/render/Uniforms.hx | 16 +++ Sources/arm/ui/TabLayers.hx | 2 +- Sources/arm/ui/UISidebar.hx | 7 +- 9 files changed, 204 insertions(+), 105 deletions(-) diff --git a/Sources/arm/Context.hx b/Sources/arm/Context.hx index 9c72d792..53aaad8f 100644 --- a/Sources/arm/Context.hx +++ b/Sources/arm/Context.hx @@ -131,6 +131,7 @@ class Context { public static var axisY = false; public static var axisZ = false; public static var axisStart = 0.0; + public static var axisLoc = 0.0; public static var brushNodesRadius = 1.0; public static var brushNodesOpacity = 1.0; diff --git a/Sources/arm/Layers.hx b/Sources/arm/Layers.hx index 97146089..6472276b 100644 --- a/Sources/arm/Layers.hx +++ b/Sources/arm/Layers.hx @@ -393,7 +393,6 @@ class Layers { UIHeader.inst.worktab.position = SpaceMaterial; if (current != null) current.begin(false); - return; } @@ -412,8 +411,13 @@ class Layers { setObjectMask(); if (first) { - first = false; MaterialParser.parsePaintMaterial(); + first = false; + } + + // Decal layer + if (l.uvType == UVProject) { + l.clearLayer(); } for (i in 0...fills) { @@ -434,6 +438,31 @@ class Layers { } } + public static function updateFillLayer(fills = 1) { + var current = @:privateAccess kha.graphics4.Graphics2.current; + if (current != null) current.end(); + + var selectedTool = Context.tool; + Context.pdirty = fills; + Context.layerIsMask = false; + Context.tool = ToolFill; + + // Decal layer + if (Context.layer.uvType == UVProject) { + Context.layer.clearLayer(); + } + + MaterialParser.parsePaintMaterial(); + + for (i in 0...fills) { + RenderPathPaint.commandsPaint(); + } + + Context.rdirty = 2; + Context.tool = selectedTool; + if (current != null) current.begin(false); + } + public static function setObjectMask() { var ar = ["None"]; for (p in Project.paintObjects) ar.push(p.name); diff --git a/Sources/arm/data/LayerSlot.hx b/Sources/arm/data/LayerSlot.hx index 8e38f3f8..4dd771df 100644 --- a/Sources/arm/data/LayerSlot.hx +++ b/Sources/arm/data/LayerSlot.hx @@ -43,6 +43,10 @@ class LayerSlot { public var paintEmis = true; public var paintSubs = true; + public var projectX = 0.0; // Decal layer + public var projectY = 0.0; + public var projectZ = 0.0; + var createMaskColor: Int; var createMaskImage: Image; diff --git a/Sources/arm/node/MakePaint.hx b/Sources/arm/node/MakePaint.hx index e752240a..0ace1578 100644 --- a/Sources/arm/node/MakePaint.hx +++ b/Sources/arm/node/MakePaint.hx @@ -76,7 +76,14 @@ class MakePaint { vert.write('gl_Position = vec4(tpos, 0.0, 1.0);'); - vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix'); + var decalLayer = Context.layer.material_mask != null && Context.layer.uvType == UVProject; + if (decalLayer) { + vert.add_uniform('mat4 WVP', '_decalLayerMatrix'); + } + else { + vert.add_uniform('mat4 WVP', '_worldViewProjectionMatrix'); + } + vert.add_out('vec4 ndc'); vert.write_attrib('ndc = mul(vec4(pos.xyz, 1.0), WVP);'); diff --git a/Sources/arm/node/MakeTexcoord.hx b/Sources/arm/node/MakeTexcoord.hx index 35d827aa..589b87d9 100644 --- a/Sources/arm/node/MakeTexcoord.hx +++ b/Sources/arm/node/MakeTexcoord.hx @@ -8,7 +8,8 @@ class MakeTexcoord { public static function run(vert: MaterialShader, frag: MaterialShader) { - var uvType = Context.layer.material_mask != null ? Context.layer.uvType : Context.brushPaint; + var fillLayer = Context.layer.material_mask != null; + var uvType = fillLayer ? Context.layer.uvType : Context.brushPaint; var decal = Context.tool == ToolDecal || Context.tool == ToolText; // TexCoords - project @@ -16,7 +17,12 @@ class MakeTexcoord { frag.add_uniform('float brushScale', '_brushScale'); frag.write_attrib('vec2 uvsp = sp.xy;'); - if (decal) { + if (fillLayer) { // Decal layer + frag.write_attrib('uvsp.x *= aspectRatio;'); + frag.write_attrib('uvsp.xy *= 4.0;'); + //frag.write_attrib('if (uvsp.x < 0.0 || uvsp.y < 0.0 || uvsp.x > 1.0 || uvsp.y > 1.0) discard;'); + } + else if (decal) { frag.write_attrib('uvsp -= inp.xy;'); frag.write_attrib('uvsp.x *= aspectRatio;'); frag.write_attrib('uvsp *= 0.21 / (brushRadius * 0.9);'); diff --git a/Sources/arm/plugin/Gizmo.hx b/Sources/arm/plugin/Gizmo.hx index ece12fdb..b6219b54 100644 --- a/Sources/arm/plugin/Gizmo.hx +++ b/Sources/arm/plugin/Gizmo.hx @@ -7,91 +7,141 @@ import iron.math.RayCaster; import iron.math.Vec4; import iron.Scene; import arm.ui.UISidebar; +import arm.ui.UIHeader; +import arm.Enums; class Gizmo { - public static function update() { - var gizmo = Context.gizmo; - if (!gizmo.visible) return; + static var v = new Vec4(); - if (Context.object != null) { - var cam = Scene.active.camera; - gizmo.transform.loc.setFrom(Context.object.transform.loc); - var dist = Vec4.distance(cam.transform.loc, gizmo.transform.loc) / 10; - gizmo.transform.scale.set(dist, dist, dist); - Context.gizmoX.transform.scale.set(dist, dist, dist); - Context.gizmoY.transform.scale.set(dist, dist, dist); - Context.gizmoZ.transform.scale.set(dist, dist, dist); - gizmo.transform.buildMatrix(); - } + public static function update() { + + var isRender = UIHeader.inst.worktab.position == SpaceRender; + var isPaint = UIHeader.inst.worktab.position == SpacePaint; + var isObject = isRender && Context.object != null; + var isDecal = isPaint && Context.layer.material_mask != null && Context.layer.uvType == UVProject; + + var gizmo = Context.gizmo; + gizmo.visible = isObject || isDecal; + if (!gizmo.visible) return; var mouse = Input.getMouse(); var kb = Input.getKeyboard(); - if (mouse.viewX < App.w()) { - if (kb.started("delete") || kb.started("backspace")) { - if (Context.object != null) { - Context.object.remove(); - Context.selectObject(Scene.active.getChild("Scene")); + if (isObject) { + gizmo.transform.loc.setFrom(Context.object.transform.loc); + } + else if (isDecal) { + gizmo.transform.loc.set(Context.layer.projectX, Context.layer.projectY, Context.layer.projectZ); + } + var cam = Scene.active.camera; + var dist = Vec4.distance(cam.transform.loc, gizmo.transform.loc) / 10; + gizmo.transform.scale.set(dist, dist, dist); + Context.gizmoX.transform.scale.set(dist, dist, dist); + Context.gizmoY.transform.scale.set(dist, dist, dist); + Context.gizmoZ.transform.scale.set(dist, dist, dist); + gizmo.transform.buildMatrix(); + + // Scene control + if (isObject) { + if (mouse.viewX < App.w()) { + if (kb.started("delete") || kb.started("backspace")) { + if (Context.object != null) { + Context.object.remove(); + Context.selectObject(Scene.active.getChild("Scene")); + } + } + if (kb.started("c") && Context.object != null) { + if (Std.is(Context.object, MeshObject)) { + var mo = cast(Context.object, MeshObject); + var object = Scene.active.addMeshObject(mo.data, mo.materials, Scene.active.getChild("Scene")); + object.name = mo.name + ".1"; + + object.transform.loc.setFrom(mo.transform.loc); + object.transform.rot.setFrom(mo.transform.rot); + object.transform.scale.setFrom(mo.transform.scale); + + var hit = RayCaster.planeIntersect(Vec4.zAxis(), new Vec4(), mouse.viewX, mouse.viewY, Scene.active.camera); + if (hit != null) { + object.transform.loc.x = hit.x; + object.transform.loc.y = hit.y; + object.transform.setRotation(0, 0, Math.random() * 3.1516 * 2); + } + + object.transform.buildMatrix(); + + for (t in mo.traits) { // Clone traits + var trait = Type.createInstance(Type.getClass(t), []); + object.addTrait(trait); + } + + Context.selectObject(object); + } + else if (Std.is(Context.object, LightObject)) { + var lo = cast(Context.object, LightObject); + var object = Scene.active.addLightObject(lo.data, Scene.active.getChild("Scene")); + object.name = lo.name + ".1"; + + object.transform.loc.setFrom(lo.transform.loc); + object.transform.rot.setFrom(lo.transform.rot); + object.transform.scale.setFrom(lo.transform.scale); + object.transform.buildMatrix(); + + Context.selectObject(object); + } + Context.rdirty = 3; + Context.ddirty = 3; + } + if (kb.started("m")) { // skip voxel + var raw = Context.materialScene.data.raw; + raw.skip_context = raw.skip_context == "" ? "voxel" : ""; } } - if (kb.started("c") && Context.object != null) { - if (Std.is(Context.object, MeshObject)) { - var mo = cast(Context.object, MeshObject); - var object = Scene.active.addMeshObject(mo.data, mo.materials, Scene.active.getChild("Scene")); - object.name = mo.name + ".1"; - object.transform.loc.setFrom(mo.transform.loc); - object.transform.rot.setFrom(mo.transform.rot); - object.transform.scale.setFrom(mo.transform.scale); - - var hit = RayCaster.planeIntersect(Vec4.zAxis(), new Vec4(), mouse.viewX, mouse.viewY, Scene.active.camera); - if (hit != null) { - object.transform.loc.x = hit.x; - object.transform.loc.y = hit.y; - object.transform.setRotation(0, 0, Math.random() * 3.1516 * 2); - } - - object.transform.buildMatrix(); - - for (t in mo.traits) { // Clone traits - var trait = Type.createInstance(Type.getClass(t), []); - object.addTrait(trait); - } - - Context.selectObject(object); - } - else if (Std.is(Context.object, LightObject)) { - var lo = cast(Context.object, LightObject); - var object = Scene.active.addLightObject(lo.data, Scene.active.getChild("Scene")); - object.name = lo.name + ".1"; - - object.transform.loc.setFrom(lo.transform.loc); - object.transform.rot.setFrom(lo.transform.rot); - object.transform.scale.setFrom(lo.transform.scale); - object.transform.buildMatrix(); - - Context.selectObject(object); - } - Context.rdirty = 3; - Context.ddirty = 3; + if (mouse.started("middle")) { + #if arm_physics + var physics = arm.plugin.PhysicsWorld.active; + var pb = physics.pickClosest(mouse.viewX, mouse.viewY); + if (pb != null) Context.selectObject(pb.object); + #end } - if (kb.started("m")) { // skip voxel - var raw = Context.materialScene.data.raw; - raw.skip_context = raw.skip_context == "" ? "voxel" : ""; + + if (Context.axisX || Context.axisY || Context.axisZ) { + if (Context.axisX) { + Context.object.transform.loc.x = Context.axisLoc; + } + else if (Context.axisY) { + Context.object.transform.loc.y = Context.axisLoc; + } + else if (Context.axisZ) { + Context.object.transform.loc.z = Context.axisLoc; + } + + Context.object.transform.buildMatrix(); + #if arm_physics + var pb = Context.object.getTrait(arm.plugin.PhysicsBody); + if (pb != null) pb.syncTransform(); + #end + } + } + // Decal layer control + else if (isDecal) { + if (Context.axisX || Context.axisY || Context.axisZ) { + if (Context.axisX) { + Context.layer.projectX = Context.axisLoc; + } + else if (Context.axisY) { + Context.layer.projectY = Context.axisLoc; + } + else if (Context.axisZ) { + Context.layer.projectZ = Context.axisLoc; + } + Layers.updateFillLayer(); } } - if (mouse.started("middle")) { - #if arm_physics - var physics = arm.plugin.PhysicsWorld.active; - var pb = physics.pickClosest(mouse.viewX, mouse.viewY); - if (pb != null) Context.selectObject(pb.object); - #end - } - + // Axis movement if (mouse.started("left") && Context.object.name != "Scene") { - gizmo.transform.buildMatrix(); var trs = [Context.gizmoX.transform, Context.gizmoY.transform, Context.gizmoZ.transform]; var hit = RayCaster.closestBoxIntersect(trs, mouse.viewX, mouse.viewY, Scene.active.camera); if (hit != null) { @@ -106,44 +156,35 @@ class Gizmo { } if (Context.axisX || Context.axisY || Context.axisZ) { - var t = Context.object.transform; - var v = new Vec4(); - v.set(t.worldx(), t.worldy(), t.worldz()); + Context.rdirty = 2; + + if (isObject) { + var t = Context.object.transform; + v.set(t.worldx(), t.worldy(), t.worldz()); + } + else if (isDecal) { + v.set(Context.layer.projectX, Context.layer.projectY, Context.layer.projectZ); + } if (Context.axisX) { var hit = RayCaster.planeIntersect(Vec4.yAxis(), v, mouse.viewX, mouse.viewY, Scene.active.camera); if (hit != null) { - if (Context.axisStart == 0) Context.axisStart = hit.x - Context.object.transform.loc.x; - Context.object.transform.loc.x = hit.x - Context.axisStart; - Context.object.transform.buildMatrix(); - #if arm_physics - var pb = Context.object.getTrait(arm.plugin.PhysicsBody); - if (pb != null) pb.syncTransform(); - #end + if (Context.axisStart == 0) Context.axisStart = hit.x - v.x; + Context.axisLoc = hit.x - Context.axisStart; } } else if (Context.axisY) { var hit = RayCaster.planeIntersect(Vec4.xAxis(), v, mouse.viewX, mouse.viewY, Scene.active.camera); if (hit != null) { - if (Context.axisStart == 0) Context.axisStart = hit.y - Context.object.transform.loc.y; - Context.object.transform.loc.y = hit.y - Context.axisStart; - Context.object.transform.buildMatrix(); - #if arm_physics - var pb = Context.object.getTrait(arm.plugin.PhysicsBody); - if (pb != null) pb.syncTransform(); - #end + if (Context.axisStart == 0) Context.axisStart = hit.y - v.y; + Context.axisLoc = hit.y - Context.axisStart; } } else if (Context.axisZ) { var hit = RayCaster.planeIntersect(Vec4.xAxis(), v, mouse.viewX, mouse.viewY, Scene.active.camera); if (hit != null) { - if (Context.axisStart == 0) Context.axisStart = hit.z - Context.object.transform.loc.z; - Context.object.transform.loc.z = hit.z - Context.axisStart; - Context.object.transform.buildMatrix(); - #if arm_physics - var pb = Context.object.getTrait(arm.plugin.PhysicsBody); - if (pb != null) pb.syncTransform(); - #end + if (Context.axisStart == 0) Context.axisStart = hit.z - v.z; + Context.axisLoc = hit.z - Context.axisStart; } } } diff --git a/Sources/arm/render/Uniforms.hx b/Sources/arm/render/Uniforms.hx index abc89b71..2a9360a5 100644 --- a/Sources/arm/render/Uniforms.hx +++ b/Sources/arm/render/Uniforms.hx @@ -4,6 +4,7 @@ import iron.data.MaterialData; import iron.object.Object; import iron.system.Input; import iron.math.Vec4; +import iron.math.Mat4; import iron.RenderPath; import iron.Scene; #if arm_painter @@ -21,6 +22,7 @@ class Uniforms { iron.object.Uniforms.externalVec2Links = [linkVec2]; iron.object.Uniforms.externalVec3Links = [linkVec3]; iron.object.Uniforms.externalVec4Links = [linkVec4]; + iron.object.Uniforms.externalMat4Links = [linkMat4]; iron.object.Uniforms.externalTextureLinks = [linkTex]; } @@ -327,6 +329,20 @@ class Uniforms { return null; } + public static function linkMat4(object: Object, mat: MaterialData, link: String): iron.math.Mat4 { + if (link == "_decalLayerMatrix") { // Decal layer + var camera = Scene.active.camera; + var m = iron.object.Uniforms.helpMat; + m.setFrom(object.transform.worldUnpack); + var V = Mat4.identity(); + V.setLookAt(new Vec4(Context.layer.projectX, -5, Context.layer.projectZ), new Vec4(Context.layer.projectX, 0, Context.layer.projectZ), new Vec4(0, 0, 1)); + m.multmat(V); + m.multmat(camera.P); + return m; + } + return null; + } + public static function linkTex(object: Object, mat: MaterialData, link: String): kha.Image { #if arm_painter if (link == "_texcolorid") { diff --git a/Sources/arm/ui/TabLayers.hx b/Sources/arm/ui/TabLayers.hx index f98b8156..3ab668e5 100644 --- a/Sources/arm/ui/TabLayers.hx +++ b/Sources/arm/ui/TabLayers.hx @@ -629,7 +629,7 @@ class TabLayers { var uvTypeHandle = Id.handle().nest(l.id); uvTypeHandle.position = l.uvType; - l.uvType = ui.combo(uvTypeHandle, [tr("UV Map"), tr("Triplanar")], tr("TexCoord")); + l.uvType = ui.combo(uvTypeHandle, [tr("UV Map"), tr("Triplanar"), tr("Project")], tr("TexCoord")); if (uvTypeHandle.changed) { Context.setMaterial(l.material_mask); Context.setLayer(l); diff --git a/Sources/arm/ui/UISidebar.hx b/Sources/arm/ui/UISidebar.hx index efe0f42f..7e81885a 100644 --- a/Sources/arm/ui/UISidebar.hx +++ b/Sources/arm/ui/UISidebar.hx @@ -648,9 +648,7 @@ class UISidebar { if (undoPressed) History.undo(); else if (redoPressed) History.redo(); - if (UIHeader.inst.worktab.position == SpaceRender) { - arm.plugin.Gizmo.update(); - } + arm.plugin.Gizmo.update(); if (Context.lastCombo != null || (ui.tooltipImg == null && Context.lastTooltip != null)) App.redrawUI(); Context.lastCombo = ui.comboSelectedHandle; @@ -677,7 +675,6 @@ class UISidebar { if (tabh == 0) { tabh = tabh1 = tabh2 = Std.int(System.windowHeight() / 3); } - Context.gizmo.visible = false; if (ui.window(hwnd, tabx, 0, windowW, tabh)) { TabLayers.draw(); @@ -707,8 +704,6 @@ class UISidebar { TabFonts.draw(); } - Context.gizmo.visible = UIHeader.inst.worktab.position == SpaceRender; - ui.end(); g.begin(false); }