From 7b036b1c4506fe4ddfba96b7d26c1b7fe3b2202f Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Mon, 25 Aug 2025 12:39:44 +0200 Subject: [PATCH 01/70] Added collision params edition in Model view --- bin/style.css | 43 +++++++++++++ bin/style.less | 44 +++++++++++++ hide/view/Model.hx | 154 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 239 insertions(+), 2 deletions(-) diff --git a/bin/style.css b/bin/style.css index 22deeda1a..29792cd49 100644 --- a/bin/style.css +++ b/bin/style.css @@ -2768,6 +2768,49 @@ div.sp-container input:hover { display: inline-block; width: 50%; } +/* Collision Editor */ +.collision-editor .title { + display: block; + text-align: center; + font-weight: bold; + font-size: 12px; + margin: 4px; + background-color: #1e1e1e; +} +.collision-editor dl { + overflow-x: hidden; + margin: 0 0 0 4px; + width: 100%; + display: flex; +} +.collision-editor dd, +.collision-editor dt { + vertical-align: middle; + display: inline-block; + text-wrap: wrap; + word-break: break-word; + margin: 2% 5% 0 0; + flex: 2; + align-content: center; +} +.collision-editor dd select, +.collision-editor dt select { + width: 100%; +} +.collision-editor dd input, +.collision-editor dt input { + width: 100%; +} +.collision-editor dt { + text-align: right; + font-size: 11px; + color: #aaa; + user-select: none; + text-transform: capitalize; + cursor: pointer; + font-weight: normal; + flex: 1; +} /* Script Editor */ .codeeditor { position: relative; diff --git a/bin/style.less b/bin/style.less index ec8167266..e4f0ea441 100644 --- a/bin/style.less +++ b/bin/style.less @@ -3199,6 +3199,50 @@ div.sp-container { } } +/* Collision Editor */ +.collision-editor { + .title { + display: block; + text-align: center; + font-weight: bold; + font-size: 12px; + margin: 4px; + background-color : rgb(30,30,30); + } + dl { + overflow-x:hidden; + margin:0 0 0 4px; + width:100%; + display: flex; + } + dd, dt { + vertical-align:middle; + display:inline-block; + text-wrap: wrap; + word-break: break-word; + margin:2% 5% 0 0; + flex:2; + align-content: center; + select { + width: 100%; + } + input { + width: 100%; + } + } + dt { + text-align:right; + font-size:11px; + color:#aaa; + user-select:none; + text-transform: capitalize; + cursor:pointer; + font-weight: normal; + flex:1; + } +} + + /* Script Editor */ .codeeditor { diff --git a/hide/view/Model.hx b/hide/view/Model.hx index eec394d77..a2cd7d728 100644 --- a/hide/view/Model.hx +++ b/hide/view/Model.hx @@ -1,6 +1,24 @@ package hide.view; import hxd.Key as K; +typedef CollisionSettings = { mode : Int, params : Dynamic }; + +private enum abstract CollisionMode(Int) from Int to Int { + var Default = 0; + var None = 1; + var Auto = 2; + var Count = 3; + + public function toString() { + return switch (this) { + case Default: "Default"; + case None: "None"; + case Auto: "Auto"; + default: "Undefined"; + } + } +} + class Model extends FileView { static var KEY_ANIM_PLAYING = "AnimationPlaying"; @@ -11,6 +29,8 @@ class Model extends FileView { var tabs : hide.comp.Tabs; var overlay : Element; var eventList : Element; + var collisionEditor : Element; + var collisionSettings : Map; var plight : hrt.prefab.Prefab; var light : h3d.scene.Object; @@ -70,8 +90,25 @@ class Model extends FileView {
+
+
+ +
+
Collision mode
+
+ +
+
+
+
Precision
+
Max convex hulls
+
max subdivision
+
+
+
- '); @@ -80,6 +117,7 @@ class Model extends FileView { overlay = element.find(".hide-scene-layer .tree"); tabs = new hide.comp.Tabs(null,element.find(".tabs")); eventList = element.find(".event-editor"); + initCollisionEditor(); var def = new hrt.prefab.Prefab(null, null); new hrt.prefab.RenderProps(def, null).name = "renderer"; @@ -146,6 +184,75 @@ class Model extends FileView { @:privateAccess hxd.fmt.hmd.Library.defaultDynamicBonesConfigs.clear(); } + function updateCollisionParams(settings) { + var collisionParams = element.find("#collision-params"); + switch (settings.mode) { + case Default, None: collisionParams.hide(); + case Auto: + collisionParams.show(); + + var elPrec = collisionParams.find("#precision"); + var elHull = collisionParams.find("#hulls"); + var elSubdiv = collisionParams.find("#subdiv"); + + var params = settings.params; + elPrec.val('${params.precision}'); + elHull.val('${params.maxConvexHulls}'); + elSubdiv.val('${params.maxSubdiv}'); + default: throw "Unexpected mode"; + } + } + + function initCollisionEditor() { + collisionEditor = element.find(".collision-editor"); + collisionEditor.hide(); + collisionSettings = []; + + var collisionParams = collisionEditor.find("#collision-params"); + var elPrec = collisionParams.find("#precision"); + var elHull = collisionParams.find("#hulls"); + var elSubdiv = collisionParams.find("#subdiv"); + collisionParams.on("change", function(_) { + var modelName = selectedMesh.name; + var settings = collisionSettings.get(modelName); + var prevParams = settings.params; + var curParams = { + precision : Std.parseFloat(elPrec.val()), + maxConvexHulls : Std.parseInt(elHull.val()), + maxSubdiv : Std.parseInt(elSubdiv.val()) + } + settings.params = curParams; + undo.change(Custom(function(undo) { + var params = undo ? prevParams : curParams; + settings.params = params; + if ( modelName == selectedMesh.name ) { + elPrec.val('${params.precision}'); + elHull.val('${params.maxConvexHulls}'); + elSubdiv.val('${params.maxSubdiv}'); + } + })); + }); + + var collisionDropdown = collisionEditor.find("#select-collision-mode"); + collisionDropdown.on("change", function(_) { + var modelName = selectedMesh.name; + var settings = collisionSettings.get(modelName); + var prevMode = settings.mode; + var curMode = Std.parseInt(collisionDropdown.val()); + settings.mode = curMode; + updateCollisionParams(settings); + + undo.change(Custom(function(undo) { + var mode = undo ? prevMode : curMode; + settings.mode = mode; + if ( modelName == selectedMesh.name ) { + collisionDropdown.val('${Std.int(mode)}'); + updateCollisionParams(settings); + } + })); + }); + } + override function onActivate() { if (tools != null) tools.refreshToggles(); @@ -167,12 +274,23 @@ class Model extends FileView { if (hmd == null) continue; + var collide = {}; + var settings = collisionSettings.get(o.name); + if ( settings != null ) { + switch ( settings.mode ) { + case Default: + case None: Reflect.setField(collide, "collide", null); + case Auto: Reflect.setField(collide, "collide", settings.params); + default: throw "Unexpected collision mode"; + } + } var input : h3d.prim.ModelDatabase.ModelDataInput = { resourceDirectory : @:privateAccess hmd.lib.resource.entry.directory, resourceName : @:privateAccess hmd.lib.resource.name, objectName : o.name, hmd : hmd, - skin : o.find((o) -> Std.downcast(o, h3d.scene.Skin)) + skin : o.find((o) -> Std.downcast(o, h3d.scene.Skin)), + collide : collide } // If Dynamic bones edition scope is global or folder, save it to props.json @@ -204,6 +322,11 @@ class Model extends FileView { } else { h3d.prim.ModelDatabase.current.saveModelProps(input); + var lfs = cast(hxd.res.Loader.currentInstance.fs, hxd.fs.LocalFileSystem); + var path = state.path; + lfs.removePathFromCache(path); + @:privateAccess hxd.res.Loader.currentInstance.cache.remove(path); + onRefresh(); } } @@ -286,6 +409,8 @@ class Model extends FileView { refreshSelectionHighlight(null); selectedElements = elts; + collisionEditor.hide(); + var properties = sceneEditor.properties; properties.clear(); @@ -626,6 +751,31 @@ class Model extends FileView { }); } } + + // Collision edition + var modelName = mesh.name; + + var settings = collisionSettings.get(modelName); + if ( settings == null ) { + var mode = Default; + var dirPath = @:privateAccess hmd.lib.resource.entry.directory; + var resName = @:privateAccess hmd.lib.resource.name; + var props = @:privateAccess h3d.prim.ModelDatabase.current.getModelData(dirPath, resName, modelName); + var collideField = null; + if ( props != null && Reflect.hasField(props, "collide") ) { + collideField = Reflect.field(props, "collide"); + mode = collideField == null ? None : Auto; + } + var params = collideField ?? { precision : 1.0, maxConvexHulls : 1, maxSubdiv : 32 }; + settings = { mode : mode, params : params }; + collisionSettings.set(modelName, settings); + } + + var collisionDropdown = collisionEditor.find("#select-collision-mode"); + collisionDropdown.val('${Std.int(settings.mode)}'); + updateCollisionParams(settings); + + collisionEditor.show(); } var select = e.find(".follow"); From 93a53c4f7490d1a75f04391687c702ed750a9336 Mon Sep 17 00:00:00 2001 From: Leonardo Jeanteur Date: Mon, 25 Aug 2025 15:59:19 +0200 Subject: [PATCH 02/70] Allow seeking line indices with ctrl O --- hide/comp/Dropdown.hx | 4 +++- hide/comp/GlobalSeek.hx | 22 +++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/hide/comp/Dropdown.hx b/hide/comp/Dropdown.hx index 0b0bf01b6..5a15065d0 100644 --- a/hide/comp/Dropdown.hx +++ b/hide/comp/Dropdown.hx @@ -8,6 +8,7 @@ typedef Choice = { @:optional var classes: Array; @:optional var doc: String; @:optional var index: Int; + @:optional var searchText: String; } class Dropdown extends Component { @@ -53,6 +54,7 @@ class Dropdown extends Component { } el.data("id", o.id); el.data("text", o.text); + el.data("searchText", o.searchText); el.data("index", o.index); el.click((_) -> applyValue(o.id)); el.mousemove(function(_) { @@ -73,7 +75,7 @@ class Dropdown extends Component { var v = filterInput.val(); if (v != null) { for( o in optionsCont.children().elements() ) { - var m = matches(o.data("text"), v) || (!ignoreIdInSearch && matches(o.data("id"), v)); + var m = matches(o.data("text"), v) || (!ignoreIdInSearch && matches(o.data("id"), v)) || matches(o.data("searchText"), v); o.toggleClass("hidden", !m); } var sortedChildren = optionsCont.children().elements().toArray(); diff --git a/hide/comp/GlobalSeek.hx b/hide/comp/GlobalSeek.hx index bb2245394..20fdcf734 100644 --- a/hide/comp/GlobalSeek.hx +++ b/hide/comp/GlobalSeek.hx @@ -27,16 +27,20 @@ class GlobalSeek extends Modal { } } else { function addSheet(s: cdb.Sheet) { - for (i in 0...s.all.length) { - var l = s.all[i]; + if (s.idCol == null) + return; + for (i in 0...s.lines.length) { + var l = s.lines[i]; var id = Reflect.field(l, s.idCol.name); - if (l.id != null) { - choices.push({ - id: '#${s.name}:$id', - ico: s.name, - text: l.disp, - }); - } + if (id == null) + continue; + var dispL = s.index.get(id); + choices.push({ + id: '#${s.name}:$id', + ico: s.name, + text: dispL.disp, + searchText: "" + i, + }); } } if (currentSheet != null && currentSheet.idCol != null) { From 9525c87bdd1153317fefb1d4f9262c36db9ed98c Mon Sep 17 00:00:00 2001 From: lviguier Date: Tue, 26 Aug 2025 11:53:27 +0200 Subject: [PATCH 03/70] CDB: Fix results count on search --- hide/comp/cdb/Editor.hx | 2 +- hide/view/Model.hx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hide/comp/cdb/Editor.hx b/hide/comp/cdb/Editor.hx index b1eaa73dd..22135d51a 100644 --- a/hide/comp/cdb/Editor.hx +++ b/hide/comp/cdb/Editor.hx @@ -347,7 +347,7 @@ class Editor extends Component { var results = 0; for (l in table.lines) { var filtered = isLineFilteredBySearch(table, l); - if (filtered) + if (!filtered) results++; filtered = filtered || isLineFilteredByStatus(l); diff --git a/hide/view/Model.hx b/hide/view/Model.hx index a2cd7d728..87581fd11 100644 --- a/hide/view/Model.hx +++ b/hide/view/Model.hx @@ -594,7 +594,7 @@ class Model extends FileView { '); properties.add(blendShape, null, function(pname){ - @:privateAccess hmd.blendshape.setBlendshapeAmountByIndex(blendShape.find("#bs-index").val(),blendShape.find("#bs-amount").val()); + @:privateAccess hmd.blendshape.setBlendShapeWeight(mesh, blendShape.find("#bs-index").val(), blendShape.find("#bs-amount").val()); }); } From ad4c93fcf8ec6fb997d2b373cb898b2a73ff666f Mon Sep 17 00:00:00 2001 From: lviguier Date: Tue, 26 Aug 2025 12:16:38 +0200 Subject: [PATCH 04/70] DragNDrop: add option to not use collision on drag --- hide/Config.hx | 3 +- hide/comp/SceneEditor.hx | 88 +++++++++++++++--------------- hide/tools/IdeData.hx | 1 + hide/view/settings/UserSettings.hx | 3 +- 4 files changed, 50 insertions(+), 45 deletions(-) diff --git a/hide/Config.hx b/hide/Config.hx index 077faebf6..b3c57203b 100644 --- a/hide/Config.hx +++ b/hide/Config.hx @@ -22,7 +22,6 @@ typedef HideGlobalConfig = { var svnShowModifiedFiles : Bool; var enableDBFormulas : Bool; var screenCaptureResolution : Int; - var orientMeshOnDrag : Bool; var minDistFromCameraOnDrag : Float; // Search @@ -35,6 +34,8 @@ typedef HideGlobalConfig = { var unfocusCPUSavingMode : Bool; // Scene Editor + var orientMeshOnDrag : Bool; + var collisionOnDrag : Bool; var sceneEditorClickCycleObjects : Bool; // CDB diff --git a/hide/comp/SceneEditor.hx b/hide/comp/SceneEditor.hx index 738d2467a..34574860b 100644 --- a/hide/comp/SceneEditor.hx +++ b/hide/comp/SceneEditor.hx @@ -4405,59 +4405,61 @@ class SceneEditor { var camera = scene.s3d.camera; var ray = camera.rayFromScreen(scene.s2d.mouseX, scene.s2d.mouseY); - var minDist = -1.; - var hitObj : h3d.scene.Object = null; - for (obj in scene.s3d) { - function get(obj : Object) { - if (obj == previewDraggedObj || Std.isOfType(obj, hrt.tools.Gizmo)) - return; - if (!obj.getBounds().inFrustum(camera.frustum)) - return; + if (ide.ideConfig.collisionOnDrag) { + var minDist = -1.; + var hitObj : h3d.scene.Object = null; + for (obj in scene.s3d) { + function get(obj : Object) { + if (obj == previewDraggedObj || Std.isOfType(obj, hrt.tools.Gizmo)) + return; + if (!obj.getBounds().inFrustum(camera.frustum)) + return; - try { - var dist = obj.getCollider().rayIntersection(ray, true); - if ((minDist < 0 || (dist >= 0 && dist < minDist)) && dist > ide.ideConfig.minDistFromCameraOnDrag) { - minDist = dist; - hitObj = obj; + try { + var dist = obj.getCollider().rayIntersection(ray, true); + if ((minDist < 0 || (dist >= 0 && dist < minDist)) && dist > ide.ideConfig.minDistFromCameraOnDrag) { + minDist = dist; + hitObj = obj; + } } + catch (e : Dynamic) {}; + + for (c in @:privateAccess obj.children) + get(c); } - catch (e : Dynamic) {}; - for (c in @:privateAccess obj.children) - get(c); + get(obj); } - get(obj); - } + if (minDist >= 0) { + // Find hit normal + var center = ray.getPoint(minDist); + var dx : h3d.col.Point = null; + var dy : h3d.col.Point = null; + var ray2 = camera.rayFromScreen(scene.s2d.mouseX + 1, scene.s2d.mouseY); + dx = ray2.getPoint(hitObj.getCollider().rayIntersection(ray2, true)); - if (minDist >= 0) { - // Find hit normal - var center = ray.getPoint(minDist); - var dx : h3d.col.Point = null; - var dy : h3d.col.Point = null; - var ray2 = camera.rayFromScreen(scene.s2d.mouseX + 1, scene.s2d.mouseY); - dx = ray2.getPoint(hitObj.getCollider().rayIntersection(ray2, true)); + var ray3 = camera.rayFromScreen(scene.s2d.mouseX - 1, scene.s2d.mouseY + 1); + dy = ray3.getPoint(hitObj.getCollider().rayIntersection(ray3, true)); - var ray3 = camera.rayFromScreen(scene.s2d.mouseX - 1, scene.s2d.mouseY + 1); - dy = ray3.getPoint(hitObj.getCollider().rayIntersection(ray3, true)); + var ddx = dx - center; + var ddy = dy - center; + var norm = ddx.cross(ddy); + norm.normalize(); - var ddx = dx - center; - var ddy = dy - center; - var norm = ddx.cross(ddy); - norm.normalize(); + if (ide.ideConfig.orientMeshOnDrag) { + var q = new h3d.Quat(); + q.initMoveTo(new h3d.Vector(0, 0, 1), norm); + transform = q.toMatrix(); + } + else { + transform = new h3d.Matrix(); + transform.identity(); + } - if (ide.ideConfig.orientMeshOnDrag) { - var q = new h3d.Quat(); - q.initMoveTo(new h3d.Vector(0, 0, 1), norm); - transform = q.toMatrix(); + transform.setPosition(center); + return transform; } - else { - transform = new h3d.Matrix(); - transform.identity(); - } - - transform.setPosition(center); - return transform; } // If there is no collision with objects, try to collide with z=0 plane @@ -4468,7 +4470,7 @@ class SceneEditor { return transform; } - transform.setPosition(ray.getPoint(minDist)); + transform.setPosition(ray.getPoint(10)); return transform; } diff --git a/hide/tools/IdeData.hx b/hide/tools/IdeData.hx index 0bc50c212..163b364ec 100644 --- a/hide/tools/IdeData.hx +++ b/hide/tools/IdeData.hx @@ -29,6 +29,7 @@ class IdeData { "screenCaptureResolution" => 4096, "sceneEditorClickCycleObjects" => true, "orientMeshOnDrag" => true, + "collisionOnDrag" => true, "minDistFromCameraOnDrag" => 1, ]; diff --git a/hide/view/settings/UserSettings.hx b/hide/view/settings/UserSettings.hx index 66a698603..aef24c86d 100644 --- a/hide/view/settings/UserSettings.hx +++ b/hide/view/settings/UserSettings.hx @@ -10,7 +10,6 @@ class UserSettings extends Settings { general.add("Show versioned files in filetree", new Element(''), Ide.inst.ideConfig.svnShowVersionedFiles, (v) -> {Ide.inst.ideConfig.svnShowVersionedFiles = v; for(view in Ide.inst.getViews(FileBrowser)) view.refreshVCS(); }); general.add("Show modified files in filetree", new Element(''), Ide.inst.ideConfig.svnShowModifiedFiles, (v) -> {Ide.inst.ideConfig.svnShowModifiedFiles = v; for(view in Ide.inst.getViews(FileBrowser)) view.refreshVCS(); }); general.add("Screen capture resolution", new Element(''), Ide.inst.ideConfig.screenCaptureResolution, (v) -> {Ide.inst.ideConfig.screenCaptureResolution = v; }); - general.add("Orient mesh on drag", new Element(''), Ide.inst.ideConfig.orientMeshOnDrag, (v) -> {Ide.inst.ideConfig.orientMeshOnDrag = v; }); general.add("Minimal distance from camera on drag", new Element(''), Ide.inst.ideConfig.minDistFromCameraOnDrag, (v) -> {Ide.inst.ideConfig.minDistFromCameraOnDrag = v; }); categories.push(general); @@ -28,6 +27,8 @@ class UserSettings extends Settings { categories.push(performance); var sceneEditor = new hide.view.settings.Settings.Categorie("Scene Editor"); + general.add("Use objects collision on drag", new Element(''), Ide.inst.ideConfig.collisionOnDrag, (v) -> {Ide.inst.ideConfig.collisionOnDrag = v; }); + general.add("Orient mesh on drag", new Element(''), Ide.inst.ideConfig.orientMeshOnDrag, (v) -> {Ide.inst.ideConfig.orientMeshOnDrag = v; }); sceneEditor.add("Click cycle objects under the mouse", new Element(''), Ide.inst.ideConfig.sceneEditorClickCycleObjects, (v) -> Ide.inst.ideConfig.sceneEditorClickCycleObjects = v); categories.push(sceneEditor); From 455304227a7535e14bc3a71d4f1741ee4ce19a37 Mon Sep 17 00:00:00 2001 From: lviguier Date: Tue, 26 Aug 2025 12:33:32 +0200 Subject: [PATCH 05/70] SceneEditor: fix snap on grid --- hide/comp/SceneEditor.hx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/hide/comp/SceneEditor.hx b/hide/comp/SceneEditor.hx index 34574860b..5ee3d4b41 100644 --- a/hide/comp/SceneEditor.hx +++ b/hide/comp/SceneEditor.hx @@ -4405,6 +4405,18 @@ class SceneEditor { var camera = scene.s3d.camera; var ray = camera.rayFromScreen(scene.s2d.mouseX, scene.s2d.mouseY); + function snapTransform(t : h3d.Matrix) { + if (snapForceOnGrid) { + var p = t.getPosition(); + p.x = snap(p.x, snapMoveStep); + p.y = snap(p.y, snapMoveStep); + p.z = snap(p.z, snapMoveStep); + t.setPosition(p); + } + + return t; + } + if (ide.ideConfig.collisionOnDrag) { var minDist = -1.; var hitObj : h3d.scene.Object = null; @@ -4458,7 +4470,7 @@ class SceneEditor { } transform.setPosition(center); - return transform; + return snapTransform(transform); } } @@ -4467,7 +4479,7 @@ class SceneEditor { var pt = ray.intersect(zPlane); if (pt != null) { transform.setPosition(pt); - return transform; + return snapTransform(transform); } transform.setPosition(ray.getPoint(10)); From 4ce224ecc77f23aaec5ca929cf04d2737e11cba8 Mon Sep 17 00:00:00 2001 From: lviguier Date: Tue, 26 Aug 2025 12:34:37 +0200 Subject: [PATCH 06/70] UserSettings: move on drag settings to sceneeditor category --- hide/view/settings/UserSettings.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hide/view/settings/UserSettings.hx b/hide/view/settings/UserSettings.hx index aef24c86d..de183bf22 100644 --- a/hide/view/settings/UserSettings.hx +++ b/hide/view/settings/UserSettings.hx @@ -27,8 +27,8 @@ class UserSettings extends Settings { categories.push(performance); var sceneEditor = new hide.view.settings.Settings.Categorie("Scene Editor"); - general.add("Use objects collision on drag", new Element(''), Ide.inst.ideConfig.collisionOnDrag, (v) -> {Ide.inst.ideConfig.collisionOnDrag = v; }); - general.add("Orient mesh on drag", new Element(''), Ide.inst.ideConfig.orientMeshOnDrag, (v) -> {Ide.inst.ideConfig.orientMeshOnDrag = v; }); + sceneEditor.add("Use objects collision on drag", new Element(''), Ide.inst.ideConfig.collisionOnDrag, (v) -> {Ide.inst.ideConfig.collisionOnDrag = v; }); + sceneEditor.add("Orient mesh on drag", new Element(''), Ide.inst.ideConfig.orientMeshOnDrag, (v) -> {Ide.inst.ideConfig.orientMeshOnDrag = v; }); sceneEditor.add("Click cycle objects under the mouse", new Element(''), Ide.inst.ideConfig.sceneEditorClickCycleObjects, (v) -> Ide.inst.ideConfig.sceneEditorClickCycleObjects = v); categories.push(sceneEditor); From 94aa32e9ce4471f201efdd7f08acaedcc6ae04c6 Mon Sep 17 00:00:00 2001 From: lviguier Date: Tue, 26 Aug 2025 12:38:28 +0200 Subject: [PATCH 07/70] Blendshape: WIP disable blendshapes --- hide/view/Model.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hide/view/Model.hx b/hide/view/Model.hx index 87581fd11..ee1d8966e 100644 --- a/hide/view/Model.hx +++ b/hide/view/Model.hx @@ -594,7 +594,8 @@ class Model extends FileView { '); properties.add(blendShape, null, function(pname){ - @:privateAccess hmd.blendshape.setBlendShapeWeight(mesh, blendShape.find("#bs-index").val(), blendShape.find("#bs-amount").val()); + //! WIP Disable blendshape + // @:privateAccess hmd.blendshape.setBlendShapeWeight(mesh, blendShape.find("#bs-index").val(), blendShape.find("#bs-amount").val()); }); } From c1b4de35d149d9f1dea5ba6e6a93bb62fd98c80d Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Tue, 26 Aug 2025 15:51:41 +0200 Subject: [PATCH 08/70] Light : Removed Mode and Blur from cascade shadow --- hrt/prefab/Light.hx | 46 +++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/hrt/prefab/Light.hx b/hrt/prefab/Light.hx index 4d5f128ac..ca15c224c 100644 --- a/hrt/prefab/Light.hx +++ b/hrt/prefab/Light.hx @@ -210,6 +210,13 @@ class Light extends Object3D { if( light != null ) { // PBR light.isMainLight = isMainLight; light.occlusionFactor = occlusionFactor; + light.color.setColor(color); + light.power = power; + light.shadows.mode = shadows.mode; + light.shadows.size = shadows.size; + light.shadows.blur.radius = shadows.radius; + light.shadows.blur.quality = shadows.quality; + light.shadows.bias = shadows.bias * 0.1; switch( kind ) { case Directional: @@ -230,6 +237,8 @@ class Light extends Object3D { cs.castingMaxDist = castingMaxDist; cs.transitionFraction = transitionFraction; cs.debugShader = debugShader; + cs.blur.radius = 0.0; + cs.mode = Dynamic; params.resize(cascadeNbr); for ( i in 0...params.length ) if ( params[i] == null ) @@ -265,13 +274,6 @@ class Light extends Object3D { rec.fallOff = fallOff; default: } - light.color.setColor(color); - light.power = power; - light.shadows.mode = shadows.mode; - light.shadows.size = shadows.size; - light.shadows.blur.radius = shadows.radius; - light.shadows.blur.quality = shadows.quality; - light.shadows.bias = shadows.bias * 0.1; switch (shadows.samplingMode.kind) { case None: @@ -666,15 +668,6 @@ class Light extends Object3D { var shadowGroup = new hide.Element('
-
Mode
-
- -
Size
-
Blur Radius
-
Blur Quality
-
+
+
Mode
+
+ +
+
Blur Radius
+
Blur Quality
Bias
Sampling Mode
@@ -704,11 +706,11 @@ class Light extends Object3D {
'); - var biasEl = shadowGroup.find(".bias"); + var nonCascadeParamsEl = shadowGroup.find(".nonCascadeParams"); if ( cascade ) - biasEl.hide(); + nonCascadeParamsEl.hide(); else - biasEl.show(); + nonCascadeParamsEl.show(); switch (shadows.samplingMode.kind) { case None: From f0ad07ff1a948ce51b02decc63ae4460f02d3927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 25 Aug 2025 11:58:00 +0200 Subject: [PATCH 09/70] [color] Color space tweaks --- hide/comp/ColorPicker.hx | 33 +--------------------- hrt/impl/ColorSpace.hx | 60 ++++++++++++++++++++++++++++++++++++---- hrt/prefab/Light.hx | 1 - 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/hide/comp/ColorPicker.hx b/hide/comp/ColorPicker.hx index 4e90f8eee..ab232d4f9 100644 --- a/hide/comp/ColorPicker.hx +++ b/hide/comp/ColorPicker.hx @@ -441,38 +441,7 @@ class ColorPicker extends Popup { } function getColorFromString(str:String) : Null { - if (str.charAt(0) == "#") - str = str.substr(1); - - var color = Std.parseInt("0x"+str); - if (color == null) - return null; - - color = color & 0xFFFFFFFF; - - var containsAlpha = false; - switch (str.length) { - case 2: // Assume color is shade of gray - color = (color << 16) + (color << 8) + (color); - case 3: // handle #XXX html codes - var r = (color >> 8) & 0xF; - var g = (color >> 4) & 0xF; - var b = (color >> 0) & 0xF; - color = (r << 20) + (r << 16) + (g << 12) + (g << 8) + (b << 4) + (b << 0); - case 6: - case 8: - containsAlpha = true; - default: - return null; - } - - if (!containsAlpha && canEditAlpha) { - color = (color) + (0xFF << 24); - } - else if (containsAlpha && !canEditAlpha) { - color = (color & 0xFFFFFF) ; - } - return color; + return Color.intFromString(str, canEditAlpha); } function get_value() { diff --git a/hrt/impl/ColorSpace.hx b/hrt/impl/ColorSpace.hx index 8780ba13c..b14d122ef 100644 --- a/hrt/impl/ColorSpace.hx +++ b/hrt/impl/ColorSpace.hx @@ -23,18 +23,66 @@ class Color { } inline static public function fromInt(rgb: Int, withAlpha: Bool = true) : Color { - return new Color( - (rgb >> 16) & 0xFF, - (rgb >> 8) & 0xFF, - (rgb >> 0) & 0xFF, - withAlpha ? (rgb >> 24) & 0xFF : 255 - ); + var c = new Color(); + c.load(rgb, withAlpha); + return c; + } + + public function load(rgb: Int, withAlpha: Bool = true) { + r = (rgb >> 16) & 0xFF; + g = (rgb >> 8) & 0xFF; + b = (rgb >> 0) & 0xFF; + if (withAlpha) { + a = (rgb >> 24) & 0xFF; + } else { + a = 255; + } } inline public function toInt(includeAlpha: Bool) : Int { return if (!includeAlpha) (r << 16) + (g << 8) + b else (r << 16) + (g << 8) + (b << 0) + (a << 24); } + + static public function intFromString(str:String, withAlpha: Bool) : Null { + if (str.charAt(0) == "#") + str = str.substr(1); + + var color = Std.parseInt("0x"+str); + if (color == null) + return null; + + color = color & 0xFFFFFFFF; + + var containsAlpha = false; + switch (str.length) { + case 2: // Assume color is shade of gray + color = (color << 16) + (color << 8) + (color); + case 3: // handle #XXX html codes + var r = (color >> 8) & 0xF; + var g = (color >> 4) & 0xF; + var b = (color >> 0) & 0xF; + color = (r << 20) + (r << 16) + (g << 12) + (g << 8) + (b << 4) + (b << 0); + case 6: + case 8: + containsAlpha = true; + default: + return null; + } + + if (!containsAlpha && withAlpha) { + color = (color) + (0xFF << 24); + } + else if (containsAlpha && !withAlpha) { + color = (color & 0xFFFFFF) ; + } + return color; + } + + function toString() : String { + return '[$r, $g, $b, $a]'; + } + } class ColorSpace { diff --git a/hrt/prefab/Light.hx b/hrt/prefab/Light.hx index ca15c224c..10da62afb 100644 --- a/hrt/prefab/Light.hx +++ b/hrt/prefab/Light.hx @@ -153,7 +153,6 @@ class Light extends Object3D { o.y = y; o.z = z; o.setRotation(hxd.Math.degToRad(rotationX), hxd.Math.degToRad(rotationY), hxd.Math.degToRad(rotationZ)); - } function initTexture( path : String, ?wrap : h3d.mat.Data.Wrap ) { From 1f44b5d1e1c9d970230932b180fe520aed2bdbd9 Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Tue, 26 Aug 2025 16:05:20 +0200 Subject: [PATCH 10/70] Light : minor naming improvement --- hrt/prefab/Light.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hrt/prefab/Light.hx b/hrt/prefab/Light.hx index 10da62afb..2003f9642 100644 --- a/hrt/prefab/Light.hx +++ b/hrt/prefab/Light.hx @@ -229,7 +229,7 @@ class Light extends Object3D { var cs = Std.downcast(s, h3d.pass.CascadeShadowMap); if ( cs != null ) { cs.cascade = cascadeNbr; - cs.pow = cascadePow; + cs.ditributionPower = cascadePow; cs.firstCascadeSize = firstCascadeSize; cs.minPixelSize = minPixelSize; cs.debug = debugDisplay; @@ -741,7 +741,7 @@ class Light extends Object3D {
Number
Min pixel size
First cascade size
-
Range power
+
Distribution power
Casting max dist
Transition fraction
From 43e1263b0babc94168448fd80d1f770c1ff49c4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Tue, 26 Aug 2025 16:59:40 +0200 Subject: [PATCH 11/70] [scene] sceneTree editor tweaks --- bin/style.css | 78 ++++++++++++++++++-------------- bin/style.less | 97 +++++++++++++++++++++------------------- hide/comp/SceneEditor.hx | 6 +-- 3 files changed, 98 insertions(+), 83 deletions(-) diff --git a/bin/style.css b/bin/style.css index 29792cd49..e92b5e2c7 100644 --- a/bin/style.css +++ b/bin/style.css @@ -529,6 +529,46 @@ input[type=checkbox].indeterminate:after { margin-bottom: 1px; border-radius: 3px; } +.hide-scenetree fancy-tree-item.editorOnly, +.hide-scene-layer fancy-tree-item.editorOnly { + color: #02aeda; +} +.hide-scenetree fancy-tree-item.inGameOnly, +.hide-scene-layer fancy-tree-item.inGameOnly { + color: #daa802; +} +.hide-scenetree fancy-tree-item.hidden, +.hide-scene-layer fancy-tree-item.hidden { + color: #666; +} +.hide-scenetree fancy-tree-item.hidden.selected, +.hide-scene-layer fancy-tree-item.hidden.selected { + color: #999 !important; +} +.hide-scenetree fancy-tree-item.locked, +.hide-scene-layer fancy-tree-item.locked { + font-style: italic; +} +.hide-scenetree fancy-tree-item.disabled, +.hide-scene-layer fancy-tree-item.disabled { + color: #ee6666; +} +.hide-scenetree fancy-tree-item.inRef, +.hide-scene-layer fancy-tree-item.inRef { + --background: #3a3a3a; +} +.hide-scenetree fancy-tree-item.isOverride, +.hide-scene-layer fancy-tree-item.isOverride { + --background: #0c2346; +} +.hide-scenetree fancy-tree-item.isOverride.isOverriden, +.hide-scene-layer fancy-tree-item.isOverride.isOverriden { + color: cyan; +} +.hide-scenetree fancy-tree-item.isOverride.isOverriden.isOverridenNew, +.hide-scene-layer fancy-tree-item.isOverride.isOverriden.isOverridenNew { + color: #26c726; +} .hide-range { display: inline-block; } @@ -5001,8 +5041,8 @@ fancy-tree-item { background-color: hsl(from var(--background) h s calc(var(--highlight) + l)); display: flex; } -fancy-tree-item.hidden { - filter: opacity(40%); +fancy-tree-item.selected { + color: white; } fancy-tree-item.hide-search { overflow: hidden; @@ -5012,37 +5052,6 @@ fancy-tree-item.hide-search { fancy-tree-item.open > .caret::before { transform: rotate(90deg); } -fancy-tree-item.selected { - color: white; - --background: var(--selection); -} -fancy-tree-item.editorOnly { - color: #02aeda; -} -fancy-tree-item.inGameOnly { - color: #daa802; -} -fancy-tree-item.hidden { - color: #555; -} -fancy-tree-item.locked { - font-style: italic; -} -fancy-tree-item.disabled { - color: #ee6666; -} -fancy-tree-item.inRef { - --background: #3a3a3a; -} -fancy-tree-item.isOverride { - --background: #0c2346; -} -fancy-tree-item.isOverride.isOverriden { - color: cyan; -} -fancy-tree-item.isOverride.isOverriden.isOverridenNew { - color: #26c726; -} fancy-tree-item:has(fancy-tree-children .selected) > fancy-tree-header fancy-tree-name { text-decoration: underline var(--selection); } @@ -5155,6 +5164,9 @@ fancy-tree-item.feedback-drop-in::after { z-index: 10; pointer-events: none; } +fancy-tree-item.selected { + --background: var(--selection) !important; +} fancy-gallery { display: flex; flex-direction: column; diff --git a/bin/style.less b/bin/style.less index e4f0ea441..65881da07 100644 --- a/bin/style.less +++ b/bin/style.less @@ -589,6 +589,50 @@ input[type=checkbox] { border-radius: 3px; } +.hide-scenetree, .hide-scene-layer { + fancy-tree-item { + &.editorOnly { + color: rgb(2, 174, 218); + } + + &.inGameOnly { + color: rgb(218, 168, 2); + } + + &.hidden { + color: #666; + + &.selected { + color: #999 !important; + } + } + + &.locked { + font-style: italic; + } + + &.disabled { + color: #ee6666; + } + + &.inRef { + --background: rgb(58, 58, 58); + } + + &.isOverride { + --background: rgb(12, 35, 70); + } + + &.isOverride.isOverriden { + color: cyan; + } + + &.isOverride.isOverriden.isOverridenNew { + color: rgb(38, 199, 38); + } + } +} + @tileselect-cursor-border: 1px; @@ -5962,8 +6006,8 @@ fancy-tree-item { color: #aaa; - &.hidden { - filter: opacity(40%); + &.selected { + color: white; } &.hide-search { @@ -5976,47 +6020,6 @@ fancy-tree-item { transform: rotate(90deg); } - &.selected { - color: white; - --background: var(--selection); - } - - &.editorOnly { - color: rgb(2, 174, 218); - } - - &.inGameOnly { - color: rgb(218, 168, 2); - } - - &.hidden { - color: #555; - } - - &.locked { - font-style: italic; - } - - &.disabled { - color: #ee6666; - } - - &.inRef { - --background: rgb(58, 58, 58); - } - - &.isOverride { - --background: rgb(12, 35, 70); - } - - &.isOverride.isOverriden { - color: cyan; - } - - &.isOverride.isOverriden.isOverridenNew { - color: rgb(38, 199, 38); - } - // Select if we have a children that is selected &:has(fancy-tree-children .selected) > fancy-tree-header { fancy-tree-name { @@ -6030,10 +6033,6 @@ fancy-tree-item { outline-offset: -1px; } - // &:hover { - // background-color: var(--hover); - // } - fancy-button.quieter { --size: 16px; font-size: 12px; @@ -6173,6 +6172,10 @@ fancy-tree-item { z-index: 10; pointer-events: none; } + + &.selected { + --background: var(--selection) !important; + } } fancy-gallery { diff --git a/hide/comp/SceneEditor.hx b/hide/comp/SceneEditor.hx index 5ee3d4b41..5563dbeab 100644 --- a/hide/comp/SceneEditor.hx +++ b/hide/comp/SceneEditor.hx @@ -2090,7 +2090,7 @@ class SceneEditor { var parent = p.parent; while(parent != null) { path += parent.getUniqueName() + "/" + path; - parent = parent.parent; + parent = parent.parent ?? parent.shared.parentPrefab; } return path; } @@ -2620,8 +2620,8 @@ class SceneEditor { var tag = getTag(p); if(tag != null) { - el.style.background = tag.color; - el.style.color = tag.color + "90"; + el.style.setProperty("--background", tag.color + "80"); + el.style.color = tag.color; } else { el.style.background = null; From 8ef78c944c89ef83ce4bc196cc822d3ecc4af840 Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Tue, 26 Aug 2025 17:34:28 +0200 Subject: [PATCH 12/70] Image: fix metrics --- hide/view/Image.hx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hide/view/Image.hx b/hide/view/Image.hx index 54370adb4..58105877e 100644 --- a/hide/view/Image.hx +++ b/hide/view/Image.hx @@ -491,7 +491,7 @@ class Image extends FileView { } var compTexMemSize = element.find(".comp-tex-weight"); - compTexMemSize.text('Compressed texture weight : ${@:privateAccess floatToStringPrecision(compressedTexture.mem.memSize(compressedTexture) / (1024 * 1024)) } mb'); + compTexMemSize.text('Compressed texture weight : ${@:privateAccess floatToStringPrecision(compressedTexture.mem.memSize(compressedTexture) / (1024 * 1024)) } MB'); updateImageCompressionInfos(); applyShaderConfiguration(); @@ -659,7 +659,7 @@ class Image extends FileView { size.val(texMaxSize); var uncompTWeight = element.find(".uncomp-tex-weight"); - uncompTWeight.text('Uncompressed texture weight : ${getTextureMemSize(state.path)} mb'); + uncompTWeight.text('Uncompressed texture weight : ${getTextureMemSize(state.path)} MB'); nativeFormat.text(getTextureNativeFormat(state.path).getName()); } @@ -716,7 +716,7 @@ class Image extends FileView { } var compTexMemSize = element.find(".comp-tex-weight"); - compTexMemSize.text('Compressed texture weight : ${@:privateAccess floatToStringPrecision(t.mem.memSize(t) / (1024 * 1024)) } mb'); + compTexMemSize.text('Compressed texture weight : ${@:privateAccess floatToStringPrecision(t.mem.memSize(t) / (1024 * 1024)) } MB'); applyShaderConfiguration(); onResize(); From 6ffbbe73694f6b51511ddcc21f17124e7f0b8b4c Mon Sep 17 00:00:00 2001 From: Leonardo Jeanteur Date: Wed, 27 Aug 2025 09:07:28 +0200 Subject: [PATCH 13/70] Revert "Light : Removed Mode and Blur from cascade shadow" This reverts commit c1b4de35d149d9f1dea5ba6e6a93bb62fd98c80d. --- hrt/prefab/Light.hx | 46 ++++++++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/hrt/prefab/Light.hx b/hrt/prefab/Light.hx index 2003f9642..f22938af2 100644 --- a/hrt/prefab/Light.hx +++ b/hrt/prefab/Light.hx @@ -209,13 +209,6 @@ class Light extends Object3D { if( light != null ) { // PBR light.isMainLight = isMainLight; light.occlusionFactor = occlusionFactor; - light.color.setColor(color); - light.power = power; - light.shadows.mode = shadows.mode; - light.shadows.size = shadows.size; - light.shadows.blur.radius = shadows.radius; - light.shadows.blur.quality = shadows.quality; - light.shadows.bias = shadows.bias * 0.1; switch( kind ) { case Directional: @@ -236,8 +229,6 @@ class Light extends Object3D { cs.castingMaxDist = castingMaxDist; cs.transitionFraction = transitionFraction; cs.debugShader = debugShader; - cs.blur.radius = 0.0; - cs.mode = Dynamic; params.resize(cascadeNbr); for ( i in 0...params.length ) if ( params[i] == null ) @@ -273,6 +264,13 @@ class Light extends Object3D { rec.fallOff = fallOff; default: } + light.color.setColor(color); + light.power = power; + light.shadows.mode = shadows.mode; + light.shadows.size = shadows.size; + light.shadows.blur.radius = shadows.radius; + light.shadows.blur.quality = shadows.quality; + light.shadows.bias = shadows.bias * 0.1; switch (shadows.samplingMode.kind) { case None: @@ -667,6 +665,15 @@ class Light extends Object3D { var shadowGroup = new hide.Element('
+
Mode
+
+ +
Size
-
-
Mode
-
- -
-
Blur Radius
-
Blur Quality
+
Blur Radius
+
Blur Quality
+
Bias
Sampling Mode
@@ -705,11 +703,11 @@ class Light extends Object3D {
'); - var nonCascadeParamsEl = shadowGroup.find(".nonCascadeParams"); + var biasEl = shadowGroup.find(".bias"); if ( cascade ) - nonCascadeParamsEl.hide(); + biasEl.hide(); else - nonCascadeParamsEl.show(); + biasEl.show(); switch (shadows.samplingMode.kind) { case None: From 1fae9eeb2e0f59191209b7f6ed1f7230943d7693 Mon Sep 17 00:00:00 2001 From: Leonardo Jeanteur Date: Wed, 27 Aug 2025 09:07:40 +0200 Subject: [PATCH 14/70] Revert "Light : minor naming improvement" This reverts commit 1f44b5d1e1c9d970230932b180fe520aed2bdbd9. --- hrt/prefab/Light.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hrt/prefab/Light.hx b/hrt/prefab/Light.hx index f22938af2..ee5c433fb 100644 --- a/hrt/prefab/Light.hx +++ b/hrt/prefab/Light.hx @@ -222,7 +222,7 @@ class Light extends Object3D { var cs = Std.downcast(s, h3d.pass.CascadeShadowMap); if ( cs != null ) { cs.cascade = cascadeNbr; - cs.ditributionPower = cascadePow; + cs.pow = cascadePow; cs.firstCascadeSize = firstCascadeSize; cs.minPixelSize = minPixelSize; cs.debug = debugDisplay; @@ -739,7 +739,7 @@ class Light extends Object3D {
Number
Min pixel size
First cascade size
-
Distribution power
+
Range power
Casting max dist
Transition fraction
From 4a83d886338aa88cc61a5d2a34d1982ccac1c593 Mon Sep 17 00:00:00 2001 From: lviguier Date: Wed, 27 Aug 2025 09:53:36 +0200 Subject: [PATCH 15/70] Blendshapes: enable blenshape visualization --- hide/view/Model.hx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hide/view/Model.hx b/hide/view/Model.hx index ee1d8966e..87581fd11 100644 --- a/hide/view/Model.hx +++ b/hide/view/Model.hx @@ -594,8 +594,7 @@ class Model extends FileView {
'); properties.add(blendShape, null, function(pname){ - //! WIP Disable blendshape - // @:privateAccess hmd.blendshape.setBlendShapeWeight(mesh, blendShape.find("#bs-index").val(), blendShape.find("#bs-amount").val()); + @:privateAccess hmd.blendshape.setBlendShapeWeight(mesh, blendShape.find("#bs-index").val(), blendShape.find("#bs-amount").val()); }); } From 82aa247d8a46179877bd6e6bf17ab60d3f30ba40 Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Wed, 27 Aug 2025 10:46:24 +0200 Subject: [PATCH 16/70] Reapply "Light : minor naming improvement" This reverts commit 1fae9eeb2e0f59191209b7f6ed1f7230943d7693. Reapply "Light : Removed Mode and Blur from cascade shadow" This reverts commit 6ffbbe73694f6b51511ddcc21f17124e7f0b8b4c. --- hrt/prefab/Light.hx | 50 +++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/hrt/prefab/Light.hx b/hrt/prefab/Light.hx index ee5c433fb..2003f9642 100644 --- a/hrt/prefab/Light.hx +++ b/hrt/prefab/Light.hx @@ -209,6 +209,13 @@ class Light extends Object3D { if( light != null ) { // PBR light.isMainLight = isMainLight; light.occlusionFactor = occlusionFactor; + light.color.setColor(color); + light.power = power; + light.shadows.mode = shadows.mode; + light.shadows.size = shadows.size; + light.shadows.blur.radius = shadows.radius; + light.shadows.blur.quality = shadows.quality; + light.shadows.bias = shadows.bias * 0.1; switch( kind ) { case Directional: @@ -222,13 +229,15 @@ class Light extends Object3D { var cs = Std.downcast(s, h3d.pass.CascadeShadowMap); if ( cs != null ) { cs.cascade = cascadeNbr; - cs.pow = cascadePow; + cs.ditributionPower = cascadePow; cs.firstCascadeSize = firstCascadeSize; cs.minPixelSize = minPixelSize; cs.debug = debugDisplay; cs.castingMaxDist = castingMaxDist; cs.transitionFraction = transitionFraction; cs.debugShader = debugShader; + cs.blur.radius = 0.0; + cs.mode = Dynamic; params.resize(cascadeNbr); for ( i in 0...params.length ) if ( params[i] == null ) @@ -264,13 +273,6 @@ class Light extends Object3D { rec.fallOff = fallOff; default: } - light.color.setColor(color); - light.power = power; - light.shadows.mode = shadows.mode; - light.shadows.size = shadows.size; - light.shadows.blur.radius = shadows.radius; - light.shadows.blur.quality = shadows.quality; - light.shadows.bias = shadows.bias * 0.1; switch (shadows.samplingMode.kind) { case None: @@ -665,15 +667,6 @@ class Light extends Object3D { var shadowGroup = new hide.Element('
-
Mode
-
- -
Size
-
Blur Radius
-
Blur Quality
-
+
+
Mode
+
+ +
+
Blur Radius
+
Blur Quality
Bias
Sampling Mode
@@ -703,11 +705,11 @@ class Light extends Object3D {
'); - var biasEl = shadowGroup.find(".bias"); + var nonCascadeParamsEl = shadowGroup.find(".nonCascadeParams"); if ( cascade ) - biasEl.hide(); + nonCascadeParamsEl.hide(); else - biasEl.show(); + nonCascadeParamsEl.show(); switch (shadows.samplingMode.kind) { case None: @@ -739,7 +741,7 @@ class Light extends Object3D {
Number
Min pixel size
First cascade size
-
Range power
+
Distribution power
Casting max dist
Transition fraction
From 395bc8ca32a8cb7133425f688cb3b82f6eefccaf Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Wed, 27 Aug 2025 14:07:34 +0200 Subject: [PATCH 17/70] Light : Fix mode selection with None --- hrt/prefab/Light.hx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hrt/prefab/Light.hx b/hrt/prefab/Light.hx index 2003f9642..2f354cb79 100644 --- a/hrt/prefab/Light.hx +++ b/hrt/prefab/Light.hx @@ -667,6 +667,15 @@ class Light extends Object3D { var shadowGroup = new hide.Element('
+
Mode
+
+ +
Size
-
Mode
-
- -
Blur Radius
Blur Quality
Bias
From 4c03677851bb3fe69c2a8e76b1d1ca113e86e098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Thu, 28 Aug 2025 08:32:54 +0200 Subject: [PATCH 18/70] [cdb] Fix undo state being corrupted after a while --- hide/comp/cdb/Editor.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hide/comp/cdb/Editor.hx b/hide/comp/cdb/Editor.hx index 22135d51a..0473884b1 100644 --- a/hide/comp/cdb/Editor.hx +++ b/hide/comp/cdb/Editor.hx @@ -1003,7 +1003,7 @@ class Editor extends Component { **/ public function beginChanges( ?structure : Bool ) { if (undoState.length >= @:privateAccess undo.maxHistoryCount) - undoState.shift(); + undoState.pop(); if( changesDepth == 0 ) undoState.unshift(getState()); changesDepth++; From 780df94c509a5439aa40c885355976fbff1e8f48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Thu, 28 Aug 2025 14:07:34 +0200 Subject: [PATCH 19/70] [cdb] Style refacto and hide validation filters if no validation in table --- bin/cdb.css | 34 +++++++++++++++++----------------- bin/cdb.less | 28 ++++++++++++++-------------- bin/style.css | 24 +++++++----------------- bin/style.less | 24 +++++++----------------- hide/comp/cdb/Editor.hx | 20 +++++++++----------- hide/comp/cdb/Table.hx | 7 ------- hide/view/CdbTable.hx | 19 ++++++++++++++----- 7 files changed, 68 insertions(+), 88 deletions(-) diff --git a/bin/cdb.css b/bin/cdb.css index 547437a3e..12daebad2 100644 --- a/bin/cdb.css +++ b/bin/cdb.css @@ -9,9 +9,6 @@ padding: 0 5px 0 5px; border-top: solid 1px black; border-bottom: solid 1px black; - position: sticky; - z-index: 50; - top: 0; background-color: #222222; } .cdb-view .top-bar span { @@ -45,18 +42,30 @@ color: #e12729; } .cdb-view .cdb { - margin-bottom: 350px; + overflow-y: scroll; +} +.cdb-view .cdb > table { + margin-bottom: 200px; } .cdb-view.cdb-diff .cdb-sheet th, .cdb-view.cdb-diff th.start { background-color: #d60; } .cdb { - background-color: black; + height: 100%; } .cdb:focus { outline: none; } +.cdb .cdb-sheet { + overflow-x: auto; + width: 100%; + table-layout: fixed; + border-collapse: collapse; + border-spacing: 0; + background-color: #222; + position: relative; +} .cdb .cdb-sheet td.cursorView { outline: 2px solid #ccc !important; outline-offset: -1px; @@ -104,14 +113,6 @@ .cdb .cdb-sheet td.selected.left { border-left: 1px solid #ccc; } -.cdb .cdb-sheet { - width: 100%; - table-layout: fixed; - border-collapse: collapse; - border-spacing: 0; - background-color: #222; - position: relative; -} .cdb .cdb-sheet th.start { width: 30px; border-left-color: #333; @@ -131,7 +132,7 @@ } .cdb .cdb-sheet tr.separator td { position: sticky; - top: 39px; + top: 19px; z-index: 2; border-left: none; padding-top: 6px; @@ -237,10 +238,9 @@ .cdb .cdb-sheet tr.clickable:hover { background-color: #f8f8f8; } -.cdb .cdb-sheet:not(.cdb-sub-sheet) > thead.head > th { +.cdb .cdb-sheet:not(.cdb-sub-sheet) > thead.head { position: sticky; - z-index: 600; - top: 20px; + top: 0; } .cdb .cdb-sheet tr.head, .cdb .cdb-sheet th { diff --git a/bin/cdb.less b/bin/cdb.less index c4ba01ece..e8945f525 100644 --- a/bin/cdb.less +++ b/bin/cdb.less @@ -16,9 +16,6 @@ padding: 0 5px 0 5px; border-top: solid @border-size @border-color; border-bottom: solid @border-size @border-color; - position: sticky; - z-index: 50; - top: 0; background-color: #222222; span { @@ -64,8 +61,14 @@ } .cdb { - margin-bottom: 350px; + overflow-y: scroll; + + > table { + margin-bottom: 200px; + } } + + } .cdb-view.cdb-diff { @@ -75,14 +78,16 @@ } .cdb { - - background-color : black; + height: 100%; + //background-color : black; &:focus { outline: none; } .cdb-sheet { + overflow-x: auto; + td.cursorView { outline: 2px solid #ccc !important; outline-offset: -1px; @@ -120,10 +125,6 @@ &.bot { border-bottom: 1px solid #ccc; } &.left { border-left: 1px solid #ccc; } } - } - - - .cdb-sheet { width : 100%; table-layout:fixed; @@ -153,7 +154,7 @@ height : 10px; td { position: sticky; - top: 39px; + top: 19px; z-index: 2; border-left: none; padding-top: 6px; @@ -263,10 +264,9 @@ background-color : #f8f8f8; } - &:not(.cdb-sub-sheet) > thead.head > th { + &:not(.cdb-sub-sheet) > thead.head { position: sticky; - z-index: @header-layer; - top: 20px; + top: 0; } tr.head, th { diff --git a/bin/style.css b/bin/style.css index e92b5e2c7..7945e1466 100644 --- a/bin/style.css +++ b/bin/style.css @@ -941,6 +941,8 @@ input[type=checkbox].indeterminate:after { flex: 0 0 320px; position: relative; height: 100%; + display: flex; + flex-direction: column; } .hide-tabs.masked { flex: none; @@ -973,6 +975,7 @@ input[type=checkbox].indeterminate:after { background-color: #111; padding: 2px; padding-bottom: 0px; + flex: 0 0; } .hide-tabs .tabs-header > div { cursor: pointer; @@ -1001,31 +1004,18 @@ input[type=checkbox].indeterminate:after { display: none; } .hide-tabs .tab { - max-height: 100%; - width: 100%; + flex: 1 1; + min-width: 0; + min-height: 0; display: flex; flex-direction: column; - position: absolute; } .hide-tabs .tab.expand { width: 100%; height: 100%; } .hide-tabs.tabs-bottom > .tabs-header { - width: 100%; - position: absolute; - bottom: 0px; - padding-top: 0px; - padding-bottom: 5px; - z-index: 600; -} -.hide-tabs.tabs-bottom > .tabs-header > div { - border-top: none; - border-top-right-radius: 0; - border-bottom-right-radius: 5px; -} -.hide-tabs.tabs-bottom > .tabs-header > div.active { - border-radius: 0px; + order: 9999; } .search-box { position: fixed; diff --git a/bin/style.less b/bin/style.less index 65881da07..e0d2a2a0b 100644 --- a/bin/style.less +++ b/bin/style.less @@ -1022,6 +1022,8 @@ input[type=checkbox] { flex : 0 0 320px; position: relative; height: 100%; + display: flex; + flex-direction: column; &.masked { & > * { @@ -1056,6 +1058,7 @@ input[type=checkbox] { background-color : #111; padding : 2px; padding-bottom : 0px; + flex: 0 0; &>div { cursor : pointer; display : inline-block; @@ -1084,11 +1087,11 @@ input[type=checkbox] { } } .tab { - max-height: 100%; - width: 100%; + flex: 1 1; + min-width: 0; + min-height: 0; display: flex; flex-direction: column; - position: absolute; &.expand { width: 100%; height: 100%; @@ -1098,20 +1101,7 @@ input[type=checkbox] { .hide-tabs.tabs-bottom { >.tabs-header { - width:100%; - position: absolute; - bottom : 0px; - padding-top : 0px; - padding-bottom : 5px; - z-index: @header-layer; - &>div { - border-top : none; - border-top-right-radius: 0; - border-bottom-right-radius: 5px; - &.active { - border-radius: 0px; - } - } + order: 9999; } } diff --git a/hide/comp/cdb/Editor.hx b/hide/comp/cdb/Editor.hx index 0473884b1..d117c3609 100644 --- a/hide/comp/cdb/Editor.hx +++ b/hide/comp/cdb/Editor.hx @@ -236,14 +236,13 @@ class Editor extends Component { cursor.move( e.shiftKey ? -1 : 1, 0, false, false, true); return true; case K.PGUP: - var scrollView = element.parent(".hide-scroll"); - var stickyElHeight = scrollView.find(".separator").height(); + var stickyElHeight = element.find(".separator").height(); if (Math.isNaN(stickyElHeight)) - stickyElHeight = scrollView.find("thead").outerHeight(); + stickyElHeight = element.find("thead").outerHeight(); else - stickyElHeight += scrollView.find("thead").outerHeight(); + stickyElHeight += element.find("thead").outerHeight(); - var lines = scrollView.find("tbody").find(".start"); + var lines = element.find("tbody").find(".start"); var idx = lines.length - 1; while (idx >= 0) { var b = lines[idx].getBoundingClientRect(); @@ -256,13 +255,12 @@ class Editor extends Component { lines.get(idx).scrollIntoView({ block: js.html.ScrollLogicalPosition.END }); // Handle sticky elements - scrollView.scrollTop(scrollView.scrollTop() + scrollView.parent().siblings(".tabs-header").outerHeight()); + element.scrollTop(element.scrollTop() + element.parent().siblings(".tabs-header").outerHeight()); return true; case K.PGDOWN: - var scrollView = element.parent(".hide-scroll"); - var height = scrollView.outerHeight() - (scrollView.find("thead").outerHeight() + scrollView.parent().siblings(".tabs-header").outerHeight()); - var lines = scrollView.find("tbody").find(".start"); + var height = element.outerHeight() - (element.find("thead").outerHeight() + element.parent().siblings(".tabs-header").outerHeight()); + var lines = element.find("tbody").find(".start"); var idx = 0; for (el in lines) { var b = el.getBoundingClientRect(); @@ -277,10 +275,10 @@ class Editor extends Component { cursor.setDefault(cursor.table, cursor.x, idx); // Handle sticky elements - var sepHeight = scrollView.find(".separator").height(); + var sepHeight = element.find(".separator").height(); if (Math.isNaN(sepHeight)) sepHeight = 0; - scrollView.scrollTop(scrollView.scrollTop() - (scrollView.find("thead").height() + sepHeight)); + element.scrollTop(element.scrollTop() - (element.find("thead").height() + sepHeight)); return true; case K.SPACE: diff --git a/hide/comp/cdb/Table.hx b/hide/comp/cdb/Table.hx index 984e59bae..cd8649478 100644 --- a/hide/comp/cdb/Table.hx +++ b/hide/comp/cdb/Table.hx @@ -123,13 +123,6 @@ class Table extends Component { function setupTableElement() { cloneTableHead(); - #if js - @:privateAccess { - var elt = editor.element.parent(); - var scrollbarWidth = elt.parent().width() - elt.width(); - element.width(@:privateAccess editor.cdbTable.contentWidth - scrollbarWidth); // prevent to reflow all cdb-view - } - #end } function cloneTableHead() { diff --git a/hide/view/CdbTable.hx b/hide/view/CdbTable.hx index aa47648db..22f22c012 100644 --- a/hide/view/CdbTable.hx +++ b/hide/view/CdbTable.hx @@ -8,6 +8,7 @@ class CdbTable extends hide.ui.View<{}> { var tabCache : String; var tabs : hide.comp.Tabs; var view : cdb.DiffFile.ConfigView; + var topBar : Element; public function new( ?state ) { super(state); @@ -202,6 +203,14 @@ class CdbTable extends hide.ui.View<{}> { editor.show(sheets[index],tabContents[index]); currentSheet = editor.getCurrentSheet(); ide.currentConfig.set("cdb.currentSheet", sheets[index].name); + + var validationFunc = @:privateAccess editor.formulas?.validationFuncs?.get(currentSheet); + if (validationFunc == null) { + topBar.get(0).style.display = "none"; + } else { + topBar.get(0).style.display = null; + } + haxe.Timer.delay(editor.focus,1); } @@ -225,8 +234,7 @@ class CdbTable extends hide.ui.View<{}> { tabContents = []; for( sheet in sheets ) { var tab = tabs == null ? element : tabs.createTab(sheet.name); - var sc = new hide.comp.Scrollable(tab); - tabContents.push(sc.element); + tabContents.push(tab); } if( tabs != null ) { tabs.onTabChange = setEditor; @@ -250,12 +258,12 @@ class CdbTable extends hide.ui.View<{}> { }; } - var topBar = new Element('
+ topBar = new Element('

0

0

0

'); - topBar.prependTo(element.find(".hide-scroll")); + tabs.element.prepend(topBar); function filterListener(el : Element, flag : hide.comp.cdb.Editor.FilterFlag) { var disabled = el.hasClass("disabled"); @@ -276,6 +284,7 @@ class CdbTable extends hide.ui.View<{}> { var errorEl = element.find(".error"); errorEl.on("click", function(e) { filterListener(errorEl, Error); }); + if( sheets.length > 0 ) { var idx = 0; for( i in 0...sheets.length ) @@ -283,7 +292,7 @@ class CdbTable extends hide.ui.View<{}> { idx = i; break; } - tabs.currentTab = tabContents[idx].parent(); + tabs.currentTab = tabContents[idx]; } applyCategories(ide.projectConfig.dbCategories, false); From 2164fde0d691b478a356925c0efbdf500f1e43f1 Mon Sep 17 00:00:00 2001 From: lviguier Date: Thu, 28 Aug 2025 16:12:53 +0200 Subject: [PATCH 20/70] RendererFXVolume: Move RFXVolume from hide to game --- hrt/prefab/rfx/RendererFXVolume.hx | 238 ----------------------------- 1 file changed, 238 deletions(-) delete mode 100644 hrt/prefab/rfx/RendererFXVolume.hx diff --git a/hrt/prefab/rfx/RendererFXVolume.hx b/hrt/prefab/rfx/RendererFXVolume.hx deleted file mode 100644 index b5b680a58..000000000 --- a/hrt/prefab/rfx/RendererFXVolume.hx +++ /dev/null @@ -1,238 +0,0 @@ -package hrt.prefab.rfx; - -typedef DebugVolume = { - var color : Int; - var mesh : h3d.scene.Mesh; -} - -class RendererFXVolume extends Object3D { - @:s public var priority : Int; - @:c public var innerShape : h3d.impl.RendererFXVolume.Shape; - @:c public var outerShape : h3d.impl.RendererFXVolume.Shape; - - @:s var debug : Bool = false; - var innerShapeDebug = { color : 0xFFFF00FF, mesh : null }; - var outerShapeDebug = { color : 0xFF00EEFF, mesh : null }; - - public override function new(parent:Prefab, contextShared: ContextShared) { - super(parent, contextShared); - this.innerShape = Sphere(1); - this.outerShape = Sphere(1); - } - - override function load(data: Dynamic) { - super.load(data); - - function loadShape(shape : Dynamic) : h3d.impl.RendererFXVolume.Shape { - if (shape == null) - return Sphere(1); - - return switch (shape.shape) { - case 0: - return Sphere(shape.radius); - case 1: - return Box(shape.width, shape.height); - default: - throw "not implemented"; - }; - } - - this.innerShape = loadShape(data.innerShape); - this.outerShape = loadShape(data.outerShape); - } - - override function copy(data: Dynamic) : Void { - super.copy(data); - - var s : RendererFXVolume = cast data; - this.load(s.save()); - } - - override function save() : Dynamic { - var obj = super.save(); - - function saveShape(shape : h3d.impl.RendererFXVolume.Shape) : Dynamic { - if (shape == null) - return { shape: 0, radius: 1 }; - - return switch (shape) { - case Sphere(radius): - { shape: 0, radius: radius }; - case Box(width, height): - { shape: 1, width: width, height: height }; - default: - throw { shape: 0, radius: 1 }; - }; - } - - obj.innerShape = saveShape(this.innerShape); - obj.outerShape = saveShape(this.outerShape); - return obj; - } - - override function makeObject(parent3d: h3d.scene.Object) { - var o = new h3d.impl.RendererFXVolume(parent3d); - o.innerShape = this.innerShape; - o.outerShape = this.outerShape; - o.priority = this.priority; - - return o; - } - - override function postMakeInstance() { - var o : h3d.impl.RendererFXVolume = cast local3d; - var rendererFxs : Array = cast findAll((p) -> { return Std.isOfType(p, RendererFX) && p.enabled; }); - o.effects = []; - for (r in rendererFxs) - o.effects.push(@:privateAccess r.instance); - } - - override function updateInstance(?propName : String) { - super.updateInstance(propName); - - var volume : h3d.impl.RendererFXVolume = cast local3d; - volume.innerShape = this.innerShape; - volume.outerShape = this.outerShape; - volume.priority = this.priority; - - function applyDebug(sprDebug : DebugVolume, shape : h3d.impl.RendererFXVolume.Shape) { - if (sprDebug != null) { - sprDebug.mesh.remove(); - sprDebug.mesh = null; - } - - if (!debug) return; - - sprDebug.mesh = new h3d.scene.Mesh(createPrim(shape), local3d); - sprDebug.mesh.name = "SpatialRendererFXDebug"; - sprDebug.mesh.material.mainPass.depth(true, LessEqual); - var s = new h3d.shader.AlphaMult(); - s.alpha = 0.3; - sprDebug.mesh.material.mainPass.addShader(s); - sprDebug.mesh.material.blendMode = Alpha; - sprDebug.mesh.material.mainPass.setPassName("overlay"); - sprDebug.mesh.ignoreParentTransform = false; - var c = hrt.impl.ColorSpace.Color.fromInt(sprDebug.color); - hrt.impl.ColorSpace.iRGBtofRGB(c, sprDebug.mesh.material.color); - } - - applyDebug(innerShapeDebug, this.innerShape); - applyDebug(outerShapeDebug, this.outerShape); - } - - #if editor - override function getHideProps() : hide.prefab.HideProps { - return { name : Type.getClassName(Type.getClass(this)).split(".").pop(), icon : "cubes" }; - } - - override function edit(ctx:hide.prefab.EditContext) { - var e = new hide.Element(' -
-
-
Debug
-
Priority
-
Shape
-
-
-
-
- '); - - var shapeSel = e.find("#shape-sel"); - for (idx => el in Type.getEnumConstructs(h3d.impl.RendererFXVolume.Shape)) - shapeSel.append(new hide.Element('')); - shapeSel.on("change", function(e) { - var prevInner = this.innerShape; - var prevOuter = this.outerShape; - - switch (shapeSel.val()) { - case "Sphere": - this.innerShape = Sphere(10); - this.outerShape = Sphere(15); - case "Box": - this.innerShape = Box(10, 10); - this.outerShape = Box(15, 15); - default: - } - - var newInner = this.innerShape; - var newOuter = this.outerShape; - - ctx.properties.undo.change(Custom(function(undo) { - this.innerShape = undo ? prevInner : newInner; - this.outerShape = undo ? prevOuter : newOuter; - ctx.rebuildProperties(); - })); - - ctx.rebuildProperties(); - }); - - var paramsEl = e.find("#params"); - var param : hide.Element = null; - function onChange() { - var prevInner = this.innerShape; - var prevOuter = this.outerShape; - - switch (this.innerShape) { - case Sphere(_): - this.innerShape = Sphere(Std.parseFloat(param.find('#innerRadius').val())); - this.outerShape = Sphere(Std.parseFloat(param.find('#outerRadius').val())); - case Box(_): - } - - var newInner = this.innerShape; - var newOuter = this.outerShape; - - ctx.properties.undo.change(Custom(function(undo) { - this.innerShape = undo ? prevInner : newInner; - this.outerShape = undo ? prevOuter : newOuter; - ctx.rebuildProperties(); - this.updateInstance(); - })); - - this.updateInstance(); - } - switch ([this.innerShape, this.outerShape]) { - case [Sphere(r1), Sphere(r2)]: - param = new hide.Element('
-
Inner radius
-
Outer Radius
-
'); - - function setup(e : hide.Element, value : Dynamic) { - e.val(value); - e.on("change", () -> onChange()); - } - setup(param.find('#innerRadius'), r1); - setup(param.find('#outerRadius'), r2); - - default: - param = new hide.Element('

Not supported

'); - } - paramsEl.append(param); - ctx.properties.add(e, this); - } - #end - - function createPrim(shape : h3d.impl.RendererFXVolume.Shape) : h3d.prim.Primitive { - switch(shape) { - case Sphere(radius): - var prim = new h3d.prim.Sphere(radius, 64, 64); - prim.addNormals(); - prim.addUVs(); - return prim; - case Box(width, height): - var prim = new h3d.prim.Cube(width); - prim.addNormals(); - prim.addUVs(); - return prim; - } - } - - public function getFactor(pos : h3d.col.Point) : Float { - if (local3d == null) return 0.; - return cast(local3d, h3d.impl.RendererFXVolume).getFactor(pos); - } - - static var _ = Prefab.register("RendererFXVolume", RendererFXVolume); -} \ No newline at end of file From caf4933858384e71fab8f4767ea5220cb2dd2e1f Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Thu, 28 Aug 2025 17:39:04 +0200 Subject: [PATCH 21/70] Better naming for material override --- hrt/prefab/Material.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrt/prefab/Material.hx b/hrt/prefab/Material.hx index 2a39eddb7..3557d1ba9 100644 --- a/hrt/prefab/Material.hx +++ b/hrt/prefab/Material.hx @@ -652,7 +652,7 @@ class Material extends Prefab { var dropDownMaterials = new hide.Element('
-
Name
+
Target material
'); var select = dropDownMaterials.find("select"); var materialList = findFirstLocal3d()?.getMaterials(); From 6de471e912e8da74c010f7369aec462f9a07edae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 29 Aug 2025 08:27:19 +0200 Subject: [PATCH 22/70] [cdb] Patching jquery crimes --- hide/view/CdbTable.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hide/view/CdbTable.hx b/hide/view/CdbTable.hx index 22f22c012..8137cb902 100644 --- a/hide/view/CdbTable.hx +++ b/hide/view/CdbTable.hx @@ -45,8 +45,8 @@ class CdbTable extends hide.ui.View<{}> { return; } - if (tabs.currentTab.get(0) != tabContents[index].parent().get(0)) - tabs.currentTab = tabContents[index].parent(); + if (tabs.currentTab.get(0) != tabContents[index].get(0)) + tabs.currentTab = tabContents[index]; @:privateAccess editor.filters = []; @:privateAccess editor.updateFilters(); From 012b534647c6c37d485640c3f932d435f97676e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 29 Aug 2025 09:55:06 +0200 Subject: [PATCH 23/70] [cdb] Fix more janky jquery --- hide/view/CdbTable.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hide/view/CdbTable.hx b/hide/view/CdbTable.hx index 8137cb902..2e708c400 100644 --- a/hide/view/CdbTable.hx +++ b/hide/view/CdbTable.hx @@ -152,7 +152,7 @@ class CdbTable extends hide.ui.View<{}> { return; } - tabs.currentTab = tabContents[index].parent(); + tabs.currentTab = tabContents[index]; @:privateAccess editor.filters = []; @:privateAccess editor.updateFilters(); if( line != null ) { From a74b7bbb341b80555cb81b20bf6ce18a38423eb8 Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Fri, 29 Aug 2025 10:18:47 +0200 Subject: [PATCH 24/70] Fix target material with Material Library --- hrt/prefab/Material.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/hrt/prefab/Material.hx b/hrt/prefab/Material.hx index 3557d1ba9..42d6fa73c 100644 --- a/hrt/prefab/Material.hx +++ b/hrt/prefab/Material.hx @@ -254,6 +254,7 @@ class Material extends Prefab { var propsToApply = currMat.renderProps(); propsToApply = applyOverrides(propsToApply); + currMat.materialName = materialName; currMat.applyTo(local3d, propsToApply, shared); } From 93a81484a530d90bae97a0326665618d847b828d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 29 Aug 2025 11:21:37 +0200 Subject: [PATCH 25/70] [cdb] Fix gradient editor --- hide/comp/cdb/Cell.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hide/comp/cdb/Cell.hx b/hide/comp/cdb/Cell.hx index d19a403a1..3eaeed2cb 100644 --- a/hide/comp/cdb/Cell.hx +++ b/hide/comp/cdb/Cell.hx @@ -1248,7 +1248,7 @@ class Cell { var e = new Element(elementHtml); e.addClass("edit"); if (editor.gradientEditor == null) { - editor.gradientEditor = new GradientEditor(editor.element.parents(".hide-scroll").first(), false); + editor.gradientEditor = new GradientEditor(editor.element, false); editor.gradientEditor.keepPreviewAlive = true; } editor.gradientEditor.anchor = e; From b851c784e45531456b29bf026688899ec6c39b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 29 Aug 2025 12:30:23 +0200 Subject: [PATCH 26/70] [shgragh] Cleanup macros --- hrt/shgraph/Macros.hx | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/hrt/shgraph/Macros.hx b/hrt/shgraph/Macros.hx index 1a8a47d2b..666bbe903 100644 --- a/hrt/shgraph/Macros.hx +++ b/hrt/shgraph/Macros.hx @@ -107,8 +107,7 @@ class Macros { } expr.iter(iter); - var shader = new hxsl.MacroParser().parseExpr(expr); - f.kind = FVar(null, macro @:pos(pos) $v{shader}); + var shaderExpr = new hxsl.MacroParser().parseExpr(expr); var name = Std.string(c); var check = new hxsl.Checker(); @@ -118,30 +117,15 @@ class Macros { check.loadShader = loadShader; - var shader = check.check(name, shader); - //trace(shader); - //Printer.check(shader); + var shader = check.check(name, shaderExpr); var serializer = new hxsl.Serializer(); - var str = Context.defined("display") ? "" : serializer.serialize(shader); + var str = serializer.serialize(shader); f.kind = FVar(null, { expr : EConst(CString(str)), pos : pos } ); f.meta.push({ name : ":keep", pos : pos, }); - function makeField(name: String, arr: Array) : Field - { - return { - name: name, - access: [APublic, AStatic], - kind: FVar(macro : Array, macro $v{arr}), - pos: f.pos, - meta: [{ - name : ":keep", - pos : pos,} - ], - }; - } var finalMap : Map = []; From 36c6f2f1f38a8b1400ebff8d3aea3559f36239b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 29 Aug 2025 12:30:56 +0200 Subject: [PATCH 27/70] [shgraph] Fix sgNodes using SgInput/Output variables --- hrt/shgraph/ShaderNodeHxsl.hx | 116 +++++++++++++++++++++++++++++----- 1 file changed, 101 insertions(+), 15 deletions(-) diff --git a/hrt/shgraph/ShaderNodeHxsl.hx b/hrt/shgraph/ShaderNodeHxsl.hx index a177bcaaf..fbe577687 100644 --- a/hrt/shgraph/ShaderNodeHxsl.hx +++ b/hrt/shgraph/ShaderNodeHxsl.hx @@ -7,7 +7,18 @@ import hrt.tools.MapUtils; using Lambda; -typedef CacheEntry = {expr: TExpr, funs: Array, inputs: Array, outputs: Array, idInputOrder: Map, idOutputOrder: Map}; +typedef FunctionCache = { + fun: TFunction, + useSgIO: Bool, +} +typedef CacheEntry = { + expr: TExpr, + funs: Array, + inputs: Array, + outputs: Array, + idInputOrder: Map, + idOutputOrder: Map, +}; class CustomSerializer extends hxsl.Serializer { @@ -83,18 +94,6 @@ class ShaderNodeHxsl extends ShaderNode { var unser = new CustomSerializer(); var data = @:privateAccess unser.unserialize(toUnser); - var funs = []; - var expr : TExpr = null; - for (fn in data.funs) { - if (fn.ref.name == "fragment") { - expr = fn.expr; - break; - } else { - fn.ref.name = shortName + "_" + fn.ref.name; // De-duplicate function name if multiple nodes declare the same function name to avoid conflics - funs.push(fn); - } - } - var inputs : Array = []; var outputs : Array = []; var idInputOrder : Map = []; @@ -117,6 +116,42 @@ class ShaderNodeHxsl extends ShaderNode { } } + var funs : Array = []; + var expr : TExpr = null; + for (fn in data.funs) { + if (fn.ref.name == "fragment") { + expr = fn.expr; + break; + } else { + fn.ref.name = shortName + "_" + fn.ref.name; // De-duplicate function name if multiple nodes declare the same function name to avoid conflics + + var useSgIO = false; + function hasShaderInput(e: TExpr) : Void { + switch (e.e) { + case TVar(v): + switch(infos.get(v.id)) { + case SgInput(isDynamic, defaultValue): + useSgIO = true; + return; + case SgOutput(_): + useSgIO = true; + case null: + default: + } + default: + if (!useSgIO) + e.iter(hasShaderInput); + } + }; + fn.expr.iter(hasShaderInput); + + funs.push({ + fun: fn, + useSgIO: useSgIO, + }); + } + } + return {expr: expr, funs: funs, inputs: inputs, outputs: outputs, idInputOrder: idInputOrder, idOutputOrder: idOutputOrder}; } @@ -225,7 +260,58 @@ class ShaderNodeHxsl extends ShaderNode { } } + var funs: Array = []; + + for (fun in cache.funs) { + + if (fun.useSgIO) { + // If the function use input/outputs, we need to duplicate it per Node invocation, + // because we need to patch the function to properly set the input/outputs + var fun = fun.fun; + var tvar = MapUtils.getOrPut(varsRemap, fun.ref.id, + { + name: '${fun.ref.name}_$id', + id: hxsl.Ast.Tools.allocVarId(), + type: fun.ref.type, + kind: fun.ref.kind, + parent: fun.ref.parent, + qualifiers: fun.ref.qualifiers, + }); + + var args : Array = []; + for (arg in fun.args) { + var tvar = MapUtils.getOrPut(varsRemap, arg.id, + { + name: arg.name, + id: hxsl.Ast.Tools.allocVarId(), + type: arg.type, + kind: arg.kind, + parent: arg.parent, + qualifiers: arg.qualifiers, + }); + args.push(tvar); + } + + var replacementFunc : TFunction = { + ref: tvar, + expr: fun.expr, + ret: fun.ret, + args: args, + kind: fun.kind + } + + funs.push({fun: replacementFunc, useSgIO: true}); + } + else { + funs.push(fun); + } + } + var expr = patch(cache.expr); + for (fun in funs) { + if (fun.useSgIO) + fun.fun.expr = patch(fun.fun.expr); + } if (genFailure) { for (outputId => o in cache.outputs) { @@ -258,8 +344,8 @@ class ShaderNodeHxsl extends ShaderNode { } } - for (func in cache.funs) { - ctx.addFunction(func); + for (func in funs) { + ctx.addFunction(func.fun); } } From 1b89c3c6c739084e5f1f94bad3aa6201458d6699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 29 Aug 2025 12:49:13 +0200 Subject: [PATCH 28/70] [prefab] Fix material targetMaterial not reloading properly --- hrt/prefab/Material.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrt/prefab/Material.hx b/hrt/prefab/Material.hx index 42d6fa73c..3a365fc28 100644 --- a/hrt/prefab/Material.hx +++ b/hrt/prefab/Material.hx @@ -676,7 +676,7 @@ class Material extends Prefab { })); ctx.onChange(this, null); ctx.rebuildProperties(); - ctx.scene.editor.queueRebuild(this); + ctx.scene.editor.queueRebuild(this.parent); var fx = findParent(hrt.prefab.fx.FX); if(fx != null) From 3cf10ab7b66a27723753d8c140d26d00f8a359d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 29 Aug 2025 12:58:19 +0200 Subject: [PATCH 29/70] [prefab] Fix edition of shader.targetMaterial --- hrt/prefab/Shader.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/hrt/prefab/Shader.hx b/hrt/prefab/Shader.hx index 79d59548a..91009a85f 100644 --- a/hrt/prefab/Shader.hx +++ b/hrt/prefab/Shader.hx @@ -258,6 +258,7 @@ class Shader extends Prefab { ectx.properties.add(propGroup, this, function(pname) { if( targetMaterial == "" ) targetMaterial = null; ectx.onChange(this, pname); + ectx.rebuildPrefab(this.findParent(Object3D) ?? this.findParent(Object2D)); }); var group = new hide.Element('
'); From ae9701855e880774357195edb0e9f9b8a4a0a378 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 29 Aug 2025 14:07:44 +0200 Subject: [PATCH 30/70] [hide] Fix cli --- hrt/prefab/Shader.hx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hrt/prefab/Shader.hx b/hrt/prefab/Shader.hx index 91009a85f..666f3ec2f 100644 --- a/hrt/prefab/Shader.hx +++ b/hrt/prefab/Shader.hx @@ -258,7 +258,14 @@ class Shader extends Prefab { ectx.properties.add(propGroup, this, function(pname) { if( targetMaterial == "" ) targetMaterial = null; ectx.onChange(this, pname); - ectx.rebuildPrefab(this.findParent(Object3D) ?? this.findParent(Object2D)); + + var o3d = this.findParent(Object3D); + if (o3d != null) + ectx.rebuildPrefab(o3d); + + var o2d = this.findParent(Object2D); + if (o2d != null) + ectx.rebuildPrefab(o2d); }); var group = new hide.Element('
'); From e5cbc15e9c52d9aa821ff01dae46d95dfbedb473 Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Mon, 1 Sep 2025 10:00:15 +0200 Subject: [PATCH 31/70] [cdb] Make tab move left/right only impact display order --- hide/comp/cdb/Editor.hx | 24 ++++++++++++++++++++++-- hide/view/CdbTable.hx | 32 +++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/hide/comp/cdb/Editor.hx b/hide/comp/cdb/Editor.hx index d117c3609..b825f5c07 100644 --- a/hide/comp/cdb/Editor.hx +++ b/hide/comp/cdb/Editor.hx @@ -27,6 +27,7 @@ typedef UndoState = { var separatorsState: Map; var cursor : Cursor.CursorState; var tables : Array; + var sheetOrder : Array; } typedef EditorApi = { @@ -1024,6 +1025,7 @@ class Editor extends Component { } makeParent(tables[i]); }], + sheetOrder : cdbTable.sheetsOrder.copy(), }; } @@ -1079,6 +1081,7 @@ class Editor extends Component { var state = undoState[0]; var newSheet = getCurrentSheet(); var newSaparatorsState = separatorsState; + var newSheetsOrder = cdbTable.sheetsOrder.copy(); currentValue = newValue; save(); undo.change(Custom(function(undo) { @@ -1088,11 +1091,13 @@ class Editor extends Component { currentValue = state.data; currentSheet = state.sheet; separatorsState = state.separatorsState; + cdbTable.sheetsOrder = state.sheetOrder; } else { undoState.unshift(state); currentValue = newValue; currentSheet = newSheet; separatorsState = newSaparatorsState; + cdbTable.sheetsOrder = newSheetsOrder; } api.load(currentValue); DataFiles.save(true); // save reloaded data @@ -2413,6 +2418,9 @@ class Editor extends Component { for( s in base.sheets ) if( StringTools.startsWith(s.name, old + "@") ) s.rename(name + "@" + s.name.substr(old.length + 1)); + var order = cdbTable.sheetsOrder.indexOf(old); + if( order >= 0 ) + cdbTable.sheetsOrder[order] = name; endChanges(); DataFiles.save(true,[ sheet.name => old ]); return true; @@ -2462,6 +2470,18 @@ class Editor extends Component { return null; } ide.saveDatabase(); + var orderIndex = -1; + if( index == 0 ) { + orderIndex = 0; + } else if( index > 0 ) { + var prevSheetName = base.sheets[index-1]?.name; + orderIndex = prevSheetName == null ? -1 : cdbTable.sheetsOrder.findIndex((s) -> s == prevSheetName); + if( orderIndex >= 0 ) + orderIndex += 1; + } + if( orderIndex >= 0 && orderIndex <= cdbTable.sheetsOrder.length ) { + cdbTable.sheetsOrder.insert(orderIndex, s.name); + } refreshAll(); return s; } @@ -2477,8 +2497,8 @@ class Editor extends Component { if (withMacro) { content = content.concat([ { label : "Add Sheet", click : function() { beginChanges(); var db = createDBSheet(index+1); endChanges(); if( db != null ) onChange(); } }, - { label : "Move Left", click : function() { beginChanges(); base.moveSheet(sheet,-1); endChanges(); onChange(); } }, - { label : "Move Right", click : function() { beginChanges(); base.moveSheet(sheet,1); endChanges(); onChange(); } }, + { label : "Move Left", click : function() { beginChanges(); cdbTable.moveSheetDisplayOrder(sheet,-1); endChanges(); onChange(); } }, + { label : "Move Right", click : function() { beginChanges(); cdbTable.moveSheetDisplayOrder(sheet,1); endChanges(); onChange(); } }, { label : "Rename", click : function() { var name = ide.ask("New name", sheet.name); if( name == null || name == "" || name == sheet.name ) return; diff --git a/hide/view/CdbTable.hx b/hide/view/CdbTable.hx index 2e708c400..7c349f335 100644 --- a/hide/view/CdbTable.hx +++ b/hide/view/CdbTable.hx @@ -1,7 +1,10 @@ package hide.view; +using hide.tools.Extensions; + class CdbTable extends hide.ui.View<{}> { + public var sheetsOrder : Array; var tabContents : Array; var editor : hide.comp.cdb.Editor; var currentSheet : String; @@ -23,6 +26,9 @@ class CdbTable extends hide.ui.View<{}> { undoStack[0] = editor.undo; currentSheet = this.config.get("cdb.currentSheet"); view = cast this.config.get("cdb.view"); + saveDisplayKey = "cdb:" + ide.getPath(@:privateAccess ide.databaseFile); + sheetsOrder = getDisplayState("sheetsOrder"); + if( sheetsOrder == null ) sheetsOrder = []; } override function destroy() { @@ -185,7 +191,26 @@ class CdbTable extends hide.ui.View<{}> { } public function getSheets() { - return [for( s in ide.database.sheets ) if( !s.props.hide && (view == null || view.exists(s.name)) ) s]; + var arr = [for( s in ide.database.sheets ) if( !s.props.hide && (view == null || view.exists(s.name)) ) s]; + haxe.ds.ArraySort.sort(arr, (s1, s2) -> sheetsOrder.indexOf(s1.name) - sheetsOrder.indexOf(s2.name)); + sheetsOrder = arr.map(s -> s.name); + saveSheetsOrder(); + return arr; + } + + public function saveSheetsOrder() { + saveDisplayState("sheetsOrder", sheetsOrder); + } + + public function moveSheetDisplayOrder( s : cdb.Sheet, delta : Int ) { + var index = sheetsOrder.findIndex(o -> o == s.name); + var newIndex = index + delta; + if( index < 0 || newIndex < 0 || newIndex >= sheetsOrder.length ) + return false; + var order = sheetsOrder[index]; + sheetsOrder.remove(order); + sheetsOrder.insert(newIndex, order); + return true; } function getTabCache() { @@ -239,7 +264,8 @@ class CdbTable extends hide.ui.View<{}> { if( tabs != null ) { tabs.onTabChange = setEditor; tabs.onTabRightClick = function(index) { - editor.popupSheet(true, getSheets()[index], function() { + var sheet = getSheets()[index]; + editor.popupSheet(true, sheet, function() { var newSheets = getSheets(); var delta = newSheets.length - sheets.length; var sshow = null; @@ -248,7 +274,7 @@ class CdbTable extends hide.ui.View<{}> { else if( delta < 0 ) sshow = newSheets[index-1]; else - sshow = newSheets[index]; // rename + sshow = sheet; // rename or move display order if( sshow != null ) currentSheet = sshow.name; if( getTabCache() != tabCache ) From 24b37c61261ef8366eecb391fd173785894b3541 Mon Sep 17 00:00:00 2001 From: LeoVgr Date: Mon, 1 Sep 2025 10:04:06 +0200 Subject: [PATCH 32/70] FileBrowser: add favorites --- bin/res/icons/svg/generate.hx | 2 - bin/res/icons/svg/icons.css | 0 bin/res/icons/svg/icons.less | 0 bin/style.css | 38 +++++- bin/style.less | 45 ++++++- hide/comp/FancyTree.hx | 50 +++++--- hide/comp/SceneEditor.hx | 2 +- hide/view/FileBrowser.hx | 229 +++++++++++++++++++++++++++++++++- 8 files changed, 342 insertions(+), 24 deletions(-) delete mode 100644 bin/res/icons/svg/generate.hx delete mode 100644 bin/res/icons/svg/icons.css delete mode 100644 bin/res/icons/svg/icons.less diff --git a/bin/res/icons/svg/generate.hx b/bin/res/icons/svg/generate.hx deleted file mode 100644 index 139597f9c..000000000 --- a/bin/res/icons/svg/generate.hx +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/bin/res/icons/svg/icons.css b/bin/res/icons/svg/icons.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/bin/res/icons/svg/icons.less b/bin/res/icons/svg/icons.less deleted file mode 100644 index e69de29bb..000000000 diff --git a/bin/style.css b/bin/style.css index 7945e1466..2646a3530 100644 --- a/bin/style.css +++ b/bin/style.css @@ -4893,10 +4893,38 @@ file-browser.vertical { file-browser.single > .left { flex: 1 1; } +file-browser fancy-scroll { + display: block; + width: 100%; + flex: 1 1; + min-width: 100px; + overflow-x: clip; + overflow-y: auto; +} +file-browser fancy-scroll fancy-item-container { + position: relative; + display: block; + overflow: hidden; + contain: strict; +} file-browser .left { width: 300px; min-width: 100px; - background-color: mediumaquamarine; + background-color: #222222; + display: flex; + flex-direction: column; +} +file-browser .left .top { + width: 100%; + padding-bottom: 20px; +} +file-browser .left .top.hidden { + height: 0px; + padding-bottom: 0px; +} +file-browser .left .bot { + width: 100%; + flex: 1; } file-browser .right { flex: 1 1; @@ -5244,6 +5272,14 @@ fancy-tooltip { mask-image: url("res/icons/svg/dot.svg"); color: #FE383A; } +.fancy-status-icon.fancy-status-icon-star::after { + width: 11px; + height: 11px; + left: -4px; + bottom: -1px; + mask-image: url("res/icons/svg/star.svg"); + color: #fcbf07; +} .lm_tabdropdown_list { z-index: 9999 !important; background-color: #111111; diff --git a/bin/style.less b/bin/style.less index e0d2a2a0b..748af7845 100644 --- a/bin/style.less +++ b/bin/style.less @@ -5838,10 +5838,44 @@ file-browser { height: 100%; width: 100%; + fancy-scroll { + display: block; + width: 100%; + flex: 1 1; + min-width: 100px; + overflow-x: clip; + overflow-y: auto; + + fancy-item-container { + position: relative; + display: block; + overflow: hidden; + + contain: strict; + } + + } + .left { width: 300px; min-width: 100px; - background-color: mediumaquamarine; + background-color: #222222; + display: flex; + flex-direction: column; + + .top { + &.hidden { + height: 0px; + padding-bottom: 0px; + } + width: 100%; + padding-bottom: 20px; + } + + .bot { + width: 100%; + flex: 1; + } } .right { @@ -6280,6 +6314,15 @@ fancy-tooltip { mask-image: url("res/icons/svg/dot.svg"); color: #FE383A; } + + &.fancy-status-icon-star::after { + width: 11px; + height: 11px; + left: -4px; + bottom: -1px; + mask-image: url("res/icons/svg/star.svg"); + color: #fcbf07; + } } .lm_tabdropdown_list { diff --git a/hide/comp/FancyTree.hx b/hide/comp/FancyTree.hx index 08113fd93..61994d251 100644 --- a/hide/comp/FancyTree.hx +++ b/hide/comp/FancyTree.hx @@ -68,7 +68,9 @@ typedef TreeButton = { typedef Params = { ?saveDisplayKey : String, - ?quickGoto : Bool + ?quickGoto : Bool, + ?search : Bool, + ?customScroll : js.html.Element } class FancyTree extends hide.comp.Component { @@ -83,6 +85,8 @@ class FancyTree extends hide.comp.Component { var gotoFileCurrentMatch = ""; var quickGoto : Bool = true; + var allowSearch : Bool = true; + var useCustomScroll : Bool = false; static final gotoFileKeyMaxDelay = 0.5; static final overDragOpenDelaySec = 0.5; @@ -118,6 +122,8 @@ class FancyTree extends hide.comp.Component { public function new(parent: Element, ?params: Params) { saveDisplayKey = params?.saveDisplayKey; quickGoto = params?.quickGoto != null ? params.quickGoto : true; + allowSearch = params?.search; + useCustomScroll = params?.customScroll != null; var el = new Element(' @@ -132,19 +138,21 @@ class FancyTree extends hide.comp.Component { loadState(); - searchBarClosable = new FancyClosable(null, element.find("fancy-closable")); + if (allowSearch) { + searchBarClosable = new FancyClosable(null, element.find("fancy-closable")); - searchBar = new FancySearch(null, element.find("fancy-search")); - searchBar.onSearch = (search, _) -> { - currentSearch = search.toLowerCase(); - queueRefresh(Search); - } + searchBar = new FancySearch(null, element.find("fancy-search")); + searchBar.onSearch = (search, _) -> { + currentSearch = search.toLowerCase(); + queueRefresh(Search); + } - searchBarClosable.onClose = () -> { - onSearchClose(); + searchBarClosable.onClose = () -> { + onSearchClose(); + } } - scroll = el.find("fancy-scroll").get(0); + scroll = params.customScroll == null ? el.find("fancy-scroll").get(0) : params.customScroll; itemContainer = el.find("fancy-item-container").get(0); lastHeight = null; @@ -221,6 +229,12 @@ class FancyTree extends hide.comp.Component { return []; } + public dynamic function onSearch() { + } + + public dynamic function onSearchEnd() { + } + /** Drag and drop interface. Set this struct with all of it's function callback to handle drag and drop inside your tree. @@ -442,10 +456,14 @@ class FancyTree extends hide.comp.Component { } function inputHandler(e: js.html.KeyboardEvent) { + if (!allowSearch) + return; + if (hide.ui.Keys.matchJsEvent("search", e, ide.currentConfig)) { e.stopPropagation(); e.preventDefault(); + onSearch(); searchBarClosable.toggleOpen(true); searchBar.focus(); currentSearch = searchBar.getValue().toLowerCase(); @@ -467,6 +485,7 @@ class FancyTree extends hide.comp.Component { e.stopPropagation(); e.preventDefault(); + onSearchEnd(); searchBarClosable.toggleOpen(false); searchBar.blur(); @@ -525,7 +544,7 @@ class FancyTree extends hide.comp.Component { return; } - if (currentItem == null || searchBar.hasFocus()) + if (currentItem == null || searchBar?.hasFocus()) return; if (e.key == "ArrowRight" && hasChildren(currentItem.item)) { @@ -628,7 +647,8 @@ class FancyTree extends hide.comp.Component { regenerateFlatData(); } - //itemContainer.innerHTML = ""; + var scrollHeight = scroll.getBoundingClientRect().height; + var offsetTop = useCustomScroll ? scroll.getElementsByClassName("top")[0].getBoundingClientRect().height : 0; var oldChildren = [for (node in itemContainer.childNodes) node]; var itemHeightPx = 20; @@ -639,13 +659,11 @@ class FancyTree extends hide.comp.Component { lastHeight = height; } - var scrollHeight = scroll.getBoundingClientRect().height; - if (currentRefreshFlags.has(FocusCurrent)) { var currentIndex = flatData.indexOf(currentItem); if (currentIndex >= 0) { - var currentHeight = currentIndex * itemHeightPx; + var currentHeight = currentIndex * itemHeightPx - offsetTop; if (currentHeight < scroll.scrollTop) { scroll.scrollTo(scroll.scrollLeft, currentHeight); } @@ -656,7 +674,7 @@ class FancyTree extends hide.comp.Component { } } - var clipStart = scroll.scrollTop; + var clipStart = scroll.scrollTop - offsetTop; var clipEnd = scrollHeight + clipStart; var itemStart = hxd.Math.floor(clipStart / itemHeightPx); var itemEnd = hxd.Math.ceil(clipEnd / itemHeightPx); diff --git a/hide/comp/SceneEditor.hx b/hide/comp/SceneEditor.hx index 5563dbeab..58234eab1 100644 --- a/hide/comp/SceneEditor.hx +++ b/hide/comp/SceneEditor.hx @@ -2065,7 +2065,7 @@ class SceneEditor { icons.set(f, Reflect.field(iconsConfig,f)); var saveDisplayKey = isSceneTree ? view.saveDisplayKey + '/tree' : view.saveDisplayKey + '/renderPropsTree'; - var tree = new FancyTree(null, { saveDisplayKey: saveDisplayKey, quickGoto: false }); + var tree = new FancyTree(null, { saveDisplayKey: saveDisplayKey, quickGoto: false, search: true }); tree.getChildren = (p : hrt.prefab.Prefab) -> { if (p == null) { if (isSceneTree) diff --git a/hide/view/FileBrowser.hx b/hide/view/FileBrowser.hx index 54e6a2e23..a7c38c510 100644 --- a/hide/view/FileBrowser.hx +++ b/hide/view/FileBrowser.hx @@ -2,6 +2,13 @@ package hide.view; import hide.tools.FileManager; import hide.tools.FileManager.FileEntry; + +typedef FavoriteEntry = { + parent : FavoriteEntry, + children : Array, + ?ref : FileEntry, +} + typedef FileBrowserState = { savedLayout: Layout, } @@ -14,6 +21,7 @@ enum abstract Layout(String) { } class FileBrowser extends hide.ui.View { + static var FAVORITES_KEY = "filebrowser_favorites"; var fileTree: Element; var fileIcons: Element; @@ -46,6 +54,10 @@ class FileBrowser extends hide.ui.View { override function new(state) { super(state); saveDisplayKey = "fileBrowser"; + + this.favorites = getDisplayState(FAVORITES_KEY); + if (this.favorites == null) + this.favorites = []; } override function buildTabMenu():Array { @@ -134,6 +146,9 @@ class FileBrowser extends hide.ui.View { var statFileCount: Int = 0; var statFileFiltered: Int = 0; + var favorites : Array; + var favoritesTree : hide.comp.FancyTree; + function set_filterEnabled(v : Bool) { var anySet = false; for (key => value in filterState) { @@ -355,7 +370,12 @@ class FileBrowser extends hide.ui.View { var browserLayout = new Element(' -
+
+ +
+
+
+
@@ -413,7 +433,182 @@ class FileBrowser extends hide.ui.View { } } - fancyTree = new hide.comp.FancyTree(browserLayout.find(".left"), { saveDisplayKey: "fileBrowserTree" } ); + // Favorites tree + favoritesTree = new hide.comp.FancyTree(browserLayout.find(".left").find(".top"), { saveDisplayKey: "fileBrowserTree_Favorites" } ); + favoritesTree.getChildren = (file: FavoriteEntry) -> { + function rec(parent : FavoriteEntry) { + if (parent.ref.children == null) + return; + for (c in parent.ref.children) { + var f = { parent : parent, children : [], ref: FileManager.inst.getFileEntry(c.path) }; + parent.children.push(f); + rec(f); + } + } + + if (file == null) { + var fav : FavoriteEntry = { + parent : null, + children : [], + ref : null + } + + fav.children = []; + for (f in favorites) { + // Ref could be null if this f is a favorite of another project + var ref = FileManager.inst.getFileEntry(f); + if (ref == null) + continue; + var c = { parent: fav, children: [], ref: ref } + fav.children.push(c); + rec(c); + } + + return [fav]; + } + + if (file?.ref?.kind == File) + return null; + if (file.children == null) + throw "null children"; + + return file.children; + + // return [for (c in file.children) { parent: file, children: [], ref: FileManager.inst.getFileEntry(c.ref.path) }]; + }; + favoritesTree.getName = (file: FavoriteEntry) -> return file.ref == null ? "Favorites" : file?.ref.name; + favoritesTree.getUniqueName = (file: FavoriteEntry) -> { + if (file == null) + return ""; + if (file.ref == null) + return "favorites"; + var relPath = file.ref.name; + var p = file.parent; + while (p != null) { + var name = p.ref == null ? "favorites" : p.ref.name; + relPath = name + "/" + relPath; + p = p.parent; + } + return relPath; + } + favoritesTree.getIcon = (file: FavoriteEntry) -> { + if (file.parent == null) + return '
'; + + var fav = file.parent.ref == null ? "fancy-status-icon fancy-status-icon-star" : ""; + if (file.ref.kind == Dir) + return '
'; + var ext = Extension.getExtension(file.ref.name); + if (ext != null) { + if (ext?.options.icon != null) { + return '
'; + } + } + return '
'; + }; + favoritesTree.onContextMenu = (item: FavoriteEntry, event: js.html.MouseEvent) -> { + event.stopPropagation(); + event.preventDefault(); + + var options : Array = []; + options.push({ + label: "Collapse", + click: () -> { + var collapseTarget = item; + if (item.ref.kind != Dir) + collapseTarget = item.parent; + favoritesTree.collapseItem(collapseTarget); + } + }); + options.push({ + label: "Collapse All", + click: () -> { + for (child in item.children) + favoritesTree.collapseItem(child); + } + }); + options.push({ + isSeparator: true + }); + + // Root favorite tree options + var isFavoriteRoot = item?.parent == null; + if (isFavoriteRoot) { + options.push({ + label: "Clear Favorites", + click: () -> { + favorites = []; + saveDisplayState(FAVORITES_KEY, favorites); + favoritesTree.rebuildTree(); + this.favoritesTree.element.parent().hide(); + } + }); + + hide.comp.ContextMenu.createFromEvent(event, options); + return; + } + else { + if (!this.favorites.contains(item.ref.getPath())) { + options.push({ label: "Mark as Favorite", click : function() { + this.favorites.push(item.ref.getPath()); + saveDisplayState(FAVORITES_KEY, this.favorites); + this.favoritesTree.rebuildTree(); + this.favoritesTree.element.parent().show(); + }}); + } + else { + options.push({ label: "Remove from Favorite", click : function() { + this.favorites.remove(item.ref.getPath()); + saveDisplayState(FAVORITES_KEY, this.favorites); + this.favoritesTree.rebuildTree(); + if (this.favorites.length == 0) + this.favoritesTree.element.parent().hide(); + }}); + } + } + + hide.comp.ContextMenu.createFromEvent(event, options); + }; + favoritesTree.onDoubleClick = (item: FavoriteEntry) -> { + if (item?.ref?.kind == File) + ide.openFile(item.ref.getPath()); + else + favoritesTree.openItem(item); + } + favoritesTree.onSelectionChanged = (enterKey) -> { + fancyTree.clearSelection(); + + var selection = favoritesTree.getSelectedItems(); + + // Sinc folder view with other filebrowser in SingleMiniature mode + if (selection.length > 0) { + if (selection[0].ref == null) return; + + openDir(selection[0].ref, false); + var views = ide.getViews(hide.view.FileBrowser); + for (view in views) { + if (view == this) + continue; + if (view.layout == SingleMiniature) { + view.openDir(selection[0].ref, false); + } + } + } + + if (enterKey) { + if (selection[0].ref.kind == File) { + ide.openFile(selection[0].ref.getPath()); + } + } + } + + favoritesTree.rebuildTree(); + + if (this.favorites.length == 0) + this.favoritesTree.element.parent().hide(); + + // Ressources tree + fancyTree = new hide.comp.FancyTree(browserLayout.find(".left").find(".bot"), { saveDisplayKey: "fileBrowserTree_Main", search: true, customScroll: element.find("fancy-scroll").get(0) } ); fancyTree.getChildren = (file: FileEntry) -> { if (file == null) return [root]; @@ -437,6 +632,15 @@ class FileBrowser extends hide.ui.View { fancyTree.onNameChange = renameHandler; + fancyTree.onSearch = () -> { + favoritesTree.element.parent().hide(); + } + + fancyTree.onSearchEnd = () -> { + if (this.favorites.length > 0) + favoritesTree.element.parent().show(); + } + fancyTree.dragAndDropInterface = { onDragStart: function(file: FileEntry, e: hide.tools.DragAndDrop.DragData) : Bool { @@ -526,7 +730,6 @@ class FileBrowser extends hide.ui.View { fancyGallery.getThumbnail = (item : FileEntry) -> { if (item.kind == Dir) { return ''; - } else if (item.iconPath == "loading") { return ''; @@ -585,6 +788,8 @@ class FileBrowser extends hide.ui.View { fancyTree.onSelectionChanged = (enterKey) -> { + favoritesTree.clearSelection(); + var selection = fancyTree.getSelectedItems(); // Sinc folder view with other filebrowser in SingleMiniature mode @@ -997,6 +1202,24 @@ class FileBrowser extends hide.ui.View { }}); } + if (!this.favorites.contains(item.getPath())) { + options.push({ label: "Mark as Favorite", click : function() { + this.favorites.push(item.getPath()); + saveDisplayState(FAVORITES_KEY, this.favorites); + this.favoritesTree.rebuildTree(); + this.favoritesTree.element.parent().show(); + }}); + } + else { + options.push({ label: "Remove from Favorite", click : function() { + this.favorites.remove(item.getPath()); + saveDisplayState(FAVORITES_KEY, this.favorites); + this.favoritesTree.rebuildTree(); + if (this.favorites.length == 0) + this.favoritesTree.element.parent().hide(); + }}); + } + options.push({ label: "Refresh Thumbnail(s)", click : function() { var files = FileManager.inst.getRoots(getItemAndSelection(item, isGallery)); for (file in files) { From 0ba333ccdb02957e615a6f1519104940e3f0c26d Mon Sep 17 00:00:00 2001 From: LeoVgr Date: Mon, 1 Sep 2025 10:41:56 +0200 Subject: [PATCH 33/70] FavoritesTree: fix Collapse All --- hide/view/FileBrowser.hx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hide/view/FileBrowser.hx b/hide/view/FileBrowser.hx index a7c38c510..b35f04686 100644 --- a/hide/view/FileBrowser.hx +++ b/hide/view/FileBrowser.hx @@ -523,8 +523,8 @@ class FileBrowser extends hide.ui.View { options.push({ label: "Collapse All", click: () -> { - for (child in item.children) - favoritesTree.collapseItem(child); + for (child in @:privateAccess favoritesTree.rootData) + favoritesTree.collapseItem(child.item); } }); options.push({ From 21998f21ec2f0bbbb9ea92217d67d4aed5f8ed3f Mon Sep 17 00:00:00 2001 From: Yuxiao Mao Date: Mon, 1 Sep 2025 12:02:29 +0200 Subject: [PATCH 34/70] [cdb] Fix cdbTable null access when using ObjEditor --- hide/comp/cdb/Editor.hx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hide/comp/cdb/Editor.hx b/hide/comp/cdb/Editor.hx index b825f5c07..821caef47 100644 --- a/hide/comp/cdb/Editor.hx +++ b/hide/comp/cdb/Editor.hx @@ -1025,7 +1025,7 @@ class Editor extends Component { } makeParent(tables[i]); }], - sheetOrder : cdbTable.sheetsOrder.copy(), + sheetOrder : cdbTable?.sheetsOrder.copy(), }; } @@ -1081,7 +1081,7 @@ class Editor extends Component { var state = undoState[0]; var newSheet = getCurrentSheet(); var newSaparatorsState = separatorsState; - var newSheetsOrder = cdbTable.sheetsOrder.copy(); + var newSheetsOrder = cdbTable?.sheetsOrder.copy(); currentValue = newValue; save(); undo.change(Custom(function(undo) { @@ -1091,13 +1091,13 @@ class Editor extends Component { currentValue = state.data; currentSheet = state.sheet; separatorsState = state.separatorsState; - cdbTable.sheetsOrder = state.sheetOrder; + if( cdbTable != null ) cdbTable.sheetsOrder = state.sheetOrder; } else { undoState.unshift(state); currentValue = newValue; currentSheet = newSheet; separatorsState = newSaparatorsState; - cdbTable.sheetsOrder = newSheetsOrder; + if( cdbTable != null ) cdbTable.sheetsOrder = newSheetsOrder; } api.load(currentValue); DataFiles.save(true); // save reloaded data From 223f3bde5f60cd0c35f7c95bcc0a298b1b3ae5f4 Mon Sep 17 00:00:00 2001 From: LeoVgr Date: Mon, 1 Sep 2025 12:37:33 +0200 Subject: [PATCH 35/70] CDB: Fix closing subtables when deleting line with filters --- hide/comp/cdb/Editor.hx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hide/comp/cdb/Editor.hx b/hide/comp/cdb/Editor.hx index b825f5c07..2726e1fbd 100644 --- a/hide/comp/cdb/Editor.hx +++ b/hide/comp/cdb/Editor.hx @@ -318,10 +318,8 @@ class Editor extends Component { if (filters.length == 0 && filterFlags.has(Regular) && filterFlags.has(Warning) && filterFlags.has(Error)) return; - for (s in @:privateAccess table.separators) { + for (s in @:privateAccess table.separators) @:privateAccess s.filtered = true; - s.refresh(false); - } // Clean filters var idx = filters.length; From c1df539b5e0a34fcc1d09a70c0b43b38ccbd43bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 1 Sep 2025 08:30:45 +0200 Subject: [PATCH 36/70] [shgraph] Fix constant nodes --- bin/style.css | 32 +++++++++++++++++++++++++++ bin/style.less | 38 +++++++++++++++++++++++++++++++++ hide/view/shadereditor/Box.hx | 8 ++++--- hrt/shgraph/ShaderConst.hx | 17 ++++++++++++--- hrt/shgraph/nodes/BoolConst.hx | 5 ++--- hrt/shgraph/nodes/Color.hx | 7 +++--- hrt/shgraph/nodes/FloatConst.hx | 8 +++---- 7 files changed, 98 insertions(+), 17 deletions(-) diff --git a/bin/style.css b/bin/style.css index 2646a3530..ffdb7c875 100644 --- a/bin/style.css +++ b/bin/style.css @@ -2487,6 +2487,38 @@ input[type=checkbox].indeterminate:after { .graph-view .heaps-scene svg g.box foreignObject container .play-button:hover { color: #AAA; } +.graph-view .heaps-scene svg g.box .sg-const-name { + display: flex; +} +.graph-view .heaps-scene svg g.box .sg-const-name > fancy-button { + --size: 20px; + font-size: 16px; +} +.graph-view .heaps-scene svg g.box .sg-const-name > input { + width: unset; + min-width: 0; + display: block; + border: none; + background: none; + text-align: right; + margin: 0; + padding: 0; +} +.graph-view .heaps-scene svg g.box .sg-const-name > input:hover { + background-color: rgba(0, 0, 0, 0.2); +} +.graph-view .heaps-scene svg g.box .sg-const-name > input:focus { + outline: none; + background-color: rgba(0, 0, 0, 0.3); +} +.graph-view .heaps-scene svg g.box .sg-const-name > input:focus::placeholder { + color: transparent; +} +.graph-view .heaps-scene svg g.box .sg-const-input { + display: flex; + justify-content: center; + align-items: center; +} .graph-view .heaps-scene svg g.box.comment { pointer-events: none; } diff --git a/bin/style.less b/bin/style.less index 748af7845..2e6ffd691 100644 --- a/bin/style.less +++ b/bin/style.less @@ -2864,6 +2864,44 @@ input[type=checkbox] { } } + + .sg-const-name { + display: flex; + + > fancy-button { + --size: 20px; + font-size: 16px; + } + > input { + width: unset; + min-width: 0; + display: block; + border: none; + background: none; + text-align: right; + margin: 0; + padding: 0; + &:hover { + background-color: rgba(0,0,0,0.20); + + } + &:focus { + outline: none; + background-color: rgba(0,0,0,0.30); + + &::placeholder { + color: transparent; + } + } + } + } + + .sg-const-input { + display: flex; + justify-content: center; + align-items: center; + } + &.comment { .head-box { fill: rgba(80,80,80,0.5); diff --git a/hide/view/shadereditor/Box.hx b/hide/view/shadereditor/Box.hx index 9409d96db..0184d58eb 100644 --- a/hide/view/shadereditor/Box.hx +++ b/hide/view/shadereditor/Box.hx @@ -383,10 +383,12 @@ class Box { var prop = editor.editorDisplay.group(propertiesGroup).addClass("prop-group"); prop.attr("transform", 'translate(0, ${propsHeight})'); + var height = p.height(); var propWidth = (p.width() > 0 ? p.width() : this.width); - var fObject = editor.editorDisplay.foreignObject(prop, (this.width - propWidth) / 2, 5, propWidth, p.height()); + var fObject = editor.editorDisplay.foreignObject(prop, (this.width - propWidth) / 2, 5, propWidth, height); + trace(p.height()); p.appendTo(fObject); - propsHeight += Std.int(p.outerHeight()) + 1; + propsHeight += Std.int(height) + 1; } propsHeight += 10; @@ -481,7 +483,7 @@ class Box { } var nodeHeight = getNodesHeight(); if (collapseProperties()) { - return hxd.Math.max(nodeHeight, propsHeight); + return hxd.Math.max(nodeHeight, propsHeight + HEADER_HEIGHT); } return nodeHeight + propsHeight; } diff --git a/hrt/shgraph/ShaderConst.hx b/hrt/shgraph/ShaderConst.hx index d767edb77..8bf378c92 100644 --- a/hrt/shgraph/ShaderConst.hx +++ b/hrt/shgraph/ShaderConst.hx @@ -14,10 +14,16 @@ class ShaderConst extends ShaderNode { override public function getPropertiesHTML(width : Float) : Array { var elements = super.getPropertiesHTML(width); - var element = new hide.Element('
'); - element.append(new hide.Element('')); + var element = new hide.Element('
'); + + var editBtn = new hide.Element('
'); + + element.append(editBtn); + + var input = new hide.Element(''); + + element.append(input); - var input = element.children("input"); input.on("keydown", function(e) { e.stopPropagation(); }); @@ -25,6 +31,11 @@ class ShaderConst extends ShaderNode { this.name = input.val(); }); + editBtn.on("click", function(e) { + input.focus(); + input.select(); + }); + elements.push(element); return elements; diff --git a/hrt/shgraph/nodes/BoolConst.hx b/hrt/shgraph/nodes/BoolConst.hx index 48fda3a48..e13e93bf3 100644 --- a/hrt/shgraph/nodes/BoolConst.hx +++ b/hrt/shgraph/nodes/BoolConst.hx @@ -2,11 +2,10 @@ package hrt.shgraph.nodes; using hxsl.Ast; -@name("Bool") +@name("Const Bool") @description("Boolean input (static)") @group("Property") @width(100) -@noheader() class BoolConst extends ShaderConst { @@ -26,7 +25,7 @@ class BoolConst extends ShaderConst { #if editor override public function getPropertiesHTML(width : Float) : Array { var elements = super.getPropertiesHTML(width); - var element = new hide.Element('
'); + var element = new hide.Element('
'); element.append(new hide.Element('')); var input = element.children("input"); diff --git a/hrt/shgraph/nodes/Color.hx b/hrt/shgraph/nodes/Color.hx index 5658337bf..60808cd19 100644 --- a/hrt/shgraph/nodes/Color.hx +++ b/hrt/shgraph/nodes/Color.hx @@ -2,11 +2,10 @@ package hrt.shgraph.nodes; using hxsl.Ast; -@name("Color") +@name("Const Color") @description("Color property (static)") @group("Property") @width(100) -@noheader() class Color extends ShaderConst { @prop() var r : Float = 0; @@ -28,9 +27,9 @@ class Color extends ShaderConst { #if editor override public function getPropertiesHTML(width : Float) : Array { var elements = super.getPropertiesHTML(width); - var element = new hide.Element('
'); + var element = new hide.Element('
'); var picker = new hide.comp.ColorPicker.ColorBox(element, true, true); - + element.height(picker.element.height()); var start = h3d.Vector4.fromArray([r, g, b, a]); picker.value = start.toColor(); diff --git a/hrt/shgraph/nodes/FloatConst.hx b/hrt/shgraph/nodes/FloatConst.hx index 850a98964..5cd7b7c0c 100644 --- a/hrt/shgraph/nodes/FloatConst.hx +++ b/hrt/shgraph/nodes/FloatConst.hx @@ -2,11 +2,11 @@ package hrt.shgraph.nodes; using hxsl.Ast; -@name("Value") +@name("Const Value") +@alias("Const Float") @description("Number input (static)") @group("Property") @width(100) -@noheader() class FloatConst extends ShaderConst { override function getOutputs() { @@ -25,8 +25,8 @@ class FloatConst extends ShaderConst { #if editor override public function getPropertiesHTML(width : Float) : Array { var elements = super.getPropertiesHTML(width); - var element = new hide.Element('
'); - element.append(new hide.Element('')); + var element = new hide.Element('
'); + element.append(new hide.Element('')); var input = element.children("input"); input.on("keydown", function(e) { From f748d7d586bd76b21f58f171ee61ff1fd8c2ef99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 1 Sep 2025 12:53:13 +0200 Subject: [PATCH 37/70] [hide] Prevent editor icon from casting shadows --- hrt/impl/EditorTools.hx | 1 + 1 file changed, 1 insertion(+) diff --git a/hrt/impl/EditorTools.hx b/hrt/impl/EditorTools.hx index 5cd270bcc..f55f9dd3b 100644 --- a/hrt/impl/EditorTools.hx +++ b/hrt/impl/EditorTools.hx @@ -8,6 +8,7 @@ class EditorIcon extends hrt.prefab.l3d.Billboard.BillboardObj { super(tile, parent); ignoreCollide = false; this.category = category; + this.material.castShadows = false; } override function sync(ctx) { From 504015cce75072f59015b53c8a339519351f1e90 Mon Sep 17 00:00:00 2001 From: LeoVgr Date: Mon, 1 Sep 2025 12:54:55 +0200 Subject: [PATCH 38/70] Favorites: fix null access --- hide/comp/FancyTree.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hide/comp/FancyTree.hx b/hide/comp/FancyTree.hx index 61994d251..8a001658e 100644 --- a/hide/comp/FancyTree.hx +++ b/hide/comp/FancyTree.hx @@ -152,7 +152,7 @@ class FancyTree extends hide.comp.Component { } } - scroll = params.customScroll == null ? el.find("fancy-scroll").get(0) : params.customScroll; + scroll = params?.customScroll == null ? el.find("fancy-scroll").get(0) : params.customScroll; itemContainer = el.find("fancy-item-container").get(0); lastHeight = null; From 58fbd099c20fd17185e4411d7427554b991b2a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 1 Sep 2025 15:26:46 +0200 Subject: [PATCH 39/70] [hide] Ignore .backed folder when renaming files --- hide/Ide.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hide/Ide.hx b/hide/Ide.hx index 348162b4e..058a7e70b 100644 --- a/hide/Ide.hx +++ b/hide/Ide.hx @@ -1390,6 +1390,8 @@ class Ide extends hide.tools.IdeData { function browseFiles( callb : String -> Void ) { function browseRec(path) { if( path == ".tmp" ) return; + if( path == ".backed" ) return; + for( p in sys.FileSystem.readDirectory(resourceDir + "/" + path) ) { var p = path == "" ? p : path + "/" + p; if( sys.FileSystem.isDirectory(resourceDir+"/"+p) ) { From cea9dc347c6ccdf3bed54719cf104bc79c27e777 Mon Sep 17 00:00:00 2001 From: LeoVgr Date: Tue, 2 Sep 2025 09:25:54 +0200 Subject: [PATCH 40/70] FancyTree: fix focus item --- hide/comp/FancyTree.hx | 2 +- hide/comp/cdb/Editor.hx | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/hide/comp/FancyTree.hx b/hide/comp/FancyTree.hx index 8a001658e..05c6d1a35 100644 --- a/hide/comp/FancyTree.hx +++ b/hide/comp/FancyTree.hx @@ -663,7 +663,7 @@ class FancyTree extends hide.comp.Component { var currentIndex = flatData.indexOf(currentItem); if (currentIndex >= 0) { - var currentHeight = currentIndex * itemHeightPx - offsetTop; + var currentHeight = currentIndex * itemHeightPx + offsetTop; if (currentHeight < scroll.scrollTop) { scroll.scrollTo(scroll.scrollLeft, currentHeight); } diff --git a/hide/comp/cdb/Editor.hx b/hide/comp/cdb/Editor.hx index da9f75979..a42f2f5f3 100644 --- a/hide/comp/cdb/Editor.hx +++ b/hide/comp/cdb/Editor.hx @@ -372,7 +372,6 @@ class Editor extends Component { searchBox.find("#results").text(results > 0 ? '$results Results' : 'No results'); - // if (updateCursor) cursor.update(); } From 55f44d828a537ff2575c1b4dd39243cc16f57530 Mon Sep 17 00:00:00 2001 From: LeoVgr Date: Tue, 2 Sep 2025 12:41:55 +0200 Subject: [PATCH 41/70] RFX: Fix color grading modulate --- hrt/prefab/rfx/ColorGrading.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrt/prefab/rfx/ColorGrading.hx b/hrt/prefab/rfx/ColorGrading.hx index 92cad33ed..19b5163a4 100644 --- a/hrt/prefab/rfx/ColorGrading.hx +++ b/hrt/prefab/rfx/ColorGrading.hx @@ -114,7 +114,7 @@ class ColorGrading extends RendererFX { override function modulate(t : Float) { var c : ColorGrading = cast super.modulate(t); c.intensity = this.intensity * t; - return c.instance; + return c; } override function transition( r1 : h3d.impl.RendererFX, r2 : h3d.impl.RendererFX ) : h3d.impl.RendererFX.RFXTransition { From d41179d9aabc61d863ea734b92d139753591eeff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Tue, 2 Sep 2025 12:53:15 +0200 Subject: [PATCH 42/70] [prefab] Restored text3D --- hrt/prefab/l3d/Text3D.hx | 49 +++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/hrt/prefab/l3d/Text3D.hx b/hrt/prefab/l3d/Text3D.hx index 9def5ce05..065e24544 100644 --- a/hrt/prefab/l3d/Text3D.hx +++ b/hrt/prefab/l3d/Text3D.hx @@ -16,6 +16,7 @@ class Text3DPrimitive extends h2d.TileGroup.TileLayerContent { tmp.push(1); tmp.push(t.u); tmp.push(t.v); + tmp.push(sx + t.width); tmp.push(sy); tmp.push(1); @@ -24,6 +25,7 @@ class Text3DPrimitive extends h2d.TileGroup.TileLayerContent { tmp.push(1); tmp.push(t.u2); tmp.push(t.v); + tmp.push(sx); tmp.push(sy + t.height); tmp.push(1); @@ -32,6 +34,7 @@ class Text3DPrimitive extends h2d.TileGroup.TileLayerContent { tmp.push(1); tmp.push(t.u); tmp.push(t.v2); + tmp.push(sx + t.width); tmp.push(sy + t.height); tmp.push(1); @@ -48,12 +51,29 @@ class Text3DPrimitive extends h2d.TileGroup.TileLayerContent { y += t.height; if( x > xMax ) xMax = x; if( y > yMax ) yMax = y; + + } + } + + override public function alloc(engine:h3d.Engine) { + if( tmp == null ) { + clear(); + indexes = null; + return; + } + if( tmp.length > 0 ) { + buffer = tmp.length < useAllocatorLimit + ? hxd.impl.Allocator.get().ofFloats(tmp, hxd.BufferFormat.POS3D_NORMAL_UV) + : h3d.Buffer.ofFloats(tmp, hxd.BufferFormat.POS3D_NORMAL_UV); + + indexes = engine.mem.getQuadIndexes(buffer.vertices); } } override public function render( engine : h3d.Engine ) { if( tmp == null || tmp.length == 0) return; - super.render(engine); + if( buffer == null || buffer.isDisposed() ) alloc(engine); + engine.renderIndexed(buffer,indexes, 0, buffer.vertices >> 1); } override function getBounds() { @@ -81,6 +101,8 @@ class SignedDistanceField3D extends hxsl.Shader { function fragment() { pixelColor = vec4(color.r, color.g, color.b, smoothstep(alphaCutoff - smoothing, alphaCutoff + smoothing, median(pixelColor.r, pixelColor.g, pixelColor.b))); + if (pixelColor.a <= 0.0) + discard; } } @@ -180,12 +202,11 @@ class Text3D extends Object3D { return; var mesh : h3d.scene.Mesh = cast local3d; var h2dFont = loadFont(); - var h2dText = null/*(cast local2d : h2d.Text)*/; - h2dText.font = h2dFont; - h2dText.letterSpacing = letterSpacing; - h2dText.text = text; - h2dText.smooth = true; - h2dText.textAlign = switch (align) { + text2d.font = h2dFont; + text2d.letterSpacing = letterSpacing; + text2d.text = text; + text2d.smooth = true; + text2d.textAlign = switch (align) { case 1: h2d.Text.Align.Center; case 2: @@ -193,15 +214,17 @@ class Text3D extends Object3D { default: h2d.Text.Align.Left; } - @:privateAccess h2dText.glyphs.content = (cast mesh.primitive : Text3DPrimitive); + @:privateAccess text2d.glyphs.content = (cast mesh.primitive : Text3DPrimitive); @:privateAccess { - h2dText.initGlyphs(text); - h2dText.glyphs.setDefaultColor(color, 1); - mesh.primitive = h2dText.glyphs.content; + text2d.initGlyphs(text); + text2d.glyphs.setDefaultColor(color, 1); + mesh.primitive = text2d.glyphs.content; mesh.material.texture = h2dFont.tile.getTexture(); mesh.material.shadows = false; - mesh.material.mainPass.setPassName("overlay"); - mesh.material.mainPass.depth(false, LessEqual); + mesh.material.mainPass.setPassName("afterTonemapping"); + + //mesh.material.mainPass.setPassName("overlay"); + //mesh.material.mainPass.depth(false, LessEqual); var shader = mesh.material.mainPass.getShader(SignedDistanceField3D); if (shader != null) { From 6ee993e52bbe65a545d47ece224ff13d7cc9290d Mon Sep 17 00:00:00 2001 From: borisrp Date: Tue, 2 Sep 2025 16:27:14 +0200 Subject: [PATCH 43/70] Add LocalVolumetricLighting, permit to simulate a localFog. Drawn during VolumetricOverlay pass to minimize visual artifact when VolumetricLighting is enabled. --- hrt/prefab/l3d/LocalVolumetricLighting.hx | 259 ++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 hrt/prefab/l3d/LocalVolumetricLighting.hx diff --git a/hrt/prefab/l3d/LocalVolumetricLighting.hx b/hrt/prefab/l3d/LocalVolumetricLighting.hx new file mode 100644 index 000000000..8cc741536 --- /dev/null +++ b/hrt/prefab/l3d/LocalVolumetricLighting.hx @@ -0,0 +1,259 @@ +package hrt.prefab.l3d; + +class LocalVolumetricShader extends hxsl.Shader { + + static var SRC = { + + final EPSILON = 1e-4; + final FLT_MAX = 3.402823466e+38; + + @global var depthMap : Channel; + + @global var camera : { + var position : Vec3; + var inverseViewProj : Mat4; + }; + + @global var global : { + @perObject var modelView : Mat4; + @perObject var modelViewInverse : Mat4; + }; + + @param var obH : Vec3; + + @param var fogColor : Vec4; + @param var fogDensity : Float; + @param var fogFade : Float; + + var screenUV : Vec2; + var transformedPosition : Vec3; + var transformedNormal : Vec3; + var pixelColor : Vec4; + + function maxComp(a : Vec3) : Float { return max(a.x, max(a.y, a.z)); } + function minComp(a : Vec3) : Float { return min(a.x, min(a.y, a.z)); } + + function getPositionAt( uv: Vec2 ) : Vec3 { + var depth = depthMap.get(uv); + var uv2 = uvToScreen(uv); + var temp = vec4(uv2, depth, 1) * camera.inverseViewProj; + var originWS = temp.xyz / temp.w; + return originWS; + } + + function getPosition() : Vec3 { + return getPositionAt(screenUV); + } + + function rayBoxIntersection( o : Vec3, d : Vec3) : Vec3 { + var m = 1.0/d; + var n = m*o; + var k = abs(m)*obH; + var t1 = -n - k; + var t2 = -n + k; + var tN = maxComp(t1); + var tF = minComp(t2); + var hit = vec3(tN, tF, 1.0); + if(tN>tF || tF<0.0) { + hit = vec3(-1.0, -1.0, -1.0); + } + return hit; + } + + function getPath(o : Vec3, d : Vec3) : Vec4 { + var dir = normalize(d); + var hit = rayBoxIntersection(o, dir); + var path = vec4(o, -1.0); + if(hit.z > 0.0){ + if(hit.x > 0.0){ + path = vec4(o+hit.x*dir, hit.y - hit.x); + } else { + path.w = hit.y; + } + } + + var backgroundLocalPosition = (vec4(getPosition(), 1.0) * global.modelViewInverse).xyz; + var backgroundDist = length(backgroundLocalPosition-path.xyz); + path.w = min(path.w, backgroundDist); + return path; + } + + function boxDistance(p : Vec3) : Float { + var d = abs(p) - obH; + return length(max(d,0.0)) + min(maxComp(d),0.0); + } + + function boxDensity( o : Vec3, d : Vec3, t : Float) : Float{ + var ir2 = 1.0/(obH*obH); + var a = 1.0 - (o*o)*ir2; + var b = - 2.0*(o*d)*ir2; + var c = - (d*d)*ir2; + + var t1 = t; + var t2 = t1*t1; + var t3 = t2*t1; + var t4 = t2*t2; + var t5 = t2*t3; + var t6 = t3*t3; + var t7 = t3*t4; + + var f = (t1/1.0) *(a.x*a.y*a.z) + + (t2/2.0) *(a.x*a.y*b.z + a.x*b.y*a.z + b.x*a.y*a.z) + + (t3/3.0) *(a.x*a.y*c.z + a.x*b.y*b.z + a.x*c.y*a.z + b.x*a.y*b.z + b.x*b.y*a.z + c.x*a.y*a.z) + + (t4/4.0) *(a.x*b.y*c.z + a.x*c.y*b.z + b.x*a.y*c.z + b.x*b.y*b.z + b.x*c.y*a.z + c.x*a.y*b.z + c.x*b.y*a.z) + + (t5/5.0) *(a.x*c.y*c.z + b.x*b.y*c.z + b.x*c.y*b.z + c.x*a.y*c.z + c.x*b.y*b.z + c.x*c.y*a.z) + + (t6/6.0) *(b.x*c.y*c.z + c.x*b.y*c.z + c.x*c.y*b.z) + + (t7/7.0) *(c.x*c.y*c.z); + + return f; + } + + function sampleFog(pos : Vec3, dir : Vec3, dist : Float) : Float { + return clamp(fogDensity * boxDensity(pos, dir, dist) / fogFade, 0.0, fogDensity); + } + + function integrateBox(pos : Vec3, dir: Vec3, dist : Float, integrationValues : Vec4) : Vec4 { + var extinction = sampleFog(pos, dir, dist/length(dir)); + var clampedExtinction = max(extinction, 1e-5); + var transmittance = exp(-extinction*dist); + var integScatt = fogColor.rgb; + + integrationValues.rgb += integrationValues.a * integScatt; + integrationValues.a *= transmittance; + + return integrationValues; + } + + function evaluate() : Vec4 { + var dir = normalize(transformedPosition - camera.position); + var pos = camera.position; + + dir = dir * global.modelViewInverse.mat3(); + pos = (vec4(pos, 1) * global.modelViewInverse).xyz; + + var path = getPath(pos, dir); + + var integrationValues = vec4(0.0,0.0,0.0,1.0); + return integrateBox(path.xyz, dir, path.w, integrationValues); + } + + function fragment() { + var volumetric = evaluate(); + volumetric.a = saturate(1.0 - volumetric.a); + volumetric.a = volumetric.a > 1.0 - 1e-3 ? 1.0 : volumetric.a; + pixelColor = volumetric; + } + } +} + +class LocalVolumetricLightingObject extends h3d.scene.Object { + + public var localVolume : LocalVolumetricLighting; + public var bounds : h3d.col.OrientedBounds; + + public var mesh : h3d.scene.Mesh; + public var boundsDisplay : h3d.scene.Graphics; + + public var shader : LocalVolumetricShader; + + public function new(parent:h3d.scene.Object, localVolume:LocalVolumetricLighting) { + this.localVolume = localVolume; + super(parent); + bounds = new h3d.col.OrientedBounds(); + + var prim = new h3d.prim.Cube(1,1,1,true); + prim.addNormals(); + mesh = new h3d.scene.Mesh(prim, this); + + var material = mesh.material; + material.castShadows = false; + mesh.material.mainPass.setPassName("volumetricOverlay"); + mesh.material.mainPass.setBlendMode(h3d.mat.BlendMode.Alpha); + + shader = new LocalVolumetricShader(); + + material.mainPass.addShader(shader); + + refresh(); + } + + function isInside(ctx : h3d.scene.RenderContext) : Bool { + var pos = ctx.camera.pos.clone().add(ctx.camera.getForward().scaled(ctx.camera.zNear)); + pos.transform(this.getInvPos()); + return pos.x >= -bounds.hx && pos.x <= bounds.hx && + pos.y >= -bounds.hy && pos.y <= bounds.hy && + pos.z >= -bounds.hz && pos.z <= bounds.hz; + } + + override function sync(ctx : h3d.scene.RenderContext) { + var inside = isInside(ctx); + if(inside){ + mesh.material.mainPass.culling = Front; + mesh.material.mainPass.depthTest = Always; + } else{ + mesh.material.mainPass.culling = Back; + mesh.material.mainPass.depthTest = Less; + } + } + + public function refresh() { + var ob = bounds; + shader.obH.set(ob.hx, ob.hy, ob.hz); + + shader.fogColor.setColor(localVolume.color); + shader.fogDensity = localVolume.fogDensity; + shader.fogFade = localVolume.fogFade; + + if(localVolume.showBounds){ + boundsDisplay = bounds.makeDebugObj(); + boundsDisplay.lineStyle(2, 0xFFFFFF); + addChild(boundsDisplay); + } else if(boundsDisplay != null){ + removeChild(boundsDisplay); + boundsDisplay = null; + } + } +} + +class LocalVolumetricLighting extends hrt.prefab.Object3D { + + var localVolumeObject : LocalVolumetricLightingObject; + + @:s public var fogDensity : Float = 1.0; + @:s public var fogFade : Float = 1.0; + @:s public var color : Int = 0xFFFFFF; + + @:s public var showBounds : Bool = false; + + override function makeObject(parent3d: h3d.scene.Object) : h3d.scene.Object { + localVolumeObject = new LocalVolumetricLightingObject(parent3d, this); + return localVolumeObject; + } + + override function updateInstance(?propName) { + super.updateInstance(propName); + localVolumeObject.refresh(); + } + + #if editor + override function edit( ctx : hide.prefab.EditContext ) { + super.edit(ctx); + ctx.properties.add(new hide.Element(' +
+
+
Density
+
Fade
+
Color
+
+
+
+
+
Show Bounds
+
+
+ '), this, function(pname) { ctx.onChange(this, pname); }); + } + #end + + static var _ = hrt.prefab.Prefab.register("LocalVolumeLighting", LocalVolumetricLighting); +} \ No newline at end of file From da4d4c6151ab38aa912db1eb5b24f451ed6e7464 Mon Sep 17 00:00:00 2001 From: LeoVgr Date: Tue, 2 Sep 2025 16:42:42 +0200 Subject: [PATCH 44/70] FavoritesTree: add drag & drop --- hide/view/FileBrowser.hx | 59 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/hide/view/FileBrowser.hx b/hide/view/FileBrowser.hx index b35f04686..203ff3ee4 100644 --- a/hide/view/FileBrowser.hx +++ b/hide/view/FileBrowser.hx @@ -601,6 +601,65 @@ class FileBrowser extends hide.ui.View { } } } + favoritesTree.dragAndDropInterface = { + onDragStart: function(file: FavoriteEntry, e: hide.tools.DragAndDrop.DragData) : Bool { + var selection = favoritesTree.getSelectedItems(); + if (selection.length <= 0) + return false; + + var fileEntries = []; + for (s in selection) { + if (s.ref != null) + fileEntries.push(s.ref); + } + + e.data.set("drag/filetree", fileEntries); + ide.setData("drag/filetree", cast fileEntries); + return true; + }, + getItemDropFlags: function(target: FavoriteEntry, e: hide.tools.DragAndDrop.DragData) : hide.comp.FancyTree.DropFlags { + if (target == null) + return Reorder; + + var fileEntries : Array = cast e.data.get("drag/filetree") ?? []; + fileEntries = fileEntries.copy(); + var containsFiles = fileEntries != null && fileEntries.length > 0; + + if (!containsFiles) + return hide.comp.FancyTree.DropFlags.ofInt(0); + + // Can't drop a file on itself + fileEntries.remove(target.ref); + + if (fileEntries.length == 0) + return hide.comp.FancyTree.DropFlags.ofInt(0); + + if (target.ref.kind == Dir) + return (Reorder:hide.comp.FancyTree.DropFlags) | Reparent; + + return Reorder; + }, + onDrop: function(target: FavoriteEntry, operation: hide.comp.FancyTree.DropOperation, e: hide.tools.DragAndDrop.DragData) : Bool { + if (target.ref.kind != Dir) + target = target.parent; + + var fileEntries : Array = cast e.data.get("drag/filetree") ?? []; + fileEntries = fileEntries.copy(); + fileEntries.remove(target.ref); + + var files = [ for (f in fileEntries) f.path ]; + if (files.length == 0) + return false; + + if(!ide.confirm('Really move files :\n${files.join("\n")}\nto target folder :\n${target.ref.getRelPath()}\n?\n(This could take a long time)')) { + return true; + } + + moveFiles(target.ref.getRelPath(), files); + + return true; + } + } favoritesTree.rebuildTree(); From 3a9470e71d5d8399ed4ac8b0919690986efd304d Mon Sep 17 00:00:00 2001 From: borisrp Date: Wed, 3 Sep 2025 09:48:05 +0200 Subject: [PATCH 45/70] Fix indentation --- hrt/prefab/l3d/LocalVolumetricLighting.hx | 358 +++++++++++----------- 1 file changed, 179 insertions(+), 179 deletions(-) diff --git a/hrt/prefab/l3d/LocalVolumetricLighting.hx b/hrt/prefab/l3d/LocalVolumetricLighting.hx index 8cc741536..e7192d682 100644 --- a/hrt/prefab/l3d/LocalVolumetricLighting.hx +++ b/hrt/prefab/l3d/LocalVolumetricLighting.hx @@ -4,34 +4,34 @@ class LocalVolumetricShader extends hxsl.Shader { static var SRC = { - final EPSILON = 1e-4; - final FLT_MAX = 3.402823466e+38; + final EPSILON = 1e-4; + final FLT_MAX = 3.402823466e+38; - @global var depthMap : Channel; + @global var depthMap : Channel; @global var camera : { var position : Vec3; - var inverseViewProj : Mat4; + var inverseViewProj : Mat4; }; - @global var global : { - @perObject var modelView : Mat4; + @global var global : { + @perObject var modelView : Mat4; @perObject var modelViewInverse : Mat4; }; - @param var obH : Vec3; + @param var obH : Vec3; - @param var fogColor : Vec4; - @param var fogDensity : Float; - @param var fogFade : Float; + @param var fogColor : Vec4; + @param var fogDensity : Float; + @param var fogFade : Float; - var screenUV : Vec2; - var transformedPosition : Vec3; - var transformedNormal : Vec3; - var pixelColor : Vec4; + var screenUV : Vec2; + var transformedPosition : Vec3; + var transformedNormal : Vec3; + var pixelColor : Vec4; - function maxComp(a : Vec3) : Float { return max(a.x, max(a.y, a.z)); } - function minComp(a : Vec3) : Float { return min(a.x, min(a.y, a.z)); } + function maxComp(a : Vec3) : Float { return max(a.x, max(a.y, a.z)); } + function minComp(a : Vec3) : Float { return min(a.x, min(a.y, a.z)); } function getPositionAt( uv: Vec2 ) : Vec3 { var depth = depthMap.get(uv); @@ -45,78 +45,78 @@ class LocalVolumetricShader extends hxsl.Shader { return getPositionAt(screenUV); } - function rayBoxIntersection( o : Vec3, d : Vec3) : Vec3 { - var m = 1.0/d; - var n = m*o; - var k = abs(m)*obH; - var t1 = -n - k; - var t2 = -n + k; - var tN = maxComp(t1); - var tF = minComp(t2); - var hit = vec3(tN, tF, 1.0); - if(tN>tF || tF<0.0) { - hit = vec3(-1.0, -1.0, -1.0); - } - return hit; - } - - function getPath(o : Vec3, d : Vec3) : Vec4 { - var dir = normalize(d); - var hit = rayBoxIntersection(o, dir); - var path = vec4(o, -1.0); - if(hit.z > 0.0){ - if(hit.x > 0.0){ - path = vec4(o+hit.x*dir, hit.y - hit.x); - } else { - path.w = hit.y; - } - } - - var backgroundLocalPosition = (vec4(getPosition(), 1.0) * global.modelViewInverse).xyz; - var backgroundDist = length(backgroundLocalPosition-path.xyz); - path.w = min(path.w, backgroundDist); - return path; - } - - function boxDistance(p : Vec3) : Float { - var d = abs(p) - obH; - return length(max(d,0.0)) + min(maxComp(d),0.0); - } - - function boxDensity( o : Vec3, d : Vec3, t : Float) : Float{ - var ir2 = 1.0/(obH*obH); - var a = 1.0 - (o*o)*ir2; - var b = - 2.0*(o*d)*ir2; - var c = - (d*d)*ir2; - - var t1 = t; - var t2 = t1*t1; - var t3 = t2*t1; - var t4 = t2*t2; - var t5 = t2*t3; - var t6 = t3*t3; - var t7 = t3*t4; - - var f = (t1/1.0) *(a.x*a.y*a.z) + - (t2/2.0) *(a.x*a.y*b.z + a.x*b.y*a.z + b.x*a.y*a.z) + - (t3/3.0) *(a.x*a.y*c.z + a.x*b.y*b.z + a.x*c.y*a.z + b.x*a.y*b.z + b.x*b.y*a.z + c.x*a.y*a.z) + - (t4/4.0) *(a.x*b.y*c.z + a.x*c.y*b.z + b.x*a.y*c.z + b.x*b.y*b.z + b.x*c.y*a.z + c.x*a.y*b.z + c.x*b.y*a.z) + - (t5/5.0) *(a.x*c.y*c.z + b.x*b.y*c.z + b.x*c.y*b.z + c.x*a.y*c.z + c.x*b.y*b.z + c.x*c.y*a.z) + - (t6/6.0) *(b.x*c.y*c.z + c.x*b.y*c.z + c.x*c.y*b.z) + - (t7/7.0) *(c.x*c.y*c.z); - - return f; - } - - function sampleFog(pos : Vec3, dir : Vec3, dist : Float) : Float { - return clamp(fogDensity * boxDensity(pos, dir, dist) / fogFade, 0.0, fogDensity); - } - - function integrateBox(pos : Vec3, dir: Vec3, dist : Float, integrationValues : Vec4) : Vec4 { - var extinction = sampleFog(pos, dir, dist/length(dir)); + function rayBoxIntersection( o : Vec3, d : Vec3) : Vec3 { + var m = 1.0/d; + var n = m*o; + var k = abs(m)*obH; + var t1 = -n - k; + var t2 = -n + k; + var tN = maxComp(t1); + var tF = minComp(t2); + var hit = vec3(tN, tF, 1.0); + if(tN>tF || tF<0.0) { + hit = vec3(-1.0, -1.0, -1.0); + } + return hit; + } + + function getPath(o : Vec3, d : Vec3) : Vec4 { + var dir = normalize(d); + var hit = rayBoxIntersection(o, dir); + var path = vec4(o, -1.0); + if(hit.z > 0.0){ + if(hit.x > 0.0){ + path = vec4(o+hit.x*dir, hit.y - hit.x); + } else { + path.w = hit.y; + } + } + + var backgroundLocalPosition = (vec4(getPosition(), 1.0) * global.modelViewInverse).xyz; + var backgroundDist = length(backgroundLocalPosition-path.xyz); + path.w = min(path.w, backgroundDist); + return path; + } + + function boxDistance(p : Vec3) : Float { + var d = abs(p) - obH; + return length(max(d,0.0)) + min(maxComp(d),0.0); + } + + function boxDensity( o : Vec3, d : Vec3, t : Float) : Float{ + var ir2 = 1.0/(obH*obH); + var a = 1.0 - (o*o)*ir2; + var b = - 2.0*(o*d)*ir2; + var c = - (d*d)*ir2; + + var t1 = t; + var t2 = t1*t1; + var t3 = t2*t1; + var t4 = t2*t2; + var t5 = t2*t3; + var t6 = t3*t3; + var t7 = t3*t4; + + var f = (t1/1.0) *(a.x*a.y*a.z) + + (t2/2.0) *(a.x*a.y*b.z + a.x*b.y*a.z + b.x*a.y*a.z) + + (t3/3.0) *(a.x*a.y*c.z + a.x*b.y*b.z + a.x*c.y*a.z + b.x*a.y*b.z + b.x*b.y*a.z + c.x*a.y*a.z) + + (t4/4.0) *(a.x*b.y*c.z + a.x*c.y*b.z + b.x*a.y*c.z + b.x*b.y*b.z + b.x*c.y*a.z + c.x*a.y*b.z + c.x*b.y*a.z) + + (t5/5.0) *(a.x*c.y*c.z + b.x*b.y*c.z + b.x*c.y*b.z + c.x*a.y*c.z + c.x*b.y*b.z + c.x*c.y*a.z) + + (t6/6.0) *(b.x*c.y*c.z + c.x*b.y*c.z + c.x*c.y*b.z) + + (t7/7.0) *(c.x*c.y*c.z); + + return f; + } + + function sampleFog(pos : Vec3, dir : Vec3, dist : Float) : Float { + return clamp(fogDensity * boxDensity(pos, dir, dist) / fogFade, 0.0, fogDensity); + } + + function integrateBox(pos : Vec3, dir: Vec3, dist : Float, integrationValues : Vec4) : Vec4 { + var extinction = sampleFog(pos, dir, dist/length(dir)); var clampedExtinction = max(extinction, 1e-5); var transmittance = exp(-extinction*dist); - var integScatt = fogColor.rgb; + var integScatt = fogColor.rgb; integrationValues.rgb += integrationValues.a * integScatt; integrationValues.a *= transmittance; @@ -124,129 +124,129 @@ class LocalVolumetricShader extends hxsl.Shader { return integrationValues; } - function evaluate() : Vec4 { - var dir = normalize(transformedPosition - camera.position); - var pos = camera.position; + function evaluate() : Vec4 { + var dir = normalize(transformedPosition - camera.position); + var pos = camera.position; - dir = dir * global.modelViewInverse.mat3(); - pos = (vec4(pos, 1) * global.modelViewInverse).xyz; + dir = dir * global.modelViewInverse.mat3(); + pos = (vec4(pos, 1) * global.modelViewInverse).xyz; - var path = getPath(pos, dir); + var path = getPath(pos, dir); - var integrationValues = vec4(0.0,0.0,0.0,1.0); - return integrateBox(path.xyz, dir, path.w, integrationValues); - } + var integrationValues = vec4(0.0,0.0,0.0,1.0); + return integrateBox(path.xyz, dir, path.w, integrationValues); + } function fragment() { - var volumetric = evaluate(); - volumetric.a = saturate(1.0 - volumetric.a); - volumetric.a = volumetric.a > 1.0 - 1e-3 ? 1.0 : volumetric.a; - pixelColor = volumetric; + var volumetric = evaluate(); + volumetric.a = saturate(1.0 - volumetric.a); + volumetric.a = volumetric.a > 1.0 - 1e-3 ? 1.0 : volumetric.a; + pixelColor = volumetric; } } } class LocalVolumetricLightingObject extends h3d.scene.Object { - public var localVolume : LocalVolumetricLighting; - public var bounds : h3d.col.OrientedBounds; - - public var mesh : h3d.scene.Mesh; - public var boundsDisplay : h3d.scene.Graphics; - - public var shader : LocalVolumetricShader; - - public function new(parent:h3d.scene.Object, localVolume:LocalVolumetricLighting) { - this.localVolume = localVolume; - super(parent); - bounds = new h3d.col.OrientedBounds(); - - var prim = new h3d.prim.Cube(1,1,1,true); - prim.addNormals(); - mesh = new h3d.scene.Mesh(prim, this); - - var material = mesh.material; - material.castShadows = false; - mesh.material.mainPass.setPassName("volumetricOverlay"); - mesh.material.mainPass.setBlendMode(h3d.mat.BlendMode.Alpha); - - shader = new LocalVolumetricShader(); - - material.mainPass.addShader(shader); - - refresh(); - } - - function isInside(ctx : h3d.scene.RenderContext) : Bool { - var pos = ctx.camera.pos.clone().add(ctx.camera.getForward().scaled(ctx.camera.zNear)); - pos.transform(this.getInvPos()); - return pos.x >= -bounds.hx && pos.x <= bounds.hx && - pos.y >= -bounds.hy && pos.y <= bounds.hy && - pos.z >= -bounds.hz && pos.z <= bounds.hz; - } - - override function sync(ctx : h3d.scene.RenderContext) { - var inside = isInside(ctx); - if(inside){ - mesh.material.mainPass.culling = Front; - mesh.material.mainPass.depthTest = Always; - } else{ - mesh.material.mainPass.culling = Back; - mesh.material.mainPass.depthTest = Less; - } - } - - public function refresh() { - var ob = bounds; - shader.obH.set(ob.hx, ob.hy, ob.hz); - - shader.fogColor.setColor(localVolume.color); - shader.fogDensity = localVolume.fogDensity; - shader.fogFade = localVolume.fogFade; - - if(localVolume.showBounds){ - boundsDisplay = bounds.makeDebugObj(); - boundsDisplay.lineStyle(2, 0xFFFFFF); - addChild(boundsDisplay); - } else if(boundsDisplay != null){ - removeChild(boundsDisplay); - boundsDisplay = null; - } - } + public var localVolume : LocalVolumetricLighting; + public var bounds : h3d.col.OrientedBounds; + + public var mesh : h3d.scene.Mesh; + public var boundsDisplay : h3d.scene.Graphics; + + public var shader : LocalVolumetricShader; + + public function new(parent:h3d.scene.Object, localVolume:LocalVolumetricLighting) { + this.localVolume = localVolume; + super(parent); + bounds = new h3d.col.OrientedBounds(); + + var prim = new h3d.prim.Cube(1,1,1,true); + prim.addNormals(); + mesh = new h3d.scene.Mesh(prim, this); + + var material = mesh.material; + material.castShadows = false; + mesh.material.mainPass.setPassName("volumetricOverlay"); + mesh.material.mainPass.setBlendMode(h3d.mat.BlendMode.Alpha); + + shader = new LocalVolumetricShader(); + + material.mainPass.addShader(shader); + + refresh(); + } + + function isInside(ctx : h3d.scene.RenderContext) : Bool { + var pos = ctx.camera.pos.clone().add(ctx.camera.getForward().scaled(ctx.camera.zNear)); + pos.transform(this.getInvPos()); + return pos.x >= -bounds.hx && pos.x <= bounds.hx && + pos.y >= -bounds.hy && pos.y <= bounds.hy && + pos.z >= -bounds.hz && pos.z <= bounds.hz; + } + + override function sync(ctx : h3d.scene.RenderContext) { + var inside = isInside(ctx); + if(inside){ + mesh.material.mainPass.culling = Front; + mesh.material.mainPass.depthTest = Always; + } else{ + mesh.material.mainPass.culling = Back; + mesh.material.mainPass.depthTest = Less; + } + } + + public function refresh() { + var ob = bounds; + shader.obH.set(ob.hx, ob.hy, ob.hz); + + shader.fogColor.setColor(localVolume.color); + shader.fogDensity = localVolume.fogDensity; + shader.fogFade = localVolume.fogFade; + + if(localVolume.showBounds){ + boundsDisplay = bounds.makeDebugObj(); + boundsDisplay.lineStyle(2, 0xFFFFFF); + addChild(boundsDisplay); + } else if(boundsDisplay != null){ + removeChild(boundsDisplay); + boundsDisplay = null; + } + } } class LocalVolumetricLighting extends hrt.prefab.Object3D { - var localVolumeObject : LocalVolumetricLightingObject; + var localVolumeObject : LocalVolumetricLightingObject; - @:s public var fogDensity : Float = 1.0; - @:s public var fogFade : Float = 1.0; - @:s public var color : Int = 0xFFFFFF; + @:s public var fogDensity : Float = 1.0; + @:s public var fogFade : Float = 1.0; + @:s public var color : Int = 0xFFFFFF; - @:s public var showBounds : Bool = false; + @:s public var showBounds : Bool = false; - override function makeObject(parent3d: h3d.scene.Object) : h3d.scene.Object { - localVolumeObject = new LocalVolumetricLightingObject(parent3d, this); - return localVolumeObject; + override function makeObject(parent3d: h3d.scene.Object) : h3d.scene.Object { + localVolumeObject = new LocalVolumetricLightingObject(parent3d, this); + return localVolumeObject; } override function updateInstance(?propName) { - super.updateInstance(propName); + super.updateInstance(propName); localVolumeObject.refresh(); } #if editor override function edit( ctx : hide.prefab.EditContext ) { - super.edit(ctx); + super.edit(ctx); ctx.properties.add(new hide.Element('
-
Density
-
Fade
+
Density
+
Fade
Color
-
+
Show Bounds
@@ -255,5 +255,5 @@ class LocalVolumetricLighting extends hrt.prefab.Object3D { } #end - static var _ = hrt.prefab.Prefab.register("LocalVolumeLighting", LocalVolumetricLighting); -} \ No newline at end of file + static var _ = hrt.prefab.Prefab.register("LocalVolumeLighting", LocalVolumetricLighting); +} From 318fd34692beb11a871e71af9db437161739420d Mon Sep 17 00:00:00 2001 From: lviguier Date: Wed, 3 Sep 2025 11:41:53 +0200 Subject: [PATCH 46/70] Tree/Properties: fix layout --- bin/style.css | 1 + bin/style.less | 1 + hide/comp/FancyTree.hx | 18 ++++++++---------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bin/style.css b/bin/style.css index ffdb7c875..4d3668cab 100644 --- a/bin/style.css +++ b/bin/style.css @@ -1195,6 +1195,7 @@ input[type=checkbox].indeterminate:after { .hide-properties dd { position: relative; width: calc(200px - var(--level) * 2%); + max-width: 200px; margin-left: 10px; } .hide-properties .texture-preview { diff --git a/bin/style.less b/bin/style.less index 2e6ffd691..1ea3072c9 100644 --- a/bin/style.less +++ b/bin/style.less @@ -1312,6 +1312,7 @@ input[type=checkbox] { dd { position:relative; width: calc(200px - var(--level) * 2%); + max-width: 200px; margin-left:10px; } diff --git a/hide/comp/FancyTree.hx b/hide/comp/FancyTree.hx index 05c6d1a35..48504538c 100644 --- a/hide/comp/FancyTree.hx +++ b/hide/comp/FancyTree.hx @@ -138,18 +138,16 @@ class FancyTree extends hide.comp.Component { loadState(); - if (allowSearch) { - searchBarClosable = new FancyClosable(null, element.find("fancy-closable")); + searchBarClosable = new FancyClosable(null, element.find("fancy-closable")); - searchBar = new FancySearch(null, element.find("fancy-search")); - searchBar.onSearch = (search, _) -> { - currentSearch = search.toLowerCase(); - queueRefresh(Search); - } + searchBar = new FancySearch(null, element.find("fancy-search")); + searchBar.onSearch = (search, _) -> { + currentSearch = search.toLowerCase(); + queueRefresh(Search); + } - searchBarClosable.onClose = () -> { - onSearchClose(); - } + searchBarClosable.onClose = () -> { + onSearchClose(); } scroll = params?.customScroll == null ? el.find("fancy-scroll").get(0) : params.customScroll; From 0c76c072937dbc22e3bf51017e12b25592f55d77 Mon Sep 17 00:00:00 2001 From: borisrp Date: Thu, 4 Sep 2025 12:09:24 +0200 Subject: [PATCH 47/70] Fix terrain shader that can cause infinite loop under certain conditions --- hrt/shader/Terrain.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrt/shader/Terrain.hx b/hrt/shader/Terrain.hx index 6d48f54d0..2f52f909b 100644 --- a/hrt/shader/Terrain.hx +++ b/hrt/shader/Terrain.hx @@ -111,7 +111,7 @@ class Terrain extends hxsl.Shader { var viewNS = normalize(camera.position - transformedPosition) * TBN; viewNS.xy /= viewNS.z; viewNS.x *= -1; - var numLayers = mix(float(maxStep), float(minStep), viewNS.dot(terrainNormal)); + var numLayers = mix(float(maxStep), float(minStep), saturate(viewNS.dot(terrainNormal))); var layerDepth = 1.0 / numLayers; var curLayerDepth = 0.; var delta = (viewNS.xy * parallaxAmount / primSize) / numLayers; From 08c86ecfb9770c78d3e111c54922d256f47da4d3 Mon Sep 17 00:00:00 2001 From: borisrp Date: Thu, 4 Sep 2025 17:02:39 +0200 Subject: [PATCH 48/70] Fix behavior where shadowMode is None but the shadow display because cascade is enabled. We keep the choice to turn all cascadeShadows enabled to be dynamic because we can't handle static nor mixed cascadeShadows. --- hrt/prefab/Light.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrt/prefab/Light.hx b/hrt/prefab/Light.hx index 2f354cb79..ba001d942 100644 --- a/hrt/prefab/Light.hx +++ b/hrt/prefab/Light.hx @@ -237,7 +237,7 @@ class Light extends Object3D { cs.transitionFraction = transitionFraction; cs.debugShader = debugShader; cs.blur.radius = 0.0; - cs.mode = Dynamic; + cs.mode = shadows.mode == None ? None : Dynamic; params.resize(cascadeNbr); for ( i in 0...params.length ) if ( params[i] == null ) From 8b2454cb8cc853845bccbfaf320119eb2009db81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Fri, 5 Sep 2025 17:02:48 +0200 Subject: [PATCH 49/70] [cdb] Set max size to image preview --- bin/cdb.css | 4 ++++ bin/cdb.less | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/bin/cdb.css b/bin/cdb.css index 12daebad2..ee25c68fe 100644 --- a/bin/cdb.css +++ b/bin/cdb.css @@ -532,6 +532,7 @@ border: 1px solid black; padding: 5px; z-index: 810; + max-width: 500px; } .cdb .cdb-sheet td.t_file .preview .previewContent .label { text-align: center; @@ -539,6 +540,9 @@ background-color: #444; font-family: monospace; } +.cdb .cdb-sheet td.t_file .preview .previewContent > img { + width: 100%; +} .cdb .cdb-sheet td.t_file .inlineImage > img { max-height: 100px; } diff --git a/bin/cdb.less b/bin/cdb.less index e8945f525..63d892509 100644 --- a/bin/cdb.less +++ b/bin/cdb.less @@ -605,6 +605,12 @@ border : 1px solid black; padding : 5px; z-index : @cdb-preview-layer; + + max-width: 500px; + + >img { + width: 100%; + } } } .inlineImage { From cc91122a03b6cf22228acc804286c5c80be4d830 Mon Sep 17 00:00:00 2001 From: ncannasse Date: Sat, 6 Sep 2025 11:03:43 +0200 Subject: [PATCH 50/70] review formulas types & scoping for group + enums --- hide/comp/cdb/Formulas.hx | 84 ++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/hide/comp/cdb/Formulas.hx b/hide/comp/cdb/Formulas.hx index 754942892..a782c8f3d 100644 --- a/hide/comp/cdb/Formulas.hx +++ b/hide/comp/cdb/Formulas.hx @@ -179,29 +179,34 @@ class Formulas { if( s.props.hasIndex ) m.index = s.lines.indexOf(o); if( s.props.hasGroup ) { - var gid = -1; var sindex = 0; var sheet = s; + var last = "None"; // skip separators if at head while( true ) { var s = sheet.separators[sindex]; if( s == null || s.index != 0 ) break; sindex++; - if( s.title != null ) gid++; + if( s.title != null ) + last = s.title; } - if( gid < 0 ) gid++; // None insert var index = s.lines.indexOf(o); for( i in sindex...sheet.separators.length ) { var s = sheet.separators[i]; if( s.index > index ) break; - if( s.title != null ) gid++; + if( s.title != null ) + last = s.title; } - m.group = gid; + m.group = toIdent(last); } return m; } + public static function toIdent( name : String ) { + return ~/[^A-Za-z0-9_]/g.replace(name,"_"); + } + function load() { var code = try sys.io.File.getContent(ide.getPath(formulasFile)) catch( e : Dynamic ) return; var parser = new hscript.Parser(); @@ -209,16 +214,25 @@ class Formulas { var expr = try parser.parseString(code) catch( e : Dynamic ) return; var sheetNames = new Map(); - for( s in editor.base.sheets ) - sheetNames.set(getTypeName(s), s); + var enumNames = new Map(); + for( s in editor.base.sheets ) { + var name = getTypeName(s); + sheetNames.set(name, s); + if( s.props.hasGroup ) + enumNames.set(name+"_group", true); + for( c in s.columns ) { + switch( c.type ) { + case TEnum(_): + enumNames.set(name+"_"+c.name, true); + default: + } + } + } var changed = false; var refs : Array = []; function replaceRec( e : hscript.Expr ) { switch( e.e ) { - case EField({ e : EIdent(s) }, name) if ( s == "Sheets" ): - e.e = EIdent(name); - changed = true; case EField({ e : EIdent(s) }, name) if( sheetNames.exists(s) ): if( name == "all" || name == "resolve" ) { var found = false; @@ -229,6 +243,8 @@ class Formulas { refs.push(new SheetAccess(this, s)); } else if( sheetNames.get(s).idCol != null ) e.e = EConst(CString(name)); // replace for faster eval + case EField({ e : EIdent(s) }, name) if( enumNames.exists(s) ): + e.e = EConst(CString(name)); // replace for faster eval default: hscript.Tools.iter(e, replaceRec); } @@ -246,6 +262,8 @@ class Formulas { var o : Dynamic = { Math : Math, Ok : ValidationResult.Ok, Error : ValidationResult.Error, Warning : ValidationResult.Warning }; for( r in refs ) Reflect.setField(o,r.name, r); + + hscript.JsInterp.defineArrayExtensions(); var interp = new hscript.JsInterp(); interp.ctx = o; interp.properties = ["all" => true]; @@ -433,8 +451,8 @@ class FormulasView extends hide.view.Script { } var carray = switch( _tarray ) { case TInst(c,_): c; default: throw "assert"; } function tarray(t) return TInst(carray,[t]); + function mkType(name,t) return TType({name:name,params:[],t:t},[]); - var sfields : Array<{name : String, t : TType, opt : Bool}> = []; var cdefs = new Map(); for( s in ide.database.sheets ) { var cdef : CClass = { @@ -449,20 +467,33 @@ class FormulasView extends hide.view.Script { name : "all", t : tarray(TInst(cdef,[])), opt : false, - }, - { + } + ]; + if( s.idCol != null ) { + var tkind = skind.get(s.name); + afields.push({ name : "resolve", t : TFun([{t:tstring,name:"id",opt:false}],TInst(cdef,[])), opt : false, + }); + for( v in s.getLines() ) { + var id = Reflect.field(v, s.idCol.name); + if( id != null && id != "" ) + afields.push({ name : id, t : tkind, opt : false }); } - ]; + } + var t = mkType("#"+cdef.name,TAnon(afields)); + check.checker.setGlobal(cdef.name, t); + } - sfields.push({name: cdef.name, t : TAnon(afields), opt : false}); - check.checker.setGlobal(cdef.name, TAnon(afields)); + function defineEnum(name,values:Array) { + values = [for( v in values ) Formulas.toIdent(v)]; + var t = TEnum({ name : name, params : [], constructors : [for( v in values ) {name:v}] },[]); + var tvalues = [for( v in values ) {name:v,t:t,opt:false}]; + check.checker.setGlobal(name,mkType("#"+name,TAnon(tvalues))); + return t; } - check.checker.setGlobal("Sheets", TAnon(sfields)); - var tenum = TInst(check.checker.types.defineClass("EnumValue"),[]); for( s in ide.database.sheets ) { var cdef = cdefs.get(s.name); inline function addField(name,t) { @@ -473,9 +504,7 @@ class FormulasView extends hide.view.Script { case TId: skind.get(s.name); case TInt, TColor: TInt; case TEnum(values): - for( v in values ) - check.checker.setGlobal(v,tenum); - tenum; + defineEnum(cdef.name+"_"+c.name, values); case TFlags(flags): TAnon([for(f in flags) { name : f, t : TBool, opt : true }]); case TFloat: TFloat; @@ -492,8 +521,17 @@ class FormulasView extends hide.view.Script { if( t == null ) continue; addField(c.name,t); } - if( s.props.hasGroup ) - addField("group",TInt); + if( s.props.hasGroup ) { + var groups = []; + for( s in s.separators ) { + if( s.level == null && s.title != null ) { + if( s.index != 0 && groups.length == 0 ) groups.push("None"); + groups.push(s.title); + } + } + var t = defineEnum(cdef.name+"_group",groups); + addField("group",t); + } if( s.props.hasIndex ) addField("index",TInt); check.checker.types.defineClass(cdef.name, cdef); From e8eb803343abb40ae0b838b1e410d3e75198125c Mon Sep 17 00:00:00 2001 From: ncannasse Date: Sat, 6 Sep 2025 11:12:57 +0200 Subject: [PATCH 51/70] don't define values for subsheets --- hide/comp/cdb/Formulas.hx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hide/comp/cdb/Formulas.hx b/hide/comp/cdb/Formulas.hx index a782c8f3d..7a8870329 100644 --- a/hide/comp/cdb/Formulas.hx +++ b/hide/comp/cdb/Formulas.hx @@ -462,6 +462,8 @@ class FormulasView extends hide.view.Script { params : [], }; cdefs.set(s.name, cdef); + if( s.getParent() != null ) + continue; var afields = [ { name : "all", From a9ade080065aaaaf0b0a769b0575c4ff1fdbe1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 8 Sep 2025 08:18:15 +0200 Subject: [PATCH 52/70] [cdb] Fix paste/delete affecting hidden cells --- hide/comp/cdb/Cursor.hx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/hide/comp/cdb/Cursor.hx b/hide/comp/cdb/Cursor.hx index 7f4aa0527..a954da58a 100644 --- a/hide/comp/cdb/Cursor.hx +++ b/hide/comp/cdb/Cursor.hx @@ -379,7 +379,13 @@ class Cursor { public function getLinesFromSelection(sel : Selection) { if (sel == null || sel.x1 >= 0) return null; - return [for( iy in sel.y1...(sel.y2 + 1) ) table.lines[iy]]; + var array : Array = []; + for( iy in sel.y1...(sel.y2 + 1) ) { + var line = table.lines[iy]; + if (!line.element.hasClass("filtered")) + array.push(line); + } + return array; } public function getCellsFromSelection(sel : Selection) { @@ -389,15 +395,21 @@ class Cursor { var cells = []; if (sel.x1 == -1) { for (y in sel.y1...(sel.y2 + 1)) { - for (x in 0...(table.lines[y].cells.length)) { - cells.push(table.lines[y].cells[x]); + var line = table.lines[y]; + if (line.element.hasClass("filtered")) + continue; + for (x in 0...(line.cells.length)) { + cells.push(line.cells[x]); } } } else { for (y in sel.y1...(sel.y2 + 1)) { + var line = table.lines[y]; + if (line.element.hasClass("filtered")) + continue; for (x in sel.x1...(sel.x2 + 1)) { - cells.push(table.lines[y].cells[x]); + cells.push(line.cells[x]); } } } From 8b3699531842a0e75eef2d2b44d926493e8821bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 8 Sep 2025 15:49:49 +0200 Subject: [PATCH 53/70] [ide] Remove filewatch pause when renaming dirs - Also batch updating the references to the renamed files to further improve performance gains. - Removing the pause lead to big perf increase (1 min) because with the new filebrowser all the files are watched and the pause compute the hash of all the files. Could potentially lead to frezzes but none were found during testing. --- hide/tools/FileManager.hx | 40 +++++++++++++++++++++------------------ hide/view/FileBrowser.hx | 37 +++++++++++------------------------- 2 files changed, 33 insertions(+), 44 deletions(-) diff --git a/hide/tools/FileManager.hx b/hide/tools/FileManager.hx index 6a9afab1c..fc91ba87b 100644 --- a/hide/tools/FileManager.hx +++ b/hide/tools/FileManager.hx @@ -600,12 +600,12 @@ class FileManager { queueProcessPendingMessages(); } - public static function doRename(path:String, name:String) { - var isDir = sys.FileSystem.isDirectory(hide.Ide.inst.getPath(path)); - if( isDir ) hide.Ide.inst.fileWatcher.pause(); - var ret = onRenameRec(path, name); - if( isDir ) hide.Ide.inst.fileWatcher.resume(); - return ret; + public static function doRename(operations: Array<{from: String, to: String}>) { + for (op in operations) { + onRenameRec(op.from, "/" + op.to); + } + + replacePathInFiles(operations); } public static function onRenameRec(path:String, name:String) { @@ -623,6 +623,9 @@ class FileManager { if( newPath == path ) return false; + if (!sys.FileSystem.exists(ide.getPath(path))) + return false; + if( sys.FileSystem.exists(ide.getPath(newPath)) ) { function addPath(path:String,rand:String) { var p = path.split("."); @@ -679,8 +682,6 @@ class FileManager { if( !wasRenamed ) sys.FileSystem.rename(ide.getPath(path), ide.getPath(newPath)); - replacePathInFiles(path, newPath, isDir); - var dataDir = new haxe.io.Path(path); if( dataDir.ext != "dat" ) { dataDir.ext = "dat"; @@ -782,20 +783,23 @@ class FileManager { return true; } - public static function replacePathInFiles(oldPath: String, newPath: String, isDir: Bool = false) { + public static function replacePathInFiles(operations: Array<{from: String, to: String}>) { function filter(ctx: hide.Ide.FilterPathContext) { var p = ctx.valueCurrent; if( p == null ) return; - if( p == oldPath ) { - ctx.change(newPath); - return; - } - if( p == "/"+oldPath ) { - ctx.change(newPath); - return; - } - if( isDir ) { + for (op in operations) { + var oldPath = op.from; + var newPath = op.to; + + if( p == oldPath ) { + ctx.change(newPath); + return; + } + if( p == "/"+oldPath ) { + ctx.change(newPath); + return; + } if( StringTools.startsWith(p,oldPath+"/") ) { ctx.change(newPath + p.substr(oldPath.length)); return; diff --git a/hide/view/FileBrowser.hx b/hide/view/FileBrowser.hx index 203ff3ee4..cdd7d65ac 100644 --- a/hide/view/FileBrowser.hx +++ b/hide/view/FileBrowser.hx @@ -665,7 +665,7 @@ class FileBrowser extends hide.ui.View { if (this.favorites.length == 0) this.favoritesTree.element.parent().hide(); - + // Ressources tree fancyTree = new hide.comp.FancyTree(browserLayout.find(".left").find(".bot"), { saveDisplayKey: "fileBrowserTree_Main", search: true, customScroll: element.find("fancy-scroll").get(0) } ); fancyTree.getChildren = (file: FileEntry) -> { @@ -965,27 +965,13 @@ class FileBrowser extends hide.ui.View { static function execMoveFiles(operations: Array<{from: String, to: String}>, isUndo: Bool) : Void { if (!isUndo) { - for (file in operations) { - // File could have been removed by the system in between our undo/redo operations - if (sys.FileSystem.exists(hide.Ide.inst.getPath(file.from))) { - try { - FileManager.doRename(file.from, "/" + file.to); - } catch (e) { - hide.Ide.inst.quickError('move file ${file.from} -> ${file.to} failed : $e'); - } - } - } + FileManager.doRename(operations); } else { - for (file in operations) { - // File could have been removed by the system in between our undo/redo operations - if (sys.FileSystem.exists(hide.Ide.inst.getPath(file.to))) { - try { - FileManager.doRename(file.to, "/" + file.from); - } catch (e) { - hide.Ide.inst.quickError('move file ${file.from} -> ${file.to} failed : $e'); - } - } + var rev = []; + for (op in operations) { + rev.push({from: op.to, to: op.from}); } + FileManager.doRename(rev); } } @@ -1250,12 +1236,11 @@ class FileBrowser extends hide.ui.View { options.push({ label: "Replace Refs With", click : function() { ide.chooseFile(["*"], (newPath: String) -> { - var selection = [for (file in getItemAndSelection(item, isGallery)) file.getRelPath()]; - if(ide.confirm('Replace all refs of $selection with $newPath ? This action can not be undone')) { - for (oldPath in selection) { - FileManager.replacePathInFiles(oldPath, newPath, false); - } - ide.message("Done"); + var files = [for (file in getItemAndSelection(item, isGallery)) file.getRelPath()]; + if(ide.confirm('Replace all refs of $files with $newPath ? This action can not be undone')) { + var selection = [for (file in files) {from: file, to: newPath}]; + FileManager.replacePathInFiles(selection); + ide.message("All references replaced"); } }); }}); From 8e4defc8a0eff9295fdcab22ca607542b41952a8 Mon Sep 17 00:00:00 2001 From: borisrp Date: Wed, 10 Sep 2025 11:20:05 +0200 Subject: [PATCH 54/70] Use correct packIntColor and unpackIntColor shader functions --- hrt/prefab/fx/gpuemitter/BaseSimulation.hx | 4 ++-- hrt/prefab/fx/gpuemitter/BaseSpawn.hx | 2 +- hrt/prefab/fx/gpuemitter/GPUEmitterObject.hx | 2 +- hrt/prefab/fx/gpuemitter/RandomColorSpawn.hx | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hrt/prefab/fx/gpuemitter/BaseSimulation.hx b/hrt/prefab/fx/gpuemitter/BaseSimulation.hx index bb1af293a..cd3329390 100644 --- a/hrt/prefab/fx/gpuemitter/BaseSimulation.hx +++ b/hrt/prefab/fx/gpuemitter/BaseSimulation.hx @@ -44,7 +44,7 @@ class BaseSimulation extends ComputeUtils { lifeTime = particleBuffer[computeVar.globalInvocation.x].lifeTime; prevModelView = batchBuffer[computeVar.globalInvocation.x].modelView; particleRandom = particleBuffer[computeVar.globalInvocation.x].random; - particleColor = int2rgba(floatBitsToInt(particleBuffer[computeVar.globalInvocation.x].color)); + particleColor = unpackIntColor(floatBitsToInt(particleBuffer[computeVar.globalInvocation.x].color)); relativeTransform = scaleMatrix(((INFINITE || life < lifeTime) ? 1.0 : 0.0) * (computeVar.globalInvocation.x > curCount ? 0.0 : 1.0) * vec3(particleRandom * (maxSize - minSize) + minSize)); } @@ -62,7 +62,7 @@ class BaseSimulation extends ComputeUtils { var idx = computeVar.globalInvocation.x; particleBuffer[idx].life = life + dt; particleBuffer[idx].speed = speed; - particleBuffer[idx].color = intBitsToFloat(rgba2int(particleColor)); + particleBuffer[idx].color = intBitsToFloat(packIntColor(particleColor)); batchBuffer[idx].modelView = modelView; } } diff --git a/hrt/prefab/fx/gpuemitter/BaseSpawn.hx b/hrt/prefab/fx/gpuemitter/BaseSpawn.hx index ce0a436d7..a0776ca21 100644 --- a/hrt/prefab/fx/gpuemitter/BaseSpawn.hx +++ b/hrt/prefab/fx/gpuemitter/BaseSpawn.hx @@ -56,7 +56,7 @@ class BaseSpawn extends ComputeUtils { particleBuffer[idx].life = 0.0; // Keep in memory duration of particle to normalize curve update. particleBuffer[idx].lifeTime = life; - particleBuffer[idx].color = intBitsToFloat(rgba2int(particleColor)); + particleBuffer[idx].color = intBitsToFloat(packIntColor(particleColor)); } } } diff --git a/hrt/prefab/fx/gpuemitter/GPUEmitterObject.hx b/hrt/prefab/fx/gpuemitter/GPUEmitterObject.hx index 5ab14ca57..8ad46e34b 100644 --- a/hrt/prefab/fx/gpuemitter/GPUEmitterObject.hx +++ b/hrt/prefab/fx/gpuemitter/GPUEmitterObject.hx @@ -29,7 +29,7 @@ class ParticleShader extends hxsl.Shader { particleLife = particleBuffer[instanceID].life; particleLifeTime = particleBuffer[instanceID].lifeTime; particleRandom = particleBuffer[instanceID].random; - particleColor = int2rgba(floatBitsToInt(particleBuffer[instanceID].color)); + particleColor = unpackIntColor(floatBitsToInt(particleBuffer[instanceID].color)); } transformedPosition = transformedPosition * absPos.mat3x4(); } diff --git a/hrt/prefab/fx/gpuemitter/RandomColorSpawn.hx b/hrt/prefab/fx/gpuemitter/RandomColorSpawn.hx index b88a6ca4c..21ba9dc85 100644 --- a/hrt/prefab/fx/gpuemitter/RandomColorSpawn.hx +++ b/hrt/prefab/fx/gpuemitter/RandomColorSpawn.hx @@ -12,8 +12,8 @@ class RandomColorSpawnShader extends ComputeUtils { var particleColor : Vec4; function main() { var idx = computeVar.globalInvocation.x; - var fromColor = int2rgba(color1); - var toColor = int2rgba(color2); + var fromColor = unpackIntColor(color1); + var toColor = unpackIntColor(color2); particleColor = mix(fromColor, toColor, particleRandom); } } From 8e6a05279d09c24887bcd251f8904c3808545e91 Mon Sep 17 00:00:00 2001 From: Leonardo Jeanteur Date: Wed, 10 Sep 2025 12:14:33 +0200 Subject: [PATCH 55/70] Add null check on Model.hx prevAbsPosFrame --- hide/view/Model.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hide/view/Model.hx b/hide/view/Model.hx index 87581fd11..d2494f865 100644 --- a/hide/view/Model.hx +++ b/hide/view/Model.hx @@ -2316,7 +2316,8 @@ class Model extends FileView { obj.playAnimation(anim); var skin = Std.downcast(obj, h3d.scene.Skin); - @:privateAccess skin.prevAbsPosFrame = -1; + if (skin != null) + @:privateAccess skin.prevAbsPosFrame = -1; buildTimeline(); buildEventPanel(); modified = false; From ac0340f25b7b8ca6c217aac717c219d5911f3077 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 11 Sep 2025 08:20:11 +0200 Subject: [PATCH 56/70] Update README.md (#277) --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index db98bdd64..f2c0e8108 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ If you don't want to build Hide from source, you can download a nightly build fr #### 1. Install Prerequisites - Install [Haxe](https://haxe.org/) using appropriate installer from https://haxe.org/download/ - Install these libraries: -``` +```shell +haxelib git format https://github.com/HaxeFoundation/format haxelib git heaps https://github.com/HeapsIO/heaps haxelib git castle https://github.com/ncannasse/castle haxelib git hxbit https://github.com/ncannasse/hxbit @@ -30,6 +31,7 @@ haxelib git hscript https://github.com/HaxeFoundation/hscript haxelib git hxnodejs https://github.com/HaxeFoundation/hxnodejs haxelib git domkit https://github.com/HeapsIO/domkit haxelib git hx3compat https://github.com/HaxeFoundation/hx3compat +haxelib git hashlink https://github.com/HaxeFoundation/hashlink master other/haxelib/ ``` #### 2. Build Heaps IDE From de144f3ded6aa611a2bcab629d9c65d37518e8ae Mon Sep 17 00:00:00 2001 From: borisrp Date: Thu, 11 Sep 2025 12:20:06 +0200 Subject: [PATCH 57/70] Fix animation events not saved. Put refresh at the end of the save process. --- hide/view/Model.hx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hide/view/Model.hx b/hide/view/Model.hx index d2494f865..2fc6d882f 100644 --- a/hide/view/Model.hx +++ b/hide/view/Model.hx @@ -264,6 +264,7 @@ class Model extends FileView { if(!modified) return; + var needRefresh = false; // Save render props if (Ide.inst.currentConfig.get("sceneeditor.renderprops.edit", false) && sceneEditor.renderPropsRoot != null) sceneEditor.renderPropsRoot.save(); @@ -326,7 +327,7 @@ class Model extends FileView { var path = state.path; lfs.removePathFromCache(path); @:privateAccess hxd.res.Loader.currentInstance.cache.remove(path); - onRefresh(); + needRefresh = true; } } @@ -348,6 +349,7 @@ class Model extends FileView { } super.save(); + if(needRefresh) onRefresh(); } override function onFileChanged( wasDeleted : Bool, rebuildView = true ) { From 890cb93dda52d6e582db132c8a4357e83714fad5 Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Thu, 11 Sep 2025 16:15:03 +0200 Subject: [PATCH 58/70] Update ModelLibrary for new mesh batch --- hrt/prefab/l3d/modellibrary/Batcher.hx | 2 +- hrt/prefab/l3d/modellibrary/GPUBatcher.hx | 6 +++-- hrt/prefab/l3d/modellibrary/ModelLibrary.hx | 29 ++++++++++++++++----- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/hrt/prefab/l3d/modellibrary/Batcher.hx b/hrt/prefab/l3d/modellibrary/Batcher.hx index 08df15626..ed2dc2d18 100644 --- a/hrt/prefab/l3d/modellibrary/Batcher.hx +++ b/hrt/prefab/l3d/modellibrary/Batcher.hx @@ -85,7 +85,7 @@ class Batcher extends h3d.scene.Object { batch.material.mainPass.addShader(library.killAlpha); } - batch.primitiveSubParts = [new h3d.scene.MeshBatch.MeshBatchPart()]; + batch.primitiveSubMeshes = []; } override function onRemove() { diff --git a/hrt/prefab/l3d/modellibrary/GPUBatcher.hx b/hrt/prefab/l3d/modellibrary/GPUBatcher.hx index 60bc5bb71..70e97914f 100644 --- a/hrt/prefab/l3d/modellibrary/GPUBatcher.hx +++ b/hrt/prefab/l3d/modellibrary/GPUBatcher.hx @@ -42,16 +42,18 @@ class GPUBatcher extends Batcher { var batch : h3d.scene.MeshBatch; if(currentBatchCount > GPUMeshBatchThreshold) { var gpuBatch = new h3d.scene.GPUMeshBatch(getPrimitive(), null, this); + gpuBatch.primitiveSubMeshes = []; gpuBatch.enableGpuCulling(); gpuBatch.enableGpuLod(); - gpuBatch.calcBounds = true; batch = gpuBatch; - } else { + } + else { batch = new h3d.scene.MeshBatch(getPrimitive(), null, this); batch.enableStorageBuffer(); } batch.forceGpuUpdate(); + batch.calcBounds = false; setupMeshBatch(batch, props, material); diff --git a/hrt/prefab/l3d/modellibrary/ModelLibrary.hx b/hrt/prefab/l3d/modellibrary/ModelLibrary.hx index e41b81c46..75cc6b279 100644 --- a/hrt/prefab/l3d/modellibrary/ModelLibrary.hx +++ b/hrt/prefab/l3d/modellibrary/ModelLibrary.hx @@ -141,13 +141,28 @@ class ModelLibrary extends Prefab { function emitInstance(bakedMaterial : BakedMaterialData, primitive : h3d.prim.HMDModel, batch : h3d.scene.MeshBatch, ?absPos : h3d.Matrix) { cache.shader.uvTransform.set(bakedMaterial.uvX, bakedMaterial.uvY, bakedMaterial.uvSX, bakedMaterial.uvSY); cache.shader.libraryParams.set(bakedMaterial.texId, 1.0 / atlasResolution / bakedMaterial.uvSX, 0.0, 0.0); - var primitiveSubPart = batch.primitiveSubParts[0]; - primitiveSubPart.indexCount = bakedMaterial.indexCount; - primitiveSubPart.indexStart = bakedMaterial.indexStart; - primitiveSubPart.lodIndexCount = bakedMaterial.lodIndexCount; - primitiveSubPart.lodIndexStart = bakedMaterial.lodIndexStart; - primitiveSubPart.lodConfig = primitive.getLodConfig(); - primitiveSubPart.bounds = cache.geomBounds[bakedMaterial.geomId]; + var curSubMesh = -1; + for ( subMeshIndex => subMesh in batch.primitiveSubMeshes ) { + var subPart = subMesh.subParts[0]; + if ( subPart.indexStart == bakedMaterial.indexStart ) + curSubMesh = subMeshIndex; + } + if ( curSubMesh == -1 ) { + var subPart = new h3d.scene.MeshBatch.SubPart(); + subPart.indexStart = bakedMaterial.indexStart; + subPart.indexCount = bakedMaterial.indexCount; + subPart.lodIndexStart = bakedMaterial.lodIndexStart; + subPart.lodIndexCount = bakedMaterial.lodIndexCount; + subPart.matIndex = 0; + var subMesh = new h3d.scene.MeshBatch.SubMesh(); + subMesh.lodCount = bakedMaterial.lodIndexCount == null ? 1 : bakedMaterial.lodIndexCount.length + 1; + subMesh.lodConfig = primitive.getLodConfig(); + subMesh.subParts = [subPart]; + subMesh.bounds = cache.geomBounds[bakedMaterial.geomId]; + batch.primitiveSubMeshes.push(subMesh); + curSubMesh = batch.primitiveSubMeshes.length - 1; + } + batch.curSubMesh = curSubMesh; if ( absPos != null ) batch.worldPosition = absPos; batch.emitInstance(); From 948d113604cdf9a981273211d8195acb15af5e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 15 Sep 2025 09:13:40 +0200 Subject: [PATCH 59/70] [cdb] Don't re-focus flags when dismissing popup --- hide/comp/cdb/Cell.hx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hide/comp/cdb/Cell.hx b/hide/comp/cdb/Cell.hx index 3eaeed2cb..10dce4487 100644 --- a/hide/comp/cdb/Cell.hx +++ b/hide/comp/cdb/Cell.hx @@ -1132,7 +1132,7 @@ class Cell { } modal.onClose = () -> { setValue(val); - closeEdit(); + closeEdit(false); }; @:privateAccess modal.reflow(); case TTilePos: @@ -1459,7 +1459,7 @@ class Cell { editor.changeObject(line,column,value); } - public function closeEdit() { + public function closeEdit(refreshFocus: Bool = true) { inEdit = false; var input = new Element(elementHtml).find("div[contenteditable]").get(0); var text : String = input?.innerText; @@ -1469,7 +1469,9 @@ class Cell { } refresh(); - focus(); + if (refreshFocus) { + focus(); + } } public function editCustomType(typeName : String, ctValue : Dynamic, col : cdb.Data.Column, parentEl : Element, rightAnchor: Float, topAnchor : Float, depth : Int = 0) { From 27750193500963581d3e5cc12971fb017346be7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 15 Sep 2025 10:09:51 +0200 Subject: [PATCH 60/70] [popup] Add option to close on escape --- hide/comp/Popup.hx | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/hide/comp/Popup.hx b/hide/comp/Popup.hx index f4dbe1f36..f272d5751 100644 --- a/hide/comp/Popup.hx +++ b/hide/comp/Popup.hx @@ -9,6 +9,7 @@ class Popup extends Component { var timer : haxe.Timer; var isSearchable:Bool; public var anchor : Element; + var globalKeyListener : Dynamic = null; function onMouseDown(e : js.html.MouseEvent) { originalTarget = e.target; @@ -25,7 +26,7 @@ class Popup extends Component { var originalTarget : js.html.EventTarget; public function new(?parent:Element, isSearchable = false) { - super(parent,new Element("
")); + super(parent,new Element("
")); element.attr("popover", "").addClass("popup"); @@ -43,9 +44,6 @@ class Popup extends Component { var body = parent.closest(".lm_content"); if (body.length == 0) body = new Element("body"); - // Browser.document.addEventListener("mousedown",onMouseDown); - // Browser.document.addEventListener("mouseup", onMouseUp); - timer = new haxe.Timer(500); timer.run = function() { if( parent.closest("body").length == 0 ) { @@ -58,6 +56,24 @@ class Popup extends Component { reflow(); } + public function bindCloseOnEscape() { + globalKeyListener = (e: js.html.KeyboardEvent) -> { + // in case somehow our event wasn't properly cleaned up + if (element.closest("body") == null) { + cleanupGlobalKeyListener(); + return; + } + + if (e.key == "Escape") { + close(); + e.preventDefault(); + e.stopPropagation(); + } + }; + + Browser.document.addEventListener("keydown", globalKeyListener, true); + } + public function open() { untyped element.get(0).showPopover(); element.show(); @@ -79,9 +95,17 @@ class Popup extends Component { } element.hide(); onClose(); + if (globalKeyListener != null) { + cleanupGlobalKeyListener(); + } } } + function cleanupGlobalKeyListener() { + Browser.document.removeEventListener("keydown", globalKeyListener, true); + globalKeyListener = null; + } + function fixInputSelect() { var e = new Element("input"); e.each(function (id : Int, elem : js.html.Element) { From 2c78580665ede3e9376bdb0304f5f5b8e3b3bf84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Mon, 15 Sep 2025 10:10:20 +0200 Subject: [PATCH 61/70] [cdb] Close Curve and Flags popup on escape --- hide/comp/cdb/Cell.hx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hide/comp/cdb/Cell.hx b/hide/comp/cdb/Cell.hx index 10dce4487..b8f044a79 100644 --- a/hide/comp/cdb/Cell.hx +++ b/hide/comp/cdb/Cell.hx @@ -1105,6 +1105,8 @@ class Cell { elementHtml.innerHTML = null; var modal = new hide.comp.Popup(new Element(elementHtml)); + modal.bindCloseOnEscape(); + var div = modal.element; div.addClass("flagValues"); div.click(function(e) e.stopPropagation()).dblclick(function(e) e.stopPropagation()); @@ -1316,6 +1318,7 @@ class Cell { var e = new Element(elementHtml); e.addClass("edit"); var curveEditor = new hide.comp.CurveEditor.CurvePopup(e, editor.undo); + curveEditor.bindCloseOnEscape(); var prefabCurve = new hrt.prefab.Curve(null, null); var linear : Float = cast hrt.prefab.Curve.CurveKeyMode.Linear; From 4464a3e01a4a24827be2bf8de4ed4a3f5c0ef758 Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Mon, 15 Sep 2025 11:51:45 +0200 Subject: [PATCH 62/70] Sharpen : Fix on change and unnecessary depth binding --- hrt/prefab/rfx/Sharpen.hx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hrt/prefab/rfx/Sharpen.hx b/hrt/prefab/rfx/Sharpen.hx index ae40af596..e052c1cff 100644 --- a/hrt/prefab/rfx/Sharpen.hx +++ b/hrt/prefab/rfx/Sharpen.hx @@ -34,7 +34,7 @@ class Sharpen extends RendererFX { r.mark("Sharpen"); var sharpen = r.allocTarget("sharpen", true, 1.0, RGBA); var ctx = r.ctx; - ctx.engine.pushTarget(sharpen); + ctx.engine.pushTarget(sharpen, NotBound); sharpenPass.shader.source = ctx.getGlobal("ldrMap"); sharpenPass.shader.intensity = intensity; sharpenPass.shader.resolution.set(ctx.engine.width, ctx.engine.height); @@ -53,7 +53,9 @@ class Sharpen extends RendererFX {
Intensity
- '),this); + '), this, function(pname) { + ctx.onChange(this,pname); + }); } #end From 14878d609dcec12a566b16b49696c07ba4b29545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Tue, 16 Sep 2025 10:16:39 +0200 Subject: [PATCH 63/70] [model] Fix toolbar disapearing --- bin/style.css | 5 +++++ bin/style.less | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/bin/style.css b/bin/style.css index 4d3668cab..747f5c44f 100644 --- a/bin/style.css +++ b/bin/style.css @@ -348,6 +348,8 @@ input[type=checkbox].indeterminate:after { max-height: 100%; overflow: auto; position: relative; + min-width: 0; + min-height: 0; } .hide-modal { position: fixed; @@ -601,6 +603,8 @@ input[type=checkbox].indeterminate:after { .flex-elt { flex: 1; display: flex; + min-height: 0; + min-width: 0; } .flex.vertical { flex-direction: column; @@ -1013,6 +1017,7 @@ input[type=checkbox].indeterminate:after { .hide-tabs .tab.expand { width: 100%; height: 100%; + overflow-y: auto; } .hide-tabs.tabs-bottom > .tabs-header { order: 9999; diff --git a/bin/style.less b/bin/style.less index 1ea3072c9..0a3ede7d9 100644 --- a/bin/style.less +++ b/bin/style.less @@ -374,6 +374,8 @@ input[type=checkbox] { max-height : 100%; overflow : auto; position: relative; + min-width: 0; + min-height: 0; } .hide-modal { @@ -676,6 +678,8 @@ input[type=checkbox] { .flex-elt { flex: 1; display: flex; + min-height: 0; + min-width: 0; } .flex.vertical { @@ -1095,6 +1099,7 @@ input[type=checkbox] { &.expand { width: 100%; height: 100%; + overflow-y: auto; } } } From 9c23526fff9b0b384c08373fd473197e0dbb12ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Tue, 16 Sep 2025 10:26:16 +0200 Subject: [PATCH 64/70] [css] Fix project settings scrolling --- bin/style.css | 25 +++++++++++++++++++++---- bin/style.less | 26 ++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/bin/style.css b/bin/style.css index 747f5c44f..29686e306 100644 --- a/bin/style.css +++ b/bin/style.css @@ -3667,6 +3667,12 @@ div.gradient-box { .project-settings { width: 100%; height: 100%; + display: flex; + flex-direction: column; +} +.project-settings, +.project-settings * { + box-sizing: border-box; } .project-settings h1 { margin: 5px 5px 5px 10px; @@ -3680,11 +3686,13 @@ div.gradient-box { align-self: center; } .project-settings .body { - width: 100%; - height: 100%; + min-height: 0; + flex-grow: 1; display: flex; } .project-settings .body .left-panel { + display: flex; + flex-direction: column; flex: 0.5; padding: 10px; } @@ -3701,11 +3709,20 @@ div.gradient-box { .project-settings .body .right-panel { flex: 1; padding: 10px; + min-height: 0; + overflow-y: auto; + scrollbar-gutter: stable; +} +.project-settings .body .array { + min-height: 0; + display: flex; + flex-direction: column; } .project-settings .body .array .rows { min-height: 20px; max-height: 750px; - overflow-y: scroll; + overflow-y: auto; + scrollbar-gutter: stable; width: 100%; background: #3f3f3f; border-radius: 2px 2px 0px 2px; @@ -3737,7 +3754,7 @@ div.gradient-box { display: none; } .project-settings .body .array .buttons { - float: right; + align-self: flex-end; padding: 5px 10px 5px 10px; border-radius: 0px 0px 2px 2px; background: #3f3f3f; diff --git a/bin/style.less b/bin/style.less index 0a3ede7d9..7bb9e1b28 100644 --- a/bin/style.less +++ b/bin/style.less @@ -4293,6 +4293,13 @@ div.gradient-box { width: 100%; height: 100%; + display: flex; + flex-direction: column; + + &, * { + box-sizing: border-box; + } + h1 { margin: 5px 5px 5px 10px; } @@ -4308,11 +4315,14 @@ div.gradient-box { } .body { - width: 100%; - height:100%; + min-height: 0; + flex-grow: 1; display: flex; .left-panel { + display: flex; + flex-direction: column; + flex: 0.5; padding: 10px; @@ -4333,13 +4343,21 @@ div.gradient-box { .right-panel { flex: 1; padding: 10px; + min-height: 0; + overflow-y: auto; + scrollbar-gutter: stable; } .array { + min-height: 0; + display: flex; + flex-direction: column; .rows { + min-height: 20px; max-height: 750px; - overflow-y: scroll; + overflow-y: auto; + scrollbar-gutter: stable; width: 100%; background: #3f3f3f; border-radius: 2px 2px 0px 2px; @@ -4378,7 +4396,7 @@ div.gradient-box { } .buttons { - float: right; + align-self: flex-end; padding: 5px 10px 5px 10px; border-radius: 0px 0px 2px 2px; background: #3f3f3f; From 96c4c2855f25a510b1ce86a9e23b72c2b5bb2f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Tue, 16 Sep 2025 11:31:58 +0200 Subject: [PATCH 65/70] [model] Added project setting to hightlight materials that have unset mat libs --- bin/style.css | 3 +++ bin/style.less | 4 ++++ hide/view/Model.hx | 11 +++++++++++ 3 files changed, 18 insertions(+) diff --git a/bin/style.css b/bin/style.css index 29686e306..3f64b0e3c 100644 --- a/bin/style.css +++ b/bin/style.css @@ -5525,3 +5525,6 @@ fancy-gallery-item.details .icon-placement { margin-left: 0.2em; font-size: 0.8em; } +.model-view-mat-not-set { + color: #ee6666 !important; +} diff --git a/bin/style.less b/bin/style.less index 7bb9e1b28..73929c8b4 100644 --- a/bin/style.less +++ b/bin/style.less @@ -6618,4 +6618,8 @@ fancy-gallery-item { margin-left: 0.2em; font-size: 0.8em; } +} + +.model-view-mat-not-set { + color: #ee6666 !important; } \ No newline at end of file diff --git a/hide/view/Model.hx b/hide/view/Model.hx index 2fc6d882f..e8ca8fb22 100644 --- a/hide/view/Model.hx +++ b/hide/view/Model.hx @@ -1054,6 +1054,7 @@ class Model extends FileView { } h3d.mat.MaterialSetup.current.saveMaterialProps(m, defaultProps); Ide.inst.quickMessage('Properties for mat (${m.name}) had been saved'); + tree.queueRefresh(RegenHeader); }; saveButton.click(saveCallback); properties.add(matLibrary, m); @@ -1700,6 +1701,16 @@ class Model extends FileView { tree.rebuildTree(); tree.openItem(obj, true); + tree.applyStyle = (item: Dynamic, elt : js.html.Element) -> { + if (hide.Ide.inst.currentConfig.get("highlightUnsetMats") ?? false) { + var mat = Std.downcast(item, h3d.mat.Material); + if (mat != null) { + var props : Dynamic = h3d.mat.MaterialSetup.current.loadMaterialProps(mat); + elt.classList.toggle("model-view-mat-not-set", props == null || props.__ref == null); + } + } + } + tools.clear(); var anims = scene.listAnims(getPath()); From 4c821c0dfa4999fc5402153eb66930df1b979a04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Tue, 16 Sep 2025 14:13:38 +0200 Subject: [PATCH 66/70] [hide] Prevent crash in thumbnail generation --- hide/tools/ThumbnailGenerator.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hide/tools/ThumbnailGenerator.hx b/hide/tools/ThumbnailGenerator.hx index 26c317749..0e393bb51 100644 --- a/hide/tools/ThumbnailGenerator.hx +++ b/hide/tools/ThumbnailGenerator.hx @@ -195,7 +195,7 @@ class ThumbnailGenerator { toHash += getRenderProps(filePath, config); toHash += sys.FileSystem.stat(filePath).mtime.getTime(); if (filePath.split(".").pop().toLowerCase() == "fbx") { - var matInfo = getMaterialInfo(filePath); + var matInfo = try getMaterialInfo(filePath) catch(e) "__error__"; toHash += matInfo; } return haxe.crypto.Md5.encode(toHash); From 49a69abc798b3217e5c867237c400bf5ae061e4d Mon Sep 17 00:00:00 2001 From: TothBenoit Date: Tue, 16 Sep 2025 18:03:03 +0200 Subject: [PATCH 67/70] Update VolumetricLighting --- hrt/prefab/rfx/VolumetricLighting.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hrt/prefab/rfx/VolumetricLighting.hx b/hrt/prefab/rfx/VolumetricLighting.hx index 4bda5d949..1b8b7818b 100644 --- a/hrt/prefab/rfx/VolumetricLighting.hx +++ b/hrt/prefab/rfx/VolumetricLighting.hx @@ -130,7 +130,7 @@ class VolumetricLightingShader extends h3d.shader.pbr.DefaultForward { var skipShadow : Bool = false; function evaluateCascadeShadow() : Float { - var i = dirLightStride + pointLightStride + spotLightStride; + var i = cascadeLightStride; var shadow = 1.0; var shadowProj = mat3x4(lightInfos[i + 2], lightInfos[i + 3], lightInfos[i + 4]); From 674cb732ac586986bc82cd0a8dde8c1f8b7fbde6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Espeute?= Date: Wed, 17 Sep 2025 09:02:24 +0200 Subject: [PATCH 68/70] [cdb] Fix header zOrdering, separator refacto and style tweaks --- bin/cdb.css | 59 +++++++++++------------------------- bin/cdb.less | 62 +++++++++++++------------------------- hide/comp/cdb/Separator.hx | 3 +- 3 files changed, 39 insertions(+), 85 deletions(-) diff --git a/bin/cdb.css b/bin/cdb.css index ee25c68fe..82a08185a 100644 --- a/bin/cdb.css +++ b/bin/cdb.css @@ -61,7 +61,6 @@ overflow-x: auto; width: 100%; table-layout: fixed; - border-collapse: collapse; border-spacing: 0; background-color: #222; position: relative; @@ -123,16 +122,18 @@ cursor: pointer; background-color: #333; border-left: none; + border-bottom: 1px solid #444; } .cdb .cdb-sheet tr.head td.start { cursor: nw-resize; } .cdb .cdb-sheet tr.separator { + --level: 0; height: 10px; } .cdb .cdb-sheet tr.separator td { position: sticky; - top: 19px; + top: 21px; z-index: 2; border-left: none; padding-top: 6px; @@ -148,41 +149,11 @@ .cdb .cdb-sheet tr.separator td .toggle:hover { color: #ccc; } -.cdb .cdb-sheet tr.separator.seplevel-1 td { - background-color: #3d3d3d; -} -.cdb .cdb-sheet tr.separator.seplevel-1 td .toggle { - padding-left: 25px; -} -.cdb .cdb-sheet tr.separator.seplevel-2 td { - background-color: #383838; -} -.cdb .cdb-sheet tr.separator.seplevel-2 td .toggle { - padding-left: 40px; -} -.cdb .cdb-sheet tr.separator.seplevel-3 td { - background-color: #343434; -} -.cdb .cdb-sheet tr.separator.seplevel-3 td .toggle { - padding-left: 50px; -} -.cdb .cdb-sheet tr.separator.seplevel-4 td { - background-color: #303030; -} -.cdb .cdb-sheet tr.separator.seplevel-4 td .toggle { - padding-left: 60px; -} -.cdb .cdb-sheet tr.separator.seplevel-5 td { - background-color: #303030; -} -.cdb .cdb-sheet tr.separator.seplevel-5 td .toggle { - padding-left: 70px; -} -.cdb .cdb-sheet tr.separator.seplevel-6 td { - background-color: #303030; +.cdb .cdb-sheet tr.separator td { + background-color: #NaNNaNNaN; } -.cdb .cdb-sheet tr.separator.seplevel-6 td .toggle { - padding-left: 80px; +.cdb .cdb-sheet tr.separator td .toggle { + padding-left: calc(25px + var(--level) * 20px); } .cdb .cdb-sheet tr.locIgnored { background-color: #221C1C; @@ -238,18 +209,25 @@ .cdb .cdb-sheet tr.clickable:hover { background-color: #f8f8f8; } +.cdb .cdb-sheet thead.head { + background-color: #2A2A2A; + z-index: 9; +} .cdb .cdb-sheet:not(.cdb-sub-sheet) > thead.head { position: sticky; top: 0; } +.cdb .cdb-sheet .cdb-sub-sheet > thead.head { + top: 21px; + z-index: 10; +} .cdb .cdb-sheet tr.head, .cdb .cdb-sheet th { font-weight: bold; text-align: center; padding: 1px 10px 4px 10px; - box-shadow: inset 0px -1px 1px #666; - border-left: 1px solid #444; - background-color: #222; + border-left: 1px solid #666; + border-bottom: 1px solid #666; color: #ddd; width: auto; white-space: nowrap; @@ -263,8 +241,6 @@ .cdb .cdb-sheet td { user-select: none; border-left: 1px solid #444; -} -.cdb .cdb-sheet tr { border-bottom: 1px solid #333; } .cdb .cdb-sheet tr.validation-error td { @@ -397,7 +373,6 @@ outline: 1px solid black; } .cdb .cdb-sheet td.t_flags { - position: relative; overflow: visible; } .cdb .cdb-sheet td.t_ref, diff --git a/bin/cdb.less b/bin/cdb.less index 63d892509..d7b87a06b 100644 --- a/bin/cdb.less +++ b/bin/cdb.less @@ -128,7 +128,7 @@ width : 100%; table-layout:fixed; - border-collapse : collapse; + //border-collapse : collapse; border-spacing : 0; background-color: #222; position: relative; // so that error message follow along with scrolling @@ -144,6 +144,7 @@ cursor : pointer; background-color: #333; border-left: none; + border-bottom : 1px solid #444; } tr.head td.start { @@ -151,10 +152,11 @@ } tr.separator { + --level: 0; height : 10px; td { position: sticky; - top: 19px; + top: 21px; z-index: 2; border-left: none; padding-top: 6px; @@ -170,41 +172,12 @@ } } } - &.seplevel-1 td { - .toggle { - padding-left : 25px; - } - background-color : #3d3d3d; - } - &.seplevel-2 td { - .toggle { - padding-left : 40px; - } - background-color : #383838; - } - &.seplevel-3 td { - .toggle { - padding-left : 50px; - } - background-color : #343434; - } - &.seplevel-4 td { - .toggle { - padding-left : 60px; - } - background-color : #303030; - } - &.seplevel-5 td { - .toggle { - padding-left : 70px; - } - background-color : #303030; - } - &.seplevel-6 td { + + & td { .toggle { - padding-left : 80px; + padding-left : calc(25px + var(--level) * 20px); } - background-color : #303030; + background-color: mix(#3d3d3d, #303030, calc(var(--level) / 6)); } } @@ -264,18 +237,28 @@ background-color : #f8f8f8; } + thead.head { + background-color : #2A2A2A; + z-index: 9; + } + &:not(.cdb-sub-sheet) > thead.head { position: sticky; top: 0; } + .cdb-sub-sheet > thead.head { + top: 21px; + z-index: 10; + + } + tr.head, th { font-weight: bold; text-align: center; padding: 1px 10px 4px 10px; - box-shadow: inset 0px -1px 1px #666; - border-left: 1px solid #444; - background-color : #222; + border-left: 1px solid #666; + border-bottom: 1px solid #666; color : #ddd; width: auto; white-space: nowrap; @@ -291,9 +274,7 @@ td { user-select: none; border-left : 1px solid #444; - } - tr { border-bottom : 1px solid #333; } @@ -446,7 +427,6 @@ } td.t_flags { - position: relative; overflow: visible; } diff --git a/hide/comp/cdb/Separator.hx b/hide/comp/cdb/Separator.hx index 5b8f3d044..1b123809c 100644 --- a/hide/comp/cdb/Separator.hx +++ b/hide/comp/cdb/Separator.hx @@ -238,8 +238,7 @@ class Separator extends Component { } element.attr("level", data.level == null ? 0 : data.level); - element.removeClass("seplevel-"+(data.level == null ? 0 : data.level)); - element.addClass('seplevel-'+(data.level == null ? 0 : data.level)); + element.get(0).style.setProperty("--level", data.level == null ? "0" : ""+data.level); if (refreshChildren) { for (s in subs) From 4464641f6898e142327310bafca994bf3b9eb675 Mon Sep 17 00:00:00 2001 From: borisrp Date: Thu, 18 Sep 2025 09:13:45 +0200 Subject: [PATCH 69/70] Remove unnecessary end of line spaces. --- hrt/prefab/l3d/LocalVolumetricLighting.hx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hrt/prefab/l3d/LocalVolumetricLighting.hx b/hrt/prefab/l3d/LocalVolumetricLighting.hx index e7192d682..05f59177e 100644 --- a/hrt/prefab/l3d/LocalVolumetricLighting.hx +++ b/hrt/prefab/l3d/LocalVolumetricLighting.hx @@ -97,14 +97,14 @@ class LocalVolumetricShader extends hxsl.Shader { var t6 = t3*t3; var t7 = t3*t4; - var f = (t1/1.0) *(a.x*a.y*a.z) + - (t2/2.0) *(a.x*a.y*b.z + a.x*b.y*a.z + b.x*a.y*a.z) + + var f = (t1/1.0) *(a.x*a.y*a.z) + + (t2/2.0) *(a.x*a.y*b.z + a.x*b.y*a.z + b.x*a.y*a.z) + (t3/3.0) *(a.x*a.y*c.z + a.x*b.y*b.z + a.x*c.y*a.z + b.x*a.y*b.z + b.x*b.y*a.z + c.x*a.y*a.z) + - (t4/4.0) *(a.x*b.y*c.z + a.x*c.y*b.z + b.x*a.y*c.z + b.x*b.y*b.z + b.x*c.y*a.z + c.x*a.y*b.z + c.x*b.y*a.z) + - (t5/5.0) *(a.x*c.y*c.z + b.x*b.y*c.z + b.x*c.y*b.z + c.x*a.y*c.z + c.x*b.y*b.z + c.x*c.y*a.z) + - (t6/6.0) *(b.x*c.y*c.z + c.x*b.y*c.z + c.x*c.y*b.z) + + (t4/4.0) *(a.x*b.y*c.z + a.x*c.y*b.z + b.x*a.y*c.z + b.x*b.y*b.z + b.x*c.y*a.z + c.x*a.y*b.z + c.x*b.y*a.z) + + (t5/5.0) *(a.x*c.y*c.z + b.x*b.y*c.z + b.x*c.y*b.z + c.x*a.y*c.z + c.x*b.y*b.z + c.x*c.y*a.z) + + (t6/6.0) *(b.x*c.y*c.z + c.x*b.y*c.z + c.x*c.y*b.z) + (t7/7.0) *(c.x*c.y*c.z); - + return f; } From 48c455d042f24fe000a6be08ec9bb280cd769aa0 Mon Sep 17 00:00:00 2001 From: Leonardo Jeanteur Date: Thu, 18 Sep 2025 09:57:21 +0200 Subject: [PATCH 70/70] Fix moveBack after F12 --- hide/comp/cdb/Editor.hx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hide/comp/cdb/Editor.hx b/hide/comp/cdb/Editor.hx index a42f2f5f3..37b67c0f1 100644 --- a/hide/comp/cdb/Editor.hx +++ b/hide/comp/cdb/Editor.hx @@ -190,7 +190,8 @@ class Editor extends Component { keys.register("cdb.globalSeekIds", () -> new GlobalSeek(cdbTable.element, cdbTable, GlobalIds, currentSheet)); base = sheet.base; - cursor = new Cursor(this); + if( cursor == null ) + cursor = new Cursor(this); if( displayMode == null ) displayMode = Table; DataFiles.load(); @@ -563,7 +564,7 @@ class Editor extends Component { } function onCopy() { - if( cursor.selection == null ) + if( cursor.selection == null || cursor.table == null ) return; function saveValue(out: Dynamic, obj: Dynamic, c: cdb.Data.Column) {