From 334a73305ed080247970dc3a4d45ea190b67a232 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Fri, 23 May 2025 13:23:10 +0200 Subject: [PATCH 01/10] Update LightControl: add validateSupportedLightType() method --- .../com/jme3/scene/control/LightControl.java | 133 +++++++++++------- 1 file changed, 84 insertions(+), 49 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index 0b8bf40a96..3326607607 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2023 jMonkeyEngine + * Copyright (c) 2009-2025 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,19 +49,21 @@ import java.io.IOException; /** - * This Control maintains a reference to a Light, - * which will be synched with the position (worldTranslation) - * of the current spatial. + * `LightControl` synchronizes the world transformation (position and/or + * direction) of a `Light` with its attached `Spatial`. This control allows + * a light to follow a spatial or vice-versa, depending on the chosen + * {@link ControlDirection}. + *

+ * This is particularly useful for attaching lights to animated characters, + * moving vehicles, or dynamically controlled objects. + *

* - * @author tim + * @author Tim + * @author Markil 3 */ public class LightControl extends AbstractControl { - private static final String CONTROL_DIR_NAME = "controlDir"; - private static final String LIGHT_NAME = "light"; - public enum ControlDirection { - /** * Means, that the Light's transform is "copied" * to the Transform of the Spatial. @@ -78,23 +80,33 @@ public enum ControlDirection { private ControlDirection controlDir = ControlDirection.SpatialToLight; /** - * Constructor used for Serialization. + * For serialization only. Do not use. */ public LightControl() { } /** + * Creates a new `LightControl` that synchronizes the light's transform to the spatial. + * * @param light The light to be synced. + * @throws IllegalArgumentException if the light type is not supported + * (only Point, Directional, and Spot lights are supported). */ public LightControl(Light light) { + validateSupportedLightType(light); this.light = light; } /** + * Creates a new `LightControl` with a specified synchronization direction. + * * @param light The light to be synced. - * @param controlDir SpatialToLight or LightToSpatial + * @param controlDir The direction of synchronization (SpatialToLight or LightToSpatial). + * @throws IllegalArgumentException if the light type is not supported + * (only Point, Directional, and Spot lights are supported). */ public LightControl(Light light, ControlDirection controlDir) { + validateSupportedLightType(light); this.light = light; this.controlDir = controlDir; } @@ -104,6 +116,7 @@ public Light getLight() { } public void setLight(Light light) { + validateSupportedLightType(light); this.light = light; } @@ -115,80 +128,102 @@ public void setControlDir(ControlDirection controlDir) { this.controlDir = controlDir; } - // fields used when inverting ControlDirection: + private void validateSupportedLightType(Light light) { + switch (light.getType()) { + case Point: + case Directional: + case Spot: + // These types are supported, validation passes. + break; + default: + throw new IllegalArgumentException( + "LightControl does not support unknown Light type: " + light.getType()); + } + } + @Override protected void controlUpdate(float tpf) { - if (spatial != null && light != null) { - switch (controlDir) { - case SpatialToLight: - spatialToLight(light); - break; - case LightToSpatial: - lightToSpatial(light); - break; - } + switch (controlDir) { + case SpatialToLight: + spatialToLight(light); + break; + case LightToSpatial: + lightToSpatial(light); + break; } } /** - * Sets the light to adopt the spatial's world transformations. + * Updates the light's position and/or direction to match the spatial's + * world transformation. * - * @author Markil 3 - * @author pspeed42 + * @param light The light whose properties will be set. */ private void spatialToLight(Light light) { TempVars vars = TempVars.get(); - final Vector3f worldTranslation = vars.vect1; - worldTranslation.set(spatial.getWorldTranslation()); - final Vector3f worldDirection = vars.vect2; - spatial.getWorldRotation().mult(Vector3f.UNIT_Z, worldDirection).negateLocal(); + final Vector3f worldPosition = vars.vect1; + worldPosition.set(spatial.getWorldTranslation()); + + final Vector3f zDirection = vars.vect2; + spatial.getWorldRotation().mult(Vector3f.UNIT_Z, zDirection).negateLocal(); if (light instanceof PointLight) { - ((PointLight) light).setPosition(worldTranslation); + ((PointLight) light).setPosition(worldPosition); + } else if (light instanceof DirectionalLight) { - ((DirectionalLight) light).setDirection(worldDirection); + ((DirectionalLight) light).setDirection(zDirection); + } else if (light instanceof SpotLight) { - final SpotLight spotLight = (SpotLight) light; - spotLight.setPosition(worldTranslation); - spotLight.setDirection(worldDirection); + SpotLight sl = (SpotLight) light; + sl.setPosition(worldPosition); + sl.setDirection(zDirection); } vars.release(); } /** - * Sets the spatial to adopt the light's world transformations. + * Updates the spatial's local transformation (position and/or rotation) + * to match the light's world transformation. * - * @author Markil 3 + * @param light The light from which properties will be read. */ private void lightToSpatial(Light light) { TempVars vars = TempVars.get(); Vector3f translation = vars.vect1; Vector3f direction = vars.vect2; Quaternion rotation = vars.quat1; - boolean rotateSpatial = false, translateSpatial = false; + boolean rotateSpatial = false; + boolean translateSpatial = false; if (light instanceof PointLight) { - PointLight pLight = (PointLight) light; - translation.set(pLight.getPosition()); + PointLight pl = (PointLight) light; + translation.set(pl.getPosition()); translateSpatial = true; + } else if (light instanceof DirectionalLight) { - DirectionalLight dLight = (DirectionalLight) light; - direction.set(dLight.getDirection()).negateLocal(); + DirectionalLight dl = (DirectionalLight) light; + direction.set(dl.getDirection()).negateLocal(); rotateSpatial = true; + } else if (light instanceof SpotLight) { - SpotLight sLight = (SpotLight) light; - translation.set(sLight.getPosition()); - direction.set(sLight.getDirection()).negateLocal(); - translateSpatial = rotateSpatial = true; + SpotLight sl = (SpotLight) light; + translation.set(sl.getPosition()); + direction.set(sl.getDirection()).negateLocal(); + translateSpatial = true; + rotateSpatial = true; } + + // Transform light's world properties to spatial's parent's local space if (spatial.getParent() != null) { + // Get inverse of parent's world matrix spatial.getParent().getLocalToWorldMatrix(vars.tempMat4).invertLocal(); vars.tempMat4.rotateVect(translation); vars.tempMat4.translateVect(translation); vars.tempMat4.rotateVect(direction); } + // Apply transformed properties to spatial's local transformation if (rotateSpatial) { rotation.lookAt(direction, Vector3f.UNIT_Y).normalizeLocal(); spatial.setLocalRotation(rotation); @@ -214,15 +249,15 @@ public void cloneFields(final Cloner cloner, final Object original) { public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule ic = im.getCapsule(this); - controlDir = ic.readEnum(CONTROL_DIR_NAME, ControlDirection.class, ControlDirection.SpatialToLight); - light = (Light) ic.readSavable(LIGHT_NAME, null); + controlDir = ic.readEnum("controlDir", ControlDirection.class, ControlDirection.SpatialToLight); + light = (Light) ic.readSavable("light", null); } @Override public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule oc = ex.getCapsule(this); - oc.write(controlDir, CONTROL_DIR_NAME, ControlDirection.SpatialToLight); - oc.write(light, LIGHT_NAME, null); + oc.write(controlDir, "controlDir", ControlDirection.SpatialToLight); + oc.write(light, "light", null); } -} \ No newline at end of file +} From 826c86060e84711b20be5ddd5f5f9030a712d13e Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Fri, 23 May 2025 13:28:21 +0200 Subject: [PATCH 02/10] Update exception message --- .../src/main/java/com/jme3/scene/control/LightControl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index 3326607607..5c1bfa69dd 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -137,7 +137,7 @@ private void validateSupportedLightType(Light light) { break; default: throw new IllegalArgumentException( - "LightControl does not support unknown Light type: " + light.getType()); + "Unsupported Light type: " + light.getType()); } } From 9612b188b838ab3edb740dd6929c7f9898489628 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Fri, 23 May 2025 14:33:55 +0200 Subject: [PATCH 03/10] Update LightControl: add axisRotation control --- .../com/jme3/scene/control/LightControl.java | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index 5c1bfa69dd..9a9259acb9 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -78,6 +78,7 @@ public enum ControlDirection { private Light light; private ControlDirection controlDir = ControlDirection.SpatialToLight; + private int axisRotation = 2; // Default to Z-axis /** * For serialization only. Do not use. @@ -128,6 +129,31 @@ public void setControlDir(ControlDirection controlDir) { this.controlDir = controlDir; } + /** + * Returns the index of the spatial's local axis (0=X, 1=Y, 2=Z) that determines + * the light's direction when synchronizing Spatial to Light. + * Defaults to 2 (Z-axis). + * + * @return The axis index (0 for X, 1 for Y, 2 for Z). + */ + public int getAxisRotation() { + return axisRotation; + } + + /** + * Sets the spatial's local axis to be used as the light's forward direction + * when synchronizing Spatial to Light. + * + * @param axisRotation The index of the axis (0, 1, or 2). + * @throws IllegalArgumentException if {@code axisRotation} is not 0, 1, or 2. + */ + public void setAxisRotation(int axisRotation) { + if (axisRotation < 0 || axisRotation > 2) { + throw new IllegalArgumentException("Axis rotation must be 0 (X), 1 (Y), or 2 (Z)."); + } + this.axisRotation = axisRotation; + } + private void validateSupportedLightType(Light light) { switch (light.getType()) { case Point: @@ -165,19 +191,19 @@ private void spatialToLight(Light light) { final Vector3f worldPosition = vars.vect1; worldPosition.set(spatial.getWorldTranslation()); - final Vector3f zDirection = vars.vect2; - spatial.getWorldRotation().mult(Vector3f.UNIT_Z, zDirection).negateLocal(); + final Vector3f lightDirection = vars.vect2; + spatial.getWorldRotation().getRotationColumn(axisRotation, lightDirection).negateLocal(); if (light instanceof PointLight) { ((PointLight) light).setPosition(worldPosition); } else if (light instanceof DirectionalLight) { - ((DirectionalLight) light).setDirection(zDirection); + ((DirectionalLight) light).setDirection(lightDirection); } else if (light instanceof SpotLight) { SpotLight sl = (SpotLight) light; sl.setPosition(worldPosition); - sl.setDirection(zDirection); + sl.setDirection(lightDirection); } vars.release(); } @@ -251,6 +277,7 @@ public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this); controlDir = ic.readEnum("controlDir", ControlDirection.class, ControlDirection.SpatialToLight); light = (Light) ic.readSavable("light", null); + axisRotation = ic.readInt("axisRotation", 2); } @Override @@ -259,5 +286,6 @@ public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); oc.write(controlDir, "controlDir", ControlDirection.SpatialToLight); oc.write(light, "light", null); + oc.write(axisRotation, "axisRotation", 2); } } From 133dac7c11c148f1948cd5208b5258889e30150d Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Sun, 1 Jun 2025 20:46:07 +0200 Subject: [PATCH 04/10] fix wrong lightDirection --- .../src/main/java/com/jme3/scene/control/LightControl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index 9a9259acb9..933e965e63 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -192,7 +192,7 @@ private void spatialToLight(Light light) { worldPosition.set(spatial.getWorldTranslation()); final Vector3f lightDirection = vars.vect2; - spatial.getWorldRotation().getRotationColumn(axisRotation, lightDirection).negateLocal(); + spatial.getWorldRotation().getRotationColumn(axisRotation, lightDirection); if (light instanceof PointLight) { ((PointLight) light).setPosition(worldPosition); From 0c8aa04c755b91d9d66d481f4989053ff8e5c760 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Thu, 5 Jun 2025 11:26:13 +0200 Subject: [PATCH 05/10] Update LightControl: add axisRotation and axisDirection enum --- .../com/jme3/scene/control/LightControl.java | 77 +++++++++++++------ 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index 933e965e63..df9a11ae8a 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -76,9 +76,26 @@ public enum ControlDirection { SpatialToLight } + /** + * Represents the local axis of the spatial (X, Y, or Z) to be used + * for determining the light's direction when `ControlDirection` is + * `SpatialToLight`. + */ + public enum Axis { + X, Y, Z + } + + /** + * Represents the direction (positive or negative) along the chosen axis. + */ + public enum Direction { + Positive, Negative + } + private Light light; private ControlDirection controlDir = ControlDirection.SpatialToLight; - private int axisRotation = 2; // Default to Z-axis + private Axis axisRotation = Axis.Z; + private Direction axisDirection = Direction.Positive; /** * For serialization only. Do not use. @@ -112,6 +129,24 @@ public LightControl(Light light, ControlDirection controlDir) { this.controlDir = controlDir; } + /** + * Creates a new `LightControl` with a specified + * axis of rotation, and axis direction. + * + * @param light The light to be synced. + * @param axisRotation The spatial's local axis to be used as the light's forward direction + * when synchronizing Spatial to Light. + * @param axisDirection The direction along the chosen axis. + * @throws IllegalArgumentException if the light type is not supported + * (only Point, Directional, and Spot lights are supported). + */ + public LightControl(Light light, Axis axisRotation, Direction axisDirection) { + validateSupportedLightType(light); + this.light = light; + this.axisRotation = axisRotation; + this.axisDirection = axisDirection; + } + public Light getLight() { return light; } @@ -129,31 +164,22 @@ public void setControlDir(ControlDirection controlDir) { this.controlDir = controlDir; } - /** - * Returns the index of the spatial's local axis (0=X, 1=Y, 2=Z) that determines - * the light's direction when synchronizing Spatial to Light. - * Defaults to 2 (Z-axis). - * - * @return The axis index (0 for X, 1 for Y, 2 for Z). - */ - public int getAxisRotation() { + public Axis getAxisRotation() { return axisRotation; } - /** - * Sets the spatial's local axis to be used as the light's forward direction - * when synchronizing Spatial to Light. - * - * @param axisRotation The index of the axis (0, 1, or 2). - * @throws IllegalArgumentException if {@code axisRotation} is not 0, 1, or 2. - */ - public void setAxisRotation(int axisRotation) { - if (axisRotation < 0 || axisRotation > 2) { - throw new IllegalArgumentException("Axis rotation must be 0 (X), 1 (Y), or 2 (Z)."); - } + public void setAxisRotation(Axis axisRotation) { this.axisRotation = axisRotation; } + public Direction getAxisDirection() { + return axisDirection; + } + + public void setAxisDirection(Direction axisDirection) { + this.axisDirection = axisDirection; + } + private void validateSupportedLightType(Light light) { switch (light.getType()) { case Point: @@ -192,7 +218,10 @@ private void spatialToLight(Light light) { worldPosition.set(spatial.getWorldTranslation()); final Vector3f lightDirection = vars.vect2; - spatial.getWorldRotation().getRotationColumn(axisRotation, lightDirection); + spatial.getWorldRotation().getRotationColumn(axisRotation.ordinal(), lightDirection); + if (axisDirection == Direction.Negative) { + lightDirection.negateLocal(); + } if (light instanceof PointLight) { ((PointLight) light).setPosition(worldPosition); @@ -277,7 +306,8 @@ public void read(JmeImporter im) throws IOException { InputCapsule ic = im.getCapsule(this); controlDir = ic.readEnum("controlDir", ControlDirection.class, ControlDirection.SpatialToLight); light = (Light) ic.readSavable("light", null); - axisRotation = ic.readInt("axisRotation", 2); + axisRotation = ic.readEnum("axisRotation", Axis.class, Axis.Z); + axisDirection = ic.readEnum("axisDirection", Direction.class, Direction.Positive); } @Override @@ -286,6 +316,7 @@ public void write(JmeExporter ex) throws IOException { OutputCapsule oc = ex.getCapsule(this); oc.write(controlDir, "controlDir", ControlDirection.SpatialToLight); oc.write(light, "light", null); - oc.write(axisRotation, "axisRotation", 2); + oc.write(axisRotation, "axisRotation", Axis.Z); + oc.write(axisDirection, "axisDirection", Direction.Positive); } } From 8911d07eb190bcc5a0202dbb287c80995908c01d Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Thu, 5 Jun 2025 11:30:06 +0200 Subject: [PATCH 06/10] Update LightControl: add toString method --- .../java/com/jme3/scene/control/LightControl.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index df9a11ae8a..ffc00a42c4 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -319,4 +319,16 @@ public void write(JmeExporter ex) throws IOException { oc.write(axisRotation, "axisRotation", Axis.Z); oc.write(axisDirection, "axisDirection", Direction.Positive); } + + @Override + public String toString() { + return getClass().getSimpleName() + + "[light=" + light + + ", controlDir=" + controlDir + + ", axisRotation=" + axisRotation + + ", axisDirection=" + axisDirection + + ", enabled=" + enabled + + ", spatial=" + spatial + + "]"; + } } From 99f6b9de618adde76c1521440d4c5bbe599fd1cf Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Thu, 5 Jun 2025 12:08:45 +0200 Subject: [PATCH 07/10] LightControl: fix lightToSpatial --- .../com/jme3/scene/control/LightControl.java | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index ffc00a42c4..97a4ff056d 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -60,18 +60,20 @@ * * @author Tim * @author Markil 3 + * @author capdevon */ public class LightControl extends AbstractControl { + /** + * Defines the direction of synchronization between the light and the spatial. + */ public enum ControlDirection { /** - * Means, that the Light's transform is "copied" - * to the Transform of the Spatial. + * The light's transform is copied to the spatial's transform. */ LightToSpatial, /** - * Means, that the Spatial's transform is "copied" - * to the Transform of the light. + * The spatial's transform is copied to the light's transform. */ SpatialToLight } @@ -87,6 +89,9 @@ public enum Axis { /** * Represents the direction (positive or negative) along the chosen axis. + * This influences how the light's direction is set when `SpatialToLight` + * and how the spatial's rotation is derived from the light's direction + * when `LightToSpatial`. */ public enum Direction { Positive, Negative @@ -129,24 +134,6 @@ public LightControl(Light light, ControlDirection controlDir) { this.controlDir = controlDir; } - /** - * Creates a new `LightControl` with a specified - * axis of rotation, and axis direction. - * - * @param light The light to be synced. - * @param axisRotation The spatial's local axis to be used as the light's forward direction - * when synchronizing Spatial to Light. - * @param axisDirection The direction along the chosen axis. - * @throws IllegalArgumentException if the light type is not supported - * (only Point, Directional, and Spot lights are supported). - */ - public LightControl(Light light, Axis axisRotation, Direction axisDirection) { - validateSupportedLightType(light); - this.light = light; - this.axisRotation = axisRotation; - this.axisDirection = axisDirection; - } - public Light getLight() { return light; } @@ -245,26 +232,32 @@ private void spatialToLight(Light light) { */ private void lightToSpatial(Light light) { TempVars vars = TempVars.get(); - Vector3f translation = vars.vect1; - Vector3f direction = vars.vect2; + Vector3f lightPosition = vars.vect1; + Vector3f lightDirection = vars.vect2; Quaternion rotation = vars.quat1; boolean rotateSpatial = false; boolean translateSpatial = false; if (light instanceof PointLight) { PointLight pl = (PointLight) light; - translation.set(pl.getPosition()); + lightPosition.set(pl.getPosition()); translateSpatial = true; } else if (light instanceof DirectionalLight) { DirectionalLight dl = (DirectionalLight) light; - direction.set(dl.getDirection()).negateLocal(); + lightDirection.set(dl.getDirection()); + if (axisDirection == Direction.Negative) { + lightDirection.negateLocal(); + } rotateSpatial = true; } else if (light instanceof SpotLight) { SpotLight sl = (SpotLight) light; - translation.set(sl.getPosition()); - direction.set(sl.getDirection()).negateLocal(); + lightPosition.set(sl.getPosition()); + lightDirection.set(sl.getDirection()); + if (axisDirection == Direction.Negative) { + lightDirection.negateLocal(); + } translateSpatial = true; rotateSpatial = true; } @@ -273,18 +266,18 @@ private void lightToSpatial(Light light) { if (spatial.getParent() != null) { // Get inverse of parent's world matrix spatial.getParent().getLocalToWorldMatrix(vars.tempMat4).invertLocal(); - vars.tempMat4.rotateVect(translation); - vars.tempMat4.translateVect(translation); - vars.tempMat4.rotateVect(direction); + vars.tempMat4.rotateVect(lightPosition); + vars.tempMat4.translateVect(lightPosition); + vars.tempMat4.rotateVect(lightDirection); } // Apply transformed properties to spatial's local transformation if (rotateSpatial) { - rotation.lookAt(direction, Vector3f.UNIT_Y).normalizeLocal(); + rotation.lookAt(lightDirection, Vector3f.UNIT_Y).normalizeLocal(); spatial.setLocalRotation(rotation); } if (translateSpatial) { - spatial.setLocalTranslation(translation); + spatial.setLocalTranslation(lightPosition); } vars.release(); } @@ -304,8 +297,8 @@ public void cloneFields(final Cloner cloner, final Object original) { public void read(JmeImporter im) throws IOException { super.read(im); InputCapsule ic = im.getCapsule(this); - controlDir = ic.readEnum("controlDir", ControlDirection.class, ControlDirection.SpatialToLight); light = (Light) ic.readSavable("light", null); + controlDir = ic.readEnum("controlDir", ControlDirection.class, ControlDirection.SpatialToLight); axisRotation = ic.readEnum("axisRotation", Axis.class, Axis.Z); axisDirection = ic.readEnum("axisDirection", Direction.class, Direction.Positive); } @@ -314,8 +307,8 @@ public void read(JmeImporter im) throws IOException { public void write(JmeExporter ex) throws IOException { super.write(ex); OutputCapsule oc = ex.getCapsule(this); - oc.write(controlDir, "controlDir", ControlDirection.SpatialToLight); oc.write(light, "light", null); + oc.write(controlDir, "controlDir", ControlDirection.SpatialToLight); oc.write(axisRotation, "axisRotation", Axis.Z); oc.write(axisDirection, "axisDirection", Direction.Positive); } From 1af2acf92f3ee10c88185716f9c197693ea0db2a Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Sat, 7 Jun 2025 13:51:15 +0200 Subject: [PATCH 08/10] LightControl: replace axisDirection enum with invertAxisDirection boolean field --- .../com/jme3/scene/control/LightControl.java | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index 97a4ff056d..607dd4d2ca 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -87,20 +87,10 @@ public enum Axis { X, Y, Z } - /** - * Represents the direction (positive or negative) along the chosen axis. - * This influences how the light's direction is set when `SpatialToLight` - * and how the spatial's rotation is derived from the light's direction - * when `LightToSpatial`. - */ - public enum Direction { - Positive, Negative - } - private Light light; private ControlDirection controlDir = ControlDirection.SpatialToLight; private Axis axisRotation = Axis.Z; - private Direction axisDirection = Direction.Positive; + private boolean invertAxisDirection = false; /** * For serialization only. Do not use. @@ -159,12 +149,12 @@ public void setAxisRotation(Axis axisRotation) { this.axisRotation = axisRotation; } - public Direction getAxisDirection() { - return axisDirection; + public boolean isInvertAxisDirection() { + return invertAxisDirection; } - public void setAxisDirection(Direction axisDirection) { - this.axisDirection = axisDirection; + public void setInvertAxisDirection(boolean invertAxisDirection) { + this.invertAxisDirection = invertAxisDirection; } private void validateSupportedLightType(Light light) { @@ -206,7 +196,7 @@ private void spatialToLight(Light light) { final Vector3f lightDirection = vars.vect2; spatial.getWorldRotation().getRotationColumn(axisRotation.ordinal(), lightDirection); - if (axisDirection == Direction.Negative) { + if (invertAxisDirection) { lightDirection.negateLocal(); } @@ -246,7 +236,7 @@ private void lightToSpatial(Light light) { } else if (light instanceof DirectionalLight) { DirectionalLight dl = (DirectionalLight) light; lightDirection.set(dl.getDirection()); - if (axisDirection == Direction.Negative) { + if (invertAxisDirection) { lightDirection.negateLocal(); } rotateSpatial = true; @@ -255,7 +245,7 @@ private void lightToSpatial(Light light) { SpotLight sl = (SpotLight) light; lightPosition.set(sl.getPosition()); lightDirection.set(sl.getDirection()); - if (axisDirection == Direction.Negative) { + if (invertAxisDirection) { lightDirection.negateLocal(); } translateSpatial = true; @@ -300,7 +290,7 @@ public void read(JmeImporter im) throws IOException { light = (Light) ic.readSavable("light", null); controlDir = ic.readEnum("controlDir", ControlDirection.class, ControlDirection.SpatialToLight); axisRotation = ic.readEnum("axisRotation", Axis.class, Axis.Z); - axisDirection = ic.readEnum("axisDirection", Direction.class, Direction.Positive); + invertAxisDirection = ic.readBoolean("invertAxisDirection", false); } @Override @@ -310,7 +300,7 @@ public void write(JmeExporter ex) throws IOException { oc.write(light, "light", null); oc.write(controlDir, "controlDir", ControlDirection.SpatialToLight); oc.write(axisRotation, "axisRotation", Axis.Z); - oc.write(axisDirection, "axisDirection", Direction.Positive); + oc.write(invertAxisDirection, "invertAxisDirection", false); } @Override @@ -319,7 +309,7 @@ public String toString() { "[light=" + light + ", controlDir=" + controlDir + ", axisRotation=" + axisRotation + - ", axisDirection=" + axisDirection + + ", invertAxisDirection=" + invertAxisDirection + ", enabled=" + enabled + ", spatial=" + spatial + "]"; From 2632bd9fcbc1b1677c90192f57b13b297a58f184 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Mon, 9 Jun 2025 12:40:02 +0200 Subject: [PATCH 09/10] LightControl: setLight(Light) allows you to set null light --- .../main/java/com/jme3/scene/control/LightControl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index 607dd4d2ca..40540f400a 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -158,6 +158,10 @@ public void setInvertAxisDirection(boolean invertAxisDirection) { } private void validateSupportedLightType(Light light) { + if (light == null) { + return; + } + switch (light.getType()) { case Point: case Directional: @@ -172,6 +176,10 @@ private void validateSupportedLightType(Light light) { @Override protected void controlUpdate(float tpf) { + if (light == null) { + return; + } + switch (controlDir) { case SpatialToLight: spatialToLight(light); From 81fbfd9f1a9665976649962a21d524040a188699 Mon Sep 17 00:00:00 2001 From: Wyatt Gillette Date: Tue, 10 Jun 2025 09:34:14 +0200 Subject: [PATCH 10/10] LightControl: update toString() method --- .../src/main/java/com/jme3/scene/control/LightControl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java index 40540f400a..3c0619b912 100644 --- a/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java +++ b/jme3-core/src/main/java/com/jme3/scene/control/LightControl.java @@ -314,7 +314,7 @@ public void write(JmeExporter ex) throws IOException { @Override public String toString() { return getClass().getSimpleName() + - "[light=" + light + + "[light=" + (light != null ? light.getType() : null) + ", controlDir=" + controlDir + ", axisRotation=" + axisRotation + ", invertAxisDirection=" + invertAxisDirection +