diff --git a/README.md b/README.md index 77e43c08..860272ac 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# jMonkeyBuilder 1.6.1 # +# jMonkeyBuilder 1.7.0 # ### It's 3D Editor to prepare/work/create graphics content for jMonkeyEngine 3.2 ### [![Join the chat at https://gitter.im/jME3-SpaceShift-Editor/Lobby](https://badges.gitter.im/jME3-SpaceShift-Editor/Lobby.svg)](https://gitter.im/jME3-SpaceShift-Editor/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) diff --git a/app.version b/app.version index 2eda823f..9dbb0c00 100644 --- a/app.version +++ b/app.version @@ -1 +1 @@ -1.6.1 \ No newline at end of file +1.7.0 \ No newline at end of file diff --git a/build-native.xml b/build-native.xml index f94032b5..af43d6f8 100644 --- a/build-native.xml +++ b/build-native.xml @@ -180,7 +180,7 @@ - + diff --git a/build.gradle b/build.gradle index 1c2baa2b..ed515ea2 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ apply plugin: 'idea' apply plugin: 'org.junit.platform.gradle.plugin' group = 'com.spaceshift' -version = '1.6.1' +version = '1.7.0' sourceCompatibility = 1.8 targetCompatibility = 1.8 @@ -28,7 +28,7 @@ ext.applicationMainClass = "com.ss.editor.JfxApplication" ext.applicationVendor = "javasabr@gmail.com" ext.applicationTitle = "jMonkeyBuilder" ext.jmeVersion = "v3.3.dev-SNAPSHOT" -ext.jmbExtVersion = "1.9.8" +ext.jmbExtVersion = "2.1.1" ext.jme3_xbuf_version = '0.9.1' ext.junitPlatformVersion = "1.0.0" ext.junitJupiterVersion = "5.0.0" @@ -61,8 +61,10 @@ dependencies { compile 'org.controlsfx:controlsfx:8.40.14' compile 'com.github.JavaSaBr:RlibFX:4.1.3' - compile 'com.github.JavaSaBr:RLib:6.7.4' - compile "com.github.JavaSaBr:JME3-JFX:1.7.3" + compile 'com.github.JavaSaBr:RLib:6.7.7' + compile ("com.github.JavaSaBr:JME3-JFX:1.7.4") { + exclude group: 'org.jmonkeyengine' + } // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.6' @@ -88,7 +90,6 @@ dependencies { compile "com.github.JavaSaBr.jmonkeyengine:jme3-desktop:$jmeVersion" compile "com.github.JavaSaBr.jmonkeyengine:jme3-terrain:$jmeVersion" compile "com.github.JavaSaBr.jmonkeyengine:jme3-plugins:$jmeVersion" - compile "com.github.JavaSaBr.jmonkeyengine:jme3-effects:$jmeVersion" compile "com.github.JavaSaBr.jmonkeyengine:jme3-blender:$jmeVersion" compile "com.github.JavaSaBr.jmonkeyengine:jme3-jogg:$jmeVersion" compile ("com.github.JavaSaBr.jmonkeyengine:jme3-testdata:$jmeVersion") { @@ -163,7 +164,7 @@ task javadocJar(type: Jar, dependsOn: javadoc) { } task wrapper(type: Wrapper) { - gradleVersion = '4.4' + gradleVersion = '4.5.1' } artifacts { diff --git a/embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.1.jar b/embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.3.jar similarity index 79% rename from embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.1.jar rename to embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.3.jar index 250a8847..c9c7a2db 100644 Binary files a/embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.1.jar and b/embedded-plugins/jmb-shader-nodes/jmb-shader-nodes-1.1.3.jar differ diff --git a/embedded-plugins/jmb-sky-control/jmb-sky-control-1.0.0.jar b/embedded-plugins/jmb-sky-control/jmb-sky-control-1.1.0.jar similarity index 56% rename from embedded-plugins/jmb-sky-control/jmb-sky-control-1.0.0.jar rename to embedded-plugins/jmb-sky-control/jmb-sky-control-1.1.0.jar index f076c374..9e2191f6 100644 Binary files a/embedded-plugins/jmb-sky-control/jmb-sky-control-1.0.0.jar and b/embedded-plugins/jmb-sky-control/jmb-sky-control-1.1.0.jar differ diff --git a/embedded-plugins/jmb-tonegod-emitter/jmb-tonegodemitter-1.0.0.jar b/embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.0.2.jar similarity index 82% rename from embedded-plugins/jmb-tonegod-emitter/jmb-tonegodemitter-1.0.0.jar rename to embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.0.2.jar index d358f6c6..28e138c0 100644 Binary files a/embedded-plugins/jmb-tonegod-emitter/jmb-tonegodemitter-1.0.0.jar and b/embedded-plugins/jmb-tonegod-emitter/jmb-tonegod-emitter-1.0.2.jar differ diff --git a/embedded-plugins/jmb-tonegod-emitter/libs/tonegodemitter-2.4.1.jar b/embedded-plugins/jmb-tonegod-emitter/libs/tonegodemitter-2.6.3.jar similarity index 50% rename from embedded-plugins/jmb-tonegod-emitter/libs/tonegodemitter-2.4.1.jar rename to embedded-plugins/jmb-tonegod-emitter/libs/tonegodemitter-2.6.3.jar index 8de1ff95..e1ecfd6b 100644 Binary files a/embedded-plugins/jmb-tonegod-emitter/libs/tonegodemitter-2.4.1.jar and b/embedded-plugins/jmb-tonegod-emitter/libs/tonegodemitter-2.6.3.jar differ diff --git a/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.1.0.jar b/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.1.1.jar similarity index 79% rename from embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.1.0.jar rename to embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.1.1.jar index 4f441569..1a96a3df 100644 Binary files a/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.1.0.jar and b/embedded-plugins/jmb-tree-generator/jmb-tree-generator-1.1.1.jar differ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 01b8bf6b..c44b679a 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6d03836c..568c50bf 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Wed Jan 24 08:56:01 MSK 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip diff --git a/src/main/java/com/jme3/bullet/util/DebugShapeFactory.java b/src/main/java/com/jme3/bullet/util/DebugShapeFactory.java new file mode 100644 index 00000000..68fe74e4 --- /dev/null +++ b/src/main/java/com/jme3/bullet/util/DebugShapeFactory.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2009-2017 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.bullet.util; + +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.collision.shapes.CompoundCollisionShape; +import com.jme3.bullet.collision.shapes.infos.ChildCollisionShape; +import com.jme3.math.Matrix3f; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.util.TempVars; +import java.util.Iterator; +import java.util.List; + +/** + * + * @author CJ Hare, normenhansen + */ +public class DebugShapeFactory { + + /** The maximum corner for the aabb used for triangles to include in ConcaveShape processing.*/ + // private static final Vector3f aabbMax = new Vector3f(1e30f, 1e30f, 1e30f); + /** The minimum corner for the aabb used for triangles to include in ConcaveShape processing.*/ + // private static final Vector3f aabbMin = new Vector3f(-1e30f, -1e30f, -1e30f); + + /** + * Creates a debug shape from the given collision shape. This is mostly used internally.
+ * To attach a debug shape to a physics object, call attachDebugShape(AssetManager manager); on it. + * @param collisionShape + * @return + */ + public static Spatial getDebugShape(CollisionShape collisionShape) { + if (collisionShape == null) { + return null; + } + Spatial debugShape; + if (collisionShape instanceof CompoundCollisionShape) { + CompoundCollisionShape shape = (CompoundCollisionShape) collisionShape; + List children = shape.getChildren(); + Node node = new Node("DebugShapeNode"); + for (Iterator it = children.iterator(); it.hasNext();) { + ChildCollisionShape childCollisionShape = it.next(); + CollisionShape ccollisionShape = childCollisionShape.shape; + Geometry geometry = createDebugShape(ccollisionShape); + + // apply translation + geometry.setLocalTranslation(childCollisionShape.location); + + // apply rotation + TempVars vars = TempVars.get(); + Matrix3f tempRot = vars.tempMat3; + + tempRot.set(geometry.getLocalRotation()); + childCollisionShape.rotation.mult(tempRot, tempRot); + geometry.setLocalRotation(tempRot); + geometry.setLocalScale(ccollisionShape.getScale()); + + vars.release(); + + node.attachChild(geometry); + } + debugShape = node; + } else { + debugShape = createDebugShape(collisionShape); + } + if (debugShape == null) { + return null; + } + debugShape.updateGeometricState(); + return debugShape; + } + + private static Geometry createDebugShape(CollisionShape shape) { + Geometry geom = new Geometry(); + geom.setMesh(DebugShapeFactory.getDebugMesh(shape)); + // geom.setLocalScale(shape.getScale()); + geom.updateModelBound(); + return geom; + } + + public static Mesh getDebugMesh(CollisionShape shape) { + Mesh mesh = new Mesh(); + DebugMeshCallback callback = new DebugMeshCallback(); + /* + * Populate the mesh based on an unscaled shape; + * the shape's scale will be applied later, to the geometry. + */ + Vector3f savedScale = shape.getScale().clone(); + shape.setScale(Vector3f.UNIT_XYZ); + getVertices(shape.getObjectId(), callback); + shape.setScale(savedScale); + + mesh.setBuffer(Type.Position, 3, callback.getVertices()); + mesh.getFloatBuffer(Type.Position).clear(); + return mesh; + } + + private static native void getVertices(long shapeId, DebugMeshCallback buffer); +} diff --git a/src/main/java/com/ss/editor/JfxApplication.java b/src/main/java/com/ss/editor/JfxApplication.java index c6a45d99..bd2d0fe9 100644 --- a/src/main/java/com/ss/editor/JfxApplication.java +++ b/src/main/java/com/ss/editor/JfxApplication.java @@ -6,6 +6,8 @@ import static com.ss.editor.config.DefaultSettingsProvider.Defaults.PREF_DEFAULT_STOP_RENDER_ON_LOST_FOCUS; import static com.ss.editor.config.DefaultSettingsProvider.Preferences.*; import static com.ss.rlib.util.ObjectUtils.notNull; +import static com.ss.rlib.util.Utils.run; +import static java.nio.file.Files.createDirectories; import static java.nio.file.Files.newOutputStream; import com.jme3.renderer.Renderer; import com.jme3.system.JmeContext; @@ -40,7 +42,9 @@ import com.ss.editor.util.OpenGLVersion; import com.ss.editor.util.svg.SvgImageLoaderFactory; import com.ss.rlib.logging.Logger; +import com.ss.rlib.logging.LoggerLevel; import com.ss.rlib.logging.LoggerManager; +import com.ss.rlib.logging.impl.FolderFileListener; import com.ss.rlib.manager.InitializeManager; import com.ss.rlib.util.ArrayUtils; import com.ss.rlib.util.array.Array; @@ -50,6 +54,7 @@ import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.collections.ObservableList; +import javafx.scene.control.ComboBoxBase; import javafx.scene.image.Image; import javafx.stage.Stage; import javafx.stage.StageStyle; @@ -61,8 +66,11 @@ import javax.imageio.ImageIO; import java.io.IOException; import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; +import java.util.logging.Level; /** * The starter of the JavaFX application. @@ -95,6 +103,7 @@ public class JfxApplication extends Application { * @throws IOException the io exception */ public static void main(final String[] args) { + configureLogger(); // need to disable to work on macos Configuration.GLFW_CHECK_THREAD0.set(false); @@ -154,6 +163,31 @@ public static void main(final String[] args) { () -> startJmeApplication(application), "LWJGL Render").start(); } + @FxThread + private static void configureLogger() { + + // disable the standard logger + if (Config.DEV_DEBUG) { + java.util.logging.Logger.getLogger("").setLevel(Level.WARNING); + } + + // configure our logger + LoggerLevel.DEBUG.setEnabled(Config.DEV_DEBUG); + LoggerLevel.INFO.setEnabled(true); + LoggerLevel.ERROR.setEnabled(true); + LoggerLevel.WARNING.setEnabled(true); + + final Path logFolder = Config.getFolderForLog(); + + if (!Files.exists(logFolder)) { + run(() -> createDirectories(logFolder)); + } + + if (!LoggerLevel.DEBUG.isEnabled()) { + LoggerManager.addListener(new FolderFileListener(logFolder)); + } + } + /** * Start the new jME application. * @@ -306,6 +340,9 @@ public void start(final Stage stage) throws Exception { addWindow(stage); try { + // initialize javaFX events in javaFX thread. + ArrayFactory.asArray(ComboBoxBase.ON_SHOWN); + final ResourceManager resourceManager = ResourceManager.getInstance(); resourceManager.reload(); @@ -340,6 +377,7 @@ public void start(final Stage stage) throws Exception { stage.setTitle(Config.TITLE); stage.show(); + if (!stage.isMaximized()) { stage.centerOnScreen(); } diff --git a/src/main/java/com/ss/editor/JmeApplication.java b/src/main/java/com/ss/editor/JmeApplication.java index 3eea79cf..7c351508 100644 --- a/src/main/java/com/ss/editor/JmeApplication.java +++ b/src/main/java/com/ss/editor/JmeApplication.java @@ -4,11 +4,10 @@ import static com.ss.editor.config.DefaultSettingsProvider.Defaults.*; import static com.ss.editor.config.DefaultSettingsProvider.Preferences.*; import static com.ss.rlib.util.ObjectUtils.notNull; -import static com.ss.rlib.util.Utils.run; -import static java.nio.file.Files.createDirectories; import com.jme3.app.DebugKeysAppState; import com.jme3.asset.AssetManager; import com.jme3.asset.AssetNotFoundException; +import com.jme3.asset.plugins.ClasspathLocator; import com.jme3.audio.AudioRenderer; import com.jme3.audio.Environment; import com.jme3.bounding.BoundingSphere; @@ -49,18 +48,13 @@ import com.ss.editor.ui.event.impl.WindowChangeFocusEvent; import com.ss.editor.util.EditorUtil; import com.ss.rlib.logging.Logger; -import com.ss.rlib.logging.LoggerLevel; import com.ss.rlib.logging.LoggerManager; -import com.ss.rlib.logging.impl.FolderFileListener; import com.ss.rlib.util.os.OperatingSystem; import jme3_ext_xbuf.XbufLoader; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.concurrent.locks.StampedLock; -import java.util.logging.Level; /** * The implementation of the {@link com.jme3.app.Application} of this Editor. @@ -104,10 +98,9 @@ public void done(final LightProbe result) { static @NotNull JmeApplication prepareToStart() { if (Config.DEV_DEBUG) { - System.err.println("config is loaded."); + System.err.println("config was loaded."); } - configureLogger(); try { final EditorConfig config = EditorConfig.getInstance(); @@ -126,31 +119,6 @@ public void done(final LightProbe result) { return JME_APPLICATION; } - @JmeThread - private static void configureLogger() { - - // disable the standard logger - if (!Config.DEV_DEBUG) { - java.util.logging.Logger.getLogger("").setLevel(Level.WARNING); - } - - // configure our logger - LoggerLevel.DEBUG.setEnabled(Config.DEV_DEBUG); - LoggerLevel.INFO.setEnabled(true); - LoggerLevel.ERROR.setEnabled(true); - LoggerLevel.WARNING.setEnabled(true); - - final Path logFolder = Config.getFolderForLog(); - - if (!Files.exists(logFolder)) { - run(() -> createDirectories(logFolder)); - } - - if (!LoggerLevel.DEBUG.isEnabled()) { - LoggerManager.addListener(new FolderFileListener(logFolder)); - } - } - /** * The main synchronizer of this application. */ @@ -266,7 +234,7 @@ public void simpleInitApp() { super.simpleInitApp(); renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); - renderManager.setSinglePassLightBatchSize(15); + renderManager.setSinglePassLightBatchSize(10); assetManager.registerLoader(XbufLoader.class, FileExtensions.MODEL_XBUF); @@ -276,8 +244,11 @@ public void simpleInitApp() { LOGGER.debug(this, "OS: " + system.getDistribution()); final AssetManager assetManager = getAssetManager(); + assetManager.unregisterLocator("", ClasspathLocator.class); + assetManager.unregisterLocator("/", ClasspathLocator.class); assetManager.registerLocator("", FolderAssetLocator.class); assetManager.registerLocator("", FileSystemAssetLocator.class); + assetManager.registerLocator("", ClasspathLocator.class); assetManager.addAssetEventListener(EditorConfig.getInstance()); final AudioRenderer audioRenderer = getAudioRenderer(); diff --git a/src/main/java/com/ss/editor/Messages.java b/src/main/java/com/ss/editor/Messages.java index ee451c95..6b6dad20 100644 --- a/src/main/java/com/ss/editor/Messages.java +++ b/src/main/java/com/ss/editor/Messages.java @@ -298,6 +298,8 @@ public class Messages { public static final String MODEL_NODE_TREE_ACTION_SPHERE_COLLISION_SHAPE; public static final String MODEL_NODE_TREE_ACTION_ADD_WHEEL; public static final String MODEL_NODE_TREE_ACTION_ADD_TERRAIN; + public static final String MODEL_NODE_TREE_ACTION_ENABLE_ALL_CONTROLS; + public static final String MODEL_NODE_TREE_ACTION_DISABLE_ALL_CONTROLS; public static final String MODEL_PROPERTY_CULL_HINT; public static final String MODEL_PROPERTY_SHADOW_MODE; @@ -305,6 +307,7 @@ public class Messages { public static final String MODEL_PROPERTY_LOCATION; public static final String MODEL_PROPERTY_SCALE; public static final String MODEL_PROPERTY_ROTATION; + public static final String MODEL_PROPERTY_TRANSFORMATION; public static final String MODEL_PROPERTY_MATERIAL; public static final String MODEL_PROPERTY_DIRECTION; public static final String MODEL_PROPERTY_RADIUS; @@ -352,6 +355,8 @@ public class Messages { public static final String MODEL_PROPERTY_FALL_SPEED; public static final String MODEL_PROPERTY_GRAVITY; public static final String MODEL_PROPERTY_JUMP_SPEED; + public static final String MODEL_PROPERTY_JUMP_FORCE; + public static final String MODEL_PROPERTY_PHYSICS_DAMPING; public static final String MODEL_PROPERTY_MAX_SLOPE; public static final String MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL; public static final String MODEL_PROPERTY_IS_USE_VIEW_DIRECTION; @@ -635,20 +640,22 @@ public class Messages { public static final String CREATE_PARTICLE_EMITTER_TORUS_SHAPE_DIALOG_TITLE; public static final String CREATE_PARTICLE_EMITTER_TRIANGLE_SHAPE_DIALOG_TITLE; - public static final String EDITING_COMPONENT_BRUSH_SIZE; - public static final String EDITING_COMPONENT_BRUSH_POWER; - public static final String EDITING_COMPONENT_SMOOTHLY; - public static final String EDITING_COMPONENT_LIMITED; - public static final String EDITING_COMPONENT_USE_MARKER; - public static final String EDITING_COMPONENT_LEVEL; - public static final String EDITING_COMPONENT_ROUGHNESS; - public static final String EDITING_COMPONENT_FREQUENCY; - public static final String EDITING_COMPONENT_LACUNARITY; - public static final String EDITING_COMPONENT_OCTAVES; - public static final String EDITING_COMPONENT_SCALE; - public static final String EDITING_COMPONENT_TRI_PLANAR; - public static final String EDITING_COMPONENT_SHININESS; - public static final String EDITING_COMPONENT_LAYER; + public static final String PAINTING_COMPONENT_BRUSH_SIZE; + public static final String PAINTING_COMPONENT_BRUSH_POWER; + public static final String PAINTING_COMPONENT_SMOOTHLY; + public static final String PAINTING_COMPONENT_LIMITED; + public static final String PAINTING_COMPONENT_USE_MARKER; + public static final String PAINTING_COMPONENT_LEVEL; + public static final String PAINTING_COMPONENT_ROUGHNESS; + public static final String PAINTING_COMPONENT_FREQUENCY; + public static final String PAINTING_COMPONENT_LACUNARITY; + public static final String PAINTING_COMPONENT_OCTAVES; + public static final String PAINTING_COMPONENT_SCALE; + public static final String PAINTING_COMPONENT_TRI_PLANAR; + public static final String PAINTING_COMPONENT_SHININESS; + public static final String PAINTING_COMPONENT_LAYER; + public static final String PAINTING_COMPONENT_MODEL; + public static final String PAINTING_COMPONENT_METHOD; public static final String MODEL_CONVERTER_DIALOG_TITLE; public static final String MODEL_CONVERTER_DIALOG_RESULT_NAME; @@ -692,6 +699,10 @@ public class Messages { public static final String PAINTING_COMPONENT_CONTAINER_TOOL; public static final String PAINTING_COMPONENT_CONTAINER_NO_TOOLS; public static final String PAINTING_COMPONENT_TERRAIN_EDITOR; + public static final String PAINTING_COMPONENT_SPAWN_MODELS; + public static final String PAINTING_COMPONENT_SPAWN_MODELS_METHOD_AS_IS; + public static final String PAINTING_COMPONENT_SPAWN_MODELS_METHOD_LINK; + public static final String PAINTING_COMPONENT_SPAWN_MODELS_METHOD_BATCH; static { @@ -989,6 +1000,8 @@ public class Messages { MODEL_NODE_TREE_ACTION_SPHERE_COLLISION_SHAPE = bundle.getString("ModelNodeTreeActionSphereCollisionShape"); MODEL_NODE_TREE_ACTION_ADD_WHEEL = bundle.getString("ModelNodeTreeActionAddWheel"); MODEL_NODE_TREE_ACTION_ADD_TERRAIN = bundle.getString("ModelNodeTreeActionAddTerrain"); + MODEL_NODE_TREE_ACTION_ENABLE_ALL_CONTROLS = bundle.getString("ModelNodeTreeActionEnableAllControls"); + MODEL_NODE_TREE_ACTION_DISABLE_ALL_CONTROLS = bundle.getString("ModelNodeTreeActionDisableAllControls"); MODEL_PROPERTY_CULL_HINT = bundle.getString("ModelPropertyCullHint"); MODEL_PROPERTY_SHADOW_MODE = bundle.getString("ModelPropertyShadowMode"); @@ -996,6 +1009,7 @@ public class Messages { MODEL_PROPERTY_LOCATION = bundle.getString("ModelPropertyLocation"); MODEL_PROPERTY_SCALE = bundle.getString("ModelPropertyScale"); MODEL_PROPERTY_ROTATION = bundle.getString("ModelPropertyRotation"); + MODEL_PROPERTY_TRANSFORMATION = bundle.getString("ModelPropertyTransformation"); MODEL_PROPERTY_MATERIAL = bundle.getString("ModelPropertyMaterial"); MODEL_PROPERTY_DIRECTION = bundle.getString("ModelPropertyDirection"); MODEL_PROPERTY_RADIUS = bundle.getString("ModelPropertyRadius"); @@ -1043,6 +1057,8 @@ public class Messages { MODEL_PROPERTY_FALL_SPEED = bundle.getString("ModelPropertyFallSpeed"); MODEL_PROPERTY_GRAVITY = bundle.getString("ModelPropertyGravity"); MODEL_PROPERTY_JUMP_SPEED = bundle.getString("ModelPropertyJumpSpeed"); + MODEL_PROPERTY_JUMP_FORCE = bundle.getString("ModelPropertyJumpForce"); + MODEL_PROPERTY_PHYSICS_DAMPING = bundle.getString("ModelPropertyPhysicsDamping"); MODEL_PROPERTY_MAX_SLOPE = bundle.getString("ModelPropertyMaxSlope"); MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL = bundle.getString("ModelPropertyIsApplyPhysicsLocal"); MODEL_PROPERTY_IS_USE_VIEW_DIRECTION = bundle.getString("ModelPropertyIsUseViewDirection"); @@ -1327,20 +1343,22 @@ public class Messages { CREATE_PARTICLE_EMITTER_TORUS_SHAPE_DIALOG_TITLE = bundle.getString("CreateParticleEmitterTorusShapeDialogTitle"); CREATE_PARTICLE_EMITTER_TRIANGLE_SHAPE_DIALOG_TITLE = bundle.getString("CreateParticleEmitterTriangleShapeDialogTitle"); - EDITING_COMPONENT_BRUSH_SIZE = bundle.getString("EditingComponentBrushSize"); - EDITING_COMPONENT_BRUSH_POWER = bundle.getString("EditingComponentBrushPower"); - EDITING_COMPONENT_SMOOTHLY = bundle.getString("EditingComponentSmoothly"); - EDITING_COMPONENT_LIMITED = bundle.getString("EditingComponentLimited"); - EDITING_COMPONENT_USE_MARKER = bundle.getString("EditingComponentUseMarker"); - EDITING_COMPONENT_LEVEL = bundle.getString("EditingComponentLevel"); - EDITING_COMPONENT_ROUGHNESS = bundle.getString("EditingComponentRoughness"); - EDITING_COMPONENT_FREQUENCY = bundle.getString("EditingComponentFrequency"); - EDITING_COMPONENT_LACUNARITY = bundle.getString("EditingComponentLacunarity"); - EDITING_COMPONENT_OCTAVES = bundle.getString("EditingComponentOctaves"); - EDITING_COMPONENT_SCALE = bundle.getString("EditingComponentScale"); - EDITING_COMPONENT_TRI_PLANAR = bundle.getString("EditingComponentTriPlanar"); - EDITING_COMPONENT_SHININESS = bundle.getString("EditingComponentShininess"); - EDITING_COMPONENT_LAYER = bundle.getString("EditingComponentLayer"); + PAINTING_COMPONENT_BRUSH_SIZE = bundle.getString("PaintingComponentBrushSize"); + PAINTING_COMPONENT_BRUSH_POWER = bundle.getString("PaintingComponentBrushPower"); + PAINTING_COMPONENT_SMOOTHLY = bundle.getString("PaintingComponentSmoothly"); + PAINTING_COMPONENT_LIMITED = bundle.getString("PaintingComponentLimited"); + PAINTING_COMPONENT_USE_MARKER = bundle.getString("PaintingComponentUseMarker"); + PAINTING_COMPONENT_LEVEL = bundle.getString("PaintingComponentLevel"); + PAINTING_COMPONENT_ROUGHNESS = bundle.getString("PaintingComponentRoughness"); + PAINTING_COMPONENT_FREQUENCY = bundle.getString("PaintingComponentFrequency"); + PAINTING_COMPONENT_LACUNARITY = bundle.getString("PaintingComponentLacunarity"); + PAINTING_COMPONENT_OCTAVES = bundle.getString("PaintingComponentOctaves"); + PAINTING_COMPONENT_SCALE = bundle.getString("PaintingComponentScale"); + PAINTING_COMPONENT_TRI_PLANAR = bundle.getString("PaintingComponentTriPlanar"); + PAINTING_COMPONENT_SHININESS = bundle.getString("PaintingComponentShininess"); + PAINTING_COMPONENT_LAYER = bundle.getString("PaintingComponentLayer"); + PAINTING_COMPONENT_MODEL = bundle.getString("PaintingComponentModel"); + PAINTING_COMPONENT_METHOD = bundle.getString("PaintingComponentMethod"); MODEL_CONVERTER_DIALOG_TITLE = bundle.getString("ModelConverterDialogTitle"); MODEL_CONVERTER_DIALOG_RESULT_NAME = bundle.getString("ModelConverterDialogResultName"); @@ -1384,5 +1402,9 @@ public class Messages { PAINTING_COMPONENT_CONTAINER_TOOL = bundle.getString("PaintingComponentContainerTool"); PAINTING_COMPONENT_CONTAINER_NO_TOOLS = bundle.getString("PaintingComponentContainerNoTools"); PAINTING_COMPONENT_TERRAIN_EDITOR = bundle.getString("PaintingComponentTerrainEditor"); + PAINTING_COMPONENT_SPAWN_MODELS = bundle.getString("PaintingComponentSpawnModels"); + PAINTING_COMPONENT_SPAWN_MODELS_METHOD_AS_IS = bundle.getString("PaintingComponentSpawnModelsMethodAsIs"); + PAINTING_COMPONENT_SPAWN_MODELS_METHOD_LINK = bundle.getString("PaintingComponentSpawnModelsMethodLink"); + PAINTING_COMPONENT_SPAWN_MODELS_METHOD_BATCH = bundle.getString("PaintingComponentSpawnModelsMethodBatch"); } } \ No newline at end of file diff --git a/src/main/java/com/ss/editor/config/Config.java b/src/main/java/com/ss/editor/config/Config.java index d632958a..f27650aa 100644 --- a/src/main/java/com/ss/editor/config/Config.java +++ b/src/main/java/com/ss/editor/config/Config.java @@ -42,7 +42,7 @@ public final class Config { * The editor's version. */ @NotNull - public static final Version APP_VERSION = new Version("1.6.1"); + public static final Version APP_VERSION = new Version("1.7.0"); /** * The string version. diff --git a/src/main/java/com/ss/editor/control/painting/PaintingControl.java b/src/main/java/com/ss/editor/control/painting/PaintingControl.java index 9393329b..94ed3fd4 100644 --- a/src/main/java/com/ss/editor/control/painting/PaintingControl.java +++ b/src/main/java/com/ss/editor/control/painting/PaintingControl.java @@ -1,7 +1,7 @@ package com.ss.editor.control.painting; +import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; -import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; import com.ss.editor.annotation.JmeThread; import org.jetbrains.annotations.NotNull; @@ -20,18 +20,36 @@ public interface PaintingControl extends Control { * @return the painted model. */ @JmeThread - default @Nullable Spatial getPaintedModel() { + default @Nullable Object getPaintedModel() { return null; } + /** + * Set the brush size. + * + * @param brushSize the brush size. + */ + @JmeThread + void setBrushSize(float brushSize); + + /** + * Set the brush power. + * + * @param brushPower the brush power. + */ + @JmeThread + void setBrushPower(float brushPower); + /** * Start painting. * - * @param paintingInput the type of input. + * @param brushRotation the brush rotation. + * @param input the type of input. * @param contactPoint the contact point. */ @JmeThread - default void startPainting(@NotNull final PaintingInput paintingInput, @NotNull final Vector3f contactPoint) { + default void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { } /** @@ -47,19 +65,23 @@ default void startPainting(@NotNull final PaintingInput paintingInput, @NotNull /** * Finish painting. * - * @param contactPoint the contact point. + * @param brushRotation the brush rotation. + * @param contactPoint the contact point. */ @JmeThread - default void finishPainting(@NotNull final Vector3f contactPoint) { + default void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { } /** * Update painting. * - * @param contactPoint the contact point. + * @param brushRotation the brush rotation. + * @param contactPoint the contact point. + * @param tpf the tpf. */ @JmeThread - default void updatePainting(@NotNull final Vector3f contactPoint) { + default void updatePainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint, + float tpf) { } /** diff --git a/src/main/java/com/ss/editor/control/painting/impl/AbstractPaintingControl.java b/src/main/java/com/ss/editor/control/painting/impl/AbstractPaintingControl.java index a40d119a..9158868b 100644 --- a/src/main/java/com/ss/editor/control/painting/impl/AbstractPaintingControl.java +++ b/src/main/java/com/ss/editor/control/painting/impl/AbstractPaintingControl.java @@ -2,16 +2,20 @@ import com.jme3.material.Material; import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.renderer.RenderManager; import com.jme3.renderer.ViewPort; +import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import com.jme3.scene.control.AbstractControl; +import com.jme3.scene.shape.Sphere; import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.annotation.JmeThread; import com.ss.editor.control.painting.PaintingControl; import com.ss.editor.control.painting.PaintingInput; +import com.ss.editor.ui.component.painting.PaintingComponent; import com.ss.editor.util.EditorUtil; import com.ss.editor.util.LocalObjects; import org.jetbrains.annotations.NotNull; @@ -22,22 +26,103 @@ * * @author JavaSaBr */ -public class AbstractPaintingControl extends AbstractControl implements PaintingControl { +public abstract class AbstractPaintingControl extends AbstractControl implements PaintingControl { @NotNull private static final ThreadLocal TOOL_OBJECTS = ThreadLocal.withInitial(LocalObjects::new); + /** + * The painting component. + */ + @NotNull + protected final T component; + + /** + * The brush geometry. + */ + @NotNull + protected final Geometry brush; + /** * The current painting input. */ @Nullable private PaintingInput paintingInput; + /** + * The brush size. + */ + private float brushSize; + + /** + * The brush power. + */ + private float brushPower; + /** * The flag of painting state. */ private boolean painting; + protected AbstractPaintingControl(@NotNull final T component) { + this.component = component; + this.brush = new Geometry("Brush", new Sphere(8, 8, 1)); + this.brush.setMaterial(createWireframeMaterial(getBrushColor())); + } + + /** + * Get the brush. + * + * @return the brush geometry. + */ + @JmeThread + protected @NotNull Geometry getBrush() { + return brush; + } + + @Override + @JmeThread + public void setBrushSize(final float brushSize) { + this.brushSize = brushSize; + getBrush().setLocalScale(brushSize); + } + + /** + * Get the brush size. + * + * @return the brush size. + */ + @JmeThread + public float getBrushSize() { + return brushSize; + } + + @Override + @JmeThread + public void setBrushPower(final float brushPower) { + this.brushPower = brushPower; + } + + /** + * Get the brush power. + * + * @return the brush power. + */ + @JmeThread + public float getBrushPower() { + return brushPower; + } + + /** + * Get the brush color. + * + * @return the brush color. + */ + @FromAnyThread + protected @NotNull ColorRGBA getBrushColor() { + return ColorRGBA.Black; + } + /** * Get the local objects. * @@ -118,14 +203,15 @@ protected void setPainting(final boolean painting) { @Override @JmeThread - public void startPainting(@NotNull final PaintingInput input, @NotNull final Vector3f contactPoint) { + public void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { setPainting(true); setPaintingInput(input); } @Override @JmeThread - public void finishPainting(@NotNull final Vector3f contactPoint) { + public void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { setPainting(false); } @@ -152,6 +238,7 @@ private void setPaintingInput(@Nullable final PaintingInput input) { */ @JmeThread protected void onAttached(@NotNull final Node node) { + node.attachChild(brush); } /** @@ -161,5 +248,6 @@ protected void onAttached(@NotNull final Node node) { */ @JmeThread protected void onDetached(@NotNull final Node node) { + node.detachChild(brush); } } diff --git a/src/main/java/com/ss/editor/control/painting/spawn/SpawnToolControl.java b/src/main/java/com/ss/editor/control/painting/spawn/SpawnToolControl.java new file mode 100644 index 00000000..849f2618 --- /dev/null +++ b/src/main/java/com/ss/editor/control/painting/spawn/SpawnToolControl.java @@ -0,0 +1,417 @@ +package com.ss.editor.control.painting.spawn; + +import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_IGNORE_RAY_CAST; +import static com.ss.editor.util.EditorUtil.getAssetManager; +import static com.ss.rlib.util.ObjectUtils.notNull; +import static com.ss.rlib.util.array.ArrayCollectors.toArray; +import com.jme3.asset.ModelKey; +import com.jme3.collision.CollisionResult; +import com.jme3.collision.CollisionResults; +import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; +import com.jme3.math.Ray; +import com.jme3.math.Vector3f; +import com.jme3.scene.AssetLinkNode; +import com.jme3.scene.Geometry; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.terrain.Terrain; +import com.ss.editor.Messages; +import com.ss.editor.annotation.FromAnyThread; +import com.ss.editor.annotation.JmeThread; +import com.ss.editor.control.painting.PaintingInput; +import com.ss.editor.control.painting.impl.AbstractPaintingControl; +import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.ui.component.painting.spawn.SpawnPaintingComponent; +import com.ss.editor.model.undo.impl.AddChildOperation; +import com.ss.editor.util.GeomUtils; +import com.ss.editor.util.LocalObjects; +import com.ss.editor.util.NodeUtils; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; +import jme3tools.optimize.GeometryBatchFactory; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.concurrent.ThreadLocalRandom; + +/** + * The implementation of spawn tool. + * + * @author JavaSaBr + */ +public class SpawnToolControl extends AbstractPaintingControl { + + public enum SpawnMethod { + AS_IS(Messages.PAINTING_COMPONENT_SPAWN_MODELS_METHOD_AS_IS), + BATCH(Messages.PAINTING_COMPONENT_SPAWN_MODELS_METHOD_BATCH), + LINK(Messages.PAINTING_COMPONENT_SPAWN_MODELS_METHOD_LINK); + + @NotNull + private final String label; + + SpawnMethod(@NotNull final String label) { + this.label = label; + } + + @Override + public String toString() { + return label; + } + } + + /** + * The list of spawned models. + */ + @NotNull + private final Array spawnedModels; + + /** + * The list of examples model. + */ + @NotNull + private final Array examples; + + /** + * The models scale. + */ + @NotNull + private final Vector3f scale; + + /** + * The spawn method. + */ + @NotNull + private SpawnMethod method; + + /** + * The painting time. + */ + private float time; + + public SpawnToolControl(@NotNull final SpawnPaintingComponent component) { + super(component); + this.spawnedModels = ArrayFactory.newArray(Spatial.class); + this.examples = ArrayFactory.newArray(Spatial.class); + this.method = SpawnMethod.BATCH; + this.scale = new Vector3f(1F, 1F, 1F); + } + + /** + * Get the spawn method. + * + * @return the spawn method. + */ + @JmeThread + public @NotNull SpawnMethod getMethod() { + return method; + } + + /** + * Set the spawn method. + * + * @param method the spawn method. + */ + @JmeThread + public void setMethod(@NotNull final SpawnMethod method) { + this.method = method; + } + + /** + * Get the models scale. + * + * @return the models scale. + */ + @JmeThread + private @NotNull Vector3f getScale() { + return scale; + } + + /** + * Set the models scale. + * + * @param scale the models scale. + */ + @JmeThread + public void setScale(@NotNull final Vector3f scale) { + this.scale.set(scale); + } + + @Override + @FromAnyThread + protected @NotNull ColorRGBA getBrushColor() { + return ColorRGBA.Orange; + } + + /** + * Get the list of spawned models. + * + * @return the list of spawned models. + */ + @JmeThread + private @NotNull Array getSpawnedModels() { + return spawnedModels; + } + + /** + * Update available examples. + * + * @param examples the list of available examples. + */ + @JmeThread + public void updateExamples(@NotNull final Array examples) { + this.examples.clear(); + this.examples.addAll(examples); + } + + /** + * Get the list of examples model. + * + * @return the list of examples model. + */ + @JmeThread + private @NotNull Array getExamples() { + return examples; + } + + /** + * Get the change consumer. + * + * @return the change consumer. + */ + @FromAnyThread + protected @NotNull ModelChangeConsumer getChangeConsumer() { + return component.getChangeConsumer(); + } + + @Override + @JmeThread + public @Nullable Node getPaintedModel() { + return component.getPaintedObject(); + } + + @Override + public void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { + + final Array spawnedModel = getExamples(); + if (spawnedModel.isEmpty()) { + return; + } + + super.startPainting(input, brushRotation, contactPoint); + + getSpawnedModels().clear(); + time = 0; + } + + @Override + @JmeThread + public void updatePainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint, + final float tpf) { + + time += (tpf * 10F); + + if (time > getBrushPower()) { + time = 0; + return; + } + + final PaintingInput currentInput = notNull(getCurrentInput()); + + switch (currentInput) { + case MOUSE_PRIMARY: { + spawn(brushRotation, contactPoint); + break; + } + } + } + + /** + * Spawn models. + * + * @param brushRotation the brush rotation. + * @param contactPoint the contact point. + */ + @JmeThread + protected void spawn(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { + + final float brushSize = getBrushSize(); + + final ThreadLocalRandom random = ThreadLocalRandom.current(); + final LocalObjects local = getLocalObjects(); + final Vector3f spawnPosition = local.nextVector(); + + final Node paintedModel = getPaintedModel(); + final Vector3f direction = GeomUtils.getDirection(brushRotation, local.nextVector()) + .negateLocal() + .multLocal(10); + + final Vector3f sourcePoint = contactPoint.subtract(direction, local.nextVector()); + final Ray ray = local.nextRay(); + ray.setOrigin(sourcePoint); + + final Vector3f scale = getScale(); + final Vector3f resultPosition = local.nextVector(); + final CollisionResults collisions = local.nextCollisionResults(); + final CollisionResults spawnedCollisions = local.nextCollisionResults(); + + final int maxCount = (int) Math.max(getBrushPower() / 2F, 1F); + + for(int count = 0; count < maxCount; count++) { + for (int attempts = 0; attempts < 10; attempts++, attempts++) { + collisions.clear(); + spawnedCollisions.clear(); + + final float x = nextOffset(brushSize, random); + final float y = nextOffset(brushSize, random); + final float z = nextOffset(brushSize, random); + + spawnPosition.set(x, y, z) + .addLocal(contactPoint) + .subtractLocal(sourcePoint) + .normalizeLocal(); + + ray.setDirection(spawnPosition); + + paintedModel.collideWith(ray, collisions); + + final CollisionResult closest = collisions.getClosestCollision(); + if (closest == null || contactPoint.distance(closest.getContactPoint()) > brushSize / 2) { + continue; + } + + resultPosition.set(closest.getContactPoint()) + .subtractLocal(paintedModel.getWorldTranslation()); + + final Spatial clone = examples.get(random.nextInt(0, examples.size())).clone(); + clone.setUserData(KEY_IGNORE_RAY_CAST, Boolean.TRUE); + clone.setLocalTranslation(resultPosition); + clone.setLocalScale(scale); + clone.updateModelBound(); + + if (paintedModel.collideWith(clone.getWorldBound(), spawnedCollisions) > 2) { + continue; + } + + getSpawnedModels().add(clone); + paintedModel.attachChild(clone); + break; + } + } + } + + /** + * Calculate next random offset. + * + * @param brushSize the brush size. + * @param random the random. + * @return the new coordinate. + */ + @JmeThread + protected float nextOffset(final float brushSize, @NotNull final ThreadLocalRandom random) { + float result = random.nextInt(0, (int) (brushSize * 100)) / 100F; + result /= 2F; + return random.nextBoolean() ? result * -1 : result; + } + + @Override + @JmeThread + public void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { + super.finishPainting(brushRotation, contactPoint); + + final Array spawnedModels = getSpawnedModels(); + if (spawnedModels.isEmpty()) { + return; + } + + final LocalObjects local = getLocalObjects(); + final Vector3f location = local.nextVector(); + final Vector3f offset = local.nextVector(); + offset.set(contactPoint); + + spawnedModels.stream().peek(Spatial::removeFromParent) + .forEach(sp -> sp.setUserData(KEY_IGNORE_RAY_CAST, null)); + + final Node paintedModel = notNull(getPaintedModel()); + final Node parent = paintedModel instanceof Terrain ? + NodeUtils.findParent(paintedModel, sp -> !(sp instanceof Terrain)) : paintedModel; + + if (parent != paintedModel) { + final Vector3f diff = local.nextVector(); + diff.set(parent.getWorldTranslation()).subtractLocal(paintedModel.getWorldTranslation()); + offset.addLocal(diff); + } + + final ModelChangeConsumer changeConsumer = getChangeConsumer(); + + final SpawnMethod method = getMethod(); + switch (method) { + case AS_IS: { + final Node spawnedNode = new Node("Spawned"); + spawnedNode.setLocalTranslation(contactPoint); + spawnedModels.forEach(geom -> updatePositionAndAttach(offset, location, spawnedNode, geom)); + spawnedNode.updateModelBound(); + changeConsumer.execute(new AddChildOperation(spawnedNode, parent, false)); + break; + } + case LINK: { + + final Node spawnedNode = new Node("Spawned"); + spawnedNode.setLocalTranslation(contactPoint); + spawnedModels.stream().map(this::linkSpatial) + .forEach(geom -> updatePositionAndAttach(offset, location, spawnedNode, geom)); + + spawnedNode.updateModelBound(); + + changeConsumer.execute(new AddChildOperation(spawnedNode, parent, false)); + break; + } + case BATCH: { + + final Node spawnedNode = new Node("Spawned"); + spawnedNode.setLocalTranslation(contactPoint); + final Array geometries = spawnedModels.stream() + .flatMap(NodeUtils::children) + .filter(Geometry.class::isInstance) + .map(Geometry.class::cast) + .collect(toArray(Geometry.class)); + + GeometryBatchFactory.makeBatches(geometries) + .forEach(geom -> updatePositionAndAttach(offset, location, spawnedNode, geom)); + + spawnedNode.updateModelBound(); + + changeConsumer.execute(new AddChildOperation(spawnedNode, parent, false)); + break; + } + } + } + + @JmeThread + protected void updatePositionAndAttach(@NotNull final Vector3f contactPoint, @NotNull final Vector3f location, + @NotNull final Node spawnedNode, @NotNull final Spatial geom) { + + final Vector3f newPosition = location.set(geom.getLocalTranslation()) + .subtractLocal(contactPoint); + + geom.setLocalTranslation(newPosition); + spawnedNode.attachChild(geom); + } + + /** + * Create an asset link node for the spatial. + * + * @param spatial the spatial. + * @return the asset link node. + */ + @JmeThread + protected @NotNull AssetLinkNode linkSpatial(@NotNull final Spatial spatial) { + final AssetLinkNode linkNode = new AssetLinkNode(); + linkNode.setLocalTranslation(spatial.getLocalTranslation()); + linkNode.setName(spatial.getName()); + linkNode.setLocalScale(getScale()); + linkNode.attachLinkedChild(getAssetManager(), (ModelKey) spatial.getKey()); + return linkNode; + } +} diff --git a/src/main/java/com/ss/editor/control/painting/terrain/LevelTerrainToolControl.java b/src/main/java/com/ss/editor/control/painting/terrain/LevelTerrainToolControl.java index dc1f6105..f99f0883 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/LevelTerrainToolControl.java +++ b/src/main/java/com/ss/editor/control/painting/terrain/LevelTerrainToolControl.java @@ -3,6 +3,7 @@ import static com.ss.editor.util.PaintingUtils.*; import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; @@ -95,8 +96,9 @@ protected void controlUpdate(final float tpf) { @Override @JmeThread - public void startPainting(@NotNull final PaintingInput input, @NotNull final Vector3f contactPoint) { - super.startPainting(input, contactPoint); + public void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { + super.startPainting(input, brushRotation, contactPoint); switch (input) { case MOUSE_PRIMARY: { @@ -113,7 +115,8 @@ public void startPainting(@NotNull final PaintingInput input, @NotNull final Vec @Override @JmeThread - public void updatePainting(@NotNull final Vector3f contactPoint) { + public void updatePainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint, + final float tpf) { final PaintingInput input = notNull(getCurrentInput()); @@ -131,8 +134,8 @@ public void updatePainting(@NotNull final Vector3f contactPoint) { @Override @JmeThread - public void finishPainting(@NotNull final Vector3f contactPoint) { - super.finishPainting(contactPoint); + public void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { + super.finishPainting(brushRotation, contactPoint); final PaintingInput input = notNull(getCurrentInput()); diff --git a/src/main/java/com/ss/editor/control/painting/terrain/PaintTerrainToolControl.java b/src/main/java/com/ss/editor/control/painting/terrain/PaintTerrainToolControl.java index f8e56a0c..09c2e9cf 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/PaintTerrainToolControl.java +++ b/src/main/java/com/ss/editor/control/painting/terrain/PaintTerrainToolControl.java @@ -2,6 +2,7 @@ import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.scene.Spatial; @@ -139,14 +140,15 @@ public PaintTerrainToolControl(@NotNull final TerrainPaintingComponent component @Override @JmeThread - public void startPainting(@NotNull final PaintingInput input, @NotNull final Vector3f contactPoint) { + public void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { final Texture alphaTexture = getAlphaTexture(); if (alphaTexture == null) { return; } - super.startPainting(input, contactPoint); + super.startPainting(input, brushRotation, contactPoint); switch (input) { case MOUSE_PRIMARY: @@ -160,7 +162,8 @@ public void startPainting(@NotNull final PaintingInput input, @NotNull final Vec @Override @JmeThread - public void updatePainting(@NotNull final Vector3f contactPoint) { + public void updatePainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint, + final float tpf) { final PaintingInput input = notNull(getCurrentInput()); @@ -175,7 +178,7 @@ public void updatePainting(@NotNull final Vector3f contactPoint) { @Override @JmeThread - public void finishPainting(@NotNull final Vector3f contactPoint) { + public void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { final PaintingInput input = notNull(getCurrentInput()); @@ -188,7 +191,7 @@ public void finishPainting(@NotNull final Vector3f contactPoint) { } } - super.finishPainting(contactPoint); + super.finishPainting(brushRotation, contactPoint); } /** diff --git a/src/main/java/com/ss/editor/control/painting/terrain/RaiseLowerTerrainToolControl.java b/src/main/java/com/ss/editor/control/painting/terrain/RaiseLowerTerrainToolControl.java index 6d50b958..a590fbb9 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/RaiseLowerTerrainToolControl.java +++ b/src/main/java/com/ss/editor/control/painting/terrain/RaiseLowerTerrainToolControl.java @@ -4,6 +4,7 @@ import static com.ss.editor.util.PaintingUtils.isContains; import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; @@ -39,8 +40,9 @@ public RaiseLowerTerrainToolControl(@NotNull final TerrainPaintingComponent comp @Override @JmeThread - public void startPainting(@NotNull final PaintingInput input, @NotNull final Vector3f contactPoint) { - super.startPainting(input, contactPoint); + public void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { + super.startPainting(input, brushRotation, contactPoint); switch (input) { case MOUSE_PRIMARY: @@ -53,7 +55,8 @@ public void startPainting(@NotNull final PaintingInput input, @NotNull final Vec @Override @JmeThread - public void updatePainting(@NotNull final Vector3f contactPoint) { + public void updatePainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint, + final float tpf) { final PaintingInput input = notNull(getCurrentInput()); @@ -67,8 +70,8 @@ public void updatePainting(@NotNull final Vector3f contactPoint) { @Override @JmeThread - public void finishPainting(@NotNull final Vector3f contactPoint) { - super.finishPainting(contactPoint); + public void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { + super.finishPainting(brushRotation, contactPoint); final PaintingInput input = notNull(getCurrentInput()); diff --git a/src/main/java/com/ss/editor/control/painting/terrain/RoughTerrainToolControl.java b/src/main/java/com/ss/editor/control/painting/terrain/RoughTerrainToolControl.java index 86f87c09..86534e41 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/RoughTerrainToolControl.java +++ b/src/main/java/com/ss/editor/control/painting/terrain/RoughTerrainToolControl.java @@ -5,6 +5,7 @@ import static java.lang.Math.max; import static java.lang.Math.min; import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; @@ -56,8 +57,9 @@ public RoughTerrainToolControl(@NotNull final TerrainPaintingComponent component @Override @JmeThread - public void startPainting(@NotNull final PaintingInput input, @NotNull final Vector3f contactPoint) { - super.startPainting(input, contactPoint); + public void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { + super.startPainting(input, brushRotation, contactPoint); switch (input) { case MOUSE_PRIMARY: { @@ -69,7 +71,8 @@ public void startPainting(@NotNull final PaintingInput input, @NotNull final Vec @Override @JmeThread - public void updatePainting(@NotNull final Vector3f contactPoint) { + public void updatePainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint, + final float tpf) { final PaintingInput input = notNull(getCurrentInput()); @@ -82,8 +85,8 @@ public void updatePainting(@NotNull final Vector3f contactPoint) { @Override @JmeThread - public void finishPainting(@NotNull final Vector3f contactPoint) { - super.finishPainting(contactPoint); + public void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { + super.finishPainting(brushRotation, contactPoint); final PaintingInput input = notNull(getCurrentInput()); diff --git a/src/main/java/com/ss/editor/control/painting/terrain/SlopeTerrainToolControl.java b/src/main/java/com/ss/editor/control/painting/terrain/SlopeTerrainToolControl.java index ad9d3be9..ab488379 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/SlopeTerrainToolControl.java +++ b/src/main/java/com/ss/editor/control/painting/terrain/SlopeTerrainToolControl.java @@ -3,10 +3,7 @@ import static com.ss.editor.util.PaintingUtils.*; import static com.ss.rlib.util.ObjectUtils.notNull; import static java.lang.Math.max; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Plane; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; +import com.jme3.math.*; import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; @@ -127,8 +124,9 @@ protected void controlUpdate(final float tpf) { @Override @JmeThread - public void startPainting(@NotNull final PaintingInput input, @NotNull final Vector3f contactPoint) { - super.startPainting(input, contactPoint); + public void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { + super.startPainting(input, brushRotation, contactPoint); switch (input) { case MOUSE_PRIMARY: { @@ -149,7 +147,8 @@ public void startPainting(@NotNull final PaintingInput input, @NotNull final Vec @Override @JmeThread - public void updatePainting(@NotNull final Vector3f contactPoint) { + public void updatePainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint, + final float tpf) { final PaintingInput input = notNull(getCurrentInput()); @@ -171,8 +170,8 @@ public void updatePainting(@NotNull final Vector3f contactPoint) { @Override @JmeThread - public void finishPainting(@NotNull final Vector3f contactPoint) { - super.finishPainting(contactPoint); + public void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { + super.finishPainting(brushRotation, contactPoint); final PaintingInput input = notNull(getCurrentInput()); diff --git a/src/main/java/com/ss/editor/control/painting/terrain/SmoothTerrainToolControl.java b/src/main/java/com/ss/editor/control/painting/terrain/SmoothTerrainToolControl.java index 9f067924..d18e590e 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/SmoothTerrainToolControl.java +++ b/src/main/java/com/ss/editor/control/painting/terrain/SmoothTerrainToolControl.java @@ -5,6 +5,7 @@ import static java.lang.Float.isNaN; import static java.lang.Math.min; import com.jme3.math.ColorRGBA; +import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; import com.jme3.scene.Geometry; @@ -40,8 +41,9 @@ public SmoothTerrainToolControl(@NotNull final TerrainPaintingComponent componen @Override @JmeThread - public void startPainting(@NotNull final PaintingInput input, @NotNull final Vector3f contactPoint) { - super.startPainting(input, contactPoint); + public void startPainting(@NotNull final PaintingInput input, @NotNull final Quaternion brushRotation, + @NotNull final Vector3f contactPoint) { + super.startPainting(input, brushRotation, contactPoint); switch (input) { case MOUSE_PRIMARY: { @@ -53,7 +55,8 @@ public void startPainting(@NotNull final PaintingInput input, @NotNull final Vec @Override @JmeThread - public void updatePainting(@NotNull final Vector3f contactPoint) { + public void updatePainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint, + final float tpf) { final PaintingInput input = notNull(getCurrentInput()); @@ -66,8 +69,8 @@ public void updatePainting(@NotNull final Vector3f contactPoint) { @Override @JmeThread - public void finishPainting(@NotNull final Vector3f contactPoint) { - super.finishPainting(contactPoint); + public void finishPainting(@NotNull final Quaternion brushRotation, @NotNull final Vector3f contactPoint) { + super.finishPainting(brushRotation, contactPoint); final PaintingInput input = notNull(getCurrentInput()); diff --git a/src/main/java/com/ss/editor/control/painting/terrain/TerrainToolControl.java b/src/main/java/com/ss/editor/control/painting/terrain/TerrainToolControl.java index c6748453..ff6cbab0 100644 --- a/src/main/java/com/ss/editor/control/painting/terrain/TerrainToolControl.java +++ b/src/main/java/com/ss/editor/control/painting/terrain/TerrainToolControl.java @@ -1,10 +1,6 @@ package com.ss.editor.control.painting.terrain; -import com.jme3.math.ColorRGBA; -import com.jme3.scene.Geometry; -import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.jme3.scene.shape.Sphere; import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.annotation.JmeThread; import com.ss.editor.control.painting.impl.AbstractPaintingControl; @@ -18,64 +14,10 @@ * * @author JavaSaBr */ -public class TerrainToolControl extends AbstractPaintingControl { - - /** - * The editing component. - */ - @NotNull - protected final TerrainPaintingComponent component; - - /** - * The brush geometry. - */ - @NotNull - protected final Geometry brush; - - /** - * The brush size. - */ - private float brushSize; - - /** - * The brush power. - */ - private float brushPower; +public class TerrainToolControl extends AbstractPaintingControl { public TerrainToolControl(@NotNull final TerrainPaintingComponent component) { - this.component = component; - this.brush = new Geometry("Brush", new Sphere(8, 8, 1)); - this.brush.setMaterial(createWireframeMaterial(getBrushColor())); - } - - /** - * Get the brush color. - * - * @return the brush color. - */ - @FromAnyThread - protected @NotNull ColorRGBA getBrushColor() { - return ColorRGBA.Black; - } - - @Override - @JmeThread - protected void onAttached(@NotNull final Node node) { - super.onAttached(node); - node.attachChild(brush); - } - - @Override - @JmeThread - protected void onDetached(@NotNull final Node node) { - super.onDetached(node); - node.detachChild(brush); - } - - @Override - @JmeThread - public @Nullable Spatial getPaintedModel() { - return component.getPaintedObject(); + super(component); } /** @@ -88,54 +30,9 @@ protected void onDetached(@NotNull final Node node) { return component.getChangeConsumer(); } - /** - * Get the brush. - * - * @return the brush geometry. - */ - @JmeThread - protected @NotNull Geometry getBrush() { - return brush; - } - - /** - * Set the brush size. - * - * @param brushSize the brush size. - */ - @JmeThread - public void setBrushSize(final float brushSize) { - this.brushSize = brushSize; - getBrush().setLocalScale(brushSize); - } - - /** - * Get the brush size. - * - * @return the brush size. - */ - @JmeThread - public float getBrushSize() { - return brushSize; - } - - /** - * Set the brush power. - * - * @param brushPower the brush power. - */ - @JmeThread - public void setBrushPower(final float brushPower) { - this.brushPower = brushPower; - } - - /** - * Get the brush power. - * - * @return the brush power. - */ + @Override @JmeThread - public float getBrushPower() { - return brushPower; + public @Nullable Spatial getPaintedModel() { + return component.getPaintedObject(); } } diff --git a/src/main/java/com/ss/editor/file/delete/handler/impl/AbstractFileDeleteHandler.java b/src/main/java/com/ss/editor/file/delete/handler/impl/AbstractFileDeleteHandler.java index db174dc7..73d35b30 100644 --- a/src/main/java/com/ss/editor/file/delete/handler/impl/AbstractFileDeleteHandler.java +++ b/src/main/java/com/ss/editor/file/delete/handler/impl/AbstractFileDeleteHandler.java @@ -1,6 +1,8 @@ package com.ss.editor.file.delete.handler.impl; import com.ss.editor.file.delete.handler.FileDeleteHandler; +import com.ss.rlib.logging.Logger; +import com.ss.rlib.logging.LoggerManager; import org.jetbrains.annotations.NotNull; import java.nio.file.Path; @@ -12,6 +14,9 @@ */ public abstract class AbstractFileDeleteHandler implements FileDeleteHandler { + @NotNull + protected static final Logger LOGGER = LoggerManager.getLogger(FileDeleteHandler.class); + @Override public void preDelete(@NotNull final Path file) { } diff --git a/src/main/java/com/ss/editor/file/delete/handler/impl/DeleteMaterialsModelFileDeleteHandler.java b/src/main/java/com/ss/editor/file/delete/handler/impl/DeleteMaterialsModelFileDeleteHandler.java index f49928a4..b78a6ca9 100644 --- a/src/main/java/com/ss/editor/file/delete/handler/impl/DeleteMaterialsModelFileDeleteHandler.java +++ b/src/main/java/com/ss/editor/file/delete/handler/impl/DeleteMaterialsModelFileDeleteHandler.java @@ -46,7 +46,14 @@ public void preDelete(@NotNull final Path file) { final Path assetFile = notNull(getAssetFile(file)); final String assetPath = toAssetPath(assetFile); - final Spatial model = assetManager.loadModel(assetPath); + final Spatial model; + + try { + model = assetManager.loadModel(assetPath); + } catch (final Exception e) { + LOGGER.warning(this, e); + return; + } NodeUtils.visitGeometry(model, geometry -> { @@ -73,7 +80,9 @@ public void postDelete(@NotNull final Path file) { super.postDelete(file); final Array assetKeys = getAssetKeys(); - if (assetKeys.isEmpty()) return; + if (assetKeys.isEmpty()) { + return; + } String question = Messages.FILE_DELETE_HANDLER_DELETE_MATERIALS; question = question.replace("%file_name%", file.getFileName().toString()); diff --git a/src/main/java/com/ss/editor/manager/RemoteControlManager.java b/src/main/java/com/ss/editor/manager/RemoteControlManager.java index b4ab415d..b61f0031 100644 --- a/src/main/java/com/ss/editor/manager/RemoteControlManager.java +++ b/src/main/java/com/ss/editor/manager/RemoteControlManager.java @@ -3,9 +3,11 @@ import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.config.Config; import com.ss.editor.manager.ClasspathManager.Scope; +import com.ss.rlib.network.NetworkConfig; import com.ss.rlib.network.NetworkFactory; import com.ss.rlib.network.packet.ReadablePacket; import com.ss.rlib.network.packet.ReadablePacketRegistry; +import com.ss.rlib.network.server.AcceptHandler; import com.ss.rlib.network.server.ServerNetwork; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,6 +22,20 @@ */ public class RemoteControlManager { + @NotNull + private static final NetworkConfig NETWORK_CONFIG = new NetworkConfig() { + + @Override + public int getReadBufferSize() { + return Short.MAX_VALUE * 2; + } + + @Override + public int getWriteBufferSize() { + return Short.MAX_VALUE * 2; + } + }; + @Nullable private static RemoteControlManager instance; @@ -56,7 +72,7 @@ private synchronized void start() { return; } - serverNetwork = NetworkFactory.newDefaultAsyncServerNetwork(packetRegistry); + serverNetwork = NetworkFactory.newDefaultAsyncServerNetwork(NETWORK_CONFIG, packetRegistry, AcceptHandler.newDefault()); try { serverNetwork.bind(new InetSocketAddress(Config.REMOTE_CONTROL_PORT)); } catch (final IOException e) { diff --git a/src/main/java/com/ss/editor/manager/ResourceManager.java b/src/main/java/com/ss/editor/manager/ResourceManager.java index e1a23fb6..9d1ed0cf 100644 --- a/src/main/java/com/ss/editor/manager/ResourceManager.java +++ b/src/main/java/com/ss/editor/manager/ResourceManager.java @@ -283,8 +283,8 @@ public synchronized void assetRequested(@NotNull final AssetKey key) { return; } - final Path assetFile = getRealFile(Paths.get(key.getName())); - if (assetFile == null || !Files.exists(assetFile)) { + final Path realFile = getRealFile(Paths.get(key.getName())); + if (realFile == null || !Files.exists(realFile)) { return; } @@ -292,7 +292,7 @@ public synchronized void assetRequested(@NotNull final AssetKey key) { final long timestamp = reference.getLong(); - final FileTime lastModifiedTime = Files.getLastModifiedTime(assetFile); + final FileTime lastModifiedTime = Files.getLastModifiedTime(realFile); if (lastModifiedTime.to(TimeUnit.MILLISECONDS) <= timestamp) { return; } diff --git a/src/main/java/com/ss/editor/model/EditorCamera.java b/src/main/java/com/ss/editor/model/EditorCamera.java index 5b370ebd..0b42dd04 100644 --- a/src/main/java/com/ss/editor/model/EditorCamera.java +++ b/src/main/java/com/ss/editor/model/EditorCamera.java @@ -452,9 +452,13 @@ protected void verticalRotateCamera(final float value) { * @param tpf the tpf */ public void updateCamera(float tpf) { - if (!enabled) return; - targetLocation.set(target.getWorldTranslation()).addLocal(lookAtOffset); + if (!enabled) { + return; + } + + targetLocation.set(target.getWorldTranslation()) + .addLocal(lookAtOffset); if (smoothMotion) { diff --git a/src/main/java/com/ss/editor/model/undo/editor/ChangeConsumer.java b/src/main/java/com/ss/editor/model/undo/editor/ChangeConsumer.java index 48112885..9837911a 100644 --- a/src/main/java/com/ss/editor/model/undo/editor/ChangeConsumer.java +++ b/src/main/java/com/ss/editor/model/undo/editor/ChangeConsumer.java @@ -15,13 +15,23 @@ public interface ChangeConsumer { /** - * Notify about changed property from jME thread. + * Notify about an attempt to change the property from jME thread. * - * @param object the object - * @param propertyName the property name + * @param object the object. + * @param propertyName the property name. + */ + @JmeThread + default void notifyJmePreChangeProperty(@NotNull Object object, @NotNull String propertyName) { + } + + /** + * Notify about changed the property from jME thread. + * + * @param object the object. + * @param propertyName the property name. */ @JmeThread - default void notifyJmeChangeProperty(@NotNull Object object, @NotNull String propertyName) { + default void notifyJmeChangedProperty(@NotNull Object object, @NotNull String propertyName) { } /** diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddChildOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddChildOperation.java similarity index 87% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddChildOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/AddChildOperation.java index 5f255ee7..da9c9d31 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddChildOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/AddChildOperation.java @@ -1,7 +1,8 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Node; import com.jme3.scene.Spatial; +import com.ss.editor.Messages; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.model.undo.impl.AbstractEditorOperation; import com.ss.editor.plugin.api.RenderFilterExtension; @@ -44,7 +45,10 @@ public AddChildOperation(@NotNull final Spatial newChild, @NotNull final Node pa @Override protected void redoImpl(@NotNull final ModelChangeConsumer editor) { EXECUTOR_MANAGER.addJmeTask(() -> { + + editor.notifyJmePreChangeProperty(newChild, Messages.MODEL_PROPERTY_TRANSFORMATION); parent.attachChildAt(newChild, 0); + editor.notifyJmeChangedProperty(newChild, Messages.MODEL_PROPERTY_TRANSFORMATION); final RenderFilterExtension filterExtension = RenderFilterExtension.getInstance(); filterExtension.refreshFilters(); diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddControlOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddControlOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddControlOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/AddControlOperation.java index 5e8d3c09..cea63f40 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddControlOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/AddControlOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddLightOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddLightOperation.java similarity index 95% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddLightOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/AddLightOperation.java index 08e24ca5..89227b7e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddLightOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/AddLightOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.light.Light; import com.jme3.scene.Node; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddVehicleWheelOperation.java b/src/main/java/com/ss/editor/model/undo/impl/AddVehicleWheelOperation.java similarity index 98% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddVehicleWheelOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/AddVehicleWheelOperation.java index 4bf27f3f..fa304f47 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/AddVehicleWheelOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/AddVehicleWheelOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.bullet.control.VehicleControl; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/ChangeCollisionShapeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/ChangeCollisionShapeOperation.java similarity index 97% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/ChangeCollisionShapeOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/ChangeCollisionShapeOperation.java index f560781a..ca72e05e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/ChangeCollisionShapeOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/ChangeCollisionShapeOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.bullet.collision.PhysicsCollisionObject; import com.jme3.bullet.collision.shapes.CollisionShape; diff --git a/src/main/java/com/ss/editor/model/undo/impl/ChangeControlsOperation.java b/src/main/java/com/ss/editor/model/undo/impl/ChangeControlsOperation.java new file mode 100644 index 00000000..fedfde03 --- /dev/null +++ b/src/main/java/com/ss/editor/model/undo/impl/ChangeControlsOperation.java @@ -0,0 +1,87 @@ +package com.ss.editor.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.control.Control; +import com.ss.editor.annotation.FxThread; +import com.ss.editor.annotation.JmeThread; +import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.rlib.util.array.Array; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link AbstractEditorOperation} to chane {@link com.jme3.scene.control.AbstractControl} in {@link Node}. + * + * @author JavaSaBr. + */ +public class ChangeControlsOperation extends AbstractEditorOperation { + + /** + * The controls to change. + */ + @NotNull + private final Array controls; + + public ChangeControlsOperation(@NotNull final Array controls) { + this.controls = controls; + } + + @Override + @JmeThread + protected void redoImpl(@NotNull final ModelChangeConsumer editor) { + EXECUTOR_MANAGER.addJmeTask(() -> { + + for (final Control control : controls) { + redoChange(control); + } + + EXECUTOR_MANAGER.addFxTask(() -> { + controls.forEach(editor, (control, consumer) -> + consumer.notifyFxChangeProperty(control, getPropertyName())); + }); + }); + } + + /** + * Apply new changes to the control. + * + * @param control the control. + */ + @JmeThread + protected void redoChange(@NotNull final Control control) { + } + + @Override + @JmeThread + protected void undoImpl(@NotNull final ModelChangeConsumer editor) { + EXECUTOR_MANAGER.addJmeTask(() -> { + + for (final Control control : controls) { + undoChange(control); + } + + EXECUTOR_MANAGER.addFxTask(() -> { + controls.forEach(editor, (control, consumer) -> + consumer.notifyFxChangeProperty(control, getPropertyName())); + }); + }); + } + + /** + * Revert changes for the control. + * + * @param control the control. + */ + @JmeThread + protected void undoChange(@NotNull final Control control) { + } + + /** + * Get the property name. + * + * @return the property name. + */ + @FxThread + protected @NotNull String getPropertyName() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/ChangeMeshOperation.java b/src/main/java/com/ss/editor/model/undo/impl/ChangeMeshOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/ChangeMeshOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/ChangeMeshOperation.java index bc9d08fb..c13dc531 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/ChangeMeshOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/ChangeMeshOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Geometry; import com.jme3.scene.Mesh; diff --git a/src/main/java/com/ss/editor/model/undo/impl/DisableControlsOperation.java b/src/main/java/com/ss/editor/model/undo/impl/DisableControlsOperation.java new file mode 100644 index 00000000..ce3620bb --- /dev/null +++ b/src/main/java/com/ss/editor/model/undo/impl/DisableControlsOperation.java @@ -0,0 +1,37 @@ +package com.ss.editor.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.control.Control; +import com.ss.editor.Messages; +import com.ss.editor.util.ControlUtils; +import com.ss.rlib.util.array.Array; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link AbstractEditorOperation} to disable {@link com.jme3.scene.control.AbstractControl} in {@link Node}. + * + * @author JavaSaBr. + */ +public class DisableControlsOperation extends ChangeControlsOperation { + + public DisableControlsOperation(@NotNull final Array controls) { + super(controls); + } + + @Override + protected void redoChange(final @NotNull Control control) { + super.redoChange(control); + ControlUtils.setEnabled(control, false); + } + + @Override + protected void undoChange(final @NotNull Control control) { + super.undoChange(control); + ControlUtils.setEnabled(control, true); + } + + @Override + protected @NotNull String getPropertyName() { + return Messages.MODEL_PROPERTY_IS_ENABLED; + } +} diff --git a/src/main/java/com/ss/editor/model/undo/impl/EnableControlsOperation.java b/src/main/java/com/ss/editor/model/undo/impl/EnableControlsOperation.java new file mode 100644 index 00000000..f7fbf8ee --- /dev/null +++ b/src/main/java/com/ss/editor/model/undo/impl/EnableControlsOperation.java @@ -0,0 +1,37 @@ +package com.ss.editor.model.undo.impl; + +import com.jme3.scene.Node; +import com.jme3.scene.control.Control; +import com.ss.editor.Messages; +import com.ss.editor.util.ControlUtils; +import com.ss.rlib.util.array.Array; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of {@link AbstractEditorOperation} to enable {@link com.jme3.scene.control.AbstractControl} in {@link Node}. + * + * @author JavaSaBr. + */ +public class EnableControlsOperation extends ChangeControlsOperation { + + public EnableControlsOperation(@NotNull final Array controls) { + super(controls); + } + + @Override + protected void redoChange(final @NotNull Control control) { + super.redoChange(control); + ControlUtils.setEnabled(control, true); + } + + @Override + protected void undoChange(final @NotNull Control control) { + super.undoChange(control); + ControlUtils.setEnabled(control, false); + } + + @Override + protected @NotNull String getPropertyName() { + return Messages.MODEL_PROPERTY_IS_ENABLED; + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/MoveChildOperation.java b/src/main/java/com/ss/editor/model/undo/impl/MoveChildOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/MoveChildOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/MoveChildOperation.java index 6b588099..f809c4b1 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/MoveChildOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/MoveChildOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Node; import com.jme3.scene.Spatial; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/MoveControlOperation.java b/src/main/java/com/ss/editor/model/undo/impl/MoveControlOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/MoveControlOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/MoveControlOperation.java index 1ac73aad..3744aaf6 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/MoveControlOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/MoveControlOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/OptimizeGeometryOperation.java b/src/main/java/com/ss/editor/model/undo/impl/OptimizeGeometryOperation.java similarity index 97% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/OptimizeGeometryOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/OptimizeGeometryOperation.java index cd16aff4..89ae41b1 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/OptimizeGeometryOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/OptimizeGeometryOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Node; import com.jme3.scene.Spatial; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveChildOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveChildOperation.java similarity index 82% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveChildOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/RemoveChildOperation.java index 0ad50d11..9ded9abf 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveChildOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/RemoveChildOperation.java @@ -1,14 +1,15 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Node; import com.jme3.scene.Spatial; +import com.ss.editor.annotation.JmeThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.model.undo.impl.AbstractEditorOperation; import org.jetbrains.annotations.NotNull; /** - * The implementation of the {@link AbstractEditorOperation} for removing a {@link Spatial} from the {@link Node}. + * The implementation of the {@link AbstractEditorOperation} to remove {@link Spatial} from the {@link Node}. * * @author JavaSaBr. */ @@ -31,12 +32,6 @@ public class RemoveChildOperation extends AbstractEditorOperation { parent.detachChild(child); @@ -52,6 +48,7 @@ protected void redoImpl(@NotNull final ModelChangeConsumer editor) { } @Override + @JmeThread protected void undoImpl(@NotNull final ModelChangeConsumer editor) { EXECUTOR_MANAGER.addJmeTask(() -> { parent.attachChildAt(child, childIndex); diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveControlOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveControlOperation.java similarity index 87% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveControlOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/RemoveControlOperation.java index 896baff8..196603da 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveControlOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/RemoveControlOperation.java @@ -1,7 +1,8 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; +import com.ss.editor.annotation.JmeThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.model.undo.impl.AbstractEditorOperation; @@ -26,18 +27,13 @@ public class RemoveControlOperation extends AbstractEditorOperation { parent.removeControl(control); @@ -46,6 +42,7 @@ protected void redoImpl(@NotNull final ModelChangeConsumer editor) { } @Override + @JmeThread protected void undoImpl(@NotNull final ModelChangeConsumer editor) { EXECUTOR_MANAGER.addJmeTask(() -> { parent.addControl(control); diff --git a/src/main/java/com/ss/editor/model/undo/impl/RemoveElementsOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveElementsOperation.java new file mode 100644 index 00000000..95079c23 --- /dev/null +++ b/src/main/java/com/ss/editor/model/undo/impl/RemoveElementsOperation.java @@ -0,0 +1,197 @@ +package com.ss.editor.model.undo.impl; + +import com.jme3.animation.AnimControl; +import com.jme3.animation.Animation; +import com.jme3.light.Light; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.editor.annotation.JmeThread; +import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.model.undo.impl.AbstractEditorOperation; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; +import org.jetbrains.annotations.NotNull; + +/** + * The implementation of the {@link AbstractEditorOperation} to remove elements from a scene. + * + * @author JavaSaBr. + */ +public class RemoveElementsOperation extends AbstractEditorOperation { + + public static class Element { + + /** + * The element to remove. + */ + @NotNull + private final Object element; + + /** + * The element's parent. + */ + @NotNull + private final Object parent; + + /** + * The index of position in the parent. + */ + private int index; + + public Element(@NotNull final Object element, @NotNull final Object parent) { + this.element = element; + this.parent = parent; + this.index = -1; + } + + /** + * Get the element to remove. + * + * @return the element to remove. + */ + private @NotNull Object getElement() { + return element; + } + + /** + * Get the element's parent. + * + * @return the element's parent. + */ + private @NotNull Object getParent() { + return parent; + } + + /** + * Get the index of position in the parent. + * + * @return the index of position in the parent. + */ + private int getIndex() { + return index; + } + + /** + * Set the index of position in the parent. + * + * @param index the index of position in the parent. + */ + private void setIndex(final int index) { + this.index = index; + } + } + + /** + * The elements to remove. + */ + @NotNull + private final Array elements; + + public RemoveElementsOperation(@NotNull final Array elements) { + this.elements = elements; + } + + @Override + @JmeThread + protected void redoImpl(@NotNull final ModelChangeConsumer editor) { + EXECUTOR_MANAGER.addJmeTask(() -> { + + for (final Element element : elements) { + + final Object toRemove = element.getElement(); + + if (toRemove instanceof Spatial) { + removeSpatial(element, (Spatial) toRemove); + } else if (toRemove instanceof Light) { + removeLight(element, (Light) toRemove); + } else if (toRemove instanceof Animation) { + removeAnimation(element, (Animation) toRemove); + } else if (toRemove instanceof Control) { + removeControl(element, (Control) toRemove); + } + } + + EXECUTOR_MANAGER.addFxTask(() -> { + elements.forEach(editor, (element, consumer) -> + consumer.notifyFxRemovedChild(element.getParent(), element.getElement())); + }); + }); + } + + @Override + @JmeThread + protected void undoImpl(@NotNull final ModelChangeConsumer editor) { + EXECUTOR_MANAGER.addJmeTask(() -> { + + for (final Element element : elements) { + + final Object toRestore = element.getElement(); + + if (toRestore instanceof Spatial) { + restoreSpatial(element, (Spatial) toRestore); + } else if (toRestore instanceof Light) { + restoreLight(element, (Light) toRestore); + } else if (toRestore instanceof Animation) { + restoreAnimation(element, (Animation) toRestore); + } else if (toRestore instanceof Control) { + restoreControl(element, (Control) toRestore); + } + } + + EXECUTOR_MANAGER.addFxTask(() -> { + elements.forEach(editor, (element, consumer) -> + consumer.notifyFxAddedChild(element.getParent(), element.getElement(), element.getIndex(), false)); + }); + }); + } + + @JmeThread + private void removeSpatial(@NotNull final Element element, @NotNull final Spatial toRemove) { + final Node parent = (Node) element.getParent(); + element.setIndex(parent.getChildIndex(toRemove)); + parent.detachChild(toRemove); + } + + @JmeThread + private void restoreSpatial(@NotNull final Element element, @NotNull final Spatial toRestore) { + final Node parent = (Node) element.getParent(); + parent.attachChildAt(toRestore, element.getIndex()); + } + + @JmeThread + private void removeControl(@NotNull final Element element, @NotNull final Control toRemove) { + final Spatial parent = (Spatial) element.getParent(); + parent.removeControl(toRemove); + } + + @JmeThread + private void restoreControl(@NotNull final Element element, @NotNull final Control toRestore) { + final Spatial parent = (Spatial) element.getParent(); + parent.addControl(toRestore); + } + + @JmeThread + private void removeLight(@NotNull final Element element, @NotNull final Light toRemove) { + final Spatial parent = (Spatial) element.getParent(); + parent.removeLight(toRemove); + } + + @JmeThread + private void restoreLight(@NotNull final Element element, @NotNull final Light toRestore) { + final Spatial parent = (Spatial) element.getParent(); + parent.addLight(toRestore); + } + + @JmeThread + private void removeAnimation(@NotNull final Element element, @NotNull final Animation toRemove) { + final AnimControl parent = (AnimControl) element.getParent(); + parent.removeAnim(toRemove); + } + + @JmeThread + private void restoreAnimation(@NotNull final Element element, @NotNull final Animation toRestore) { + final AnimControl parent = (AnimControl) element.getParent(); + parent.addAnim(toRestore); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveLightOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveLightOperation.java similarity index 87% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveLightOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/RemoveLightOperation.java index e521a88d..2b338ba7 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveLightOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/RemoveLightOperation.java @@ -1,8 +1,9 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.light.Light; import com.jme3.scene.Node; import com.jme3.scene.Spatial; +import com.ss.editor.annotation.JmeThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.model.undo.impl.AbstractEditorOperation; @@ -27,18 +28,13 @@ public class RemoveLightOperation extends AbstractEditorOperation { parent.removeLight(light); @@ -47,6 +43,7 @@ protected void redoImpl(@NotNull final ModelChangeConsumer editor) { } @Override + @JmeThread protected void undoImpl(@NotNull final ModelChangeConsumer editor) { EXECUTOR_MANAGER.addJmeTask(() -> { parent.addLight(light); diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveVehicleWheelOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RemoveVehicleWheelOperation.java similarity index 93% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveVehicleWheelOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/RemoveVehicleWheelOperation.java index dabb91a6..38b52092 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RemoveVehicleWheelOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/RemoveVehicleWheelOperation.java @@ -1,9 +1,10 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.bullet.control.VehicleControl; import com.jme3.bullet.objects.VehicleWheel; import com.jme3.math.Vector3f; +import com.ss.editor.annotation.JmeThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.model.undo.impl.AbstractEditorOperation; import org.jetbrains.annotations.NotNull; @@ -61,12 +62,6 @@ public class RemoveVehicleWheelOperation extends AbstractEditorOperation { @@ -99,6 +95,7 @@ protected void redoImpl(@NotNull final ModelChangeConsumer editor) { } @Override + @JmeThread protected void undoImpl(@NotNull final ModelChangeConsumer editor) { EXECUTOR_MANAGER.addJmeTask(() -> { diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RenameLightOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RenameLightOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RenameLightOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/RenameLightOperation.java index fc0fedd1..43b1cc65 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RenameLightOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/RenameLightOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.light.Light; import com.ss.editor.model.undo.editor.ModelChangeConsumer; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RenameNodeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/RenameNodeOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RenameNodeOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/RenameNodeOperation.java index b8e24184..ef1dd08c 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/RenameNodeOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/RenameNodeOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation; +package com.ss.editor.model.undo.impl; import com.jme3.scene.Spatial; import com.ss.editor.model.undo.editor.ModelChangeConsumer; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/AddAnimationNodeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/animation/AddAnimationNodeOperation.java similarity index 95% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/AddAnimationNodeOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/animation/AddAnimationNodeOperation.java index 79e24e30..f3dc624b 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/AddAnimationNodeOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/animation/AddAnimationNodeOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation.animation; +package com.ss.editor.model.undo.impl.animation; import com.jme3.animation.AnimControl; import com.jme3.animation.Animation; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/RemoveAnimationNodeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/animation/RemoveAnimationNodeOperation.java similarity index 86% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/RemoveAnimationNodeOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/animation/RemoveAnimationNodeOperation.java index 8e77ed97..a9980022 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/RemoveAnimationNodeOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/animation/RemoveAnimationNodeOperation.java @@ -1,7 +1,8 @@ -package com.ss.editor.ui.control.tree.action.impl.operation.animation; +package com.ss.editor.model.undo.impl.animation; import com.jme3.animation.AnimControl; import com.jme3.animation.Animation; +import com.ss.editor.annotation.JmeThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.model.undo.impl.AbstractEditorOperation; import org.jetbrains.annotations.NotNull; @@ -25,18 +26,13 @@ public class RemoveAnimationNodeOperation extends AbstractEditorOperation { control.removeAnim(animation); @@ -45,6 +41,7 @@ protected void redoImpl(@NotNull final ModelChangeConsumer editor) { } @Override + @JmeThread protected void undoImpl(@NotNull final ModelChangeConsumer editor) { EXECUTOR_MANAGER.addJmeTask(() -> { control.addAnim(animation); diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/RenameAnimationNodeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/animation/RenameAnimationNodeOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/RenameAnimationNodeOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/animation/RenameAnimationNodeOperation.java index 49c4940a..04cfeb8f 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/animation/RenameAnimationNodeOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/animation/RenameAnimationNodeOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation.animation; +package com.ss.editor.model.undo.impl.animation; import com.jme3.animation.AnimControl; import com.jme3.animation.Animation; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/particle/emitter/ChangeEmitterShapeOperation.java b/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeEmitterShapeOperation.java similarity index 95% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/particle/emitter/ChangeEmitterShapeOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeEmitterShapeOperation.java index 34324a94..48c2fe9f 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/particle/emitter/ChangeEmitterShapeOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeEmitterShapeOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation.particle.emitter; +package com.ss.editor.model.undo.impl.emitter; import com.jme3.effect.ParticleEmitter; import com.jme3.effect.shapes.EmitterShape; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/particle/emitter/ChangeParticleInfluencerOperation.java b/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/particle/emitter/ChangeParticleInfluencerOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java index 5003a37f..add6f942 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/particle/emitter/ChangeParticleInfluencerOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/emitter/ChangeParticleInfluencerOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation.particle.emitter; +package com.ss.editor.model.undo.impl.emitter; import com.jme3.effect.ParticleEmitter; import com.jme3.effect.influencers.ParticleInfluencer; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/AddSceneLayerOperation.java b/src/main/java/com/ss/editor/model/undo/impl/scene/AddSceneLayerOperation.java similarity index 96% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/AddSceneLayerOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/scene/AddSceneLayerOperation.java index 6ec1fd16..976eb0d8 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/AddSceneLayerOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/scene/AddSceneLayerOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation.scene; +package com.ss.editor.model.undo.impl.scene; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.model.undo.impl.AbstractEditorOperation; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/ChangeVisibleSceneLayerOperation.java b/src/main/java/com/ss/editor/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java similarity index 97% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/ChangeVisibleSceneLayerOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java index 694f5047..b781ec4d 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/ChangeVisibleSceneLayerOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/scene/ChangeVisibleSceneLayerOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation.scene; +package com.ss.editor.model.undo.impl.scene; import com.jme3.scene.Spatial; import com.ss.editor.model.undo.editor.ModelChangeConsumer; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/RemoveSceneLayerOperation.java b/src/main/java/com/ss/editor/model/undo/impl/scene/RemoveSceneLayerOperation.java similarity index 97% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/RemoveSceneLayerOperation.java rename to src/main/java/com/ss/editor/model/undo/impl/scene/RemoveSceneLayerOperation.java index 2c8818da..33239f33 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/operation/scene/RemoveSceneLayerOperation.java +++ b/src/main/java/com/ss/editor/model/undo/impl/scene/RemoveSceneLayerOperation.java @@ -1,4 +1,4 @@ -package com.ss.editor.ui.control.tree.action.impl.operation.scene; +package com.ss.editor.model.undo.impl.scene; import com.jme3.scene.Spatial; import com.ss.editor.model.undo.editor.ModelChangeConsumer; diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/AbstractSceneEditor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/AbstractSceneEditor3DPart.java index 9732692f..e5e2f7ca 100644 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/AbstractSceneEditor3DPart.java +++ b/src/main/java/com/ss/editor/part3d/editor/impl/scene/AbstractSceneEditor3DPart.java @@ -31,6 +31,7 @@ import com.jme3.scene.shape.Line; import com.jme3.scene.shape.Quad; import com.jme3.scene.shape.Sphere; +import com.ss.editor.Messages; import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.annotation.JmeThread; import com.ss.editor.control.painting.PaintingControl; @@ -42,7 +43,9 @@ import com.ss.editor.model.scene.*; import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.part3d.editor.impl.scene.handler.ApplyScaleToPhysicsControlsHandler; import com.ss.editor.part3d.editor.impl.scene.handler.DisableControlsTransformationHandler; +import com.ss.editor.part3d.editor.impl.scene.handler.PhysicsControlTransformationHandler; import com.ss.editor.part3d.editor.impl.scene.handler.ReactivatePhysicsControlsTransformationHandler; import com.ss.editor.plugin.api.editor.part3d.Advanced3DEditorPart; import com.ss.editor.ui.component.editor.impl.scene.AbstractSceneFileEditor; @@ -73,11 +76,11 @@ public abstract class AbstractSceneEditor3DPart extends Advanced3DEditorPart implements EditorTransformSupport { - /** - * The constant LOADED_MODEL_KEY. - */ - @NotNull - public static String LOADED_MODEL_KEY = EditorTransformSupport.class.getName() + ".loadedModel"; + public static final String KEY_LOADED_MODEL = "jMB.sceneEditor.loadedModel"; + public static final String KEY_IGNORE_RAY_CAST = "jMB.sceneEditor.ignoreRayCast"; + public static final String KEY_MODEL_NODE = "jMB.sceneEditor.modelNode"; + public static final String KEY_SHAPE_CENTER = "jMB.sceneEditor.shapeCenter"; + public static final String KEY_SHAPE_INIT_SCALE = "jMB.sceneEditor.initScale"; private static final String KEY_S = "SSEditor.sceneEditorState.S"; private static final String KEY_G = "SSEditor.sceneEditorState.G"; @@ -157,10 +160,14 @@ public static void registerPostTransformHandler(@NotNull final Consumer // default handlers final DisableControlsTransformationHandler disableControlsHandler = new DisableControlsTransformationHandler(); + final ApplyScaleToPhysicsControlsHandler applyScaleToPhysicsControlsHandler = new ApplyScaleToPhysicsControlsHandler(); registerPreTransformHandler(disableControlsHandler::onPreTransform); registerPostTransformHandler(disableControlsHandler::onPostTransform); registerPostTransformHandler(new ReactivatePhysicsControlsTransformationHandler()); + registerPostTransformHandler(new PhysicsControlTransformationHandler()); + registerPreTransformHandler(applyScaleToPhysicsControlsHandler::onPreTransform); + registerPostTransformHandler(applyScaleToPhysicsControlsHandler::onPostTransform); } /** @@ -203,7 +210,7 @@ public static void registerPostTransformHandler(@NotNull final Consumer * The selection models of selected models. */ @NotNull - private final ObjectDictionary selectionShape; + private final ObjectDictionary selectionShape; /** * The array of selected models. @@ -347,11 +354,6 @@ public static void registerPostTransformHandler(@NotNull final Consumer */ private boolean activeTransform; - /** - * The flag of existing active editing. - */ - private boolean activeEditing; - /** * The flag of painting mode. */ @@ -363,7 +365,7 @@ public AbstractSceneEditor3DPart(@NotNull final T fileEditor) { this.cachedAudioNodes = DictionaryFactory.newObjectDictionary(); this.cachedPresentableObjects = DictionaryFactory.newObjectDictionary(); this.modelNode = new Node("TreeNode"); - this.modelNode.setUserData(EditorTransformSupport.class.getName(), true); + this.modelNode.setUserData(KEY_MODEL_NODE, true); this.selected = ArrayFactory.newArray(Spatial.class); this.selectionShape = DictionaryFactory.newObjectDictionary(); this.toolNode = new Node("ToolNode"); @@ -516,7 +518,17 @@ private void createToolElements() { grid.setCullHint(Spatial.CullHint.Never); grid.setLocalTranslation(gridSize / 2 * -1, 0, gridSize / 2 * -1); + final Quad quad = new Quad(gridSize, gridSize); + final Geometry gridCollision = new Geometry("collision", quad); + gridCollision.setMaterial(createColorMaterial(gridColor)); + gridCollision.setQueueBucket(RenderQueue.Bucket.Transparent); + gridCollision.setShadowMode(RenderQueue.ShadowMode.Off); + gridCollision.setCullHint(Spatial.CullHint.Always); + gridCollision.setLocalTranslation(gridSize / 2 * -1, 0, gridSize / 2 * -1); + gridCollision.setLocalRotation(new Quaternion().fromAngles(AngleUtils.degreeToRadians(90), 0, 0)); + gridNode.attachChild(grid); + gridNode.attachChild(gridCollision); // Red line for X axis final Line xAxis = new Line(new Vector3f(-gridSize / 2, 0f, 0f), new Vector3f(gridSize / 2 - 1, 0f, 0f)); @@ -580,7 +592,7 @@ private void createManipulators() { moveTool.getChild("move_z").setMaterial(greenMaterial); moveTool.getChild("collision_move_z").setMaterial(greenMaterial); moveTool.getChild("collision_move_z").setCullHint(Spatial.CullHint.Always); - moveTool.scale(0.1f); + moveTool.scale(0.2f); moveTool.addControl(new MoveToolControl(this)); rotateTool = (Node) assetManager.loadModel("graphics/models/manipulators/manipulators_rotate.j3o"); @@ -593,7 +605,7 @@ private void createManipulators() { rotateTool.getChild("rot_z").setMaterial(greenMaterial); rotateTool.getChild("collision_rot_z").setMaterial(greenMaterial); rotateTool.getChild("collision_rot_z").setCullHint(Spatial.CullHint.Always); - rotateTool.scale(0.1f); + rotateTool.scale(0.2f); rotateTool.addControl(new RotationToolControl(this)); scaleTool = (Node) assetManager.loadModel("graphics/models/manipulators/manipulators_scale.j3o"); @@ -606,7 +618,7 @@ private void createManipulators() { scaleTool.getChild("scale_z").setMaterial(greenMaterial); scaleTool.getChild("collision_scale_z").setMaterial(greenMaterial); scaleTool.getChild("collision_scale_z").setCullHint(Spatial.CullHint.Always); - scaleTool.scale(0.1f); + scaleTool.scale(0.2f); scaleTool.addControl(new ScaleToolControl(this)); } @@ -785,6 +797,8 @@ public float getTransformDeltaZ() { } /** + * Set true of we have active transformation. + * * @param activeTransform true of we have active transformation. */ @FromAnyThread @@ -793,6 +807,8 @@ private void setActiveTransform(final boolean activeTransform) { } /** + * Return true of we have active transformation. + * * @return true of we have active transformation. */ @FromAnyThread @@ -800,22 +816,6 @@ private boolean isActiveTransform() { return activeTransform; } - /** - * @return true if we have active editing. - */ - @FromAnyThread - private boolean isActiveEditing() { - return activeEditing; - } - - /** - * @param activeEditing true of we have active editing. - */ - @FromAnyThread - private void setActiveEditing(final boolean activeEditing) { - this.activeEditing = activeEditing; - } - @Override protected void preCameraUpdate(final float tpf) { super.preCameraUpdate(tpf); @@ -857,7 +857,6 @@ protected void postCameraUpdate(final float tpf) { final Array selected = getSelected(); selected.forEach(this, (spatial, state) -> { - if (spatial == null) return; if (spatial instanceof EditorLightNode) { spatial = ((EditorLightNode) spatial).getModel(); @@ -867,15 +866,47 @@ protected void postCameraUpdate(final float tpf) { spatial = ((EditorPresentableNode) spatial).getModel(); } + if (spatial == null) { + return; + } + state.updateTransformNode(spatial.getWorldTransform()); - final ObjectDictionary selectionShape = state.getSelectionShape(); - final Spatial shape = selectionShape.get(spatial); - if (shape == null) return; + final ObjectDictionary selectionShape = state.getSelectionShape(); + final Geometry shape = selectionShape.get(spatial); + if (shape == null) { + return; + } + + final Vector3f position = shape.getLocalTranslation(); + position.set(spatial.getWorldTranslation()); + + final Vector3f center = shape.getUserData(KEY_SHAPE_CENTER); + final Vector3f initScale = shape.getUserData(KEY_SHAPE_INIT_SCALE); + + if (center != null) { + + if (!initScale.equals(spatial.getLocalScale())) { + + initScale.set(spatial.getLocalScale()); + + NodeUtils.updateWorldBound(spatial); + + final BoundingBox bound = (BoundingBox) spatial.getWorldBound(); + bound.getCenter().subtract(spatial.getWorldTranslation(), center); + + final WireBox mesh = (WireBox) shape.getMesh(); + mesh.updatePositions(bound.getXExtent(), bound.getYExtent(), bound.getZExtent()); + } + + position.addLocal(center); + + } else { + shape.setLocalRotation(spatial.getWorldRotation()); + shape.setLocalScale(spatial.getWorldScale()); + } - shape.setLocalTranslation(spatial.getWorldTranslation()); - shape.setLocalRotation(spatial.getWorldRotation()); - shape.setLocalScale(spatial.getWorldScale()); + shape.setLocalTranslation(position); }); transformToolNode.detachAllChildren(); @@ -890,15 +921,16 @@ protected void postCameraUpdate(final float tpf) { final Node toolNode = getToolNode(); - if (selected.isEmpty()) { + // FIXME change when will support transform multi-nodes + if (selected.size() != 1) { toolNode.detachChild(transformToolNode); } else if (!isPaintingMode()) { toolNode.attachChild(transformToolNode); } if (isPaintingMode()) { - updateEditingNodes(); - updatePainting(); + updatePaintingNodes(); + updatePainting(tpf); } } @@ -906,19 +938,51 @@ protected void postCameraUpdate(final float tpf) { * Update editing nodes. */ @JmeThread - private void updateEditingNodes() { - if (!isPaintingMode()) return; + private void updatePaintingNodes() { + + if (!isPaintingMode()) { + return; + } final Node cursorNode = getCursorNode(); final PaintingControl control = PaintingUtils.getPaintingControl(cursorNode); - final Spatial editedModel = PaintingUtils.getPaintedModel(control); - if (editedModel == null) return; + final Spatial paintedModel = PaintingUtils.getPaintedModel(control); + if (paintedModel == null) { + return; + } + + final CollisionResults collisions = GeomUtils.getCollisionsFromCursor(paintedModel, getCamera()); + if (collisions.size() < 1) { + return; + } - final Vector3f contactPoint = GeomUtils.getContactPointFromCursor(editedModel, getCamera()); + CollisionResult result = null; - if (contactPoint != null) { - cursorNode.setLocalTranslation(contactPoint); + for (final CollisionResult collision : collisions) { + + final Geometry geometry = collision.getGeometry(); + final Object parent = NodeUtils.findParent(geometry, spatial -> + spatial.getUserData(KEY_IGNORE_RAY_CAST) == Boolean.TRUE); + + if (parent == null) { + result = collision; + break; + } } + + if (result == null) { + result = collisions.getClosestCollision(); + } + + final Vector3f contactPoint = result.getContactPoint(); + final Vector3f contactNormal = result.getContactNormal(); + + final LocalObjects local = LocalObjects.get(); + final Quaternion rotation = local.nextRotation(); + rotation.lookAt(contactNormal, Vector3f.UNIT_Y); + + cursorNode.setLocalRotation(rotation); + cursorNode.setLocalTranslation(contactPoint); } /** @@ -926,7 +990,10 @@ private void updateEditingNodes() { */ @JmeThread private void updateTransformNode(@Nullable final Transform transform) { - if (transform == null) return; + + if (transform == null) { + return; + } final TransformationMode transformationMode = getTransformationMode(); final Vector3f location = transform.getTranslation(); @@ -978,7 +1045,7 @@ private void updateTransformNode(@Nullable final Transform transform) { * @return the selection models of selected models. */ @FromAnyThread - private @NotNull ObjectDictionary getSelectionShape() { + private @NotNull ObjectDictionary getSelectionShape() { return selectionShape; } @@ -1043,37 +1110,61 @@ private void updateTransformNode(@Nullable final Transform transform) { } /** - * Update selected models. + * Select the objects. * - * @param spatials the spatials + * @param objects the objects. */ @FromAnyThread - public void updateSelection(@NotNull final Array spatials) { - EXECUTOR_MANAGER.addJmeTask(() -> updateSelectionImpl(spatials)); + public void select(@NotNull final Array objects) { + EXECUTOR_MANAGER.addJmeTask(() -> selectImpl(objects)); } /** - * The process of updating selected models. + * Select the object. + * + * @param object the object. + */ + @FromAnyThread + public void select(@NotNull final Spatial object) { + EXECUTOR_MANAGER.addJmeTask(() -> { + + final Array toSelect = LocalObjects.get().nextSpatialArray(); + toSelect.add(object); + + selectImpl(toSelect); + }); + } + + /** + * The process of selecting the objects. + * + * @param objects the objects. */ @JmeThread - private void updateSelectionImpl(@NotNull final Array spatials) { + private void selectImpl(@NotNull final Array objects) { final Array selected = getSelected(); - for (final ArrayIterator iterator = selected.iterator(); iterator.hasNext(); ) { + if (objects.isEmpty()) { + selected.forEach(this, (spatial, ed) -> ed.removeFromSelection(spatial)); + selected.clear(); + } else { - final Spatial spatial = iterator.next(); - if (spatials.contains(spatial)) { - continue; - } + for (final ArrayIterator iterator = selected.iterator(); iterator.hasNext(); ) { - removeFromSelection(spatial); - iterator.fastRemove(); - } + final Spatial spatial = iterator.next(); + if (objects.contains(spatial)) { + continue; + } - for (final Spatial spatial : spatials) { - if (!selected.contains(spatial)) { - addToSelection(spatial); + removeFromSelection(spatial); + iterator.fastRemove(); + } + + for (final Spatial spatial : objects) { + if (!selected.contains(spatial)) { + addToSelection(spatial); + } } } @@ -1139,7 +1230,7 @@ private void addToSelection(@NotNull final Spatial spatial) { return; } - Spatial shape; + Geometry shape; if (spatial instanceof ParticleEmitter) { shape = buildBoxSelection(spatial); @@ -1149,14 +1240,16 @@ private void addToSelection(@NotNull final Spatial spatial) { shape = buildBoxSelection(spatial); } - if (shape == null) return; + if (shape == null) { + return; + } if (isShowSelection()) { final Node toolNode = getToolNode(); toolNode.attachChild(shape); } - final ObjectDictionary selectionShape = getSelectionShape(); + final ObjectDictionary selectionShape = getSelectionShape(); selectionShape.put(spatial, shape); } @@ -1168,7 +1261,7 @@ private void removeFromSelection(@NotNull final Spatial spatial) { setTransformCenter(null); setToTransform(null); - final ObjectDictionary selectionShape = getSelectionShape(); + final ObjectDictionary selectionShape = getSelectionShape(); final Spatial shape = selectionShape.remove(spatial); if (shape != null) { @@ -1184,19 +1277,27 @@ private void removeFromSelection(@NotNull final Spatial spatial) { * Build the selection box for the spatial. */ @JmeThread - private Spatial buildBoxSelection(@NotNull final Spatial spatial) { - spatial.updateModelBound(); + private Geometry buildBoxSelection(@NotNull final Spatial spatial) { + NodeUtils.updateWorldBound(spatial); final BoundingVolume bound = spatial.getWorldBound(); if (bound instanceof BoundingBox) { final BoundingBox boundingBox = (BoundingBox) bound; + final Vector3f center = boundingBox.getCenter().subtract(spatial.getWorldTranslation()); + final Vector3f initScale = spatial.getLocalScale().clone(); final Geometry geometry = WireBox.makeGeometry(boundingBox); geometry.setName("SelectionShape"); geometry.setMaterial(getSelectionMaterial()); - geometry.setLocalTranslation(boundingBox.getCenter().subtract(spatial.getWorldTranslation())); + geometry.setUserData(KEY_SHAPE_CENTER, center); + geometry.setUserData(KEY_SHAPE_INIT_SCALE, initScale); + + final Vector3f position = geometry.getLocalTranslation(); + position.addLocal(center); + + geometry.setLocalTranslation(position); return geometry; @@ -1209,7 +1310,7 @@ private Spatial buildBoxSelection(@NotNull final Spatial spatial) { final Geometry geometry = new Geometry("SelectionShape", wire); geometry.setMaterial(getSelectionMaterial()); - geometry.setLocalTranslation(boundingSphere.getCenter().subtract(spatial.getWorldTranslation())); + geometry.setLocalTranslation(spatial.getWorldTranslation()); return geometry; } @@ -1226,10 +1327,12 @@ private Spatial buildBoxSelection(@NotNull final Spatial spatial) { * Build selection grid for the geometry. */ @JmeThread - private Spatial buildGeometrySelection(@NotNull final Geometry geom) { + private Geometry buildGeometrySelection(@NotNull final Geometry geom) { final Mesh mesh = geom.getMesh(); - if (mesh == null) return null; + if (mesh == null) { + return null; + } final Geometry geometry = new Geometry("SelectionShape", mesh); geometry.setMaterial(getSelectionMaterial()); @@ -1293,9 +1396,12 @@ public void updateShowSelection(final boolean showSelection) { */ @JmeThread private void updateShowSelectionImpl(final boolean showSelection) { - if (isShowSelection() == showSelection) return; - final ObjectDictionary selectionShape = getSelectionShape(); + if (isShowSelection() == showSelection) { + return; + } + + final ObjectDictionary selectionShape = getSelectionShape(); final Node toolNode = getToolNode(); if (showSelection && !selectionShape.isEmpty()) { @@ -1370,12 +1476,14 @@ private void processSelect() { return; } - final Geometry anyGeometry = GeomUtils.getGeometryFromCursor(notNull(getModelNode()), getCamera()); + final Node modelNode = notNull(getModelNode()); + final Geometry anyGeometry = GeomUtils.getGeometryFromCursor(modelNode, getCamera()); + final M currentModel = notNull(getCurrentModel()); Object toSelect = anyGeometry == null ? null : findToSelect(anyGeometry); if (toSelect == null && anyGeometry != null) { - final Geometry modelGeometry = GeomUtils.getGeometryFromCursor(notNull(getCurrentModel()), getCamera()); + final Geometry modelGeometry = GeomUtils.getGeometryFromCursor(currentModel, getCamera()); toSelect = modelGeometry == null ? null : findToSelect(modelGeometry); } @@ -1421,7 +1529,7 @@ private void processSelect() { return parent; } - parent = NodeUtils.findParent(spatial, p -> Boolean.TRUE.equals(p.getUserData(LOADED_MODEL_KEY))); + parent = NodeUtils.findParent(spatial, p -> Boolean.TRUE.equals(p.getUserData(KEY_LOADED_MODEL))); if (parent != null) { return parent; } @@ -1461,7 +1569,7 @@ private void notifySelected(@Nullable final Object object) { } /** - * Get a position on a scene for a cursor position on a screen. + * Get a position on a scene for a cursor position. * * @param screenX the x position on screen. * @param screenY the y position on screen. @@ -1473,14 +1581,36 @@ private void notifySelected(@Nullable final Object object) { final Camera camera = getCamera(); final M currentModel = notNull(getCurrentModel()); - Vector3f result = GeomUtils.getContactPointFromScreenPos(currentModel, camera, screenX, screenY); - if (result != null) { - return result; + final Vector3f modelPoint = GeomUtils.getContactPointFromScreenPos(currentModel, camera, screenX, screenY); + final Vector3f gridPoint = GeomUtils.getContactPointFromScreenPos(getGrid(), camera, screenX, screenY); + + if (modelPoint == null) { + return gridPoint == null ? Vector3f.ZERO : gridPoint; + } else if (gridPoint == null) { + return modelPoint; } - result = GeomUtils.getContactPointFromScreenPos(getGrid(), camera, screenX, screenY); + final float distance = modelPoint.distance(camera.getLocation()); - return result == null ? Vector3f.ZERO : result; + if (gridPoint.distance(camera.getLocation()) < distance) { + return gridPoint; + } else { + return modelPoint; + } + } + + /** + * Get a normal on a scene for a cursor position. + * + * @param screenX the x position on screen. + * @param screenY the y position on screen. + * @return the normal on the current scene or null. + */ + @JmeThread + public @Nullable Vector3f getSceneNormalByScreenPos(final float screenX, final float screenY) { + final Camera camera = getCamera(); + final M currentModel = notNull(getCurrentModel()); + return GeomUtils.getContactNormalFromScreenPos(currentModel, camera, screenX, screenY); } /** @@ -1548,7 +1678,7 @@ private void endTransform() { final Transform newValue = toTransform.getLocalTransform().clone(); final PropertyOperation operation = - new PropertyOperation<>(toTransform, "transform", newValue, oldValue); + new PropertyOperation<>(toTransform, "internal_transformation", newValue, oldValue); operation.setApplyHandler((spatial, transform) -> { PRE_TRANSFORM_HANDLERS.forEach(spatial, Consumer::accept); @@ -1636,7 +1766,7 @@ private void startPainting(@NotNull final PaintingInput input) { return; } - control.startPainting(input, cursorNode.getLocalTranslation()); + control.startPainting(input, cursorNode.getLocalRotation(), cursorNode.getLocalTranslation()); } /** @@ -1655,14 +1785,14 @@ private void finishPainting(@NotNull final PaintingInput input) { return; } - control.finishPainting(cursorNode.getLocalTranslation()); + control.finishPainting(cursorNode.getLocalRotation(), cursorNode.getLocalTranslation()); } /** * Update painting. */ @JmeThread - private void updatePainting() { + private void updatePainting(final float tpf) { final Node cursorNode = getCursorNode(); final PaintingControl control = PaintingUtils.getPaintingControl(cursorNode); @@ -1672,16 +1802,32 @@ private void updatePainting() { return; } - control.updatePainting(cursorNode.getLocalTranslation()); + control.updatePainting(cursorNode.getLocalRotation(), cursorNode.getLocalTranslation(), tpf); + } + + /** + * Notify about an attempt to change the property from jME thread. + * + * @param object the object. + * @param name the property name. + */ + @JmeThread + public void notifyPropertyPreChanged(@NotNull final Object object, @NotNull final String name) { + if (object instanceof Spatial) { + if (isTransformationProperty(name)) { + PRE_TRANSFORM_HANDLERS.forEach((Spatial) object, Consumer::accept); + } + } } /** * Notify about property changes. * * @param object the object with changes. + * @param name the property name. */ @JmeThread - public void notifyPropertyChanged(@NotNull Object object) { + public void notifyPropertyChanged(@NotNull Object object, @NotNull final String name) { if (object instanceof SimpleProperty) { object = ((SimpleProperty) object).getObject(); @@ -1697,6 +1843,19 @@ public void notifyPropertyChanged(@NotNull Object object) { final EditorPresentableNode node = getPresentableNode((ScenePresentable) object); if (node != null) node.sync(); } + + if (object instanceof Spatial) { + if (isTransformationProperty(name)) { + POST_TRANSFORM_HANDLERS.forEach((Spatial) object, Consumer::accept); + } + } + } + + protected boolean isTransformationProperty(@NotNull final String name) { + return Messages.MODEL_PROPERTY_LOCATION.equals(name) || + Messages.MODEL_PROPERTY_SCALE.equals(name) || + Messages.MODEL_PROPERTY_ROTATION.equals(name) || + Messages.MODEL_PROPERTY_TRANSFORMATION.equals(name); } /** @@ -1751,7 +1910,9 @@ private void openModelImpl(@NotNull final M model) { } }); + PRE_TRANSFORM_HANDLERS.forEach(model, Consumer::accept); attachModel(model, modelNode); + POST_TRANSFORM_HANDLERS.forEach(model, Consumer::accept); setCurrentModel(model); } @@ -1810,7 +1971,7 @@ private void addLightImpl(@NotNull final Light light) { final EditorLightNode lightModel = notNull(cachedLights.get(light, () -> { final Node model = (Node) node.clone(); - model.setLocalScale(0.01F); + model.setLocalScale(0.03F); final EditorLightNode result = new EditorLightNode(camera); result.setModel(model); @@ -1849,16 +2010,46 @@ public void moveCameraTo(@NotNull final Vector3f location) { } /** - * Look at the position from the camera. + * Look at the spatial. * - * @param location the location. + * @param spatial the spatial. */ @FromAnyThread - public void cameraLookAt(@NotNull final Vector3f location) { + public void cameraLookAt(@NotNull final Spatial spatial) { EXECUTOR_MANAGER.addJmeTask(() -> { + final EditorCamera editorCamera = notNull(getEditorCamera()); - editorCamera.setTargetDistance(location.distance(getCamera().getLocation())); - getNodeForCamera().setLocalTranslation(location); + + final LocalObjects local = LocalObjects.get(); + float distance; + + final BoundingVolume worldBound = spatial.getWorldBound(); + + if (worldBound != null) { + distance = worldBound.getVolume(); + + if (worldBound instanceof BoundingBox) { + final BoundingBox boundingBox = (BoundingBox) worldBound; + distance = boundingBox.getXExtent(); + distance = Math.max(distance, boundingBox.getYExtent()); + distance = Math.max(distance, boundingBox.getZExtent()); + distance *= 2F; + } else if (worldBound instanceof BoundingSphere) { + distance = ((BoundingSphere) worldBound).getRadius() * 2F; + } + + } else { + + distance = getCamera().getLocation() + .distance(spatial.getWorldTranslation()); + } + + editorCamera.setTargetDistance(distance); + + final Vector3f position = local.nextVector() + .set(spatial.getWorldTranslation()); + + getNodeForCamera().setLocalTranslation(position); }); } @@ -1879,11 +2070,15 @@ public void removeLight(@NotNull final Light light) { private void removeLightImpl(@NotNull final Light light) { final Node node = LIGHT_MODEL_TABLE.get(light.getType()); - if (node == null) return; + if (node == null) { + return; + } final ObjectDictionary cachedLights = getCachedLights(); final EditorLightNode lightModel = cachedLights.get(light); - if (lightModel == null) return; + if (lightModel == null) { + return; + } lightModel.setLight(null); @@ -1915,7 +2110,7 @@ private void addAudioNodeImpl(@NotNull final AudioNode audio) { final EditorAudioNode audioModel = notNull(cachedAudioNodes.get(audio, () -> { final Node model = (Node) AUDIO_NODE_MODEL.clone(); - model.setLocalScale(0.005F); + model.setLocalScale(0.01F); final EditorAudioNode result = new EditorAudioNode(getCamera()); result.setModel(model); @@ -1951,7 +2146,9 @@ private void removeAudioNodeImpl(@NotNull final AudioNode audio) { final ObjectDictionary cachedAudioNodes = getCachedAudioNodes(); final EditorAudioNode audioModel = cachedAudioNodes.get(audio); - if (audioModel == null) return; + if (audioModel == null) { + return; + } audioModel.setAudioNode(null); @@ -2041,7 +2238,9 @@ private void removePresentableImpl(@NotNull final ScenePresentable presentable) final ObjectDictionary presentableNodes = getCachedPresentableObjects(); final EditorPresentableNode node = presentableNodes.get(presentable); - if (node == null) return; + if (node == null) { + return; + } node.setObject(null); diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/SceneEditor3DPart.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/SceneEditor3DPart.java index d7e09d4d..e85725e7 100644 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/SceneEditor3DPart.java +++ b/src/main/java/com/ss/editor/part3d/editor/impl/scene/SceneEditor3DPart.java @@ -217,7 +217,10 @@ public void updateLightShowed(final boolean showed) { */ @JmeThread private void updateLightShowedImpl(final boolean showed) { - if (showed == isLightShowed()) return; + + if (showed == isLightShowed()) { + return; + } final Node lightNode = getLightNode(); final Node modelNode = getModelNode(); @@ -246,7 +249,10 @@ public void updateAudioShowed(final boolean showed) { */ @JmeThread private void updateAudioShowedImpl(final boolean showed) { - if (showed == isAudioShowed()) return; + + if (showed == isAudioShowed()) { + return; + } final Node audioNode = getAudioNode(); final Node modelNode = getModelNode(); diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java new file mode 100644 index 00000000..6efdaa68 --- /dev/null +++ b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ApplyScaleToPhysicsControlsHandler.java @@ -0,0 +1,86 @@ +package com.ss.editor.part3d.editor.impl.scene.handler; + +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.editor.annotation.FromAnyThread; +import com.ss.editor.annotation.JmeThread; +import com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart; +import com.ss.editor.util.ControlUtils; +import com.ss.editor.util.NodeUtils; +import com.ss.rlib.util.dictionary.DictionaryFactory; +import com.ss.rlib.util.dictionary.ObjectDictionary; +import org.jetbrains.annotations.NotNull; + +/** + * The handler to disable all controls during transforming spatial. + * + * @author JavaSaBr + */ +public class ApplyScaleToPhysicsControlsHandler { + + /** + * The condition to find a model root. + * + * @param spatial the model. + * @return true if the node is model root. + */ + @FromAnyThread + protected static boolean isModelRoot(@NotNull final Spatial spatial) { + final Node parent = spatial.getParent(); + return parent == null || parent.getUserData(AbstractSceneEditor3DPart.KEY_MODEL_NODE) != null; + } + + /** + * The saved previous scales. + */ + @NotNull + private final ObjectDictionary previousScales; + + public ApplyScaleToPhysicsControlsHandler() { + this.previousScales = DictionaryFactory.newObjectDictionary(); + } + + /** + * Disable all controls before transform. + * + * @param spatial the spatial. + */ + @JmeThread + public void onPreTransform(@NotNull final Spatial spatial) { + NodeUtils.children(NodeUtils.findParent(spatial, ApplyScaleToPhysicsControlsHandler::isModelRoot)) + .filter(sp -> ControlUtils.has(sp, PhysicsCollisionObject.class)) + .peek(sp -> previousScales.put(sp, sp.getWorldScale().clone())) + .flatMap(NodeUtils::children) + .filter(ch -> !previousScales.containsKey(ch)) + .forEach(ch -> previousScales.put(ch, ch.getWorldScale().clone())); + } + + + /** + * Enable disabled controls before transform. + * + * @param spatial the spatial. + */ + @JmeThread + public void onPostTransform(@NotNull final Spatial spatial) { + + NodeUtils.children(NodeUtils.findParent(spatial, ApplyScaleToPhysicsControlsHandler::isModelRoot)) + .filter(sp -> ControlUtils.has(sp, PhysicsCollisionObject.class)) + .filter(previousScales::containsKey) + .filter(sp -> isChanged(sp) || NodeUtils.children(sp).anyMatch(this::isChanged)) + .forEach(sp -> ControlUtils.controls(sp) + .filter(PhysicsCollisionObject.class::isInstance) + .map(PhysicsCollisionObject.class::cast) + .forEach(object -> ControlUtils.applyScale(sp, sp.getWorldScale(), object))); + + previousScales.clear(); + } + + @JmeThread + protected boolean isChanged(@NotNull final Spatial sp) { + final Vector3f prevScale = previousScales.remove(sp); + return prevScale != null && !prevScale.equals(sp.getWorldScale()); + } +} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/DisableControlsTransformationHandler.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/DisableControlsTransformationHandler.java index 7937f828..5cf51894 100644 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/DisableControlsTransformationHandler.java +++ b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/DisableControlsTransformationHandler.java @@ -1,6 +1,9 @@ package com.ss.editor.part3d.editor.impl.scene.handler; import static com.ss.rlib.util.array.ArrayCollectors.toArray; + +import com.jme3.bullet.control.PhysicsControl; +import com.jme3.bullet.control.RigidBodyControl; import com.jme3.scene.Spatial; import com.jme3.scene.control.Control; import com.ss.editor.annotation.JmeThread; diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/PhysicsControlTransformationHandler.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/PhysicsControlTransformationHandler.java new file mode 100644 index 00000000..cd3fe3f5 --- /dev/null +++ b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/PhysicsControlTransformationHandler.java @@ -0,0 +1,20 @@ +package com.ss.editor.part3d.editor.impl.scene.handler; + +import com.jme3.scene.Spatial; +import com.ss.editor.extension.util.JmbExtUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; + +/** + * The handler to updated positions for physics controls on spatial transformations. + * + * @author JavaSaBr + */ +public class PhysicsControlTransformationHandler implements Consumer { + + @Override + public void accept(@NotNull final Spatial spatial) { + JmbExtUtils.resetPhysicsControlPositions(spatial); + } +} diff --git a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java index 01fceebd..e49f63a9 100644 --- a/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java +++ b/src/main/java/com/ss/editor/part3d/editor/impl/scene/handler/ReactivatePhysicsControlsTransformationHandler.java @@ -23,6 +23,7 @@ public void accept(@NotNull final Spatial spatial) { .filter(RigidBodyControl.class::isInstance) .map(RigidBodyControl.class::cast) .filter(RigidBodyControl::isEnabled) + .filter(control -> Float.compare(control.getMass(), 0.0F) != 0) .filter(control -> !control.isActive()) .forEach(PhysicsRigidBody::activate); } diff --git a/src/main/java/com/ss/editor/plugin/api/dialog/GenericFactoryDialog.java b/src/main/java/com/ss/editor/plugin/api/dialog/GenericFactoryDialog.java index a3840ca0..0967a242 100644 --- a/src/main/java/com/ss/editor/plugin/api/dialog/GenericFactoryDialog.java +++ b/src/main/java/com/ss/editor/plugin/api/dialog/GenericFactoryDialog.java @@ -40,13 +40,13 @@ public class GenericFactoryDialog extends AbstractSimpleEditorDialog { * The list of all definitions. */ @NotNull - private final Array<@NotNull PropertyDefinition> definitions; + private final Array definitions; /** * The handler to handle result properties. */ @NotNull - private final Consumer<@NotNull VarTable> handler; + private final Consumer handler; /** * THe callback to call re-validating. @@ -58,7 +58,7 @@ public class GenericFactoryDialog extends AbstractSimpleEditorDialog { * The validator of all properties. */ @NotNull - private Predicate<@NotNull VarTable> validator; + private Predicate validator; /** * The root content container. @@ -66,14 +66,14 @@ public class GenericFactoryDialog extends AbstractSimpleEditorDialog { @Nullable private VBox root; - public GenericFactoryDialog(@NotNull final Array<@NotNull PropertyDefinition> definitions, - @NotNull final Consumer<@NotNull VarTable> handler) { + public GenericFactoryDialog(@NotNull final Array definitions, + @NotNull final Consumer handler) { this(definitions, handler, varTable -> true); } - public GenericFactoryDialog(@NotNull final Array<@NotNull PropertyDefinition> definitions, - @NotNull final Consumer<@NotNull VarTable> handler, - @NotNull final Predicate<@NotNull VarTable> validator) { + public GenericFactoryDialog(@NotNull final Array definitions, + @NotNull final Consumer handler, + @NotNull final Predicate validator) { this.definitions = definitions; this.handler = handler; this.validator = validator; @@ -84,7 +84,7 @@ public GenericFactoryDialog(@NotNull final Array<@NotNull PropertyDefinition> de } /** - * Sets the title. + * Set the title. * * @param title the new title. */ @@ -94,7 +94,7 @@ public void setTitle(@NotNull final String title) { } /** - * Sets the text to the OK button. + * Set the text to the OK button. * * @param text the new text. */ @@ -104,7 +104,7 @@ public void setButtonOkText(@NotNull final String text) { } /** - * Sets the text to the Close button. + * Set the text to the close button. * * @param text the new text. */ @@ -127,7 +127,7 @@ protected void createContent(@NotNull final VBox root) { } /** - * Gets the root to place controls. + * Get the root to place controls. * * @return the root. */ @@ -159,6 +159,8 @@ private void createControls() { } /** + * Get the list of all definitions. + * * @return the list of all definitions. */ @FxThread diff --git a/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithRightTool.java b/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithRightTool.java index a69fe1a8..87008b41 100644 --- a/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithRightTool.java +++ b/src/main/java/com/ss/editor/plugin/api/editor/Advanced3DFileEditorWithRightTool.java @@ -64,7 +64,9 @@ protected void createContent(@NotNull final StackPane root) { editorToolComponent.addChangeListener((observable, oldValue, newValue) -> processChangeTool(oldValue, newValue)); editorToolComponent.getSelectionModel().selectedIndexProperty().addListener((observable, oldValue, newValue) -> { final S editorState = getEditorState(); - if (editorState != null) editorState.setOpenedTool(newValue.intValue()); + if (editorState != null) { + editorState.setOpenedTool(newValue.intValue()); + } }); mainSplitContainer.initFor(editorToolComponent, getEditorAreaPane()); @@ -112,8 +114,10 @@ protected void loadState() { return; } - editorToolComponent.getSelectionModel().select(editorState.getOpenedTool()); - mainSplitContainer.updateFor(editorState); + getEditorToolComponent().getSelectionModel() + .select(editorState.getOpenedTool()); + + getMainSplitContainer().updateFor(editorState); } @Override @@ -123,6 +127,8 @@ protected void loadState() { } /** + * Get the pane of editor area. + * * @return the pane of editor area. */ @FxThread @@ -130,6 +136,26 @@ protected void loadState() { return notNull(editorAreaPane); } + /** + * Get the editor tool component. + * + * @return the editor tool component. + */ + @FxThread + protected @NotNull ScrollableEditorToolComponent getEditorToolComponent() { + return notNull(editorToolComponent); + } + + /** + * Get the main split container. + * + * @return the main split container. + */ + @FxThread + protected @NotNull EditorToolSplitPane getMainSplitContainer() { + return notNull(mainSplitContainer); + } + /** * Create and add tool components to the container. * diff --git a/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialFileEditor.java b/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialFileEditor.java index 906f5d47..631ae566 100644 --- a/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialFileEditor.java +++ b/src/main/java/com/ss/editor/plugin/api/editor/material/BaseMaterialFileEditor.java @@ -23,6 +23,7 @@ import com.ss.editor.ui.css.CssClasses; import com.ss.editor.ui.util.DynamicIconSupport; import com.ss.rlib.ui.util.FXUtils; +import com.ss.rlib.util.array.Array; import javafx.collections.ObservableList; import javafx.scene.control.*; import javafx.scene.image.ImageView; @@ -141,7 +142,7 @@ protected boolean handleKeyActionImpl(@NotNull final KeyCode keyCode, final bool protected void createToolComponents(@NotNull final EditorToolComponent container, @NotNull final StackPane root) { super.createToolComponents(container, root); - settingsTree = new NodeTree<>(this::selectedFromTree, getChangeConsumer()); + settingsTree = new NodeTree<>(this::selectFromTree, getChangeConsumer(), SelectionMode.SINGLE); propertyEditor = new PropertyEditor<>(getChangeConsumer()); propertyEditor.prefHeightProperty().bind(root.heightProperty()); @@ -177,12 +178,14 @@ protected void createToolComponents(@NotNull final EditorToolComponent container } /** - * Handle selected object from tree. + * Handle selected objects from tree. * - * @param object the selected object. + * @param objects the selected objects. */ @FxThread - private void selectedFromTree(@Nullable final Object object) { + private void selectFromTree(@NotNull final Array objects) { + + final Object object = objects.first(); Object parent = null; Object element; diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/AssetResourcePropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/AssetResourcePropertyEditorControl.java index 5ac9459f..99de0b9b 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/AssetResourcePropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/AssetResourcePropertyEditorControl.java @@ -32,7 +32,7 @@ protected AssetResourcePropertyEditorControl(@NotNull final VarTable vars, } /** - * Gets an action tester for asset dialog. + * Get the action tester for asset dialog. * * @return the action tester. */ diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/AwtFontPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/AwtFontPropertyEditorControl.java index aef245bf..524ece0a 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/AwtFontPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/AwtFontPropertyEditorControl.java @@ -93,7 +93,7 @@ protected void createComponents() { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final Font value = getPropertyValue(); final ComboBox enumComboBox = getComboBox(); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/BooleanPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/BooleanPropertyEditorControl.java index 3b2dc6f6..dd5863e4 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/BooleanPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/BooleanPropertyEditorControl.java @@ -51,7 +51,7 @@ protected void createComponents() { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final Boolean value = getPropertyValue(); getCheckBox().setSelected(value == null ? false : value); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ClasspathResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ClasspathResourcePropertyControl.java index 9f57c04a..13c73b21 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ClasspathResourcePropertyControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/ClasspathResourcePropertyControl.java @@ -74,7 +74,7 @@ private String validate(@NotNull final String resource) { @Override @FxThread - protected void reload() { + public void reload() { final String resource = getPropertyValue(); final Label resourceLabel = getResourceLabel(); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ColorPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ColorPropertyEditorControl.java index 8fc2dfc8..0b2c7292 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ColorPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/ColorPropertyEditorControl.java @@ -53,7 +53,7 @@ protected void createComponents() { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final ColorPicker colorPicker = getColorPicker(); colorPicker.setValue(UiUtils.from(getPropertyValue())); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/EnumPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/EnumPropertyEditorControl.java index 08aeb104..b1ac7662 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/EnumPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/EnumPropertyEditorControl.java @@ -60,7 +60,7 @@ protected void createComponents() { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final T value = getPropertyValue(); final ComboBox enumComboBox = getEnumComboBox(); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ExternalFileResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ExternalFileResourcePropertyControl.java index 4d3db82d..955744e4 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ExternalFileResourcePropertyControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/ExternalFileResourcePropertyControl.java @@ -58,7 +58,7 @@ private void openExternalFile(@NotNull final Path path) { @Override @FxThread - protected void reload() { + public void reload() { final Path resource = getPropertyValue(); final Label resourceLabel = getResourceLabel(); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/FileAssetResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/FileAssetResourcePropertyControl.java index a84d1db8..c12adcad 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/FileAssetResourcePropertyControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/FileAssetResourcePropertyControl.java @@ -59,7 +59,7 @@ protected void processSelect(@NotNull final Path file) { @Override @FxThread - protected void reload() { + public void reload() { final Path file = getPropertyValue(); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/FloatPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/FloatPropertyEditorControl.java index 5aa9a1b3..38976ec8 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/FloatPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/FloatPropertyEditorControl.java @@ -63,7 +63,7 @@ public void setMinMax(final float min, final float max) { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final Float value = getPropertyValue(); getValueField().setValue(value == null ? 0 : value); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/FolderAssetResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/FolderAssetResourcePropertyControl.java index 25c63419..c393f3d4 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/FolderAssetResourcePropertyControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/FolderAssetResourcePropertyControl.java @@ -53,7 +53,7 @@ protected void processSelect(@NotNull final Path file) { @Override @FxThread - protected void reload() { + public void reload() { final Path file = getPropertyValue(); final String assetPath = file == null ? NOT_SELECTED : toAssetPath(file); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/IntegerPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/IntegerPropertyEditorControl.java index 1360e9ce..87ae30ce 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/IntegerPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/IntegerPropertyEditorControl.java @@ -63,7 +63,7 @@ public void setMinMax(final float min, final float max) { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final Integer value = getPropertyValue(); getValueField().setValue(value == null ? 0 : value); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ObjectFromListPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ObjectFromListPropertyEditorControl.java index 4a4e91f2..e69877ff 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ObjectFromListPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/ObjectFromListPropertyEditorControl.java @@ -58,7 +58,7 @@ protected void createComponents() { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final Object value = getPropertyValue(); final ComboBox comboBox = getComboBox(); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControl.java index d9195940..19019585 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControl.java @@ -187,8 +187,11 @@ public void checkDependency() { return propertyType; } + /** + * Reload value of this control. + */ @FxThread - protected void reload() { + public void reload() { } @FxThread diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControlFactory.java b/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControlFactory.java index 35255474..5217b215 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControlFactory.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/PropertyEditorControlFactory.java @@ -48,6 +48,8 @@ public class PropertyEditorControlFactory { return new StringPropertyEditorControl(vars, definition, validation); case GEOMETRY_FROM_ASSET_FOLDER: return new GeometryAssetResourcePropertyControl(vars, definition, validation); + case SPATIAL_FROM_ASSET_FOLDER: + return new SpatialAssetResourcePropertyControl<>(vars, definition, validation); case FILE_FROM_ASSET_FOLDER: return new FileAssetResourcePropertyControl(vars, definition, validation); case STRING_FROM_LIST: diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/ResourcePropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/ResourcePropertyEditorControl.java index b8b676b8..79d113d1 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/ResourcePropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/ResourcePropertyEditorControl.java @@ -107,7 +107,9 @@ private void dragDropped(@NotNull final DragEvent dragEvent) { } final File file = files.get(0); - if (!canAccept(file)) return; + if (!canAccept(file)) { + return; + } handleFile(file); } @@ -135,7 +137,9 @@ private void dragOver(@NotNull final DragEvent dragEvent) { } final File file = files.get(0); - if (!canAccept(file)) return; + if (!canAccept(file)) { + return; + } final Set transferModes = dragboard.getTransferModes(); final boolean isCopy = transferModes.contains(TransferMode.COPY); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/SpatialAssetResourcePropertyControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/SpatialAssetResourcePropertyControl.java index d41658a3..5eb52ff3 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/SpatialAssetResourcePropertyControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/SpatialAssetResourcePropertyControl.java @@ -14,6 +14,7 @@ import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.plugin.api.property.PropertyDefinition; import com.ss.editor.util.EditorUtil; +import com.ss.rlib.util.FileUtils; import com.ss.rlib.util.VarTable; import com.ss.rlib.util.array.Array; import com.ss.rlib.util.array.ArrayFactory; @@ -21,6 +22,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; import java.nio.file.Path; /** @@ -78,7 +80,19 @@ protected void processSelect(@NotNull final Path file) { @Override @FxThread - protected void reload() { + protected boolean canAccept(@NotNull final File file) { + return EXTENSIONS.contains(FileUtils.getExtension(file.getName())); + } + + @Override + @FxThread + protected void handleFile(@NotNull final File file) { + processSelect(file.toPath()); + } + + @Override + @FxThread + public void reload() { final T model = getPropertyValue(); final Spatial root = model == null ? null : findParent(model, spatial -> spatial.getKey() != null); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/StringFromListPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/StringFromListPropertyEditorControl.java index b124cf03..7b3077c9 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/StringFromListPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/StringFromListPropertyEditorControl.java @@ -82,7 +82,7 @@ protected void createComponents() { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final String value = getPropertyValue(); final ComboBox comboBox = getComboBox(); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/StringPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/StringPropertyEditorControl.java index 0b10d5a5..d5a58dc6 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/StringPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/StringPropertyEditorControl.java @@ -51,7 +51,7 @@ protected void createComponents() { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final String value = getPropertyValue(); getValueField().setText(value == null ? "" : value); diff --git a/src/main/java/com/ss/editor/plugin/api/property/control/Vector3fPropertyEditorControl.java b/src/main/java/com/ss/editor/plugin/api/property/control/Vector3fPropertyEditorControl.java index 21826daf..0985723c 100644 --- a/src/main/java/com/ss/editor/plugin/api/property/control/Vector3fPropertyEditorControl.java +++ b/src/main/java/com/ss/editor/plugin/api/property/control/Vector3fPropertyEditorControl.java @@ -100,7 +100,7 @@ protected void createComponents() { @Override @FxThread - protected void reload() { + public void reload() { super.reload(); final Vector3f value = getPropertyValue(); diff --git a/src/main/java/com/ss/editor/ui/Icons.java b/src/main/java/com/ss/editor/ui/Icons.java index 03eb02c2..037b6eb8 100644 --- a/src/main/java/com/ss/editor/ui/Icons.java +++ b/src/main/java/com/ss/editor/ui/Icons.java @@ -96,6 +96,7 @@ public interface Icons { @NotNull Image PLUGIN_16 = ICON_MANAGER.getImage("/ui/icons/svg/plug-silhouette.svg"); @NotNull Image FILTER_16 = ICON_MANAGER.getImage("/ui/icons/svg/filter-filled-tool-symbol.svg"); @NotNull Image UPDATER_16 = ICON_MANAGER.getImage("/ui/icons/svg/bar-chart-reload.svg"); + @NotNull Image FOREST_16 = ICON_MANAGER.getImage("/ui/icons/svg/forest.svg"); @NotNull Image REFRESH_18 = ICON_MANAGER.getImage("/ui/icons/svg/refresh-button.svg", 18); @NotNull Image WARNING_24 = ICON_MANAGER.getImage("/ui/icons/svg/warning.svg", 24); diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTree.java b/src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTree.java index c8da328b..f3f8afb0 100644 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTree.java +++ b/src/main/java/com/ss/editor/ui/component/asset/tree/ResourceTree.java @@ -746,7 +746,15 @@ public void notifyCreated(@NotNull final Path file) { final EditorConfig editorConfig = EditorConfig.getInstance(); final Path currentAsset = editorConfig.getCurrentAsset(); final Path folder = file.getParent(); - if (!folder.startsWith(currentAsset)) return; + if (!folder.startsWith(currentAsset)) { + return; + } + + final ResourceElement fileElement = createFor(file); + final TreeItem fileItem = findItemForValue(getRoot(), fileElement); + if (fileItem != null) { + return; + } final ResourceElement element = createFor(folder); @@ -757,7 +765,9 @@ public void notifyCreated(@NotNull final Path file) { folderItem = findItemForValue(getRoot(), folder); } - if (folderItem == null) return; + if (folderItem == null) { + return; + } final TreeItem newItem = new TreeItem<>(createFor(file)); @@ -779,10 +789,14 @@ public void notifyDeleted(@NotNull final Path file) { final ResourceElement element = createFor(file); final TreeItem treeItem = findItemForValue(getRoot(), element); - if (treeItem == null) return; + if (treeItem == null) { + return; + } final TreeItem parent = treeItem.getParent(); - if (parent == null) return; + if (parent == null) { + return; + } final ObservableList> children = parent.getChildren(); children.remove(treeItem); @@ -799,11 +813,15 @@ public void notifyMoved(@NotNull final Path prevFile, @NotNull final Path newFil final ResourceElement prevElement = createFor(prevFile); final TreeItem prevItem = findItemForValue(getRoot(), prevElement); - if (prevItem == null) return; + if (prevItem == null) { + return; + } final ResourceElement newParentElement = createFor(newFile.getParent()); final TreeItem newParentItem = findItemForValue(getRoot(), newParentElement); - if (newParentItem == null) return; + if (newParentItem == null) { + return; + } final TreeItem prevParentItem = prevItem.getParent(); final ObservableList> prevParentChildren = prevParentItem.getChildren(); @@ -847,7 +865,9 @@ public void notifyRenamed(@NotNull final Path prevFile, @NotNull final Path newF final ResourceElement prevElement = createFor(prevFile); final TreeItem prevItem = findItemForValue(getRoot(), prevElement); - if (prevItem == null) return; + if (prevItem == null) { + return; + } prevItem.setValue(createFor(newFile)); @@ -862,11 +882,15 @@ public void notifyRenamed(@NotNull final Path prevFile, @NotNull final Path newF */ @FxThread private void processKey(@NotNull final KeyEvent event) { - if (isReadOnly()) return; + if (isReadOnly()) { + return; + } final EditorConfig editorConfig = EditorConfig.getInstance(); final Path currentAsset = editorConfig.getCurrentAsset(); - if (currentAsset == null) return; + if (currentAsset == null) { + return; + } updateSelectedElements(); @@ -874,14 +898,18 @@ private void processKey(@NotNull final KeyEvent event) { if (selectedElements.isEmpty()) return; final ResourceElement firstElement = selectedElements.first(); - if (firstElement instanceof LoadingResourceElement) return; + if (firstElement instanceof LoadingResourceElement) { + return; + } boolean onlyFiles = true; boolean onlyFolders = true; boolean selectedAsset = false; for (final ResourceElement element : selectedElements.array()) { - if (element == null) break; + if (element == null) { + break; + } if (element instanceof FileResourceElement) { onlyFolders = false; @@ -946,7 +974,9 @@ private void processKey(@NotNull final KeyEvent event) { private void cleanup(@NotNull final TreeItem treeItem) { final ResourceElement element = treeItem.getValue(); - if (element instanceof FileResourceElement || element instanceof LoadingResourceElement) return; + if (element instanceof FileResourceElement || element instanceof LoadingResourceElement) { + return; + } final ObservableList> children = treeItem.getChildren(); diff --git a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/DeleteFileAction.java b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/DeleteFileAction.java index a1ba6f82..63c09d26 100644 --- a/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/DeleteFileAction.java +++ b/src/main/java/com/ss/editor/ui/component/asset/tree/context/menu/action/DeleteFileAction.java @@ -91,7 +91,10 @@ private void deleteFile(@NotNull final Path file) { * Handle the answer. */ private void handle(@NotNull final Array elements, @Nullable final Boolean result) { - if (!Boolean.TRUE.equals(result)) return; + + if (!Boolean.TRUE.equals(result)) { + return; + } final EditorConfig editorConfig = EditorConfig.getInstance(); final Path currentAsset = editorConfig.getCurrentAsset(); diff --git a/src/main/java/com/ss/editor/ui/component/creator/FileCreatorRegistry.java b/src/main/java/com/ss/editor/ui/component/creator/FileCreatorRegistry.java index 37fd4b52..4afa74f1 100644 --- a/src/main/java/com/ss/editor/ui/component/creator/FileCreatorRegistry.java +++ b/src/main/java/com/ss/editor/ui/component/creator/FileCreatorRegistry.java @@ -56,7 +56,6 @@ private FileCreatorRegistry() { register(EmptyModelCreator.DESCRIPTION); register(SingleColorTextureFileCreator.DESCRIPTION); register(EmptySceneCreator.DESCRIPTION); - register(DefaultSceneCreator.DESCRIPTION); } /** diff --git a/src/main/java/com/ss/editor/ui/component/creator/impl/DefaultSceneCreator.java b/src/main/java/com/ss/editor/ui/component/creator/impl/DefaultSceneCreator.java deleted file mode 100644 index 33f13c0f..00000000 --- a/src/main/java/com/ss/editor/ui/component/creator/impl/DefaultSceneCreator.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.ss.editor.ui.component.creator.impl; - -import com.jme3.renderer.queue.RenderQueue; -import com.jme3.shadow.EdgeFilteringMode; -import com.ss.editor.Messages; -import com.ss.editor.annotation.FromAnyThread; -import com.ss.editor.extension.scene.SceneNode; -import com.ss.editor.extension.scene.app.state.impl.EditableLightingSceneAppState; -import com.ss.editor.extension.scene.app.state.impl.EditableSkySceneAppState; -import com.ss.editor.extension.scene.filter.impl.EditableFXAAFilter; -import com.ss.editor.extension.scene.filter.impl.EditableLightingStateShadowFilter; -import com.ss.editor.ui.component.creator.FileCreatorDescription; -import com.ss.editor.util.EditorUtil; -import org.jetbrains.annotations.NotNull; - -/** - * The creator to create a default scene. - * - * @author JavaSaBr - */ -public class DefaultSceneCreator extends EmptySceneCreator { - - /** - * The constant DESCRIPTION. - */ - @NotNull - public static final FileCreatorDescription DESCRIPTION = new FileCreatorDescription(); - - static { - DESCRIPTION.setFileDescription(Messages.DEFAULT_SCENE_CREATOR_DESCRIPTION); - DESCRIPTION.setConstructor(DefaultSceneCreator::new); - } - - @Override - @FromAnyThread - protected @NotNull String getTitleText() { - return Messages.DEFAULT_SCENE_CREATOR_TITLE; - } - - @Override - @NotNull - protected SceneNode createScene() { - - final EditableLightingStateShadowFilter shadowFilter = new EditableLightingStateShadowFilter(); - shadowFilter.setRenderBackFacesShadows(true); - shadowFilter.setEdgesThickness(7); - shadowFilter.setEdgeFilteringMode(EdgeFilteringMode.PCF8); - - final SceneNode sceneNode = super.createScene(); - sceneNode.addFilter(new EditableFXAAFilter()); - sceneNode.addFilter(shadowFilter); - sceneNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); - - final EditableLightingSceneAppState lightingState = new EditableLightingSceneAppState(); - lightingState.setTimeOfDay(0.947F); - - final EditableSkySceneAppState skyState = new EditableSkySceneAppState(); - skyState.setFlatShaded(false); - skyState.init(lightingState.getLightDirRef(), EditorUtil.getAssetManager()); - - sceneNode.addAppState(lightingState); - sceneNode.addAppState(skyState); - - return sceneNode; - } -} diff --git a/src/main/java/com/ss/editor/ui/component/editor/area/EditorAreaComponent.java b/src/main/java/com/ss/editor/ui/component/editor/area/EditorAreaComponent.java index 8c2261fe..7c99c8ce 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/area/EditorAreaComponent.java +++ b/src/main/java/com/ss/editor/ui/component/editor/area/EditorAreaComponent.java @@ -4,12 +4,12 @@ import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.app.state.AppStateManager; import com.jme3x.jfx.injfx.processor.FrameTransferSceneProcessor; -import com.ss.editor.JmeApplication; import com.ss.editor.JfxApplication; +import com.ss.editor.JmeApplication; import com.ss.editor.Messages; import com.ss.editor.annotation.BackgroundThread; -import com.ss.editor.annotation.FxThread; import com.ss.editor.annotation.FromAnyThread; +import com.ss.editor.annotation.FxThread; import com.ss.editor.annotation.JmeThread; import com.ss.editor.file.converter.FileConverter; import com.ss.editor.file.converter.FileConverterDescription; @@ -36,8 +36,11 @@ import com.ss.rlib.concurrent.util.ThreadUtils; import com.ss.rlib.logging.Logger; import com.ss.rlib.logging.LoggerManager; +import com.ss.rlib.util.ArrayUtils; import com.ss.rlib.util.StringUtils; import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; +import com.ss.rlib.util.array.ConcurrentArray; import com.ss.rlib.util.dictionary.ConcurrentObjectDictionary; import com.ss.rlib.util.dictionary.DictionaryFactory; import com.ss.rlib.util.dictionary.DictionaryUtils; @@ -109,6 +112,12 @@ public class EditorAreaComponent extends TabPane implements ScreenComponent { @NotNull private final ConcurrentObjectDictionary openedEditors; + /** + * The list of opening files now. + */ + @NotNull + private final ConcurrentArray openingFiles; + /** * The flag for ignoring changing the list of opened editors. */ @@ -116,6 +125,7 @@ public class EditorAreaComponent extends TabPane implements ScreenComponent { public EditorAreaComponent() { this.openedEditors = DictionaryFactory.newConcurrentAtomicObjectDictionary(); + this.openingFiles = ArrayFactory.newConcurrentStampedLockArray(Path.class); setPickOnBounds(true); setId(CssIds.EDITOR_AREA_COMPONENT); @@ -290,20 +300,33 @@ private void processConvertFile(@NotNull final RequestedConvertFileEvent event) final FileConverterDescription description = event.getDescription(); final FileConverter converter = FILE_CONVERTER_REGISTRY.newCreator(description, file); - if (converter == null) return; + if (converter == null) { + return; + } converter.convert(file); } /** + * Get the tale of opened editors. + * * @return the tale of opened editors. */ - @NotNull @FromAnyThread - private ConcurrentObjectDictionary getOpenedEditors() { + private @NotNull ConcurrentObjectDictionary getOpenedEditors() { return openedEditors; } + /** + * Get the list of opening files now. + * + * @return the list of opening files now. + */ + @FromAnyThread + private @NotNull ConcurrentArray getOpeningFiles() { + return openingFiles; + } + /** * Handle the request to create a file. */ @@ -314,7 +337,9 @@ private void processCreateFile(@NotNull final RequestedCreateFileEvent event) { final FileCreatorDescription description = event.getDescription(); final FileCreator fileCreator = CREATOR_REGISTRY.newCreator(description, file); - if (fileCreator == null) return; + if (fileCreator == null) { + return; + } fileCreator.start(file); } @@ -324,10 +349,15 @@ private void processCreateFile(@NotNull final RequestedCreateFileEvent event) { */ @FxThread private void processChangeTabs(@NotNull final ListChangeListener.Change change) { - if (!change.next()) return; + + if (!change.next()) { + return; + } final List removed = change.getRemoved(); - if (removed == null || removed.isEmpty()) return; + if (removed == null || removed.isEmpty()) { + return; + } removed.forEach(tab -> { @@ -339,10 +369,14 @@ private void processChangeTabs(@NotNull final ListChangeListener.Change openingFiles = getOpeningFiles(); + final long stamp = openingFiles.writeLock(); + try { + + if (openingFiles.contains(file)) { + return; + } + + openingFiles.add(file); + + UiUtils.incrementLoading(); + + EXECUTOR_MANAGER.addBackgroundTask(() -> processOpenFileImpl(event, file)); - EXECUTOR_MANAGER.addBackgroundTask(() -> processOpenFileImpl(event, file)); + } finally { + openingFiles.writeUnlock(stamp); + } } @BackgroundThread @@ -442,11 +490,13 @@ private void processOpenFileImpl(@NotNull final RequestedOpenFileEvent event, @N } catch (final Throwable e) { EditorUtil.handleException(null, this, new Exception(e)); EXECUTOR_MANAGER.addFxTask(scene::decrementLoading); + ArrayUtils.runInWriteLock(getOpeningFiles(), file, Array::fastRemove); return; } if (editor == null) { EXECUTOR_MANAGER.addFxTask(scene::decrementLoading); + ArrayUtils.runInWriteLock(getOpeningFiles(), file, Array::fastRemove); return; } @@ -458,6 +508,7 @@ private void processOpenFileImpl(@NotNull final RequestedOpenFileEvent event, @N editor.openFile(file); } catch (final Throwable e) { EditorUtil.handleException(null, this, new Exception(e)); + ArrayUtils.runInWriteLock(getOpeningFiles(), file, Array::fastRemove); final Workspace workspace = WORKSPACE_MANAGER.getCurrentWorkspace(); if (workspace != null) { @@ -470,6 +521,7 @@ private void processOpenFileImpl(@NotNull final RequestedOpenFileEvent event, @N }); return; + } finally { jmeApplication.asyncUnlock(stamp); } @@ -509,6 +561,7 @@ private void addEditor(@NotNull final FileEditor editor, final boolean needShow) } DictionaryUtils.runInWriteLock(getOpenedEditors(), editFile, tab, ObjectDictionary::put); + ArrayUtils.runInWriteLock(getOpeningFiles(), editFile, Array::fastRemove); UiUtils.decrementLoading(); @@ -571,7 +624,9 @@ public void notifyFinishBuild() { private void loadOpenedFiles() { final Workspace workspace = WORKSPACE_MANAGER.getCurrentWorkspace(); - if (workspace == null) return; + if (workspace == null) { + return; + } final Path assetFolder = workspace.getAssetFolder(); final String editFile = workspace.getCurrentEditedFile(); @@ -580,10 +635,14 @@ private void loadOpenedFiles() { openedFiles.forEach((assetPath, editorId) -> { final EditorDescription description = EDITOR_REGISTRY.getDescription(editorId); - if (description == null) return; + if (description == null) { + return; + } final Path file = assetFolder.resolve(assetPath); - if (!Files.exists(file)) return; + if (!Files.exists(file)) { + return; + } final RequestedOpenFileEvent event = new RequestedOpenFileEvent(); event.setFile(file); diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/AbstractFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/AbstractFileEditor.java index c0545d58..d87920b0 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/AbstractFileEditor.java +++ b/src/main/java/com/ss/editor/ui/component/editor/impl/AbstractFileEditor.java @@ -2,7 +2,11 @@ import static com.ss.rlib.util.ObjectUtils.notNull; import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; + +import com.jme3.asset.AssetKey; +import com.jme3.asset.ModelKey; import com.jme3.math.Vector3f; +import com.jme3.scene.Spatial; import com.ss.editor.JmeApplication; import com.ss.editor.Messages; import com.ss.editor.analytics.google.GAEvent; @@ -20,6 +24,7 @@ import com.ss.editor.ui.event.impl.FileChangedEvent; import com.ss.editor.ui.util.DynamicIconSupport; import com.ss.editor.ui.util.UiUtils; +import com.ss.editor.util.EditorUtil; import com.ss.rlib.logging.Logger; import com.ss.rlib.logging.LoggerManager; import com.ss.rlib.ui.util.FXUtils; @@ -61,7 +66,7 @@ public abstract class AbstractFileEditor implements FileEditor { /** - * The logger. + * The loggerA. */ @NotNull protected static final Logger LOGGER = LoggerManager.getLogger(FileEditor.class); diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/material/MaterialFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/material/MaterialFileEditor.java index 390336f8..73d6f423 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/material/MaterialFileEditor.java +++ b/src/main/java/com/ss/editor/ui/component/editor/impl/material/MaterialFileEditor.java @@ -7,6 +7,8 @@ import static com.ss.editor.util.EditorUtil.toAssetPath; import static com.ss.editor.util.MaterialUtils.updateMaterialIdNeed; import static com.ss.rlib.util.ObjectUtils.notNull; + +import com.jme3.asset.AssetKey; import com.jme3.asset.AssetManager; import com.jme3.asset.MaterialKey; import com.jme3.asset.TextureKey; diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/model/ModelFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/model/ModelFileEditor.java index 18432d6a..884b8a34 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/model/ModelFileEditor.java +++ b/src/main/java/com/ss/editor/ui/component/editor/impl/model/ModelFileEditor.java @@ -179,8 +179,8 @@ protected void doOpenFile(@NotNull final Path file) throws IOException { MaterialUtils.cleanUpMaterialParams(model); - final ModelEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.openModel(model); + final ModelEditor3DPart editor3DPart = getEditor3DPart(); + editor3DPart.openModel(model); handleAddedObject(model); diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/scene/AbstractSceneFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/scene/AbstractSceneFileEditor.java index 3f98072d..f68227e4 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/scene/AbstractSceneFileEditor.java +++ b/src/main/java/com/ss/editor/ui/component/editor/impl/scene/AbstractSceneFileEditor.java @@ -1,6 +1,6 @@ package com.ss.editor.ui.component.editor.impl.scene; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.LOADED_MODEL_KEY; +import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; import static com.ss.editor.util.EditorUtil.*; import static com.ss.editor.util.MaterialUtils.saveIfNeedTextures; import static com.ss.editor.util.MaterialUtils.updateMaterialIdNeed; @@ -12,12 +12,17 @@ import com.jme3.asset.MaterialKey; import com.jme3.asset.ModelKey; import com.jme3.audio.AudioNode; +import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingSphere; +import com.jme3.bounding.BoundingVolume; +import com.jme3.bullet.control.PhysicsControl; import com.jme3.export.binary.BinaryExporter; import com.jme3.light.DirectionalLight; import com.jme3.light.Light; import com.jme3.light.PointLight; import com.jme3.light.SpotLight; import com.jme3.material.Material; +import com.jme3.math.Quaternion; import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.scene.AssetLinkNode; @@ -43,6 +48,7 @@ import com.ss.editor.model.scene.WrapperNode; import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.part3d.editor.impl.Stats3DPart; import com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart; import com.ss.editor.plugin.api.RenderFilterExtension; @@ -56,19 +62,14 @@ import com.ss.editor.ui.control.model.ModelNodeTree; import com.ss.editor.ui.control.model.ModelPropertyEditor; import com.ss.editor.ui.control.property.operation.PropertyOperation; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; -import com.ss.editor.ui.control.tree.action.impl.operation.RemoveChildOperation; -import com.ss.editor.ui.control.tree.action.impl.operation.RemoveControlOperation; -import com.ss.editor.ui.control.tree.action.impl.operation.RemoveLightOperation; +import com.ss.editor.ui.control.tree.action.impl.multi.RemoveElementsAction; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.ui.css.CssClasses; import com.ss.editor.ui.event.impl.FileChangedEvent; import com.ss.editor.ui.util.DynamicIconSupport; import com.ss.editor.ui.util.UiUtils; -import com.ss.editor.util.EditorUtil; -import com.ss.editor.util.LocalObjects; -import com.ss.editor.util.MaterialUtils; -import com.ss.editor.util.NodeUtils; +import com.ss.editor.util.ControlUtils; +import com.ss.editor.util.*; import com.ss.rlib.ui.util.FXUtils; import com.ss.rlib.util.FileUtils; import com.ss.rlib.util.array.Array; @@ -76,10 +77,7 @@ import javafx.collections.ObservableList; import javafx.event.Event; import javafx.geometry.Point2D; -import javafx.scene.control.ComboBox; -import javafx.scene.control.Label; -import javafx.scene.control.ToggleButton; -import javafx.scene.control.Tooltip; +import javafx.scene.control.*; import javafx.scene.image.ImageView; import javafx.scene.input.DragEvent; import javafx.scene.input.KeyCode; @@ -108,14 +106,18 @@ public abstract class AbstractSceneFileEditor extends Advanced3DFileEditorWithSplitRightTool implements ModelChangeConsumer, ModelEditingProvider { - private static final int OBJECTS_TOOL = 0; - private static final int PAINTING_TOOL = 1; + protected static final int OBJECTS_TOOL = 0; + protected static final int PAINTING_TOOL = 1; + protected static final int SCRIPTING_TOOL = 2; @NotNull private static final Array ACCEPTED_FILES = ArrayFactory.asArray( FileExtensions.JME_MATERIAL, FileExtensions.JME_OBJECT); + @NotNull + private static final Array EMPTY_SELECTION = ArrayFactory.newArray(Spatial.class); + @NotNull private static final ObservableList TRANSFORMATION_MODES = observableArrayList(TransformationMode.values()); @@ -167,7 +169,7 @@ public static void registerPostSaveHandler(@NotNull Consumer handler) { * The selection handler. */ @Nullable - private Consumer selectionNodeHandler; + private Consumer> selectionNodeHandler; /** * The list of transform modes. @@ -407,15 +409,15 @@ private void updateMaterials(@NotNull final Path file) { @FxThread protected void handleAddedObject(@NotNull final Spatial model) { - final MA editor3DState = getEditor3DPart(); + final MA editor3DPart = getEditor3DPart(); final Array lights = ArrayFactory.newArray(Light.class); final Array audioNodes = ArrayFactory.newArray(AudioNode.class); NodeUtils.addLight(model, lights); NodeUtils.addAudioNodes(model, audioNodes); - lights.forEach(editor3DState, (light, state) -> state.addLight(light)); - audioNodes.forEach(editor3DState, (audioNode, state) -> state.addAudioNode(audioNode)); + lights.forEach(editor3DPart, (light, part) -> part.addLight(light)); + audioNodes.forEach(editor3DPart, (audioNode, part) -> part.addAudioNode(audioNode)); } /** @@ -426,15 +428,15 @@ protected void handleAddedObject(@NotNull final Spatial model) { @FxThread protected void handleRemovedObject(@NotNull final Spatial model) { - final MA editor3DState = getEditor3DPart(); + final MA editor3DPart = getEditor3DPart(); final Array lights = ArrayFactory.newArray(Light.class); final Array audioNodes = ArrayFactory.newArray(AudioNode.class); NodeUtils.addLight(model, lights); NodeUtils.addAudioNodes(model, audioNodes); - lights.forEach(editor3DState, (light, state) -> state.removeLight(light)); - audioNodes.forEach(editor3DState, (audioNode, state) -> state.removeAudioNode(audioNode)); + lights.forEach(editor3DPart, (light, part) -> part.removeLight(light)); + audioNodes.forEach(editor3DPart, (audioNode, part) -> part.removeAudioNode(audioNode)); } @Override @@ -495,8 +497,8 @@ protected boolean handleKeyActionImpl(@NotNull final KeyCode keyCode, final bool final boolean isControlDown, final boolean isShiftDown, final boolean isButtonMiddleDown) { - final MA editor3DState = getEditor3DPart(); - if (editor3DState.isCameraMoving()) { + final MA editor3DPart = getEditor3DPart(); + if (editor3DPart.isCameraMoving()) { return false; } @@ -520,31 +522,44 @@ protected boolean handleKeyActionImpl(@NotNull final KeyCode keyCode, final bool return true; } else if (isPressed && keyCode == KeyCode.DELETE) { - final ModelNodeTree modelNodeTree = getModelNodeTree(); - final TreeNode selected = modelNodeTree.getSelected(); - if (selected == null || !selected.canRemove()) return false; - - final Object element = selected.getElement(); - final TreeNode parent = selected.getParent(); - final Object parentElement = parent == null ? null : parent.getElement(); - - if (element instanceof Spatial) { - final Spatial spatial = (Spatial) element; - execute(new RemoveChildOperation(spatial, spatial.getParent())); - } else if (element instanceof Light && parentElement instanceof Node) { - final Light light = (Light) element; - execute(new RemoveLightOperation(light, (Node) parentElement)); - } else if (element instanceof Control && parentElement instanceof Spatial) { - final Control control = (Control) element; - execute(new RemoveControlOperation(control, (Spatial) parentElement)); + final RemoveElementsAction removeAction = findTreeAction(RemoveElementsAction.class); + + if (removeAction == null) { + return false; } + removeAction.process(); return true; + + } else if (isPressed && isControlDown && keyCode == KeyCode.C) { + //TODO + } else if (isPressed && isControlDown && keyCode == KeyCode.V) { + //TODO } return super.handleKeyActionImpl(keyCode, isPressed, isControlDown, isShiftDown, isButtonMiddleDown); } + /** + * Find a tree action for the current selected items. + * + * @param type the action's type. + * @param the action's type. + * @return the found action or null. + */ + @FxThread + protected @Nullable T findTreeAction(@NotNull final Class type) { + + final ModelNodeTree modelNodeTree = getModelNodeTree(); + final TreeNode selected = modelNodeTree.getSelected(); + if (selected == null || !selected.canRemove()) { + return null; + } + + final ContextMenu contextMenu = modelNodeTree.getContextMenu(null); + return UiUtils.findMenuItem(contextMenu.getItems(), type); + } + /** * @return true if need to ignore moving camera. */ @@ -596,10 +611,15 @@ public void notifyFxChangeProperty(@Nullable final Object parent, @NotNull final editingComponentContainer.notifyChangeProperty(object, propertyName); } + @Override + public void notifyJmePreChangeProperty(@NotNull final Object object, @NotNull final String propertyName) { + getEditor3DPart().notifyPropertyPreChanged(object, propertyName); + } + @Override @FxThread - public void notifyJmeChangeProperty(@NotNull final Object object, @NotNull final String propertyName) { - getEditor3DPart().notifyPropertyChanged(object); + public void notifyJmeChangedProperty(@NotNull final Object object, @NotNull final String propertyName) { + getEditor3DPart().notifyPropertyChanged(object, propertyName); } @Override @@ -627,7 +647,7 @@ public void notifyFxAddedChild(@NotNull final Object parent, @NotNull final Obje } if (needSelect) { - EXECUTOR_MANAGER.addJmeTask(() -> EXECUTOR_MANAGER.addFxTask(() -> modelNodeTree.select(added))); + EXECUTOR_MANAGER.addJmeTask(() -> EXECUTOR_MANAGER.addFxTask(() -> modelNodeTree.selectSingle(added))); } } @@ -635,14 +655,14 @@ public void notifyFxAddedChild(@NotNull final Object parent, @NotNull final Obje @FxThread public void notifyFxRemovedChild(@NotNull final Object parent, @NotNull final Object removed) { - final MA editor3DState = getEditor3DPart(); + final MA editor3DPart = getEditor3DPart(); final ModelNodeTree modelNodeTree = getModelNodeTree(); modelNodeTree.notifyRemoved(parent, removed); if (removed instanceof Light) { - editor3DState.removeLight((Light) removed); + editor3DPart.removeLight((Light) removed); } else if (removed instanceof AudioNode) { - editor3DState.removeAudioNode((AudioNode) removed); + editor3DPart.removeAudioNode((AudioNode) removed); } else if (removed instanceof Spatial) { handleRemovedObject((Spatial) removed); } @@ -686,7 +706,7 @@ public void notifyFxMoved(@NotNull final Object prevParent, @NotNull final Objec modelNodeTree.notifyMoved(prevParent, newParent, child, index); if (needSelect) { - EXECUTOR_MANAGER.addJmeTask(() -> EXECUTOR_MANAGER.addFxTask(() -> modelNodeTree.select(child))); + EXECUTOR_MANAGER.addJmeTask(() -> EXECUTOR_MANAGER.addFxTask(() -> modelNodeTree.selectSingle(child))); } } @@ -708,33 +728,152 @@ public void notifySelected(@Nullable Object object) { setIgnoreCameraMove(true); try { + final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.select(object); + modelNodeTree.selectSingle(object); + + final SingleSelectionModel selectionModel = getEditorToolComponent().getSelectionModel(); + if (isNeedToOpenObjectsTool(selectionModel.getSelectedIndex())) { + selectionModel.select(OBJECTS_TOOL); + } + } finally { setIgnoreCameraMove(false); } } /** - * Handle the selected object from the Tree. + * Return true if need to open objects tool. * - * @param object the object + * @param current the current opened tool. + * @return true if need to open objects tool. + */ + @FxThread + protected boolean isNeedToOpenObjectsTool(final int current) { + return !(current == OBJECTS_TOOL || current == SCRIPTING_TOOL); + } + + /** + * Return true of the spatial can be selected. + * + * @param spatial the spatial. + * @return true if the spatial can be selected. + */ + @FxThread + protected boolean canSelect(@NotNull final Spatial spatial) { + return true; + } + + /** + * Handle the selected object from the tree. + * + * @param object the selected object. */ @FxThread public void selectNodeFromTree(@Nullable final Object object) { + final Array objects = LocalObjects.get().nextObjectArray(); + objects.add(object); + + selectNodesFromTree(objects); + } + + /** + * Handle the selected objects from the tree. + * + * @param objects the selected objects. + */ + @FxThread + public void selectNodesFromTree(@NotNull final Array objects) { + final MA editor3DPart = getEditor3DPart(); + editor3DPart.select(EMPTY_SELECTION); + + if (objects.size() > 1) { + multiSelectNodesFromTree(objects, editor3DPart); + } else if (objects.size() == 1) { + singleSelectNodesFromTree(objects, editor3DPart); + return; + } else { + editor3DPart.select(EMPTY_SELECTION); + } + + getModelPropertyEditor().buildFor(null, null); + getPaintingComponentContainer().prepareFor(null); + } + + /** + * Handle multi select nodes from tree. + * + * @param objects the selected objects. + * @param editor3DPart the 3D part of this editor. + */ + @FxThread + protected void multiSelectNodesFromTree(@NotNull final Array objects, @NotNull final MA editor3DPart) { + + final Array toSelect = ArrayFactory.newArray(Spatial.class); + + for (final Object object : objects) { + + Object element; + + if (object instanceof TreeNode) { + element = ((TreeNode) object).getElement(); + } else { + element = object; + } + + if (element instanceof SceneLayer) { + element = null; + } + + Spatial spatial = null; + + if (element instanceof AudioNode) { + final EditorAudioNode audioNode = editor3DPart.getAudioNode((AudioNode) element); + spatial = audioNode == null ? null : audioNode.getEditedNode(); + } else if (element instanceof Spatial) { + spatial = (Spatial) element; + } else if (element instanceof Light) { + spatial = editor3DPart.getLightNode((Light) element); + } else if(element instanceof ScenePresentable) { + final EditorPresentableNode presentableNode = editor3DPart.getPresentableNode((ScenePresentable) element); + spatial = presentableNode == null? null : presentableNode.getEditedNode(); + } + + if (spatial != null && !spatial.isVisible()) { + spatial = null; + } + + if(spatial != null && canSelect(spatial)) { + toSelect.add(spatial); + } + } + + editor3DPart.select(toSelect); + } + + /** + * Handle single select nodes from tree. + * + * @param objects the selected objects. + * @param editor3DPart the 3D part of this editor. + */ + @FxThread + protected void singleSelectNodesFromTree(@NotNull final Array objects, @NotNull final MA editor3DPart) { Object parent = null; Object element; - if (object instanceof TreeNode) { - final TreeNode treeNode = (TreeNode) object; + final Object first = objects.first(); + + if (first instanceof TreeNode) { + final TreeNode treeNode = (TreeNode) first; final TreeNode parentNode = treeNode.getParent(); parent = parentNode == null ? null : parentNode.getElement(); element = treeNode.getElement(); } else { - element = object; + element = first; } if (element instanceof SceneLayer) { @@ -751,8 +890,8 @@ public void selectNodeFromTree(@Nullable final Object object) { parent = spatial.getParent(); } else if (element instanceof Light) { spatial = editor3DPart.getLightNode((Light) element); - } else if(object instanceof ScenePresentable) { - final EditorPresentableNode presentableNode = editor3DPart.getPresentableNode((ScenePresentable) object); + } else if(element instanceof ScenePresentable) { + final EditorPresentableNode presentableNode = editor3DPart.getPresentableNode((ScenePresentable) element); spatial = presentableNode == null? null : presentableNode.getEditedNode(); } @@ -760,17 +899,17 @@ public void selectNodeFromTree(@Nullable final Object object) { spatial = null; } - updateSelection(spatial); + if (spatial != null && canSelect(spatial)) { - if (spatial != null && !isIgnoreCameraMove() && !isVisibleOnEditor(spatial)) { - editor3DPart.cameraLookAt(spatial.getWorldTranslation()); - } + editor3DPart.select(spatial); - final ModelPropertyEditor modelPropertyEditor = getModelPropertyEditor(); - modelPropertyEditor.buildFor(element, parent); + if (!isIgnoreCameraMove() && !isVisibleOnEditor(spatial)) { + editor3DPart.cameraLookAt(spatial); + } + } - final PaintingComponentContainer editingComponentContainer = getPaintingComponentContainer(); - editingComponentContainer.prepareFor(element); + getModelPropertyEditor().buildFor(element, parent); + getPaintingComponentContainer().prepareFor(element); } @FxThread @@ -788,21 +927,6 @@ private boolean isVisibleOnEditor(@NotNull final Spatial spatial) { return !invisible; } - /** - * Update selection to 3D state. - * - * @param spatial the new selected object. - */ - @FxThread - protected void updateSelection(@Nullable final Spatial spatial) { - - final Array selection = ArrayFactory.newArray(Spatial.class); - if (spatial != null) selection.add(spatial); - - final MA editor3DState = getEditor3DPart(); - editor3DState.updateSelection(selection); - } - @Override @BackgroundThread public void doSave(@NotNull final Path toStore) throws IOException { @@ -810,7 +934,12 @@ public void doSave(@NotNull final Path toStore) throws IOException { final M currentModel = getCurrentModel(); - NodeUtils.visitGeometry(currentModel, geometry -> saveIfNeedTextures(geometry.getMaterial())); + try { + NodeUtils.visitGeometry(currentModel, geometry -> saveIfNeedTextures(geometry.getMaterial())); + } catch (final Exception e) { + EditorUtil.handleException(LOGGER, this, e); + return; + } PRE_SAVE_HANDLERS.forEach(currentModel, Consumer::accept); try { @@ -821,6 +950,8 @@ public void doSave(@NotNull final Path toStore) throws IOException { exporter.save(currentModel, out); } + } catch (final Exception e) { + EditorUtil.handleException(LOGGER, this, e); } finally { POST_SAVE_HANDLERS.forEach(currentModel, Consumer::accept); } @@ -992,7 +1123,7 @@ protected void createActions(@NotNull final HBox container) { @Override @FxThread protected void createContent(@NotNull final StackPane root) { - this.selectionNodeHandler = this::selectNodeFromTree; + this.selectionNodeHandler = this::selectNodesFromTree; propertyEditorObjectsContainer = new VBox(); modelNodeTreeEditingContainer = new VBox(); @@ -1078,7 +1209,7 @@ protected void processChangeTool(@Nullable final Number oldValue, @NotNull final if (newIndex == OBJECTS_TOOL) { FXUtils.addToPane(modelPropertyEditor, propertyContainer); FXUtils.addToPane(modelNodeTree, getModelNodeTreeObjectsContainer()); - modelPropertyEditor.rebuild(); + selectNodesFromTree(modelNodeTree.getSelectedItems()); } else if (newIndex == PAINTING_TOOL) { FXUtils.addToPane(modelNodeTree, getModelNodeTreeEditingContainer()); editingComponentContainer.notifyShowed(); @@ -1088,8 +1219,8 @@ protected void processChangeTool(@Nullable final Number oldValue, @NotNull final editingComponentContainer.notifyHided(); } - final MA editor3DState = getEditor3DPart(); - editor3DState.changePaintingMode(newIndex == PAINTING_TOOL); + final MA editor3DPart = getEditor3DPart(); + editor3DPart.changePaintingMode(newIndex == PAINTING_TOOL); } @Override @@ -1165,12 +1296,14 @@ private void addNewModel(@NotNull final DragEvent dragEvent, @NotNull final Path return; } - final ModelNodeTree modelNodeTree = getModelNodeTree(); - final Object selected = modelNodeTree.getSelectedObject(); + final ModelNodeTree nodeTree = getModelNodeTree(); + final Object selected = nodeTree.getSelectedObject(); final Node parent; - if (selected instanceof Node && findParent((Spatial) selected, AssetLinkNode.class::isInstance) == null) { + if (selected instanceof Node && + nodeTree.getSelectedCount() == 1 && + findParent((Spatial) selected, AssetLinkNode.class::isInstance) == null) { parent = (Node) selected; } else { parent = (Node) currentModel; @@ -1179,9 +1312,9 @@ private void addNewModel(@NotNull final DragEvent dragEvent, @NotNull final Path final Path assetFile = notNull(getAssetFile(file), "Not found asset file for " + file); final String assetPath = toAssetPath(assetFile); - final MA editor3DState = getEditor3DPart(); + final MA editor3DPart = getEditor3DPart(); final ModelKey modelKey = new ModelKey(assetPath); - final Camera camera = editor3DState.getCamera(); + final Camera camera = editor3DPart.getCamera(); final BorderPane area = get3DArea(); final Point2D areaPoint = area.sceneToLocal(dragEvent.getSceneX(), dragEvent.getSceneY()); @@ -1196,17 +1329,47 @@ private void addNewModel(@NotNull final DragEvent dragEvent, @NotNull final Path final AssetLinkNode assetLinkNode = new AssetLinkNode(modelKey); assetLinkNode.attachLinkedChild(loadedModel, modelKey); - assetLinkNode.setUserData(LOADED_MODEL_KEY, true); + assetLinkNode.setUserData(KEY_LOADED_MODEL, true); if (defaultLayer != null) { SceneLayer.setLayer(defaultLayer, assetLinkNode); } - final Vector3f scenePoint = editor3DState.getScenePosByScreenPos((float) areaPoint.getX(), + final Vector3f scenePoint = editor3DPart.getScenePosByScreenPos((float) areaPoint.getX(), camera.getHeight() - (float) areaPoint.getY()); final Vector3f result = local.nextVector(scenePoint) .subtractLocal(parent.getWorldTranslation()); + final boolean isPhysics = NodeUtils.children(loadedModel) + .flatMap(ControlUtils::controls) + .anyMatch(PhysicsControl.class::isInstance); + + if (isPhysics) { + + NodeUtils.updateWorldBound(loadedModel); + + final BoundingVolume worldBound = loadedModel.getWorldBound(); + + float height = 0; + + if (worldBound instanceof BoundingBox) { + height = ((BoundingBox) worldBound).getYExtent(); + height = Math.min(((BoundingBox) worldBound).getXExtent(), height); + height = Math.min(((BoundingBox) worldBound).getZExtent(), height); + } else if (worldBound instanceof BoundingSphere) { + height = ((BoundingSphere) worldBound).getRadius(); + } + + height /= 2F; + + final Quaternion localRotation = assetLinkNode.getLocalRotation(); + final Vector3f up = GeomUtils.getUp(localRotation, local.nextVector()); + up.multLocal(height); + + result.addLocal(up); + } + + assetLinkNode.setLocalTranslation(result); execute(new AddChildOperation(assetLinkNode, parent, false)); diff --git a/src/main/java/com/ss/editor/ui/component/editor/impl/scene/SceneFileEditor.java b/src/main/java/com/ss/editor/ui/component/editor/impl/scene/SceneFileEditor.java index cc993aa0..78820c86 100644 --- a/src/main/java/com/ss/editor/ui/component/editor/impl/scene/SceneFileEditor.java +++ b/src/main/java/com/ss/editor/ui/component/editor/impl/scene/SceneFileEditor.java @@ -18,6 +18,7 @@ import com.ss.editor.extension.scene.app.state.SceneAppState; import com.ss.editor.extension.scene.filter.EditableSceneFilter; import com.ss.editor.extension.scene.filter.SceneFilter; +import com.ss.editor.model.node.layer.LayersRoot; import com.ss.editor.model.undo.editor.SceneChangeConsumer; import com.ss.editor.part3d.editor.impl.scene.SceneEditor3DPart; import com.ss.editor.ui.Icons; @@ -29,14 +30,15 @@ import com.ss.editor.ui.control.app.state.list.AppStateList; import com.ss.editor.ui.control.filter.list.FilterList; import com.ss.editor.ui.control.layer.LayerNodeTree; -import com.ss.editor.model.node.layer.LayersRoot; -import com.ss.editor.ui.control.model.ModelPropertyEditor; import com.ss.editor.ui.control.model.ModelNodeTree; +import com.ss.editor.ui.control.model.ModelPropertyEditor; +import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.ui.css.CssClasses; import com.ss.editor.ui.util.DynamicIconSupport; import com.ss.editor.util.EditorUtil; import com.ss.editor.util.MaterialUtils; import com.ss.rlib.ui.util.FXUtils; +import com.ss.rlib.util.array.Array; import javafx.scene.control.ToggleButton; import javafx.scene.control.Tooltip; import javafx.scene.image.ImageView; @@ -56,8 +58,8 @@ * * @author JavaSaBr */ -public class SceneFileEditor extends - AbstractSceneFileEditor implements SceneChangeConsumer { +public class SceneFileEditor extends AbstractSceneFileEditor + implements SceneChangeConsumer { private static final int LAYERS_TOOL = 3; private static final int APP_STATES_TOOL = 4; @@ -196,10 +198,14 @@ protected void refreshTree() { @FxThread private void updateVisibility(@NotNull final Spatial spatial) { final SceneLayer layer = SceneLayer.getLayer(spatial); - if (layer != null) spatial.setVisible(layer.isShowed()); + if (layer != null) { + spatial.setVisible(layer.isShowed()); + } } /** + * Get the list with app states. + * * @return the list with app states. */ @FxThread @@ -208,6 +214,8 @@ private void updateVisibility(@NotNull final Spatial spatial) { } /** + * Get the list with filters. + * * @return the list with filters. */ @FxThread @@ -216,6 +224,8 @@ private void updateVisibility(@NotNull final Spatial spatial) { } /** + * Get the tree with layers. + * * @return the tree with layers. */ @FxThread @@ -224,6 +234,8 @@ private void updateVisibility(@NotNull final Spatial spatial) { } /** + * Get the container of property editor in layers tool. + * * @return the container of property editor in layers tool. */ @FxThread @@ -232,6 +244,8 @@ private void updateVisibility(@NotNull final Spatial spatial) { } /** + * Get the container of property editor in filters tool. + * * @return the container of property editor in filters tool. */ @FxThread @@ -239,7 +253,15 @@ private void updateVisibility(@NotNull final Spatial spatial) { return notNull(propertyEditorFiltersContainer); } + @Override + @FxThread + protected boolean isNeedToOpenObjectsTool(final int current) { + return !(current == OBJECTS_TOOL || current == LAYERS_TOOL || current == SCRIPTING_TOOL); + } + /** + * Get the container of property editor in app states tool. + * * @return the container of property editor in app states tool. */ @FxThread @@ -277,12 +299,17 @@ protected void createToolbar(@NotNull final HBox container) { */ @FxThread private void changeLight(@NotNull final Boolean newValue) { - if (isIgnoreListeners()) return; - final SceneEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.updateLightShowed(newValue); + if (isIgnoreListeners()) { + return; + } - if (editorState != null) editorState.setShowedLight(newValue); + final SceneEditor3DPart editor3DPart = getEditor3DPart(); + editor3DPart.updateLightShowed(newValue); + + if (editorState != null) { + editorState.setShowedLight(newValue); + } } /** @@ -290,12 +317,17 @@ private void changeLight(@NotNull final Boolean newValue) { */ @FxThread private void changeAudio(@NotNull final Boolean newValue) { - if (isIgnoreListeners()) return; - final SceneEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.updateAudioShowed(newValue); + if (isIgnoreListeners()) { + return; + } - if (editorState != null) editorState.setShowedAudio(newValue); + final SceneEditor3DPart editor3DPart = getEditor3DPart(); + editor3DPart.updateAudioShowed(newValue); + + if (editorState != null) { + editorState.setShowedAudio(newValue); + } } @Override @@ -335,7 +367,9 @@ protected void processChangeTool(@Nullable final Number oldValue, @NotNull final super.processChangeTool(oldValue, newValue); final int newIndex = newValue.intValue(); - if (newIndex < 2) return; + if (newIndex < 2) { + return; + } final ModelPropertyEditor modelPropertyEditor = getModelPropertyEditor(); final VBox appStateContainer = getPropertyEditorAppStateContainer(); @@ -344,24 +378,30 @@ protected void processChangeTool(@Nullable final Number oldValue, @NotNull final switch (newIndex) { case LAYERS_TOOL: { + final LayerNodeTree layerNodeTree = getLayerNodeTree(); + final TreeNode selected = layerNodeTree.getSelected(); FXUtils.addToPane(modelPropertyEditor, layersContainer); - modelPropertyEditor.rebuild(); + selectNodeFromLayersTree(selected); break; } case APP_STATES_TOOL: { + final AppStateList appStateList = getAppStateList(); FXUtils.addToPane(modelPropertyEditor, appStateContainer); - modelPropertyEditor.rebuild(); + selectAppStateFromList(appStateList.getSelected()); break; } case FILTERS_TOOL: { + final FilterList filterList = getFilterList(); FXUtils.addToPane(modelPropertyEditor, filtersContainer); - modelPropertyEditor.rebuild(); + selectFilterFromList(filterList.getSelected()); break; } } } /** + * Get the light toggle. + * * @return the light toggle. */ @FxThread @@ -370,6 +410,8 @@ protected void processChangeTool(@Nullable final Number oldValue, @NotNull final } /** + * Get the audio toggle. + * * @return the audio toggle. */ @FxThread @@ -392,22 +434,14 @@ protected void loadState() { */ @FxThread private void selectAppStateFromList(@Nullable final EditableSceneAppState appState) { - if (!isNeedSyncSelection()) return; + + if (!isNeedSyncSelection()) { + return; + } setNeedSyncSelection(false); try { - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.select(null); - - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - layerNodeTree.select(null); - - final FilterList filterList = getFilterList(); - filterList.clearSelection(); - super.selectNodeFromTree(appState); - } finally { setNeedSyncSelection(true); } @@ -418,22 +452,14 @@ private void selectAppStateFromList(@Nullable final EditableSceneAppState appSta */ @FxThread private void selectFilterFromList(@Nullable final EditableSceneFilter sceneFilter) { - if (!isNeedSyncSelection()) return; + + if (!isNeedSyncSelection()) { + return; + } setNeedSyncSelection(false); try { - - final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.select(null); - - final LayerNodeTree layerNodeTree = getLayerNodeTree(); - layerNodeTree.select(null); - - final AppStateList appStateList = getAppStateList(); - appStateList.clearSelection(); - super.selectNodeFromTree(sceneFilter); - } finally { setNeedSyncSelection(true); } @@ -444,21 +470,18 @@ private void selectFilterFromList(@Nullable final EditableSceneFilter sceneFilte */ @FxThread private void selectNodeFromLayersTree(@Nullable final Object object) { - if (!isNeedSyncSelection()) return; + + if (!isNeedSyncSelection()) { + return; + } setNeedSyncSelection(false); try { final ModelNodeTree modelNodeTree = getModelNodeTree(); - modelNodeTree.select(object); - - final AppStateList appStateList = getAppStateList(); - appStateList.clearSelection(); + modelNodeTree.selectSingle(object); - final FilterList filterList = getFilterList(); - filterList.clearSelection(); - - super.selectNodeFromTree(object); + selectNodeFromTree(object); } finally { setNeedSyncSelection(true); @@ -467,22 +490,20 @@ private void selectNodeFromLayersTree(@Nullable final Object object) { @Override @FxThread - public void selectNodeFromTree(@Nullable final Object object) { - if (!isNeedSyncSelection()) return; + public void selectNodesFromTree(@NotNull final Array objects) { + + if (!isNeedSyncSelection()) { + super.selectNodesFromTree(objects); + return; + } setNeedSyncSelection(false); try { final LayerNodeTree layerNodeTree = getLayerNodeTree(); - layerNodeTree.select(object); + layerNodeTree.selects(objects); - final AppStateList appStateList = getAppStateList(); - appStateList.clearSelection(); - - final FilterList filterList = getFilterList(); - filterList.clearSelection(); - - super.selectNodeFromTree(object); + super.selectNodesFromTree(objects); } finally { setNeedSyncSelection(true); @@ -496,6 +517,8 @@ public void selectNodeFromTree(@Nullable final Object object) { } /** + * Return true if need sync selection. + * * @param needSyncSelection true if need sync selection. */ @FxThread @@ -504,6 +527,8 @@ private void setNeedSyncSelection(final boolean needSyncSelection) { } /** + * Return true if need sync selection. + * * @return true if need sync selection. */ @FxThread @@ -512,14 +537,8 @@ private boolean isNeedSyncSelection() { } @Override - @FxThread - protected void updateSelection(@Nullable Spatial spatial) { - - if (spatial instanceof SceneNode || spatial instanceof SceneLayer) { - spatial = null; - } - - super.updateSelection(spatial); + protected boolean canSelect(@NotNull final Spatial spatial) { + return !(spatial instanceof SceneNode) && !(spatial instanceof SceneLayer) && super.canSelect(spatial); } @Override @@ -634,11 +653,11 @@ public void notifyFxChangeProperty(@Nullable final Object parent, @NotNull final @FxThread public void notifyAddedAppState(@NotNull final SceneAppState appState) { - final SceneEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.addAppState(appState); + final SceneEditor3DPart editor3DPart = getEditor3DPart(); + editor3DPart.addAppState(appState); if (appState instanceof ScenePresentable) { - editor3DState.addPresentable((ScenePresentable) appState); + editor3DPart.addPresentable((ScenePresentable) appState); } getAppStateList().fill(getCurrentModel()); @@ -648,11 +667,11 @@ public void notifyAddedAppState(@NotNull final SceneAppState appState) { @FxThread public void notifyRemovedAppState(@NotNull final SceneAppState appState) { - final SceneEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.removeAppState(appState); + final SceneEditor3DPart editor3DPart = getEditor3DPart(); + editor3DPart.removeAppState(appState); if (appState instanceof ScenePresentable) { - editor3DState.removePresentable((ScenePresentable) appState); + editor3DPart.removePresentable((ScenePresentable) appState); } getAppStateList().fill(getCurrentModel()); @@ -668,11 +687,11 @@ public void notifyChangedAppState(@NotNull final SceneAppState appState) { @FxThread public void notifyAddedFilter(@NotNull final SceneFilter sceneFilter) { - final SceneEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.addFilter(sceneFilter); + final SceneEditor3DPart editor3DPart = getEditor3DPart(); + editor3DPart.addFilter(sceneFilter); if (sceneFilter instanceof ScenePresentable) { - editor3DState.addPresentable((ScenePresentable) sceneFilter); + editor3DPart.addPresentable((ScenePresentable) sceneFilter); } getFilterList().fill(getCurrentModel()); @@ -682,11 +701,11 @@ public void notifyAddedFilter(@NotNull final SceneFilter sceneFilter) { @FxThread public void notifyRemovedFilter(@NotNull final SceneFilter sceneFilter) { - final SceneEditor3DPart editor3DState = getEditor3DPart(); - editor3DState.removeFilter(sceneFilter); + final SceneEditor3DPart editor3DPart = getEditor3DPart(); + editor3DPart.removeFilter(sceneFilter); if (sceneFilter instanceof ScenePresentable) { - editor3DState.removePresentable((ScenePresentable) sceneFilter); + editor3DPart.removePresentable((ScenePresentable) sceneFilter); } getFilterList().fill(getCurrentModel()); diff --git a/src/main/java/com/ss/editor/ui/component/log/OutputStreamWrapper.java b/src/main/java/com/ss/editor/ui/component/log/OutputStreamWrapper.java index 3234a68f..bac44953 100644 --- a/src/main/java/com/ss/editor/ui/component/log/OutputStreamWrapper.java +++ b/src/main/java/com/ss/editor/ui/component/log/OutputStreamWrapper.java @@ -16,12 +16,6 @@ public class OutputStreamWrapper extends PrintStream { @NotNull private final Consumer consumer; - /** - * Instantiates a new Output stream wrapper. - * - * @param out the out - * @param consumer the consumer - */ public OutputStreamWrapper(@NotNull final OutputStream out, @NotNull final Consumer consumer) { super(out); this.consumer = consumer; diff --git a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentRegistry.java b/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentRegistry.java index 05275ffd..4ba5ec32 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentRegistry.java +++ b/src/main/java/com/ss/editor/ui/component/painting/PaintingComponentRegistry.java @@ -2,6 +2,7 @@ import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.annotation.FxThread; +import com.ss.editor.ui.component.painting.spawn.SpawnPaintingComponent; import com.ss.editor.ui.component.painting.terrain.TerrainPaintingComponent; import com.ss.rlib.util.array.Array; import com.ss.rlib.util.array.ArrayFactory; @@ -32,6 +33,7 @@ public class PaintingComponentRegistry { private PaintingComponentRegistry() { this.constructors = ArrayFactory.newArray(Function.class); register(TerrainPaintingComponent::new); + register(SpawnPaintingComponent::new); } /** diff --git a/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingComponent.java b/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingComponent.java index 0edb2063..c010f151 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingComponent.java +++ b/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingComponent.java @@ -1,28 +1,42 @@ package com.ss.editor.ui.component.painting.impl; +import static com.ss.editor.ui.component.painting.PaintingComponentContainer.FIELD_PERCENT; +import static com.ss.editor.ui.component.painting.PaintingComponentContainer.LABEL_PERCENT; import static com.ss.rlib.util.ClassUtils.unsafeCast; import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.scene.Node; +import com.ss.editor.Messages; import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.annotation.FxThread; import com.ss.editor.annotation.JmeThread; +import com.ss.editor.control.painting.PaintingControl; import com.ss.editor.manager.ExecutorManager; import com.ss.editor.model.editor.Editor3DProvider; import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.ui.component.editor.state.EditorState; import com.ss.editor.ui.component.painting.PaintingComponent; import com.ss.editor.ui.component.painting.PaintingComponentContainer; -import com.ss.editor.ui.component.editor.state.impl.AdditionalEditorState; +import com.ss.editor.ui.css.CssClasses; +import com.ss.rlib.ui.control.input.FloatTextField; +import com.ss.rlib.ui.util.FXUtils; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; import javafx.scene.layout.VBox; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.function.Supplier; + /** * The base implementation of a processing component. * - * @param the type parameter + * @param the painted object's type. + * @param the component state's type. + * @param the painting control's type. * @author JavaSaBr */ -public abstract class AbstractPaintingComponent extends VBox implements PaintingComponent { +public abstract class AbstractPaintingComponent extends + VBox implements PaintingComponent { /** * The executor manager. @@ -36,12 +50,30 @@ public abstract class AbstractPaintingComponent changeBrushSize(newValue)); + + final Label brushPowerLabel = new Label(Messages.PAINTING_COMPONENT_BRUSH_POWER + ":"); + brushPowerLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); + + brushPowerField = new FloatTextField(); + brushPowerField.prefWidthProperty().bind(widthProperty().multiply(FIELD_PERCENT)); + brushPowerField.setScrollPower(3F); + brushPowerField.setMinMax(0.0001F, Integer.MAX_VALUE); + brushPowerField.addChangeListener((observable, oldValue, newValue) -> changeBrushPower(newValue)); + + final GridPane settings = new GridPane(); + settings.add(brushSizeLabel, 0, 0); + settings.add(brushSizeField, 1, 0); + settings.add(brushPowerLabel, 0, 1); + settings.add(brushPowerField, 1, 1); + + FXUtils.addClassTo(settings, CssClasses.DEF_GRID_PANE); + FXUtils.addClassTo(brushSizeLabel, brushPowerLabel, CssClasses.ABSTRACT_PARAM_CONTROL_PARAM_NAME_SINGLE_ROW); + FXUtils.addClassTo(brushSizeField, brushPowerField, CssClasses.ABSTRACT_PARAM_CONTROL_COMBO_BOX); + + return settings; + } + + @Override + public void loadState(@NotNull final EditorState editorState) { + final S state = editorState.getOrCreateAdditionalState(getStateType(), getStateConstructor()); + this.state = state; + readState(state); + } + + /** + * Get the component's state. + * + * @return the component's state. + */ + @FxThread + protected @NotNull S getState() { + return notNull(state); + } + + /** + * Read the saved component's state. + * + * @param state the saved component's state. + */ + @FxThread + protected void readState(@NotNull final S state) { + getBrushSizeField().setValue(state.getBrushSize()); + getBrushPowerField().setValue(state.getBrushPower()); + } + + /** + * Get the state's constructor. + * + * @return the state's constructor. + */ + @FromAnyThread + protected abstract @NotNull Supplier getStateConstructor(); + + /** + * Get the state's type. + * + * @return the state's type. + */ + @FromAnyThread + protected abstract @NotNull Class getStateType(); + + /** + * Change brush sizes. + */ + @FromAnyThread + protected void changeBrushSize(@NotNull final Float size) { + + if (state != null) { + state.setBrushSize(size); + } + + EXECUTOR_MANAGER.addJmeTask(() -> setBrushSize(size)); + } + + /** + * Set the brush size. + * + * @param size the brush size. + */ + @JmeThread + protected void setBrushSize(@NotNull final Float size) { + getToolControl().setBrushSize(size); + } + + /** + * Change brush powers. + */ + @FromAnyThread + protected void changeBrushPower(@NotNull final Float power) { + + if (state != null) { + state.setBrushPower(power); + } + + EXECUTOR_MANAGER.addJmeTask(() -> setBrushPower(power)); + } + + /** + * Set the brush power. + * + * @param power the brush power. + */ + @JmeThread + protected void setBrushPower(@NotNull final Float power) { + getToolControl().setBrushPower(power); + } + + /** + * Get the current tool control. + * + * @return the current tool control. + */ + @FromAnyThread + protected @NotNull C getToolControl() { + return notNull(toolControl); + } + + /** + * Get the current tool control. + * + * @param toolControl the current tool control. + */ + @FromAnyThread + protected void setToolControl(@Nullable final C toolControl) { + this.toolControl = toolControl; + } + + /** + * Get the brush power field. + * + * @return the brush power field. + */ + @FxThread + protected @NotNull FloatTextField getBrushPowerField() { + return notNull(brushPowerField); + } + + /** + * Get the brush size field. + * + * @return the brush size field. + */ + @FxThread + protected @NotNull FloatTextField getBrushSizeField() { + return notNull(brushSizeField); + } + @Override @FromAnyThread public @NotNull PaintingComponentContainer getContainer() { @@ -123,12 +323,14 @@ protected void createComponents() { @FxThread public void notifyShowed() { setShowed(true); + EXECUTOR_MANAGER.addJmeTask(() -> getCursorNode().addControl(getToolControl())); } @Override @FxThread public void notifyHided() { setShowed(false); + EXECUTOR_MANAGER.addJmeTask(() -> getCursorNode().removeControl(getToolControl())); } /** @@ -150,4 +352,21 @@ protected boolean isShowed() { protected void setShowed(final boolean showed) { this.showed = showed; } + + /** + * @param ignoreListeners the flag of ignoring listeners. + */ + @FxThread + protected void setIgnoreListeners(final boolean ignoreListeners) { + this.ignoreListeners = ignoreListeners; + } + + /** + * @return the flag of ignoring listeners. + */ + @FxThread + protected boolean isIgnoreListeners() { + return ignoreListeners; + } + } diff --git a/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingStateWithEditorTool.java b/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingStateWithEditorTool.java new file mode 100644 index 00000000..598b0005 --- /dev/null +++ b/src/main/java/com/ss/editor/ui/component/painting/impl/AbstractPaintingStateWithEditorTool.java @@ -0,0 +1,79 @@ +package com.ss.editor.ui.component.painting.impl; + +import static java.lang.Math.abs; +import com.ss.editor.annotation.FromAnyThread; +import com.ss.editor.annotation.FxThread; +import com.ss.editor.ui.component.editor.state.impl.AbstractEditorState; +import com.ss.editor.ui.component.editor.state.impl.AdditionalEditorState; + +/** + * The state of painting component. + * + * @author JavaSaBr + */ +public abstract class AbstractPaintingStateWithEditorTool extends AbstractEditorState implements AdditionalEditorState { + + /** + * The constant serialVersionUID. + */ + public static final long serialVersionUID = 1; + + /** + * The brush size. + */ + private volatile float brushSize; + + /** + * The brush power. + */ + private volatile float brushPower; + + public AbstractPaintingStateWithEditorTool() { + this.brushSize = getDefaultBrushSize(); + this.brushPower = getDefaultBrushPower(); + } + + /** + * Get the default brush power. + * + * @return the default brush power. + */ + @FromAnyThread + protected float getDefaultBrushPower() { + return 1; + } + + /** + * Get the default brush size. + * + * @return the default brush size. + */ + @FromAnyThread + protected float getDefaultBrushSize() { + return 10; + } + + @FxThread + public float getBrushSize() { + return brushSize; + } + + @FxThread + public void setBrushSize(final float brushSize) { + final boolean changed = abs(getBrushSize() - brushSize) > 0.001f; + this.brushSize = brushSize; + if (changed) notifyChange(); + } + + @FxThread + public float getBrushPower() { + return brushPower; + } + + @FxThread + public void setBrushPower(final float brushPower) { + final boolean changed = abs(getBrushPower() - brushPower) > 0.001f; + this.brushPower = brushPower; + if (changed) notifyChange(); + } +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/impl/PaintingBrushType.java b/src/main/java/com/ss/editor/ui/component/painting/impl/PaintingBrushType.java new file mode 100644 index 00000000..c6bc6e4c --- /dev/null +++ b/src/main/java/com/ss/editor/ui/component/painting/impl/PaintingBrushType.java @@ -0,0 +1,13 @@ +package com.ss.editor.ui.component.painting.impl; + +/** + * The enum of brush types. + * + * @author JavaSaBr + */ +public enum PaintingBrushType { + /** + * Sphere brush type. + */ + SPHERE, +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/property/PaintingPropertyDefinition.java b/src/main/java/com/ss/editor/ui/component/painting/property/PaintingPropertyDefinition.java new file mode 100644 index 00000000..4927406c --- /dev/null +++ b/src/main/java/com/ss/editor/ui/component/painting/property/PaintingPropertyDefinition.java @@ -0,0 +1,35 @@ +package com.ss.editor.ui.component.painting.property; + +import com.ss.editor.annotation.FromAnyThread; +import com.ss.editor.extension.property.EditablePropertyType; +import com.ss.editor.plugin.api.property.PropertyDefinition; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The definition of property to {@link com.ss.editor.ui.component.painting.PaintingComponent}. + * + * @author JavaSaBr + */ +public class PaintingPropertyDefinition extends PropertyDefinition { + + @NotNull + private final String category; + + public PaintingPropertyDefinition(@NotNull final String category, @NotNull final EditablePropertyType propertyType, + @NotNull final String name, @NotNull final String id, + @Nullable final Object defaultValue) { + super(propertyType, name, id, defaultValue); + this.category = category; + } + + /** + * Get the category. + * + * @return the category. + */ + @FromAnyThread + public @NotNull String getCategory() { + return category; + } +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/property/PropertiesBasedPaintingComponent.java b/src/main/java/com/ss/editor/ui/component/painting/property/PropertiesBasedPaintingComponent.java new file mode 100644 index 00000000..3c851590 --- /dev/null +++ b/src/main/java/com/ss/editor/ui/component/painting/property/PropertiesBasedPaintingComponent.java @@ -0,0 +1,139 @@ +package com.ss.editor.ui.component.painting.property; + +import com.ss.editor.annotation.FxThread; +import com.ss.editor.control.painting.PaintingControl; +import com.ss.editor.plugin.api.property.control.PropertyEditorControl; +import com.ss.editor.plugin.api.property.control.PropertyEditorControlFactory; +import com.ss.editor.ui.component.painting.PaintingComponentContainer; +import com.ss.editor.ui.component.painting.impl.AbstractPaintingComponent; +import com.ss.editor.ui.component.painting.impl.AbstractPaintingStateWithEditorTool; +import com.ss.rlib.ui.util.FXUtils; +import com.ss.rlib.util.VarTable; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; +import com.ss.rlib.util.dictionary.DictionaryFactory; +import com.ss.rlib.util.dictionary.ObjectDictionary; +import javafx.collections.ObservableList; +import javafx.scene.Node; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.VBox; +import org.jetbrains.annotations.NotNull; + +/** + * The properties based implementation of painting component. + * + * @param the painted object's type. + * @param the component state's type. + * @param the painting control's type. + * @author JavaSaBr + */ +public abstract class PropertiesBasedPaintingComponent extends + AbstractPaintingComponent { + + @NotNull + protected static final Array EMPTY_PROPERTIES = ArrayFactory.newArray(PaintingPropertyDefinition.class); + + /** + * The map of category to properties container. + */ + @NotNull + private ObjectDictionary propertyContainers; + + /** + * The property variables. + */ + @NotNull + private VarTable vars; + + public PropertiesBasedPaintingComponent(@NotNull final PaintingComponentContainer container) { + super(container); + } + + @Override + @FxThread + protected void createComponents() { + super.createComponents(); + + this.propertyContainers = DictionaryFactory.newObjectDictionary(); + this.vars = VarTable.newInstance(); + + final Runnable callback = this::syncValues; + final GridPane settings = createBrushSettings(); + + for (final PaintingPropertyDefinition definition : getPaintingProperties()) { + final PropertyEditorControl control = PropertyEditorControlFactory.build(vars, definition, callback); + final VBox container = propertyContainers.get(definition.getCategory(), this::createContainer); + FXUtils.addToPane(control, container); + } + + FXUtils.addToPane(settings, this); + } + + @Override + @FxThread + protected void readState(@NotNull final S state) { + super.readState(state); + refreshPropertyControls(); + syncValues(); + } + + /** + * Refresh property controls. + */ + @FxThread + protected void refreshPropertyControls() { + propertyContainers.forEach(container -> container.getChildren() + .stream().map(node -> (PropertyEditorControl) node) + .forEach(PropertyEditorControl::reload)); + } + + /** + * Show properties of the category. + * + * @param category the category. + */ + @FxThread + protected void showCategory(@NotNull final String category) { + final ObservableList children = getChildren(); + children.removeIf(VBox.class::isInstance); + children.add(propertyContainers.get(category)); + } + + /** + * Get the property variables. + * + * @return the property variables. + */ + @FxThread + protected @NotNull VarTable getVars() { + return vars; + } + + /** + * Synchronize values from properties. + */ + @FxThread + protected void syncValues() { + + } + + /** + * Create a container for the category. + * + * @param category the category. + */ + @FxThread + private VBox createContainer(@NotNull final String category) { + return new VBox(); + } + + /** + * Get the list of painting properties. + * + * @return the list of painting properties. + */ + @FxThread + protected @NotNull Array getPaintingProperties() { + return EMPTY_PROPERTIES; + } +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingComponent.java b/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingComponent.java new file mode 100644 index 00000000..6cb3cabb --- /dev/null +++ b/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingComponent.java @@ -0,0 +1,165 @@ +package com.ss.editor.ui.component.painting.spawn; + +import static com.ss.editor.extension.property.EditablePropertyType.*; +import com.jme3.asset.AssetManager; +import com.jme3.math.Vector3f; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.ss.editor.Messages; +import com.ss.editor.annotation.FromAnyThread; +import com.ss.editor.annotation.FxThread; +import com.ss.editor.control.painting.spawn.SpawnToolControl; +import com.ss.editor.control.painting.spawn.SpawnToolControl.SpawnMethod; +import com.ss.editor.ui.Icons; +import com.ss.editor.ui.component.painting.PaintingComponentContainer; +import com.ss.editor.ui.component.painting.property.PaintingPropertyDefinition; +import com.ss.editor.ui.component.painting.property.PropertiesBasedPaintingComponent; +import com.ss.editor.util.EditorUtil; +import com.ss.editor.util.NodeUtils; +import com.ss.rlib.util.VarTable; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +/** + * The component to spawn models. + * + * @author JavaSaBr + */ +public class SpawnPaintingComponent extends PropertiesBasedPaintingComponent { + + private static final String CATEGORY_DEFAULT = "Default"; + + private static final String PROPERTY_MODEL = "model"; + private static final String PROPERTY_METHOD = "method"; + private static final String PROPERTY_SCALE = "scale"; + + public static final int AVAILABLE_MODELS = 10; + + public SpawnPaintingComponent(@NotNull final PaintingComponentContainer container) { + super(container); + setToolControl(new SpawnToolControl(this)); + showCategory(CATEGORY_DEFAULT); + } + + @Override + @FxThread + protected @NotNull Array getPaintingProperties() { + + final Array result = ArrayFactory.newArray(PaintingPropertyDefinition.class); + result.add(new PaintingPropertyDefinition(CATEGORY_DEFAULT, ENUM, + Messages.PAINTING_COMPONENT_METHOD, PROPERTY_METHOD, SpawnMethod.BATCH)); + result.add(new PaintingPropertyDefinition(CATEGORY_DEFAULT, VECTOR_3F, + Messages.PAINTING_COMPONENT_SCALE, PROPERTY_SCALE, new Vector3f(1F, 1F, 1F))); + + for (int i = 1; i <= AVAILABLE_MODELS; i++) { + result.add(new PaintingPropertyDefinition(CATEGORY_DEFAULT, SPATIAL_FROM_ASSET_FOLDER, + Messages.PAINTING_COMPONENT_MODEL + " " + "#" + i, PROPERTY_MODEL + "_" + i, null)); + } + + return result; + } + + @Override + protected void syncValues() { + super.syncValues(); + + final VarTable vars = getVars(); + final SpawnToolControl toolControl = getToolControl(); + + final Array examples = ArrayFactory.newArray(Spatial.class); + final String[] selectedModels = new String[AVAILABLE_MODELS]; + + for (int i = 1; i <= AVAILABLE_MODELS; i++) { + + final String id = PROPERTY_MODEL + "_" + i; + if (!vars.has(id)) { + selectedModels[i - 1] = null; + continue; + } + + final Spatial spatial = vars.get(id); + examples.add(spatial); + selectedModels[i - 1] = spatial.getKey().getName(); + } + + final SpawnMethod method = vars.get(PROPERTY_METHOD); + final Vector3f scale = vars.get(PROPERTY_SCALE); + + final SpawnPaintingStateWithEditorTool state = getState(); + state.setMethod(method.ordinal()); + state.setScale(scale); + state.setSelectedModels(selectedModels); + + EXECUTOR_MANAGER.addJmeTask(() -> { + toolControl.setMethod(method); + toolControl.setScale(scale); + toolControl.updateExamples(examples); + }); + } + + @Override + @FxThread + protected void readState(@NotNull final SpawnPaintingStateWithEditorTool state) { + + final int method = state.getMethod(); + final String[] selectedModels = state.getSelectedModels(); + + final VarTable vars = getVars(); + vars.set(PROPERTY_METHOD, SpawnMethod.values()[method]); + vars.set(PROPERTY_SCALE, state.getScale()); + + final AssetManager assetManager = EditorUtil.getAssetManager(); + + for (int i = 1; i <= AVAILABLE_MODELS; i++) { + final String selectedModel = selectedModels[i - 1]; + if (selectedModel == null) { + continue; + } + vars.set(PROPERTY_MODEL + "_" + i, assetManager.loadModel(selectedModel)); + } + + super.readState(state); + } + + @Override + @FromAnyThread + protected @NotNull Supplier getStateConstructor() { + return SpawnPaintingStateWithEditorTool::new; + } + + @Override + @FromAnyThread + protected @NotNull Class getStateType() { + return SpawnPaintingStateWithEditorTool.class; + } + + @Override + @FxThread + public boolean isSupport(@NotNull final Object object) { + return object instanceof Node && + NodeUtils.findGeometry((Spatial) object) != null; + } + + @Override + @FromAnyThread + public @NotNull String getName() { + return Messages.PAINTING_COMPONENT_SPAWN_MODELS; + } + + @Override + @FxThread + public @Nullable Image getIcon() { + return Icons.FOREST_16; + } + + @Override + @FxThread + public void notifyChangeProperty(@NotNull final Object object, @NotNull final String propertyName) { + + } +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingStateWithEditorTool.java b/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingStateWithEditorTool.java new file mode 100644 index 00000000..bacb17a3 --- /dev/null +++ b/src/main/java/com/ss/editor/ui/component/painting/spawn/SpawnPaintingStateWithEditorTool.java @@ -0,0 +1,109 @@ +package com.ss.editor.ui.component.painting.spawn; + +import com.jme3.math.Vector3f; +import com.ss.editor.annotation.FxThread; +import com.ss.editor.control.painting.spawn.SpawnToolControl.SpawnMethod; +import com.ss.editor.ui.component.painting.impl.AbstractPaintingStateWithEditorTool; +import org.jetbrains.annotations.NotNull; + +import java.util.Arrays; + +/** + * The state of spawn painting component. + * + * @author JavaSaBr + */ +public class SpawnPaintingStateWithEditorTool extends AbstractPaintingStateWithEditorTool { + + /** + * The constant serialVersionUID. + */ + public static final long serialVersionUID = 3; + + /** + * The selected models. + */ + @NotNull + private String[] selectedModels; + + /** + * The models scale. + */ + @NotNull + private Vector3f scale; + + /** + * The spawn method. + */ + private int method; + + public SpawnPaintingStateWithEditorTool() { + this.method = SpawnMethod.BATCH.ordinal(); + this.selectedModels = new String[SpawnPaintingComponent.AVAILABLE_MODELS]; + this.scale = new Vector3f(Vector3f.UNIT_XYZ); + } + + /** + * Set the spawn method. + * + * @param method the spawn method. + */ + @FxThread + public void setMethod(final int method) { + final boolean changed = getMethod() != method; + this.method = method; + if (changed) notifyChange(); + } + + /** + * Get the spawn method. + * + * @return the spawn method. + */ + @FxThread + public int getMethod() { + return method; + } + + /** + * Get the models scale. + * + * @param scale the models scale. + */ + @FxThread + public void setScale(@NotNull final Vector3f scale) { + this.scale = scale; + } + + /** + * Set the models scale. + * + * @return the models scale. + */ + @FxThread + public @NotNull Vector3f getScale() { + return scale; + } + + /** + * Set the selected models. + * + * @param selectedModels the selected models. + */ + @FxThread + public void setSelectedModels(@NotNull final String[] selectedModels) { + final boolean changed = !Arrays.equals(getSelectedModels(), selectedModels); + this.selectedModels = selectedModels; + if (changed) notifyChange(); + } + + /** + * Get the selected models. + * + * @return the selected models. + */ + @FxThread + public @NotNull String[] getSelectedModels() { + return selectedModels; + } +} diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainBrushType.java b/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainBrushType.java deleted file mode 100644 index a97e4797..00000000 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainBrushType.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.ss.editor.ui.component.painting.terrain; - -/** - * The enum with brush types. - * - * @author JavaSaBr - */ -public enum TerrainBrushType { - /** - * Sphere terrain brush type. - */ - SPHERE, -} diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingComponent.java b/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingComponent.java index 4686b37d..b616dd26 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingComponent.java +++ b/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingComponent.java @@ -13,6 +13,7 @@ import com.ss.editor.Messages; import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.annotation.FxThread; +import com.ss.editor.annotation.JmeThread; import com.ss.editor.control.painting.terrain.*; import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.model.undo.editor.ModelChangeConsumer; @@ -47,13 +48,14 @@ import org.jetbrains.annotations.Nullable; import java.util.function.Function; +import java.util.function.Supplier; /** * The painting component to edit terrain. * * @author JavaSaBr */ -public class TerrainPaintingComponent extends AbstractPaintingComponent { +public class TerrainPaintingComponent extends AbstractPaintingComponent { /** * The constant TERRAIN_PARAM. @@ -194,18 +196,6 @@ public class TerrainPaintingComponent extends AbstractPaintingComponent getStateType() { + return TerrainPaintingStateWithEditorTool.class; + } + + @Override + @FromAnyThread + protected @NotNull Supplier getStateConstructor() { + return TerrainPaintingStateWithEditorTool::new; + } + @Override @FxThread public void loadState(@NotNull final EditorState editorState) { - this.state = editorState.getOrCreateAdditionalState(TerrainPaintingStateWithEditorTool.class, TerrainPaintingStateWithEditorTool::new); + super.loadState(editorState); getLevelControlLevelField().setValue(state.getLevelValue()); getLevelControlUseMarker().setSelected(state.isLevelUseMarker()); getLevelControlSmoothly().setSelected(state.isLevelSmoothly()); @@ -377,8 +368,6 @@ public void loadState(@NotNull final EditorState editorState) { getRoughControlOctavesField().setValue(state.getRoughtOctaves()); getRoughControlRoughnessField().setValue(state.getRoughtRoughness()); getRoughControlScaleField().setValue(state.getRoughtScale()); - getBrushSizeField().setValue(state.getBrushSize()); - getBrushPowerField().setValue(state.getBrushPower()); } /** @@ -421,26 +410,6 @@ public void loadState(@NotNull final EditorState editorState) { return buttonToSettings; } - /** - * Get the current tool control. - * - * @return the current tool control. - */ - @FxThread - private @Nullable TerrainToolControl getToolControl() { - return toolControl; - } - - /** - * Get the current tool control. - * - * @param toolControl the current tool control. - */ - @FxThread - private void setToolControl(@Nullable final TerrainToolControl toolControl) { - this.toolControl = toolControl; - } - /** * Get the container of control settings. * @@ -511,26 +480,6 @@ private void setToolControl(@Nullable final TerrainToolControl toolControl) { return notNull(raiseLowerButton); } - /** - * Get the brush power field. - * - * @return the brush power field. - */ - @FxThread - private @NotNull FloatTextField getBrushPowerField() { - return notNull(brushPowerField); - } - - /** - * Get the brush size field. - * - * @return the brush size field. - */ - @FxThread - private @NotNull FloatTextField getBrushSizeField() { - return notNull(brushSizeField); - } - @Override @FxThread protected void createComponents() { @@ -567,34 +516,11 @@ protected void createComponents() { FXUtils.addClassTo(buttonsContainer, CssClasses.DEF_GRID_PANE); - final Label brushSizeLabel = new Label(Messages.EDITING_COMPONENT_BRUSH_SIZE + ":"); - brushSizeLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); - - brushSizeField = new FloatTextField(); - brushSizeField.prefWidthProperty().bind(widthProperty().multiply(FIELD_PERCENT)); - brushSizeField.setMinMax(0.0001F, Integer.MAX_VALUE); - brushSizeField.addChangeListener((observable, oldValue, newValue) -> changeBrushSize(newValue)); - - final Label brushPowerLabel = new Label(Messages.EDITING_COMPONENT_BRUSH_POWER + ":"); - brushPowerLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); - - brushPowerField = new FloatTextField(); - brushPowerField.prefWidthProperty().bind(widthProperty().multiply(FIELD_PERCENT)); - brushPowerField.setScrollPower(3F); - brushPowerField.setMinMax(0.0001F, Integer.MAX_VALUE); - brushPowerField.addChangeListener((observable, oldValue, newValue) -> changeBrushPower(newValue)); - - final GridPane brushSettingsContainer = new GridPane(); - brushSettingsContainer.add(brushSizeLabel, 0, 0); - brushSettingsContainer.add(brushSizeField, 1, 0); - brushSettingsContainer.add(brushPowerLabel, 0, 1); - brushSettingsContainer.add(brushPowerField, 1, 1); - controlSettings = new VBox(); controlSettings.prefWidthProperty().bind(widthProperty()); FXUtils.addToPane(buttonsContainer, this); - FXUtils.addToPane(brushSettingsContainer, this); + FXUtils.addToPane(createBrushSettings(), this); FXUtils.addToPane(controlSettings, this); createLevelControlSettings(); @@ -605,10 +531,7 @@ protected void createComponents() { FXUtils.addClassesTo(raiseLowerButton, smoothButton, roughButton, levelButton, slopeButton, paintButton, CssClasses.MEDIUM_TOGGLE_BUTTON); - FXUtils.addClassTo(brushSettingsContainer, CssClasses.DEF_GRID_PANE); FXUtils.addClassTo(controlSettings, CssClasses.DEF_VBOX); - FXUtils.addClassTo(brushSizeLabel, brushPowerLabel, CssClasses.ABSTRACT_PARAM_CONTROL_PARAM_NAME_SINGLE_ROW); - FXUtils.addClassTo(brushSizeField, brushPowerField, CssClasses.ABSTRACT_PARAM_CONTROL_COMBO_BOX); } /** @@ -617,7 +540,7 @@ protected void createComponents() { @FxThread private void createSlopeControlSettings() { - final Label smoothlyLabel = new Label(Messages.EDITING_COMPONENT_SMOOTHLY + ":"); + final Label smoothlyLabel = new Label(Messages.PAINTING_COMPONENT_SMOOTHLY + ":"); smoothlyLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); slopeControlSmoothly = new CheckBox(); @@ -625,7 +548,7 @@ private void createSlopeControlSettings() { slopeControlSmoothly.selectedProperty() .addListener((observable, oldValue, newValue) -> changeSlopeControlSmoothly(newValue)); - final Label limitedLabel = new Label(Messages.EDITING_COMPONENT_LIMITED + ":"); + final Label limitedLabel = new Label(Messages.PAINTING_COMPONENT_LIMITED + ":"); limitedLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); slopeControlLimited = new CheckBox(); @@ -650,7 +573,7 @@ private void createSlopeControlSettings() { @FxThread private void createLevelControlSettings() { - final Label smoothlyLabel = new Label(Messages.EDITING_COMPONENT_SMOOTHLY + ":"); + final Label smoothlyLabel = new Label(Messages.PAINTING_COMPONENT_SMOOTHLY + ":"); smoothlyLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); levelControlSmoothly = new CheckBox(); @@ -658,7 +581,7 @@ private void createLevelControlSettings() { levelControlSmoothly.selectedProperty() .addListener((observable, oldValue, newValue) -> changeLevelControlSmoothly(newValue)); - final Label useMarkerLabel = new Label(Messages.EDITING_COMPONENT_USE_MARKER + ":"); + final Label useMarkerLabel = new Label(Messages.PAINTING_COMPONENT_USE_MARKER + ":"); useMarkerLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); levelControlUseMarker = new CheckBox(); @@ -666,7 +589,7 @@ private void createLevelControlSettings() { levelControlUseMarker.selectedProperty() .addListener((observable, oldValue, newValue) -> changeLevelControlUseMarker(newValue)); - final Label levelLabel = new Label(Messages.EDITING_COMPONENT_LEVEL + ":"); + final Label levelLabel = new Label(Messages.PAINTING_COMPONENT_LEVEL + ":"); levelLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); levelControlLevelField = new FloatTextField(); @@ -698,7 +621,7 @@ private void createLevelControlSettings() { @FxThread private void createRoughControlSettings() { - final Label roughnessLabel = new Label(Messages.EDITING_COMPONENT_ROUGHNESS + ":"); + final Label roughnessLabel = new Label(Messages.PAINTING_COMPONENT_ROUGHNESS + ":"); roughnessLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); roughControlRoughnessField = new FloatTextField(); @@ -706,7 +629,7 @@ private void createRoughControlSettings() { roughControlRoughnessField.setMinMax(0F, Integer.MAX_VALUE); roughControlRoughnessField.addChangeListener((observable, oldValue, newValue) -> changeRoughControlRoughness(newValue)); - final Label frequencyLabel = new Label(Messages.EDITING_COMPONENT_FREQUENCY + ":"); + final Label frequencyLabel = new Label(Messages.PAINTING_COMPONENT_FREQUENCY + ":"); frequencyLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); roughControlFrequencyField = new FloatTextField(); @@ -714,7 +637,7 @@ private void createRoughControlSettings() { roughControlFrequencyField.setMinMax(0.1F, Integer.MAX_VALUE); roughControlFrequencyField.addChangeListener((observable, oldValue, newValue) -> changeRoughControlFrequency(newValue)); - final Label lacunarityLabel = new Label(Messages.EDITING_COMPONENT_LACUNARITY + ":"); + final Label lacunarityLabel = new Label(Messages.PAINTING_COMPONENT_LACUNARITY + ":"); lacunarityLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); roughControlLacunarityField = new FloatTextField(); @@ -722,7 +645,7 @@ private void createRoughControlSettings() { roughControlLacunarityField.setMinMax(1.1F, Integer.MAX_VALUE); roughControlLacunarityField.addChangeListener((observable, oldValue, newValue) -> changeRoughControlLacunarity(newValue)); - final Label octavesLabel = new Label(Messages.EDITING_COMPONENT_OCTAVES + ":"); + final Label octavesLabel = new Label(Messages.PAINTING_COMPONENT_OCTAVES + ":"); octavesLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); roughControlOctavesField = new FloatTextField(); @@ -730,7 +653,7 @@ private void createRoughControlSettings() { roughControlOctavesField.setMinMax(0F, Integer.MAX_VALUE); roughControlOctavesField.addChangeListener((observable, oldValue, newValue) -> changeRoughControlOctaves(newValue)); - final Label scaleLabel = new Label(Messages.EDITING_COMPONENT_SCALE + ":"); + final Label scaleLabel = new Label(Messages.PAINTING_COMPONENT_SCALE + ":"); scaleLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); roughControlScaleField = new FloatTextField(); @@ -765,7 +688,7 @@ private void createRoughControlSettings() { @FxThread private void createPaintControlSettings() { - final Label triPlanarLabelLabel = new Label(Messages.EDITING_COMPONENT_TRI_PLANAR + ":"); + final Label triPlanarLabelLabel = new Label(Messages.PAINTING_COMPONENT_TRI_PLANAR + ":"); triPlanarLabelLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); triPlanarCheckBox = new CheckBox(); @@ -773,7 +696,7 @@ private void createPaintControlSettings() { triPlanarCheckBox.selectedProperty() .addListener((observable, oldValue, newValue) -> changePaintControlTriPlanar(newValue)); - final Label shininessLabel = new Label(Messages.EDITING_COMPONENT_SHININESS + ":"); + final Label shininessLabel = new Label(Messages.PAINTING_COMPONENT_SHININESS + ":"); shininessLabel.prefWidthProperty().bind(widthProperty().multiply(LABEL_PERCENT)); shininessField = new FloatTextField(); @@ -974,28 +897,18 @@ private void changeRoughControlRoughness(@NotNull final Float newRoughness) { EXECUTOR_MANAGER.addJmeTask(() -> getRoughToolControl().setRoughness(newRoughness)); } - /** - * Change brush sizes. - */ - @FromAnyThread - private void changeBrushSize(@NotNull final Float size) { - if (state != null) state.setBrushSize(size); - EXECUTOR_MANAGER.addJmeTask(() -> { - final Array toolControls = getToolControls(); - toolControls.forEach(size, TerrainToolControl::setBrushSize); - }); + @Override + @JmeThread + protected void setBrushSize(@NotNull final Float size) { + final Array toolControls = getToolControls(); + toolControls.forEach(size, TerrainToolControl::setBrushSize); } - /** - * Change brush powers. - */ - @FromAnyThread - private void changeBrushPower(@NotNull final Float power) { - if (state != null) state.setBrushPower(power); - EXECUTOR_MANAGER.addJmeTask(() -> { - final Array toolControls = getToolControls(); - toolControls.forEach(power, TerrainToolControl::setBrushPower); - }); + @Override + @JmeThread + protected void setBrushPower(@NotNull final Float power) { + final Array toolControls = getToolControls(); + toolControls.forEach(power, TerrainToolControl::setBrushPower); } /** @@ -1255,36 +1168,6 @@ public boolean isSupport(@NotNull final Object object) { NodeUtils.findSpatial((Node) object, TerrainQuad.class::isInstance) != null; } - @Override - @FxThread - public void notifyShowed() { - super.notifyShowed(); - EXECUTOR_MANAGER.addJmeTask(() -> getCursorNode().addControl(getToolControl())); - } - - @Override - @FxThread - public void notifyHided() { - super.notifyHided(); - EXECUTOR_MANAGER.addJmeTask(() -> getCursorNode().removeControl(TerrainToolControl.class)); - } - - /** - * @param ignoreListeners the flag of ignoring listeners. - */ - @FxThread - private void setIgnoreListeners(final boolean ignoreListeners) { - this.ignoreListeners = ignoreListeners; - } - - /** - * @return the flag of ignoring listeners. - */ - @FxThread - private boolean isIgnoreListeners() { - return ignoreListeners; - } - @Override @FromAnyThread public @NotNull String getName() { diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingStateWithEditorTool.java b/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingStateWithEditorTool.java index b6c1b527..954310ca 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingStateWithEditorTool.java +++ b/src/main/java/com/ss/editor/ui/component/painting/terrain/TerrainPaintingStateWithEditorTool.java @@ -2,23 +2,20 @@ import static java.lang.Math.abs; import com.ss.editor.annotation.FxThread; -import com.ss.editor.ui.component.editor.state.impl.AbstractEditorState; -import com.ss.editor.ui.component.editor.state.impl.AdditionalEditorState; +import com.ss.editor.ui.component.painting.impl.AbstractPaintingStateWithEditorTool; /** - * The state of terrain editing component. + * The state of terrain painting component. * * @author JavaSaBr */ -public class TerrainPaintingStateWithEditorTool extends AbstractEditorState implements AdditionalEditorState { +public class TerrainPaintingStateWithEditorTool extends AbstractPaintingStateWithEditorTool { /** * The constant serialVersionUID. */ - public static final long serialVersionUID = 1; + public static final long serialVersionUID = 2; - private volatile float brushSize; - private volatile float brushPower; private volatile float levelValue; private volatile float roughtFrequency; private volatile float roughtLacunarity; @@ -32,8 +29,6 @@ public class TerrainPaintingStateWithEditorTool extends AbstractEditorState impl private volatile boolean slopeSmoothly; public TerrainPaintingStateWithEditorTool() { - this.brushSize = 10; - this.brushPower = 1; this.levelValue = 1; this.roughtFrequency = 0.2f; this.roughtLacunarity = 2.12f; @@ -46,30 +41,6 @@ public TerrainPaintingStateWithEditorTool() { this.slopeSmoothly = true; } - @FxThread - public float getBrushSize() { - return brushSize; - } - - @FxThread - public void setBrushSize(final float brushSize) { - final boolean changed = abs(getBrushSize() - brushSize) > 0.001f; - this.brushSize = brushSize; - if (changed) notifyChange(); - } - - @FxThread - public float getBrushPower() { - return brushPower; - } - - @FxThread - public void setBrushPower(final float brushPower) { - final boolean changed = abs(getBrushPower() - brushPower) > 0.001f; - this.brushPower = brushPower; - if (changed) notifyChange(); - } - @FxThread public float getLevelValue() { return levelValue; diff --git a/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerCell.java b/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerCell.java index 6f5d0ed4..f89991f9 100644 --- a/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerCell.java +++ b/src/main/java/com/ss/editor/ui/component/painting/terrain/paint/TextureLayerCell.java @@ -81,7 +81,7 @@ public TextureLayerCell(final DoubleBinding prefWidth, normalTextureControl.setChangeHandler(this::updateNormal); normalTextureControl.setControlWidthPercent(PropertyControl.CONTROL_WIDTH_PERCENT_2); - final Label scaleLabel = new Label(Messages.EDITING_COMPONENT_SCALE + ":"); + final Label scaleLabel = new Label(Messages.PAINTING_COMPONENT_SCALE + ":"); scaleLabel.prefWidthProperty().bind(settingContainer.widthProperty().multiply(LABEL_PERCENT)); scaleField = new FloatTextField(); @@ -222,7 +222,7 @@ protected void refresh() { diffuseTextureControl.setTextureFile(item.getDiffuseFile()); final Label layerField = getLayerField(); - layerField.setText(Messages.EDITING_COMPONENT_LAYER + " #" + (item.getLayer() + 1)); + layerField.setText(Messages.PAINTING_COMPONENT_LAYER + " #" + (item.getLayer() + 1)); } finally { setIgnoreListeners(false); diff --git a/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateList.java b/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateList.java index 4406ad05..3be3c621 100644 --- a/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateList.java +++ b/src/main/java/com/ss/editor/ui/control/app/state/list/AppStateList.java @@ -126,6 +126,8 @@ public void fill(@NotNull final SceneNode sceneNode) { } /** + * Get the list view with created scene app states. + * * @return the list view with created scene app states. */ @FxThread @@ -142,6 +144,17 @@ public void clearSelection() { selectionModel.select(null); } + /** + * Get the current selected item. + * + * @return the current selected item. + */ + @FxThread + public @Nullable EditableSceneAppState getSelected() { + final MultipleSelectionModel selectionModel = getListView().getSelectionModel(); + return selectionModel.getSelectedItem(); + } + /** * Handle adding a new app state. */ diff --git a/src/main/java/com/ss/editor/ui/control/filter/list/FilterList.java b/src/main/java/com/ss/editor/ui/control/filter/list/FilterList.java index fb45762d..94d0440e 100644 --- a/src/main/java/com/ss/editor/ui/control/filter/list/FilterList.java +++ b/src/main/java/com/ss/editor/ui/control/filter/list/FilterList.java @@ -131,6 +131,17 @@ public void clearSelection() { selectionModel.select(null); } + /** + * Get the current selected item. + * + * @return the current selected item. + */ + @FxThread + public @Nullable EditableSceneFilter getSelected() { + final MultipleSelectionModel selectionModel = listView.getSelectionModel(); + return selectionModel.getSelectedItem(); + } + /** * Add a new filter. */ diff --git a/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTree.java b/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTree.java index c153faee..6673ffc2 100644 --- a/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTree.java +++ b/src/main/java/com/ss/editor/ui/control/layer/LayerNodeTree.java @@ -8,6 +8,8 @@ import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.NodeTreeCell; import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.rlib.util.array.Array; +import javafx.scene.control.SelectionMode; import javafx.scene.control.TreeItem; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,7 +23,7 @@ */ public class LayerNodeTree extends NodeTree { - public LayerNodeTree(@NotNull final Consumer selectionHandler, @Nullable final SceneChangeConsumer consumer) { + public LayerNodeTree(@NotNull final Consumer> selectionHandler, @Nullable final SceneChangeConsumer consumer) { super(selectionHandler, consumer); } @@ -41,7 +43,9 @@ public void notifyAdded(@NotNull final Spatial spatial) { spatial.depthFirstTraversal(child -> { final SceneLayer layer = SceneLayer.getLayer(child); - if (layer == SceneLayer.NO_LAYER) return; + if (layer == SceneLayer.NO_LAYER) { + return; + } final TreeItem> newLayerItem = findItemForValue(getTreeView(), layer); final TreeItem> treeItem = findItemForValue(getTreeView(), child); @@ -64,7 +68,9 @@ public void notifyRemoved(@NotNull final Spatial spatial) { spatial.depthFirstTraversal(child -> { final SceneLayer layer = SceneLayer.getLayer(child); - if (layer == SceneLayer.NO_LAYER) return; + if (layer == SceneLayer.NO_LAYER) { + return; + } final TreeItem> newLayerItem = findItemForValue(getTreeView(), layer); final TreeItem> treeItem = findItemForValue(getTreeView(), child); diff --git a/src/main/java/com/ss/editor/ui/control/model/ModelNodeTree.java b/src/main/java/com/ss/editor/ui/control/model/ModelNodeTree.java index 3da4033b..42af6974 100644 --- a/src/main/java/com/ss/editor/ui/control/model/ModelNodeTree.java +++ b/src/main/java/com/ss/editor/ui/control/model/ModelNodeTree.java @@ -2,6 +2,9 @@ import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.control.tree.NodeTree; +import com.ss.editor.ui.control.tree.action.impl.multi.RemoveElementsAction; +import com.ss.rlib.util.array.Array; +import javafx.scene.control.SelectionMode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,7 +17,12 @@ */ public class ModelNodeTree extends NodeTree { - public ModelNodeTree(@NotNull final Consumer selectionHandler, @Nullable final ModelChangeConsumer consumer) { - super(selectionHandler, consumer); + static { + register(RemoveElementsAction.ACTION_FILLER); + } + + public ModelNodeTree(@NotNull final Consumer> selectionHandler, + @Nullable final ModelChangeConsumer consumer) { + super(selectionHandler, consumer, SelectionMode.MULTIPLE); } } diff --git a/src/main/java/com/ss/editor/ui/control/property/PropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/PropertyControl.java index a27b4af1..d7b61a99 100644 --- a/src/main/java/com/ss/editor/ui/control/property/PropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/PropertyControl.java @@ -33,9 +33,9 @@ /** * The base implementation of the property control. * - * @param the type of a change consumer - * @param the type of an editing object - * @param the type of an editing property + * @param the type of a change consumer. + * @param the type of an editing object. + * @param the type of an editing property. * @author JavaSaBr */ public class PropertyControl extends VBox implements UpdatableControl { @@ -171,10 +171,11 @@ public PropertyControl(@Nullable final T propertyValue, @NotNull final String pr * @return the six object consumer */ @FromAnyThread - public @NotNull SixObjectConsumer<@NotNull C, @NotNull D, @NotNull String, @Nullable T, @Nullable T, @NotNull BiConsumer> newChangeHandler() { + public @NotNull SixObjectConsumer> newChangeHandler() { return (changeConsumer, object, propName, newValue, oldValue, handler) -> { - final PropertyOperation operation = new PropertyOperation<>(object, propName, newValue, oldValue); + final PropertyOperation operation = + new PropertyOperation<>(object, propName, newValue, oldValue); operation.setApplyHandler(handler); changeConsumer.execute(operation); @@ -200,7 +201,11 @@ public void setEditObject(@NotNull final D editObject) { @FxThread public void setEditObject(@NotNull final D editObject, final boolean needReload) { setEditObject(editObject); - if (!needReload) return; + + if (!needReload) { + return; + } + setIgnoreListener(true); try { reload(); diff --git a/src/main/java/com/ss/editor/ui/control/property/PropertyEditor.java b/src/main/java/com/ss/editor/ui/control/property/PropertyEditor.java index a151f15d..818596a9 100644 --- a/src/main/java/com/ss/editor/ui/control/property/PropertyEditor.java +++ b/src/main/java/com/ss/editor/ui/control/property/PropertyEditor.java @@ -135,7 +135,10 @@ public void refresh() { */ @FxThread public void buildFor(@Nullable final Object object, @Nullable final Object parent) { - if (getCurrentObject() == object) return; + + if (getCurrentObject() == object) { + return; + } final VBox container = getContainer(); final ObservableList children = container.getChildren(); diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilder.java index 17e1183d..86d5146e 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilder.java +++ b/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilder.java @@ -13,7 +13,7 @@ * * @author JavaSaBr */ -public interface PropertyBuilder { +public interface PropertyBuilder extends Comparable { /** * Build properties controls for the object to the container. @@ -26,4 +26,18 @@ public interface PropertyBuilder { @FxThread void buildFor(@NotNull Object object, @Nullable Object parent, @NotNull VBox container, @NotNull ChangeConsumer changeConsumer); + + /** + * Get the priority of this builder. + * + * @return the priority of this builder. + */ + default int getPriority() { + return 0; + } + + @Override + default int compareTo(@NotNull final PropertyBuilder o) { + return o.getPriority() - getPriority(); + } } diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderRegistry.java b/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderRegistry.java index b48b441f..61b9198c 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderRegistry.java +++ b/src/main/java/com/ss/editor/ui/control/property/builder/PropertyBuilderRegistry.java @@ -40,22 +40,22 @@ public class PropertyBuilderRegistry { private PropertyBuilderRegistry() { builders = ArrayFactory.newArray(PropertyBuilder.class); filters = ArrayFactory.newArray(PropertyBuilderFilter.class); - builders.add(AudioNodePropertyBuilder.getInstance()); - builders.add(ParticleEmitterPropertyBuilder.getInstance()); - builders.add(GeometryPropertyBuilder.getInstance()); - builders.add(LightPropertyBuilder.getInstance()); - builders.add(SpatialPropertyBuilder.getInstance()); - builders.add(SceneAppStatePropertyBuilder.getInstance()); - builders.add(SceneFilterPropertyBuilder.getInstance()); - builders.add(DefaultControlPropertyBuilder.getInstance()); - builders.add(EditableControlPropertyBuilder.getInstance()); - builders.add(CollisionShapePropertyBuilder.getInstance()); - builders.add(PrimitivePropertyBuilder.getInstance()); - builders.add(MeshPropertyBuilder.getInstance()); - builders.add(MaterialPropertyBuilder.getInstance()); - builders.add(ParticleInfluencerPropertyBuilder.getInstance()); - builders.add(EmitterShapePropertyBuilder.getInstance()); - builders.add(MaterialSettingsPropertyBuilder.getInstance()); + register(AudioNodePropertyBuilder.getInstance()); + register(ParticleEmitterPropertyBuilder.getInstance()); + register(GeometryPropertyBuilder.getInstance()); + register(LightPropertyBuilder.getInstance()); + register(SpatialPropertyBuilder.getInstance()); + register(SceneAppStatePropertyBuilder.getInstance()); + register(SceneFilterPropertyBuilder.getInstance()); + register(DefaultControlPropertyBuilder.getInstance()); + register(EditableControlPropertyBuilder.getInstance()); + register(CollisionShapePropertyBuilder.getInstance()); + register(PrimitivePropertyBuilder.getInstance()); + register(MeshPropertyBuilder.getInstance()); + register(MaterialPropertyBuilder.getInstance()); + register(ParticleInfluencerPropertyBuilder.getInstance()); + register(EmitterShapePropertyBuilder.getInstance()); + register(MaterialSettingsPropertyBuilder.getInstance()); } /** @@ -66,6 +66,7 @@ private PropertyBuilderRegistry() { @FromAnyThread public void register(@NotNull final PropertyBuilder builder) { builders.add(builder); + builders.sort(PropertyBuilder::compareTo); } /** diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/CollisionShapePropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/CollisionShapePropertyBuilder.java index cbac70f2..c3ae4278 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/CollisionShapePropertyBuilder.java +++ b/src/main/java/com/ss/editor/ui/control/property/builder/impl/CollisionShapePropertyBuilder.java @@ -26,11 +26,6 @@ public class CollisionShapePropertyBuilder extends AbstractPropertyBuilder> getProperties(@NotNull final AbstractControl control) { - if (object instanceof AbstractCinematicEvent) { - build((AbstractCinematicEvent) object, container, changeConsumer); - } else if (object instanceof VehicleWheel) { - build((VehicleWheel) object, container, changeConsumer); - } else if (object instanceof Animation) { - build((Animation) object, container, changeConsumer); - } - - if (!(object instanceof Control)) return; + final List> result = new ArrayList<>(); + result.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_ENABLED, control, + AbstractControl::isEnabled, AbstractControl::setEnabled)); - if (object instanceof AbstractControl) { - build((AbstractControl) object, container, changeConsumer); - } + return result; + } - super.buildForImpl(object, parent, container, changeConsumer); + @FxThread + protected @NotNull List> getProperties(@NotNull final PhysicsControl control) { - if (object instanceof SkeletonControl) { - build((SkeletonControl) object, container, changeConsumer); - } else if (object instanceof CharacterControl) { - build((CharacterControl) object, container, changeConsumer); - } else if (object instanceof RigidBodyControl) { - build((RigidBodyControl) object, container, changeConsumer); - } else if (object instanceof VehicleControl) { - build((VehicleControl) object, container, changeConsumer); - } else if (object instanceof MotionEvent) { - build((MotionEvent) object, container, changeConsumer); - } + final List> result = new ArrayList<>(); + result.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_ENABLED, control, + PhysicsControl::isEnabled, PhysicsControl::setEnabled)); - if (object instanceof PhysicsRigidBody) { - build((PhysicsRigidBody) object, container, changeConsumer); - } + return result; } - @Override @FxThread protected @Nullable List> getProperties(@NotNull final Object object) { - if (object instanceof LightControl) { + final List> properties = new ArrayList<>(); + + if (object instanceof VehicleWheel) { + + final VehicleWheel control = (VehicleWheel) object; + + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_FRONT, control, + VehicleWheel::isFrontWheel, VehicleWheel::setFrontWheel)); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, control, + VehicleWheel::isApplyLocal, VehicleWheel::setApplyLocal)); + properties.add(new SimpleProperty<>(STRING, Messages.MODEL_PROPERTY_OBJECT_ID, control, + wheel -> String.valueOf(wheel.getWheelId()))); + + properties.add(new SimpleProperty<>(SPATIAL_FROM_SCENE, Messages.MODEL_PROPERTY_WHEEL_SPATIAL, control, + VehicleWheel::getWheelSpatial, VehicleWheel::setWheelSpatial)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LOCATION, control, + VehicleWheel::getLocation)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, control, + VehicleWheel::getDirection)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_AXLE, control, + VehicleWheel::getAxle)); + + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_DAMPING_COMPRESSION, control, + VehicleWheel::getWheelsDampingCompression, VehicleWheel::setWheelsDampingCompression)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_FRICTION_SLIP, control, + VehicleWheel::getFrictionSlip, VehicleWheel::setFrictionSlip)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RADIUS, control, + VehicleWheel::getRadius, VehicleWheel::setRadius)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_FORCE, control, + VehicleWheel::getMaxSuspensionForce, VehicleWheel::setMaxSuspensionForce)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_TRAVEL_CM, control, + VehicleWheel::getMaxSuspensionTravelCm, VehicleWheel::setMaxSuspensionTravelCm)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MAX_SUSPENSION_TRAVEL_CM, control, + VehicleWheel::getMaxSuspensionTravelCm, VehicleWheel::setMaxSuspensionTravelCm)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_DAMPING_RELAXATION, control, + VehicleWheel::getWheelsDampingRelaxation, VehicleWheel::setWheelsDampingRelaxation)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_SUSPENSION_STIFFNESS, control, + VehicleWheel::getSuspensionStiffness, VehicleWheel::setSuspensionStiffness)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_REST_LENGTH, control, + VehicleWheel::getRestLength, VehicleWheel::setRestLength)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ROLL_INFLUENCE, control, + VehicleWheel::getRollInfluence, VehicleWheel::setRollInfluence)); + + } else if (object instanceof AbstractCinematicEvent) { + + final AbstractCinematicEvent control = (AbstractCinematicEvent) object; + + properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_LOOP_MODE, control, + AbstractCinematicEvent::getLoopMode, AbstractCinematicEvent::setLoopMode)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_INITIAL_DURATION, control, + AbstractCinematicEvent::getInitialDuration, AbstractCinematicEvent::setInitialDuration)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_SPEED, control, + AbstractCinematicEvent::getSpeed, AbstractCinematicEvent::setSpeed)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_TIME, control, + AbstractCinematicEvent::getTime, AbstractCinematicEvent::setTime)); - final LightControl control = (LightControl) object; + } else if (object instanceof Animation) { - final List> result = new ArrayList<>(2); - result.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_DIRECTION_TYPE, control, - LightControl::getControlDir, LightControl::setControlDir)); - result.add(new SimpleProperty<>(LIGHT_FROM_SCENE, Messages.MODEL_PROPERTY_LIGHT, control, - LightControl::getLight, LightControl::setLight)); + final Animation animation = (Animation) object; - return result; + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_LENGTH, animation, + Animation::getLength)); } - return super.getProperties(object); - } - - @FxThread - private void build(@NotNull final AbstractCinematicEvent control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final LoopMode loopMode = control.getLoopMode(); - - final float initialDuration = control.getInitialDuration(); - final float speed = control.getSpeed(); - final float time = control.getTime(); - - final EnumPropertyControl loopModeControl = - new EnumPropertyControl<>(loopMode, Messages.MODEL_PROPERTY_LOOP_MODE, changeConsumer, LOOP_MODES); - - loopModeControl.setApplyHandler(AbstractCinematicEvent::setLoopMode); - loopModeControl.setSyncHandler(AbstractCinematicEvent::getLoopMode); - loopModeControl.setEditObject(control); - - final FloatPropertyControl initialDurationControl = - new FloatPropertyControl<>(initialDuration, Messages.MODEL_PROPERTY_INITIAL_DURATION, changeConsumer); - - initialDurationControl.setApplyHandler(AbstractCinematicEvent::setInitialDuration); - initialDurationControl.setSyncHandler(AbstractCinematicEvent::getInitialDuration); - initialDurationControl.setEditObject(control); - - final FloatPropertyControl speedControl = - new FloatPropertyControl<>(speed, Messages.MODEL_PROPERTY_SPEED, changeConsumer); - - speedControl.setApplyHandler(AbstractCinematicEvent::setSpeed); - speedControl.setSyncHandler(AbstractCinematicEvent::getSpeed); - speedControl.setEditObject(control); - - final FloatPropertyControl timeControl = - new FloatPropertyControl<>(time, Messages.MODEL_PROPERTY_TIME, changeConsumer); + if (object instanceof MotionEvent) { - timeControl.setApplyHandler(AbstractCinematicEvent::setSpeed); - timeControl.setSyncHandler(AbstractCinematicEvent::getSpeed); - timeControl.setEditObject(control); - - FXUtils.addToPane(loopModeControl, container); - FXUtils.addToPane(initialDurationControl, container); - FXUtils.addToPane(speedControl, container); - FXUtils.addToPane(timeControl, container); - } - - @FxThread - private void build(@NotNull final AbstractControl control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final boolean enabled = control.isEnabled(); - - final BooleanPropertyControl enabledControl = - new BooleanPropertyControl<>(enabled, Messages.MODEL_PROPERTY_IS_ENABLED, changeConsumer); - - enabledControl.setApplyHandler(AbstractControl::setEnabled); - enabledControl.setSyncHandler(AbstractControl::isEnabled); - enabledControl.setEditObject(control); - - FXUtils.addToPane(enabledControl, container); - } - - @FxThread - private void build(@NotNull final MotionEvent control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f direction = control.getDirection(); - final Quaternion rotation = control.getRotation(); - - final MotionEvent.Direction directionType = control.getDirectionType(); - - final EnumPropertyControl directionTypeControl = - new EnumPropertyControl<>(directionType, Messages.MODEL_PROPERTY_DIRECTION_TYPE, changeConsumer, DIRECTIONS); - - directionTypeControl.setApplyHandler(MotionEvent::setDirectionType); - directionTypeControl.setSyncHandler(MotionEvent::getDirectionType); - directionTypeControl.setEditObject(control); - - final Vector3FPropertyControl directionControl = - new Vector3FPropertyControl<>(direction, Messages.MODEL_PROPERTY_DIRECTION, changeConsumer); - - directionControl.setApplyHandler(MotionEvent::setDirection); - directionControl.setSyncHandler(MotionEvent::getDirection); - directionControl.setEditObject(control); - - final QuaternionPropertyControl rotationControl = - new QuaternionPropertyControl<>(rotation, Messages.MODEL_PROPERTY_ROTATION, changeConsumer); - - rotationControl.setApplyHandler(MotionEvent::setRotation); - rotationControl.setSyncHandler(MotionEvent::getRotation); - rotationControl.setEditObject(control); - - FXUtils.addToPane(directionTypeControl, container); - - buildSplitLine(container); - - FXUtils.addToPane(directionControl, container); - FXUtils.addToPane(rotationControl, container); - } - - @FxThread - private void build(@NotNull final CharacterControl control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f viewDirection = control.getViewDirection(); - final Vector3f walkDirection = control.getWalkDirection(); - - final float fallSpeed = control.getFallSpeed(); - final float gravity = control.getGravity(); - final float jumpSpeed = control.getJumpSpeed(); - final float maxSlope = control.getMaxSlope(); - - final boolean applyPhysicsLocal = control.isApplyPhysicsLocal(); - final boolean useViewDirection = control.isUseViewDirection(); - final boolean enabled = control.isEnabled(); - - final BooleanPropertyControl enabledControl = - new BooleanPropertyControl<>(enabled, Messages.MODEL_PROPERTY_IS_ENABLED, changeConsumer); - - enabledControl.setApplyHandler(CharacterControl::setEnabled); - enabledControl.setSyncHandler(CharacterControl::isEnabled); - enabledControl.setEditObject(control); - - final Vector3FPropertyControl viewDirectionControl = - new Vector3FPropertyControl<>(viewDirection, Messages.MODEL_PROPERTY_VIEW_DIRECTION, changeConsumer); - - viewDirectionControl.setApplyHandler(CharacterControl::setViewDirection); - viewDirectionControl.setSyncHandler(CharacterControl::getViewDirection); - viewDirectionControl.setEditObject(control); - - final Vector3FPropertyControl walkDirectionControl = - new Vector3FPropertyControl<>(walkDirection, Messages.MODEL_PROPERTY_WALK_DIRECTION, changeConsumer); - - walkDirectionControl.setApplyHandler(CharacterControl::setWalkDirection); - walkDirectionControl.setSyncHandler(CharacterControl::getWalkDirection); - walkDirectionControl.setEditObject(control); - - final FloatPropertyControl fallSpeedControl = - new FloatPropertyControl<>(fallSpeed, Messages.MODEL_PROPERTY_FALL_SPEED, changeConsumer); - - fallSpeedControl.setApplyHandler(CharacterControl::setFallSpeed); - fallSpeedControl.setSyncHandler(CharacterControl::getFallSpeed); - fallSpeedControl.setEditObject(control); - - final FloatPropertyControl gravityControl = - new FloatPropertyControl<>(gravity, Messages.MODEL_PROPERTY_GRAVITY, changeConsumer); - - gravityControl.setApplyHandler(CharacterControl::setGravity); - gravityControl.setSyncHandler(CharacterControl::getGravity); - gravityControl.setEditObject(control); - - final FloatPropertyControl jumpSpeedControl = - new FloatPropertyControl<>(jumpSpeed, Messages.MODEL_PROPERTY_JUMP_SPEED, changeConsumer); - - jumpSpeedControl.setApplyHandler(CharacterControl::setJumpSpeed); - jumpSpeedControl.setSyncHandler(CharacterControl::getJumpSpeed); - jumpSpeedControl.setEditObject(control); - - final FloatPropertyControl maxSlopeControl = - new FloatPropertyControl<>(maxSlope, Messages.MODEL_PROPERTY_MAX_SLOPE, changeConsumer); - - maxSlopeControl.setApplyHandler(CharacterControl::setMaxSlope); - maxSlopeControl.setSyncHandler(CharacterControl::getMaxSlope); - maxSlopeControl.setEditObject(control); - - final BooleanPropertyControl applyPhysicsLocalControl = - new BooleanPropertyControl<>(applyPhysicsLocal, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, changeConsumer); - - applyPhysicsLocalControl.setApplyHandler(CharacterControl::setApplyPhysicsLocal); - applyPhysicsLocalControl.setSyncHandler(CharacterControl::isApplyPhysicsLocal); - applyPhysicsLocalControl.setEditObject(control); - - final BooleanPropertyControl useViewDirectionControl = - new BooleanPropertyControl<>(useViewDirection, Messages.MODEL_PROPERTY_IS_USE_VIEW_DIRECTION, changeConsumer); - - useViewDirectionControl.setApplyHandler(CharacterControl::setUseViewDirection); - useViewDirectionControl.setSyncHandler(CharacterControl::isUseViewDirection); - useViewDirectionControl.setEditObject(control); - - FXUtils.addToPane(enabledControl, container); - FXUtils.addToPane(applyPhysicsLocalControl, container); - FXUtils.addToPane(useViewDirectionControl, container); - FXUtils.addToPane(fallSpeedControl, container); - FXUtils.addToPane(gravityControl, container); - FXUtils.addToPane(jumpSpeedControl, container); - FXUtils.addToPane(maxSlopeControl, container); - - buildSplitLine(container); - - FXUtils.addToPane(viewDirectionControl, container); - FXUtils.addToPane(walkDirectionControl, container); - } - - @FxThread - private void build(@NotNull final SkeletonControl control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final boolean hardwareSkinningPreferred = control.isHardwareSkinningPreferred(); - - final BooleanPropertyControl hardwareSkinningPreferredControl = - new BooleanPropertyControl<>(hardwareSkinningPreferred, Messages.MODEL_PROPERTY_IS_HARDWARE_SKINNING_PREFERRED, changeConsumer); - - hardwareSkinningPreferredControl.setApplyHandler(SkeletonControl::setHardwareSkinningPreferred); - hardwareSkinningPreferredControl.setSyncHandler(SkeletonControl::isHardwareSkinningPreferred); - hardwareSkinningPreferredControl.setEditObject(control); - - FXUtils.addToPane(hardwareSkinningPreferredControl, container); - } + final MotionEvent control = (MotionEvent) object; - @FxThread - private void build(@NotNull final Animation animation, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final float length = animation.getLength(); - - final DefaultSinglePropertyControl lengthControl = - new DefaultSinglePropertyControl<>(length, Messages.MODEL_PROPERTY_LENGTH, changeConsumer); - - lengthControl.setSyncHandler(Animation::getLength); - lengthControl.setToStringFunction(value -> Float.toString(value)); - lengthControl.setEditObject(animation); - - FXUtils.addToPane(lengthControl, container); - } - - @FxThread - private void build(@NotNull final RigidBodyControl control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final boolean kinematicSpatial = control.isKinematicSpatial(); - final boolean enabled = control.isEnabled(); - - final BooleanPropertyControl enabledControl = - new BooleanPropertyControl<>(enabled, Messages.MODEL_PROPERTY_IS_ENABLED, changeConsumer); - - enabledControl.setApplyHandler(RigidBodyControl::setEnabled); - enabledControl.setSyncHandler(RigidBodyControl::isEnabled); - enabledControl.setEditObject(control); - - final BooleanPropertyControl kinematicSpatialControl = - new BooleanPropertyControl<>(kinematicSpatial, Messages.MODEL_PROPERTY_IS_KINEMATIC_SPATIAL, changeConsumer); - - kinematicSpatialControl.setApplyHandler(RigidBodyControl::setKinematicSpatial); - kinematicSpatialControl.setSyncHandler(RigidBodyControl::isKinematicSpatial); - kinematicSpatialControl.setEditObject(control); - - FXUtils.addToPane(enabledControl, container); - FXUtils.addToPane(kinematicSpatialControl, container); - } - - @FxThread - private void build(@NotNull final VehicleControl control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final boolean enabled = control.isEnabled(); - final boolean applyPhysicsLocal = control.isApplyPhysicsLocal(); - - final BooleanPropertyControl enabledControl = - new BooleanPropertyControl<>(enabled, Messages.MODEL_PROPERTY_IS_ENABLED, changeConsumer); - - enabledControl.setApplyHandler(VehicleControl::setEnabled); - enabledControl.setSyncHandler(VehicleControl::isEnabled); - enabledControl.setEditObject(control); - - final BooleanPropertyControl applyPhysicsLocalControl = - new BooleanPropertyControl<>(applyPhysicsLocal, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, changeConsumer); - - applyPhysicsLocalControl.setApplyHandler(VehicleControl::setApplyPhysicsLocal); - applyPhysicsLocalControl.setSyncHandler(VehicleControl::isApplyPhysicsLocal); - applyPhysicsLocalControl.setEditObject(control); - - FXUtils.addToPane(enabledControl, container); - FXUtils.addToPane(applyPhysicsLocalControl, container); - } - - @FxThread - private void build(@NotNull final VehicleWheel control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f axle = control.getAxle(); - final Vector3f direction = control.getDirection(); - final Vector3f location = control.getLocation(); - - final Spatial wheelSpatial = control.getWheelSpatial(); - - final long wheelId = control.getWheelId(); - - final float frictionSlip = control.getFrictionSlip(); - final float maxSuspensionForce = control.getMaxSuspensionForce(); - final float maxSuspensionTravelCm = control.getMaxSuspensionTravelCm(); - final float radius = control.getRadius(); - final float wheelsDampingCompression = control.getWheelsDampingCompression(); - final float restLength = control.getRestLength(); - final float rollInfluence = control.getRollInfluence(); - final float suspensionStiffness = control.getSuspensionStiffness(); - final float wheelsDampingRelaxation = control.getWheelsDampingRelaxation(); - - final boolean frontWheel = control.isFrontWheel(); - final boolean applyLocal = control.isApplyLocal(); - - final BooleanPropertyControl frontWheelControl = - new BooleanPropertyControl<>(frontWheel, Messages.MODEL_PROPERTY_IS_FRONT, changeConsumer); - - frontWheelControl.setApplyHandler(VehicleWheel::setFrontWheel); - frontWheelControl.setSyncHandler(VehicleWheel::isFrontWheel); - frontWheelControl.setEditObject(control); - - final BooleanPropertyControl applyLocalControl = - new BooleanPropertyControl<>(applyLocal, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, changeConsumer); - - applyLocalControl.setApplyHandler(VehicleWheel::setApplyLocal); - applyLocalControl.setSyncHandler(VehicleWheel::isApplyLocal); - applyLocalControl.setEditObject(control); - - final FloatPropertyControl dampingCompressionControl = - new FloatPropertyControl<>(wheelsDampingCompression, Messages.MODEL_PROPERTY_DAMPING_COMPRESSION, changeConsumer); - - dampingCompressionControl.setApplyHandler(VehicleWheel::setWheelsDampingCompression); - dampingCompressionControl.setSyncHandler(VehicleWheel::getWheelsDampingCompression); - dampingCompressionControl.setEditObject(control); - - final FloatPropertyControl frictionSlipControl = - new FloatPropertyControl<>(frictionSlip, Messages.MODEL_PROPERTY_FRICTION_SLIP, changeConsumer); - - frictionSlipControl.setApplyHandler(VehicleWheel::setFrictionSlip); - frictionSlipControl.setSyncHandler(VehicleWheel::getFrictionSlip); - frictionSlipControl.setEditObject(control); - - final FloatPropertyControl radiusControl = - new FloatPropertyControl<>(radius, Messages.MODEL_PROPERTY_RADIUS, changeConsumer); - - radiusControl.setApplyHandler(VehicleWheel::setRadius); - radiusControl.setSyncHandler(VehicleWheel::getRadius); - radiusControl.setEditObject(control); - - final FloatPropertyControl maxSuspensionForceControl = - new FloatPropertyControl<>(maxSuspensionForce, Messages.MODEL_PROPERTY_MAX_SUSPENSION_FORCE, changeConsumer); - - maxSuspensionForceControl.setApplyHandler(VehicleWheel::setMaxSuspensionForce); - maxSuspensionForceControl.setSyncHandler(VehicleWheel::getMaxSuspensionForce); - maxSuspensionForceControl.setEditObject(control); - - final FloatPropertyControl maxSuspensionTravelCmControl = - new FloatPropertyControl<>(maxSuspensionTravelCm, Messages.MODEL_PROPERTY_MAX_SUSPENSION_TRAVEL_CM, changeConsumer); - - maxSuspensionTravelCmControl.setApplyHandler(VehicleWheel::setMaxSuspensionTravelCm); - maxSuspensionTravelCmControl.setSyncHandler(VehicleWheel::getMaxSuspensionTravelCm); - maxSuspensionTravelCmControl.setEditObject(control); - - final FloatPropertyControl wheelsDampingRelaxationControl = - new FloatPropertyControl<>(wheelsDampingRelaxation, Messages.MODEL_PROPERTY_DAMPING_RELAXATION, changeConsumer); - - wheelsDampingRelaxationControl.setApplyHandler(VehicleWheel::setWheelsDampingRelaxation); - wheelsDampingRelaxationControl.setSyncHandler(VehicleWheel::getWheelsDampingRelaxation); - wheelsDampingRelaxationControl.setEditObject(control); - - final FloatPropertyControl suspensionStiffnessControl = - new FloatPropertyControl<>(suspensionStiffness, Messages.MODEL_PROPERTY_SUSPENSION_STIFFNESS, changeConsumer); - - suspensionStiffnessControl.setApplyHandler(VehicleWheel::setSuspensionStiffness); - suspensionStiffnessControl.setSyncHandler(VehicleWheel::getSuspensionStiffness); - suspensionStiffnessControl.setEditObject(control); - - final FloatPropertyControl restLengthControl = - new FloatPropertyControl<>(restLength, Messages.MODEL_PROPERTY_REST_LENGTH, changeConsumer); - - restLengthControl.setApplyHandler(VehicleWheel::setRestLength); - restLengthControl.setSyncHandler(VehicleWheel::getRestLength); - restLengthControl.setEditObject(control); - - final FloatPropertyControl rollInfluenceControl = - new FloatPropertyControl<>(rollInfluence, Messages.MODEL_PROPERTY_ROLL_INFLUENCE, changeConsumer); - - rollInfluenceControl.setApplyHandler(VehicleWheel::setRollInfluence); - rollInfluenceControl.setSyncHandler(VehicleWheel::getRollInfluence); - rollInfluenceControl.setEditObject(control); - - final WheelElementModelPropertyControl wheelSpatialControl = - new WheelElementModelPropertyControl(wheelSpatial, Messages.MODEL_PROPERTY_WHEEL_SPATIAL, changeConsumer); - - wheelSpatialControl.setApplyHandler(VehicleWheel::setWheelSpatial); - wheelSpatialControl.setSyncHandler(VehicleWheel::getWheelSpatial); - wheelSpatialControl.setEditObject(control); - - final DefaultSinglePropertyControl wheelIdControl = - new DefaultSinglePropertyControl<>(wheelId, Messages.MODEL_PROPERTY_OBJECT_ID, changeConsumer); - - wheelIdControl.setSyncHandler(VehicleWheel::getWheelId); - wheelIdControl.setToStringFunction(value -> Long.toString(value)); - wheelIdControl.setEditObject(control); - - final DefaultSinglePropertyControl locationControl = - new DefaultSinglePropertyControl<>(location, Messages.MODEL_PROPERTY_LOCATION, changeConsumer); - - locationControl.setSyncHandler(VehicleWheel::getLocation); - locationControl.setToStringFunction(Vector3f::toString); - locationControl.setEditObject(control); - - final DefaultSinglePropertyControl directionControl = - new DefaultSinglePropertyControl<>(direction, Messages.MODEL_PROPERTY_DIRECTION, changeConsumer); - - directionControl.setSyncHandler(VehicleWheel::getDirection); - directionControl.setToStringFunction(Vector3f::toString); - directionControl.setEditObject(control); - - final DefaultSinglePropertyControl axleControl = - new DefaultSinglePropertyControl<>(axle, Messages.MODEL_PROPERTY_AXLE, changeConsumer); - - axleControl.setSyncHandler(VehicleWheel::getAxle); - axleControl.setToStringFunction(Vector3f::toString); - axleControl.setEditObject(control); - - FXUtils.addToPane(frontWheelControl, container); - FXUtils.addToPane(applyLocalControl, container); - FXUtils.addToPane(dampingCompressionControl, container); - FXUtils.addToPane(frictionSlipControl, container); - FXUtils.addToPane(radiusControl, container); - FXUtils.addToPane(maxSuspensionForceControl, container); - FXUtils.addToPane(maxSuspensionTravelCmControl, container); - FXUtils.addToPane(wheelsDampingRelaxationControl, container); - FXUtils.addToPane(suspensionStiffnessControl, container); - FXUtils.addToPane(restLengthControl, container); - FXUtils.addToPane(rollInfluenceControl, container); - FXUtils.addToPane(wheelSpatialControl, container); - FXUtils.addToPane(wheelIdControl, container); - FXUtils.addToPane(locationControl, container); - FXUtils.addToPane(directionControl, container); - FXUtils.addToPane(axleControl, container); - } - - @FxThread - private void build(@NotNull final PhysicsRigidBody control, @NotNull final VBox container, - @NotNull final ModelChangeConsumer changeConsumer) { - - final Vector3f angularVelocity = control.getAngularVelocity(); - final Vector3f gravity = control.getGravity(); - final Vector3f linearFactor = control.getLinearFactor(); - - final float angularDamping = control.getAngularDamping(); - final float angularFactor = control.getAngularFactor(); - final float angularSleepingThreshold = control.getAngularSleepingThreshold(); - final float friction = control.getFriction(); - final float linearDamping = control.getLinearDamping(); - final float mass = control.getMass(); - final float restitution = control.getRestitution(); - - final boolean kinematic = control.isKinematic(); - - final BooleanPropertyControl kinematicControl = - new BooleanPropertyControl<>(kinematic, Messages.MODEL_PROPERTY_IS_KINEMATIC, changeConsumer); - - kinematicControl.setApplyHandler(PhysicsRigidBody::setKinematic); - kinematicControl.setSyncHandler(PhysicsRigidBody::isKinematic); - kinematicControl.setEditObject(control); - - final Vector3FPropertyControl angularVelocityControl = - new Vector3FPropertyControl<>(angularVelocity, Messages.MODEL_PROPERTY_ANGULAR_VELOCITY, changeConsumer); - - angularVelocityControl.setApplyHandler(PhysicsRigidBody::setAngularVelocity); - angularVelocityControl.setSyncHandler(PhysicsRigidBody::getAngularVelocity); - angularVelocityControl.setEditObject(control); - - final Vector3FPropertyControl gravityControl = - new Vector3FPropertyControl<>(gravity, Messages.MODEL_PROPERTY_GRAVITY, changeConsumer); + properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_DIRECTION_TYPE, control, + MotionEvent::getDirectionType, MotionEvent::setDirectionType)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_DIRECTION, control, + MotionEvent::getDirection, MotionEvent::setDirection)); + properties.add(new SimpleProperty<>(QUATERNION, Messages.MODEL_PROPERTY_ROTATION, control, + MotionEvent::getRotation, MotionEvent::setRotation)); + } - gravityControl.setApplyHandler(PhysicsRigidBody::setGravity); - gravityControl.setSyncHandler(PhysicsRigidBody::getGravity); - gravityControl.setEditObject(control); + if (!(object instanceof Control)) { + return properties; + } - final Vector3FPropertyControl linearFactorControl = - new Vector3FPropertyControl<>(linearFactor, Messages.MODEL_PROPERTY_LINEAR_FACTOR, changeConsumer); + if (object instanceof AbstractControl) { + properties.addAll(getProperties((AbstractControl) object)); + } - linearFactorControl.setApplyHandler(PhysicsRigidBody::setLinearFactor); - linearFactorControl.setSyncHandler(PhysicsRigidBody::getLinearFactor); - linearFactorControl.setEditObject(control); + if (object instanceof PhysicsControl) { + properties.addAll(getProperties((PhysicsControl) object)); + } - final FloatPropertyControl angularDampingControl = - new FloatPropertyControl<>(angularDamping, Messages.MODEL_PROPERTY_ANGULAR_DAMPING, changeConsumer); + if (object instanceof LightControl) { - angularDampingControl.setApplyHandler(PhysicsRigidBody::setAngularDamping); - angularDampingControl.setSyncHandler(PhysicsRigidBody::getAngularDamping); - angularDampingControl.setMinMax(0F, 1F); - angularDampingControl.setScrollPower(1F); - angularDampingControl.setEditObject(control); + final LightControl control = (LightControl) object; - final FloatPropertyControl angularFactorControl = - new FloatPropertyControl<>(angularFactor, Messages.MODEL_PROPERTY_ANGULAR_FACTOR, changeConsumer); + properties.add(new SimpleProperty<>(ENUM, Messages.MODEL_PROPERTY_DIRECTION_TYPE, control, + LightControl::getControlDir, LightControl::setControlDir)); + properties.add(new SimpleProperty<>(LIGHT_FROM_SCENE, Messages.MODEL_PROPERTY_LIGHT, control, + LightControl::getLight, LightControl::setLight)); - angularFactorControl.setApplyHandler(PhysicsRigidBody::setAngularFactor); - angularFactorControl.setSyncHandler(PhysicsRigidBody::getAngularFactor); - angularFactorControl.setEditObject(control); + } else if (object instanceof BetterCharacterControl) { + + final BetterCharacterControl control = (BetterCharacterControl) object; + + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, + BetterCharacterControl::getGravity, BetterCharacterControl::setGravity)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_VELOCITY, control, + BetterCharacterControl::getVelocity)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, + BetterCharacterControl::getViewDirection, BetterCharacterControl::setViewDirection)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_WALK_DIRECTION, control, + BetterCharacterControl::getWalkDirection, BetterCharacterControl::setWalkDirection)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_JUMP_FORCE, control, + BetterCharacterControl::getJumpForce, BetterCharacterControl::setJumpForce)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_WALK_DIRECTION, control, + BetterCharacterControl::getDuckedFactor, BetterCharacterControl::setDuckedFactor)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_PHYSICS_DAMPING, control, + BetterCharacterControl::getPhysicsDamping, BetterCharacterControl::setPhysicsDamping)); - final FloatPropertyControl angularSleepingThresholdControl = - new FloatPropertyControl<>(angularSleepingThreshold, Messages.MODEL_PROPERTY_ANGULAR_SLEEPING_THRESHOLD, changeConsumer); + } else if (object instanceof RigidBodyControl) { - angularSleepingThresholdControl.setApplyHandler(PhysicsRigidBody::setAngularSleepingThreshold); - angularSleepingThresholdControl.setSyncHandler(PhysicsRigidBody::getAngularSleepingThreshold); - angularSleepingThresholdControl.setEditObject(control); + final RigidBodyControl control = (RigidBodyControl) object; - final FloatPropertyControl frictionControl = - new FloatPropertyControl<>(friction, Messages.MODEL_PROPERTY_FRICTION, changeConsumer); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_KINEMATIC_SPATIAL, control, + RigidBodyControl::isKinematicSpatial, RigidBodyControl::setKinematicSpatial)); - frictionControl.setApplyHandler(PhysicsRigidBody::setFriction); - frictionControl.setSyncHandler(PhysicsRigidBody::getFriction); - frictionControl.setMinMax(0F, Integer.MAX_VALUE); - frictionControl.setScrollPower(10F); - frictionControl.setEditObject(control); + } else if (object instanceof SkeletonControl) { - final FloatPropertyControl linearDampingControl = - new FloatPropertyControl<>(linearDamping, Messages.MODEL_PROPERTY_LINEAR_DAMPING, changeConsumer); + final SkeletonControl control = (SkeletonControl) object; - linearDampingControl.setApplyHandler(PhysicsRigidBody::setLinearDamping); - linearDampingControl.setSyncHandler(PhysicsRigidBody::getLinearDamping); - linearDampingControl.setMinMax(0F, 1F); - linearDampingControl.setScrollPower(1F); - linearDampingControl.setEditObject(control); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_HARDWARE_SKINNING_PREFERRED, control, + SkeletonControl::isHardwareSkinningPreferred, SkeletonControl::setHardwareSkinningPreferred)); - FloatPropertyControl massControl = null; + } else if (object instanceof VehicleControl) { - if (control.getMass() != 0F) { + final VehicleControl control = (VehicleControl) object; - massControl = new FloatPropertyControl<>(mass, Messages.MODEL_PROPERTY_MASS, changeConsumer); + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_APPLY_PHYSICS_LOCAL, control, + VehicleControl::isApplyPhysicsLocal, VehicleControl::setApplyPhysicsLocal)); - massControl.setApplyHandler(PhysicsRigidBody::setMass); - massControl.setSyncHandler(PhysicsRigidBody::getMass); - massControl.setMinMax(0.0001F, Integer.MAX_VALUE); - massControl.setScrollPower(1F); - massControl.setEditObject(control); } - final FloatPropertyControl restitutionControl = - new FloatPropertyControl<>(restitution, Messages.MODEL_PROPERTY_RESTITUTION, changeConsumer); - - restitutionControl.setApplyHandler(PhysicsRigidBody::setRestitution); - restitutionControl.setSyncHandler(PhysicsRigidBody::getRestitution); - restitutionControl.setEditObject(control); - - FXUtils.addToPane(kinematicControl, container); - FXUtils.addToPane(angularDampingControl, container); - FXUtils.addToPane(angularFactorControl, container); - FXUtils.addToPane(angularSleepingThresholdControl, container); - FXUtils.addToPane(frictionControl, container); - FXUtils.addToPane(linearDampingControl, container); + if (object instanceof PhysicsRigidBody) { - if (massControl != null) { - FXUtils.addToPane(massControl, container); + final PhysicsRigidBody control = (PhysicsRigidBody) object; + + properties.add(new SimpleProperty<>(BOOLEAN, Messages.MODEL_PROPERTY_IS_KINEMATIC, control, + PhysicsRigidBody::isKinematic, PhysicsRigidBody::setKinematic)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_GRAVITY, control, + PhysicsRigidBody::getGravity, PhysicsRigidBody::setGravity)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_LINEAR_FACTOR, control, + PhysicsRigidBody::getLinearFactor, PhysicsRigidBody::setLinearFactor)); + properties.add(new SimpleProperty<>(VECTOR_3F, Messages.MODEL_PROPERTY_ANGULAR_VELOCITY, control, + PhysicsRigidBody::getAngularVelocity, PhysicsRigidBody::setAngularVelocity)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_DAMPING, control, + PhysicsRigidBody::getAngularDamping, PhysicsRigidBody::setAngularDamping)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_FACTOR, control, + PhysicsRigidBody::getAngularFactor, PhysicsRigidBody::setAngularFactor)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_ANGULAR_SLEEPING_THRESHOLD, control, + PhysicsRigidBody::getAngularSleepingThreshold, PhysicsRigidBody::setAngularSleepingThreshold)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_FRICTION, control, + PhysicsRigidBody::getFriction, PhysicsRigidBody::setFriction)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_MASS, control, + PhysicsRigidBody::getMass, PhysicsRigidBody::setMass)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_LINEAR_DAMPING, control, + PhysicsRigidBody::getLinearDamping, PhysicsRigidBody::setLinearDamping)); + properties.add(new SimpleProperty<>(FLOAT, Messages.MODEL_PROPERTY_RESTITUTION, control, + PhysicsRigidBody::getRestitution, PhysicsRigidBody::setRestitution)); } - FXUtils.addToPane(restitutionControl, container); - - buildSplitLine(container); + return properties; + } - FXUtils.addToPane(angularVelocityControl, container); - FXUtils.addToPane(gravityControl, container); - FXUtils.addToPane(linearFactorControl, container); + @Override + public int getPriority() { + return PRIORITY; } } diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableControlPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableControlPropertyBuilder.java index c56d8b94..460368ac 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableControlPropertyBuilder.java +++ b/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableControlPropertyBuilder.java @@ -20,11 +20,6 @@ public class EditableControlPropertyBuilder extends EditableModelObjectPropertyB @NotNull private static final EditableControlPropertyBuilder INSTANCE = new EditableControlPropertyBuilder(); - /** - * Get the single instance. - * - * @return the single instance - */ @FromAnyThread public static @NotNull EditableControlPropertyBuilder getInstance() { return INSTANCE; diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableObjectPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableObjectPropertyBuilder.java index d5d4bc81..1e5ab24e 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableObjectPropertyBuilder.java +++ b/src/main/java/com/ss/editor/ui/control/property/builder/impl/EditableObjectPropertyBuilder.java @@ -39,7 +39,9 @@ protected void buildForImpl(@NotNull final Object object, @Nullable final Object @NotNull final VBox container, @NotNull final C changeConsumer) { final List> properties = getProperties(object, parent, changeConsumer); - if (properties == null || properties.isEmpty()) return; + if (properties == null || properties.isEmpty()) { + return; + } for (final EditableProperty description : properties) { buildFor(container, changeConsumer, description); @@ -199,11 +201,12 @@ protected void buildFor(@NotNull final VBox container, @NotNull final C changeCo */ @FxThread protected void addControl(@NotNull final VBox container, @NotNull final EditableProperty property, - @NotNull final PropertyControl, T> propertyControl) { + @NotNull final PropertyControl, T> propertyControl) { propertyControl.setApplyHandler(EditableProperty::setValue); propertyControl.setSyncHandler(EditableProperty::getValue); propertyControl.setEditObject(property); + propertyControl.setDisable(property.isReadOnly()); FXUtils.addToPane(propertyControl, container); } diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialPropertyBuilder.java index 947a8d0b..50eee8c0 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialPropertyBuilder.java +++ b/src/main/java/com/ss/editor/ui/control/property/builder/impl/MaterialPropertyBuilder.java @@ -72,7 +72,10 @@ protected MaterialPropertyBuilder() { @Override @FxThread protected @Nullable List> getProperties(@NotNull final Object object) { - if(!(object instanceof Material)) return null; + + if(!(object instanceof Material)) { + return null; + } final Material material = (Material) object; final MaterialDef definition = material.getMaterialDef(); diff --git a/src/main/java/com/ss/editor/ui/control/property/builder/impl/SpatialPropertyBuilder.java b/src/main/java/com/ss/editor/ui/control/property/builder/impl/SpatialPropertyBuilder.java index a5dc9144..b0ab06ac 100644 --- a/src/main/java/com/ss/editor/ui/control/property/builder/impl/SpatialPropertyBuilder.java +++ b/src/main/java/com/ss/editor/ui/control/property/builder/impl/SpatialPropertyBuilder.java @@ -1,6 +1,6 @@ package com.ss.editor.ui.control.property.builder.impl; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.LOADED_MODEL_KEY; +import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; import com.jme3.math.ColorRGBA; import com.jme3.math.Quaternion; import com.jme3.math.Vector2f; @@ -35,6 +35,8 @@ */ public class SpatialPropertyBuilder extends AbstractPropertyBuilder { + public static final int PRIORITY = 1; + @NotNull private static final CullHint[] CULL_HINTS = CullHint.values(); @@ -47,11 +49,6 @@ public class SpatialPropertyBuilder extends AbstractPropertyBuilder(location, Messages.MODEL_PROPERTY_LOCATION, changeConsumer); locationControl.setApplyHandler(Spatial::setLocalTranslation); locationControl.setSyncHandler(Spatial::getLocalTranslation); - locationControl.setEditObject(spatial); final Vector3FPropertyControl scaleControl = @@ -262,11 +258,16 @@ protected void buildForImpl(@NotNull final Object object, @Nullable final Object @FxThread private boolean isNeedSkip(@NotNull final String key) { - return SceneLayer.KEY.equals(key) || LOADED_MODEL_KEY.equals(key); + return SceneLayer.KEY.equals(key) || KEY_LOADED_MODEL.equals(key); } @FxThread private boolean canEditTransformation(@NotNull final Spatial spatial) { return !(spatial instanceof SceneNode || spatial instanceof SceneLayer); } + + @Override + public int getPriority() { + return PRIORITY; + } } diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/AudioKeyPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/AudioKeyPropertyControl.java index a5ab162b..d50094b8 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/AudioKeyPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/AudioKeyPropertyControl.java @@ -32,6 +32,7 @@ /** * The implementation of the {@link PropertyControl} to edit the {@link AudioData}. * + * @param the change consumer's type. * @author JavaSaBr */ public class AudioKeyPropertyControl extends PropertyControl { @@ -148,14 +149,18 @@ private void addAudioData(@NotNull final Path file) { protected void processOpen() { final AudioKey element = getPropertyValue(); - if (element == null) return; + if (element == null) { + return; + } final String assetPath = element.getName(); if (StringUtils.isEmpty(assetPath)) return; final Path assetFile = Paths.get(assetPath); final Path realFile = notNull(getRealFile(assetFile)); - if (!Files.exists(realFile)) return; + if (!Files.exists(realFile)) { + return; + } final RequestedOpenFileEvent event = new RequestedOpenFileEvent(); event.setFile(realFile); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/BooleanPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/BooleanPropertyControl.java index 49501158..610ddfc0 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/BooleanPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/BooleanPropertyControl.java @@ -21,8 +21,8 @@ /** * The implementation of the {@link PropertyControl} to change boolean values. * - * @param the type of a {@link ChangeConsumer} - * @param the type of an editing object + * @param the type of a {@link ChangeConsumer}. + * @param the type of an editing object. * @author JavaSaBr */ public class BooleanPropertyControl extends PropertyControl { diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/ColorPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/ColorPropertyControl.java index 09cb3d7d..e9af5a9f 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/ColorPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/ColorPropertyControl.java @@ -17,7 +17,7 @@ /** * The implementation of the {@link PropertyControl} to edit a color values. * - * @param the type parameter + * @param the change * @param the type parameter * @author JavaSaBr */ @@ -89,7 +89,10 @@ protected void reload() { */ @FxThread private void updateValue() { - if (isIgnoreListener()) return; + + if (isIgnoreListener()) { + return; + } final ColorPicker colorPicker = getColorPicker(); final ColorRGBA newColor = UiUtils.from(colorPicker.getValue()); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/DefaultPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/DefaultPropertyControl.java index 332a22d8..b520ec12 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/DefaultPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/DefaultPropertyControl.java @@ -17,9 +17,9 @@ /** * The default implementation of the property control. * - * @param the type parameter - * @param the type parameter - * @param the type parameter + * @param the change consumer's type. + * @param the edited object's type. + * @param the edited property's type. * @author JavaSaBr */ public class DefaultPropertyControl extends PropertyControl { diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/DefaultSinglePropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/DefaultSinglePropertyControl.java index 22853d85..d9dd6c88 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/DefaultSinglePropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/DefaultSinglePropertyControl.java @@ -10,9 +10,9 @@ /** * The default implementation of the property control. * - * @param the type parameter - * @param the type parameter - * @param the type parameter + * @param the change consumer's type. + * @param the edited object's type. + * @param the edited property's type. * @author JavaSaBr */ public class DefaultSinglePropertyControl extends DefaultPropertyControl { diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/DirectionLightPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/DirectionLightPropertyControl.java index d02a8a64..bdf9af67 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/DirectionLightPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/DirectionLightPropertyControl.java @@ -8,7 +8,7 @@ /** * The implementation of the {@link Vector3FPropertyControl} to edit direction's vector of the {@link Light}. * - * @param the type parameter + * @param the light's type. * @author JavaSaBr */ public class DirectionLightPropertyControl extends Vector3FPropertyControl { diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/ElementModelPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/ElementModelPropertyControl.java index 455a3342..7b1ebfa5 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/ElementModelPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/ElementModelPropertyControl.java @@ -39,9 +39,9 @@ protected void processAdd() { } /** - * Process add. + * Process of adding the new element. * - * @param newElement the new element + * @param newElement the new element. */ @FxThread protected void processAdd(@NotNull final T newElement) { diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/EnumPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/EnumPropertyControl.java index 4c953728..c8f5ac45 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/EnumPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/EnumPropertyControl.java @@ -83,7 +83,10 @@ protected void createComponents(@NotNull final HBox container) { */ @FxThread private void change() { - if (isIgnoreListener()) return; + + if (isIgnoreListener()) { + return; + } final ComboBox enumComboBox = getEnumComboBox(); final SingleSelectionModel selectionModel = enumComboBox.getSelectionModel(); @@ -95,9 +98,7 @@ private void change() { @Override @FxThread protected void reload() { - final E element = getPropertyValue(); - final ComboBox enumComboBox = getEnumComboBox(); final SingleSelectionModel selectionModel = enumComboBox.getSelectionModel(); selectionModel.select(element); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/FloatArrayPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/FloatArrayPropertyControl.java index a7a05495..cc48b5ec 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/FloatArrayPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/FloatArrayPropertyControl.java @@ -22,8 +22,8 @@ /** * The implementation of the {@link PropertyControl} to edit float array values. * - * @param the type parameter - * @param the type parameter + * @param the change consumer's type. + * @param the edited object's type. * @author JavaSaBr */ public class FloatArrayPropertyControl extends PropertyControl { @@ -106,7 +106,10 @@ protected void reload() { */ @FxThread private void updateValue(@Nullable final KeyEvent event) { - if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) return; + + if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) { + return; + } final String textValue = getValueField().getText(); float[] newValue = null; diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/FloatPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/FloatPropertyControl.java index e6f94b19..d3d0f30f 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/FloatPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/FloatPropertyControl.java @@ -18,8 +18,8 @@ /** * The implementation of the {@link PropertyControl} to edit float values. * - * @param the type parameter - * @param the type parameter + * @param the change consumer's type. + * @param the edited object's type. * @author JavaSaBr */ public class FloatPropertyControl extends PropertyControl { @@ -125,7 +125,10 @@ protected void reload() { */ @FxThread private void updateValue() { - if (isIgnoreListener()) return; + + if (isIgnoreListener()) { + return; + } final FloatTextField valueField = getValueField(); final float value = valueField.getValue(); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/IntArrayPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/IntArrayPropertyControl.java index 9d6ffb8f..b5c6c46b 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/IntArrayPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/IntArrayPropertyControl.java @@ -22,8 +22,8 @@ /** * The implementation of the {@link PropertyControl} to edit int array values. * - * @param the type parameter - * @param the type parameter + * @param the change consumer's type. + * @param the edited object's type. * @author JavaSaBr */ public class IntArrayPropertyControl extends PropertyControl { @@ -106,7 +106,10 @@ protected void reload() { */ @FxThread private void updateValue(@Nullable final KeyEvent event) { - if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) return; + + if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) { + return; + } final String textValue = getValueField().getText(); int[] newValue = null; diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/IntegerPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/IntegerPropertyControl.java index 17ff1c14..064aac06 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/IntegerPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/IntegerPropertyControl.java @@ -15,8 +15,8 @@ /** * The implementation of the {@link PropertyControl} to edit integer values. * - * @param the type of {@link ChangeConsumer} - * @param the type of edited object + * @param the type of {@link ChangeConsumer}. + * @param the type of edited object. * @author JavaSaBr */ public class IntegerPropertyControl extends PropertyControl { @@ -115,7 +115,10 @@ protected void reload() { */ @FxThread private void updateValue() { - if (isIgnoreListener()) return; + + if (isIgnoreListener()) { + return; + } final IntegerTextField valueField = getValueField(); final int value = valueField.getValue(); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/LodLevelPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/LodLevelPropertyControl.java index 60f6af39..9d3e34e3 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/LodLevelPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/LodLevelPropertyControl.java @@ -118,7 +118,10 @@ private void updateLevel(@Nullable final Integer newValue) { @Override @FxThread protected void reload() { - if (!hasEditObject()) return; + + if (!hasEditObject()) { + return; + } final Geometry geometry = getEditObject(); final Mesh mesh = geometry.getMesh(); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/MaterialKeyPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/MaterialKeyPropertyControl.java index fcbaa7e4..4e4d933c 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/MaterialKeyPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/MaterialKeyPropertyControl.java @@ -56,14 +56,20 @@ protected void addMaterial(@NotNull final Path file) { protected void processEdit() { final MaterialKey element = getPropertyValue(); - if (element == null) return; + if (element == null) { + return; + } final String assetPath = element.getName(); - if (StringUtils.isEmpty(assetPath)) return; + if (StringUtils.isEmpty(assetPath)) { + return; + } final Path assetFile = Paths.get(assetPath); final Path realFile = notNull(getRealFile(assetFile)); - if (!Files.exists(realFile)) return; + if (!Files.exists(realFile)) { + return; + } final RequestedOpenFileEvent event = new RequestedOpenFileEvent(); event.setFile(realFile); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/MinMaxPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/MinMaxPropertyControl.java index dc86d3c2..59668649 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/MinMaxPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/MinMaxPropertyControl.java @@ -12,8 +12,8 @@ /** * The implementation of the {@link Vector2FPropertyControl} to edit min-max value range. * - * @param the type parameter - * @param the type parameter + * @param the change consumer's type. + * @param the edited object's type. * @author JavaSaBr */ public class MinMaxPropertyControl extends Vector2FPropertyControl { diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/QuaternionPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/QuaternionPropertyControl.java index 5c96e4cf..085c46b7 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/QuaternionPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/QuaternionPropertyControl.java @@ -22,8 +22,8 @@ /** * The implementation of the {@link PropertyControl} to edit {@link Quaternion} values. * - * @param the type parameter - * @param the type parameter + * @param the change consumer's type. + * @param the edited object's type. * @author JavaSaBr */ public class QuaternionPropertyControl extends PropertyControl { @@ -152,7 +152,10 @@ protected void reload() { */ @FxThread private void updateRotation(@Nullable final KeyEvent event) { - if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) return; + + if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) { + return; + } final Quaternion oldValue = notNull(getPropertyValue()); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/StringPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/StringPropertyControl.java index 88ebe0f7..fd5e05ea 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/StringPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/StringPropertyControl.java @@ -76,7 +76,10 @@ protected void reload() { */ @FxThread private void updateValue(@NotNull final KeyEvent event) { - if (isIgnoreListener() || event.getCode() != KeyCode.ENTER) return; + + if (isIgnoreListener() || event.getCode() != KeyCode.ENTER) { + return; + } final TextField valueField = getValueField(); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/Vector2FPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/Vector2FPropertyControl.java index e2f008a2..4f4e7228 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/Vector2FPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/Vector2FPropertyControl.java @@ -177,7 +177,10 @@ protected void reload() { */ @FxThread private void updateVector(@Nullable final KeyEvent event) { - if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) return; + + if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) { + return; + } final FloatTextField xField = getXField(); final float x = xField.getValue(); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/Vector3FPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/Vector3FPropertyControl.java index 05e23a36..914d2abf 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/Vector3FPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/Vector3FPropertyControl.java @@ -174,7 +174,10 @@ protected void reload() { */ @FxThread protected void updateVector(@Nullable final KeyEvent event) { - if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) return; + + if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) { + return; + } final FloatTextField xField = getXField(); final float x = xField.getValue(); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/Vector3FSingleRowPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/Vector3FSingleRowPropertyControl.java index ea904e4d..9df5a1b9 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/Vector3FSingleRowPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/Vector3FSingleRowPropertyControl.java @@ -19,8 +19,8 @@ /** * The implementation of the {@link PropertyControl} to edit {@link com.jme3.math.Vector3f} values. * - * @param the type parameter - * @param the type parameter + * @param the change consumer's type. + * @param the edited object's type. * @author JavaSaBr. */ public class Vector3FSingleRowPropertyControl extends PropertyControl { @@ -217,7 +217,10 @@ protected void reload() { */ @FxThread private void updateVector(@Nullable final KeyEvent event) { - if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) return; + + if (isIgnoreListener() || (event != null && event.getCode() != KeyCode.ENTER)) { + return; + } final FloatTextField xField = getXField(); final float x = xField.getValue(); diff --git a/src/main/java/com/ss/editor/ui/control/property/impl/WheelElementModelPropertyControl.java b/src/main/java/com/ss/editor/ui/control/property/impl/WheelElementModelPropertyControl.java index 08368860..bda07a2c 100644 --- a/src/main/java/com/ss/editor/ui/control/property/impl/WheelElementModelPropertyControl.java +++ b/src/main/java/com/ss/editor/ui/control/property/impl/WheelElementModelPropertyControl.java @@ -41,13 +41,17 @@ public WheelElementModelPropertyControl(@Nullable final Spatial propertyValue, @ private boolean checkSpatial(@NotNull final Spatial spatial) { final VehicleControl control = spatial.getControl(VehicleControl.class); - if (control == null) return false; + if (control == null) { + return false; + } final int numWheels = control.getNumWheels(); for (int i = 0; i < numWheels; i++) { final VehicleWheel wheel = control.getWheel(i); - if (wheel == getEditObject()) return true; + if (wheel == getEditObject()) { + return true; + } } return false; diff --git a/src/main/java/com/ss/editor/ui/control/property/operation/PropertyOperation.java b/src/main/java/com/ss/editor/ui/control/property/operation/PropertyOperation.java index 35efd1e6..98c70b8b 100644 --- a/src/main/java/com/ss/editor/ui/control/property/operation/PropertyOperation.java +++ b/src/main/java/com/ss/editor/ui/control/property/operation/PropertyOperation.java @@ -47,14 +47,6 @@ public class PropertyOperation extends AbstractE */ private BiConsumer applyHandler; - /** - * Instantiates a new Abstract property operation. - * - * @param target the target - * @param propertyName the property name - * @param newValue the new value - * @param oldValue the old value - */ public PropertyOperation(@NotNull final D target, @NotNull final String propertyName, @Nullable final T newValue, @Nullable final T oldValue) { this.newValue = newValue; @@ -67,8 +59,9 @@ public PropertyOperation(@NotNull final D target, @NotNull final String property @FxThread protected void redoImpl(@NotNull final C editor) { EXECUTOR_MANAGER.addJmeTask(() -> { + editor.notifyJmePreChangeProperty(target, propertyName); apply(target, newValue); - editor.notifyJmeChangeProperty(target, propertyName); + editor.notifyJmeChangedProperty(target, propertyName); EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(target, propertyName)); }); } @@ -77,8 +70,9 @@ protected void redoImpl(@NotNull final C editor) { @FxThread protected void undoImpl(@NotNull final C editor) { EXECUTOR_MANAGER.addJmeTask(() -> { + editor.notifyJmePreChangeProperty(target, propertyName); apply(target, oldValue); - editor.notifyJmeChangeProperty(target, propertyName); + editor.notifyJmeChangedProperty(target, propertyName); EXECUTOR_MANAGER.addFxTask(() -> editor.notifyFxChangeProperty(target, propertyName)); }); } diff --git a/src/main/java/com/ss/editor/ui/control/scene/SceneNodeTree.java b/src/main/java/com/ss/editor/ui/control/scene/SceneNodeTree.java index 67cd8382..170aaffa 100644 --- a/src/main/java/com/ss/editor/ui/control/scene/SceneNodeTree.java +++ b/src/main/java/com/ss/editor/ui/control/scene/SceneNodeTree.java @@ -2,6 +2,8 @@ import com.ss.editor.model.undo.editor.SceneChangeConsumer; import com.ss.editor.ui.control.tree.NodeTree; +import com.ss.rlib.util.array.Array; +import javafx.scene.control.SelectionMode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,7 +16,7 @@ */ public class SceneNodeTree extends NodeTree { - public SceneNodeTree(@NotNull final Consumer selectionHandler, @Nullable final SceneChangeConsumer consumer) { - super(selectionHandler, consumer); + public SceneNodeTree(@NotNull final Consumer> selectionHandler, @Nullable final SceneChangeConsumer consumer) { + super(selectionHandler, consumer, SelectionMode.SINGLE); } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/NodeTree.java b/src/main/java/com/ss/editor/ui/control/tree/NodeTree.java index d2c7bef2..6c474f60 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/NodeTree.java +++ b/src/main/java/com/ss/editor/ui/control/tree/NodeTree.java @@ -8,14 +8,21 @@ import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.ui.control.tree.node.factory.TreeNodeFactoryRegistry; import com.ss.editor.ui.css.CssClasses; +import com.ss.editor.util.LocalObjects; +import com.ss.rlib.function.TripleConsumer; import com.ss.rlib.ui.util.FXUtils; import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayCollectors; +import com.ss.rlib.util.array.ArrayFactory; +import javafx.beans.value.ObservableValue; import javafx.collections.ObservableList; import javafx.scene.control.*; import javafx.scene.layout.VBox; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.Objects; import java.util.function.Consumer; /** @@ -30,7 +37,7 @@ public class NodeTree extends VBox { * The executor manager. */ @NotNull - private static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); + protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); /** * The tree node factory. @@ -38,11 +45,28 @@ public class NodeTree extends VBox { @NotNull protected static final TreeNodeFactoryRegistry FACTORY_REGISTRY = TreeNodeFactoryRegistry.getInstance(); + /** + * The list of action fillers. + */ + @NotNull + private static final Array, List, Array>>> MULTI_ITEMS_ACTION_FILLERS = + ArrayFactory.newArray(TripleConsumer.class); + + /** + * Register the new multi items action filler. + * + * @param actionFiller the new multi items action filler. + */ + @FxThread + public static void register(@NotNull final TripleConsumer, List, Array>> actionFiller) { + MULTI_ITEMS_ACTION_FILLERS.add(actionFiller); + } + /** * The handler of selected objects. */ @NotNull - private final Consumer selectionHandler; + private final Consumer> selectionHandler; /** * The consumer of changes of the model. @@ -50,15 +74,27 @@ public class NodeTree extends VBox { @Nullable private final C changeConsumer; + /** + * The selection mode. + */ + @NotNull + private final SelectionMode selectionMode; + /** * The tree with structure of the model. */ @Nullable private TreeView> treeView; - public NodeTree(@NotNull final Consumer selectionHandler, @Nullable final C consumer) { + public NodeTree(@NotNull final Consumer> selectionHandler, @Nullable final C consumer) { + this(selectionHandler, consumer, SelectionMode.SINGLE); + } + + public NodeTree(@NotNull final Consumer> selectionHandler, @Nullable final C consumer, + @NotNull final SelectionMode selectionMode) { this.selectionHandler = selectionHandler; this.changeConsumer = consumer; + this.selectionMode = selectionMode; createComponents(); FXUtils.addClassTo(this, CssClasses.ABSTRACT_NODE_TREE_CONTAINER); } @@ -78,7 +114,8 @@ protected void createComponents() { treeView.prefWidthProperty().bind(widthProperty()); final MultipleSelectionModel>> selectionModel = treeView.getSelectionModel(); - selectionModel.selectedItemProperty().addListener((observable, oldValue, newValue) -> processSelect(newValue)); + selectionModel.setSelectionMode(selectionMode); + selectionModel.selectedItemProperty().addListener(this::updateSelection); FXUtils.addToPane(treeView, this); } @@ -97,18 +134,27 @@ protected void createComponents() { * Select the item. */ @FxThread - private void processSelect(@Nullable final TreeItem> treeItem) { + private void updateSelection(@NotNull final ObservableValue>> observable, + @Nullable final TreeItem> oldValue, + @Nullable final TreeItem> treeItem) { - if (treeItem == null) { - selectionHandler.accept(null); - return; + final ObservableList>> selectedItems = getTreeView() + .getSelectionModel() + .getSelectedItems(); + + final Array objects = LocalObjects.get().nextObjectArray(); + objects.clear(); + + for (final TreeItem> selectedItem : selectedItems) { + if (selectedItem == null) continue; + objects.add(selectedItem.getValue()); } - selectionHandler.accept(treeItem.getValue()); + selectionHandler.accept(objects); } /** - * Gets tree view. + * Get the tree view. * * @return the tree of this model. */ @@ -149,10 +195,11 @@ private void fill(@NotNull final TreeItem> treeItem, final boolean e treeItem.setExpanded(expanded || level == 1); final TreeNode element = treeItem.getValue(); - if (!element.hasChildren(this)) return; + if (!element.hasChildren(this)) { + return; + } final ObservableList>> items = treeItem.getChildren(); - final Array> children = element.getChildren(this); children.forEach(child -> { element.notifyChildPreAdd(child); @@ -195,7 +242,9 @@ private void expandToLevel(final TreeItem> item, final int currentLe public void refresh(@NotNull final Object object) { final TreeItem> treeItem = findItemForValue(getTreeView(), object); - if (treeItem == null) return; + if (treeItem == null) { + return; + } final TreeNode treeNode = treeItem.getValue(); final ObservableList>> items = treeItem.getChildren(); @@ -205,7 +254,9 @@ public void refresh(@NotNull final Object object) { final TreeNode selected = getSelected(); final TreeNode element = treeItem.getValue(); - if (!element.hasChildren(this)) return; + if (!element.hasChildren(this)) { + return; + } final Array> children = element.getChildren(this); children.forEach(child -> items.add(new TreeItem<>(child))); @@ -214,7 +265,7 @@ public void refresh(@NotNull final Object object) { treeItem.setExpanded(expanded); if (selected == treeNode) { - select(treeNode); + selectSingle(treeNode); } } @@ -238,26 +289,46 @@ public void update(@NotNull final TreeNode treeNode) { /** * Get the context menu for the element. * - * @param treeNode the model node - * @return the context menu + * @param requestedNode the requested node. + * @return the context menu. */ @FxThread - public ContextMenu getContextMenu(@NotNull final TreeNode treeNode) { + public ContextMenu getContextMenu(@Nullable final TreeNode requestedNode) { final C changeConsumer = getChangeConsumer(); if (changeConsumer == null) { return null; } - final ContextMenu contextMenu = new ContextMenu(); - final ObservableList items = contextMenu.getItems(); - treeNode.fillContextMenu(this, items); + final ObservableList>> selectedItems = getTreeView() + .getSelectionModel() + .getSelectedItems(); - if (items.isEmpty()) { + if (selectedItems.isEmpty()) { return null; } - treeNode.handleResultContextMenu(this, items); + final ContextMenu contextMenu = new ContextMenu(); + final ObservableList items = contextMenu.getItems(); + + if (selectedItems.size() == 1 && requestedNode != null) { + + requestedNode.fillContextMenu(this, items); + + if (items.isEmpty()) { + return null; + } + + requestedNode.handleResultContextMenu(this, items); + + } else { + + final Array> treeNodes = selectedItems.stream() + .map(TreeItem::getValue) + .collect(ArrayCollectors.toArray(TreeNode.class)); + + MULTI_ITEMS_ACTION_FILLERS.forEach(filler -> filler.accept(this, items, treeNodes)); + } return contextMenu; } @@ -309,7 +380,7 @@ private void notifyMoved(@Nullable final TreeNode prevParent, @Nullable final newParentTreeNode.notifyChildAdded(node); - EXECUTOR_MANAGER.addFxTask(() -> select(node.getElement())); + EXECUTOR_MANAGER.addFxTask(() -> selectSingle(node.getElement())); } /** @@ -322,10 +393,11 @@ private void notifyMoved(@Nullable final TreeNode prevParent, @Nullable final public void notifyChanged(@Nullable Object parent, @NotNull final Object object) { final TreeItem> treeItem = tryToFindItem(parent, object); - if (treeItem == null) return; + if (treeItem == null) { + return; + } final TreeItem> parentItem = treeItem.getParent(); - if (parentItem == null) { final TreeNode node = treeItem.getValue(); treeItem.setValue(null); @@ -387,7 +459,9 @@ public void notifyReplace(@Nullable final Object parent, @Nullable final Object parentNode.notifyChildRemoved(oldChildNode); } - if (newChild == null) return; + if (newChild == null) { + return; + } final TreeItem> childItem = new TreeItem<>(FACTORY_REGISTRY.createFor(newChild)); final TreeNode newChildNode = childItem.getValue(); @@ -398,35 +472,47 @@ public void notifyReplace(@Nullable final Object parent, @Nullable final Object children.add(index, childItem); parentNode.notifyChildAdded(newChildNode); - if (needSelect) selectionModel.select(childItem); + if (needSelect) { + selectionModel.select(childItem); + } } /** * Notify about adding the element. * - * @param parent the parent - * @param child the child - * @param index the index + * @param parent the parent. + * @param child the child. + * @param index the index. */ @FxThread public void notifyAdded(@Nullable final Object parent, @Nullable final Object child, final int index) { - if (child == null || parent == null) return; + + if (child == null || parent == null) { + return; + } final TreeView> treeView = getTreeView(); final TreeItem> parentItem = findItemForValue(treeView, parent); - if (parentItem == null) return; + if (parentItem == null || findItemForValue(parentItem, child) != null) { + return; + } final TreeNode childNode = FACTORY_REGISTRY.createFor(child); - if (childNode == null) return; + if (childNode == null) { + return; + } final TreeNode parentNode = parentItem.getValue(); parentNode.notifyChildPreAdd(childNode); final TreeItem> childItem = new TreeItem<>(childNode); - final ObservableList>> children = parentItem.getChildren(); - if (index == -1) children.add(childItem); - else children.add(index, childItem); + + if (index == -1) { + children.add(childItem); + } else { + children.add(index, childItem); + } parentItem.setExpanded(true); parentNode.notifyChildAdded(childNode); @@ -444,7 +530,9 @@ public void notifyAdded(@Nullable final Object parent, @Nullable final Object ch public void notifyRemoved(@Nullable final Object parent, @NotNull final Object child) { final TreeItem> treeItem = tryToFindItem(parent, child); - if (treeItem == null) return; + if (treeItem == null) { + return; + } final TreeItem> parentItem = treeItem.getParent(); final TreeNode parentNode = parentItem.getValue(); @@ -493,7 +581,9 @@ public void notifyRemoved(@Nullable final Object parent, @NotNull final Object c public @Nullable TreeNode findParent(@NotNull final TreeNode treeNode) { final TreeItem> treeItem = findItemForValue(getTreeView(), treeNode); - if (treeItem == null) return null; + if (treeItem == null) { + return null; + } final TreeItem> parent = treeItem.getParent(); return parent == null ? null : parent.getValue(); @@ -509,7 +599,9 @@ public void startEdit(@NotNull final TreeNode treeNode) { final TreeView> treeView = getTreeView(); final TreeItem> treeItem = findItemForValue(treeView, treeNode); - if (treeItem == null) return; + if (treeItem == null) { + return; + } treeView.edit(treeItem); } @@ -517,16 +609,16 @@ public void startEdit(@NotNull final TreeNode treeNode) { /** * Select the object in the tree. * - * @param object the object + * @param object the object. */ @FxThread - public void select(@Nullable final Object object) { + public void selectSingle(@Nullable final Object object) { final TreeView> treeView = getTreeView(); final MultipleSelectionModel>> selectionModel = treeView.getSelectionModel(); if (object == null) { - selectionModel.select(null); + selectionModel.clearSelection(); return; } @@ -534,17 +626,37 @@ public void select(@Nullable final Object object) { final TreeItem> treeItem = findItemForValue(treeView, treeNode); if (treeItem == null) { - selectionModel.select(null); + selectionModel.clearSelection(); return; } + selectionModel.clearSelection(); selectionModel.select(treeItem); } /** - * Gets selected. + * Select the objects in the tree. * - * @return the selected + * @param objects the objects. + */ + @FxThread + public void selects(@NotNull final Array objects) { + + final TreeView> treeView = getTreeView(); + final MultipleSelectionModel>> selectionModel = treeView.getSelectionModel(); + selectionModel.clearSelection(); + + objects.stream().map(FACTORY_REGISTRY::createFor) + .filter(Objects::nonNull) + .map(node -> findItemForValue(treeView, node)) + .filter(Objects::nonNull) + .forEach(selectionModel::select); + } + + /** + * Get the selected item. + * + * @return the selected item or null. */ @FxThread public @Nullable TreeNode getSelected() { @@ -560,6 +672,33 @@ public void select(@Nullable final Object object) { return selectedItem.getValue(); } + /** + * Get the current selected items count. + * + * @return the current selected items count. + */ + @FxThread + public int getSelectedCount() { + final TreeView> treeView = getTreeView(); + return treeView.getSelectionModel() + .getSelectedItems().size(); + } + + /** + * Get the selected nodes. + * + * @return the selected nodes. + */ + @FxThread + public @NotNull Array> getSelectedItems() { + final TreeView> treeView = getTreeView(); + return treeView.getSelectionModel() + .getSelectedItems() + .stream() + .map(TreeItem::getValue) + .collect(ArrayCollectors.toArray(TreeNode.class)); + } + /** * Gets selected object. * diff --git a/src/main/java/com/ss/editor/ui/control/tree/NodeTreeCell.java b/src/main/java/com/ss/editor/ui/control/tree/NodeTreeCell.java index d911e7e8..0bb3a203 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/NodeTreeCell.java +++ b/src/main/java/com/ss/editor/ui/control/tree/NodeTreeCell.java @@ -4,6 +4,7 @@ import static com.ss.editor.ui.util.UiUtils.findItemForValue; import static com.ss.rlib.util.ClassUtils.unsafeCast; import static com.ss.rlib.util.ObjectUtils.notNull; +import com.ss.editor.annotation.FxThread; import com.ss.editor.manager.ExecutorManager; import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.ui.Icons; @@ -66,7 +67,9 @@ public String toString(@Nullable final TreeNode object) { public TreeNode fromString(@NotNull final String string) { final TreeNode item = getItem(); - if (item == null) return null; + if (item == null) { + return null; + } item.changeName(getNodeTree(), string); @@ -202,6 +205,7 @@ public NodeTreeCell(@NotNull final M nodeTree) { /** * Update hide status. */ + @FxThread private void processHide(@NotNull final MouseEvent event) { event.consume(); @@ -222,11 +226,16 @@ private void processHide(@NotNull final MouseEvent event) { } @Override + @FxThread public void startEdit() { - if (!isEditable()) return; + if (!isEditable()) { + return; + } final TreeItem> treeItem = getTreeItem(); - if (treeItem != null) treeItem.setGraphic(null); + if (treeItem != null) { + treeItem.setGraphic(null); + } setIgnoreUpdate(true); try { @@ -242,6 +251,7 @@ public void startEdit() { /** * @return true if need to ignore update. */ + @FxThread private boolean isIgnoreUpdate() { return ignoreUpdate; } @@ -249,39 +259,59 @@ private boolean isIgnoreUpdate() { /** * @param ignoreUpdate the flag of ignoring updates. */ + @FxThread private void setIgnoreUpdate(final boolean ignoreUpdate) { this.ignoreUpdate = ignoreUpdate; } @Override + @FxThread public void cancelEdit() { super.cancelEdit(); + editing.setValue(false); + final TreeItem> treeItem = getTreeItem(); - if (treeItem != null) treeItem.setGraphic(content); + if (treeItem != null) { + treeItem.setGraphic(content); + } + setText(StringUtils.EMPTY); } @Override + @FxThread public void commitEdit(@NotNull final TreeNode newValue) { super.commitEdit(newValue); + editing.setValue(false); + final TreeItem> treeItem = getTreeItem(); - if (treeItem != null) treeItem.setGraphic(content); + if (treeItem != null) { + treeItem.setGraphic(content); + } + setText(StringUtils.EMPTY); } /** - * @return the icon of node. + * Get the icon. + * + * @return the icon. */ + @FxThread private @NotNull ImageView getIcon() { return icon; } @Override + @FxThread public void updateItem(@Nullable final TreeNode item, final boolean empty) { super.updateItem(item, empty); - if (isIgnoreUpdate()) return; + + if (isIgnoreUpdate()) { + return; + } final ImageView icon = getIcon(); @@ -324,10 +354,11 @@ public void updateItem(@Nullable final TreeNode item, final boolean empty) { } /** - * Gets node tree. + * Get the node tree. * - * @return the tree. + * @return the node tree. */ + @FxThread protected @NotNull M getNodeTree() { return nodeTree; } @@ -335,17 +366,24 @@ public void updateItem(@Nullable final TreeNode item, final boolean empty) { /** * Handle a mouse click. */ + @FxThread private void processClick(@NotNull final MouseEvent event) { final TreeNode item = getItem(); - if (item == null) return; + if (item == null) { + return; + } final MouseButton button = event.getButton(); - if (button != MouseButton.SECONDARY) return; + if (button != MouseButton.SECONDARY) { + return; + } final M nodeTree = getNodeTree(); final ContextMenu contextMenu = nodeTree.getContextMenu(item); - if (contextMenu == null) return; + if (contextMenu == null) { + return; + } EXECUTOR_MANAGER.addFxTask(() -> contextMenu.show(this, Side.BOTTOM, 0, 0)); } @@ -353,6 +391,7 @@ private void processClick(@NotNull final MouseEvent event) { /** * Handle stopping dragging. */ + @FxThread private void stopDrag(@NotNull final DragEvent event) { dragged.setValue(false); setCursor(Cursor.DEFAULT); @@ -362,18 +401,25 @@ private void stopDrag(@NotNull final DragEvent event) { /** * Handle starting dragging. */ + @FxThread private void startDrag(@NotNull final MouseEvent mouseEvent) { final TreeNode item = getItem(); - if (item == null) return; + if (item == null) { + return; + } final TreeView> treeView = getTreeView(); final TreeItem> treeItem = findItemForValue(treeView, item); - if (treeView.getRoot() == treeItem) return; + if (treeView.getRoot() == treeItem) { + return; + } TransferMode transferMode = item.canMove() ? TransferMode.MOVE : null; transferMode = item.canCopy() && mouseEvent.isControlDown() ? TransferMode.COPY : transferMode; - if (transferMode == null) return; + if (transferMode == null) { + return; + } final Dragboard dragBoard = startDragAndDrop(transferMode); final ClipboardContent content = new ClipboardContent(); @@ -390,10 +436,13 @@ private void startDrag(@NotNull final MouseEvent mouseEvent) { /** * Handle dropping a dragged element. */ + @FxThread private void dragDropped(@NotNull final DragEvent dragEvent) { final TreeNode item = getItem(); - if (item == null) return; + if (item == null) { + return; + } final Dragboard dragboard = dragEvent.getDragboard(); final Long objectId = (Long) dragboard.getContent(DATA_FORMAT); @@ -409,10 +458,14 @@ private void dragDropped(@NotNull final DragEvent dragEvent) { final TreeView> treeView = getTreeView(); final TreeItem> dragTreeItem = findItem(treeView, objectId); final TreeNode dragItem = dragTreeItem == null ? null : dragTreeItem.getValue(); - if (dragItem == null || !item.canAccept(dragItem, isCopy)) return; + if (dragItem == null || !item.canAccept(dragItem, isCopy)) { + return; + } final TreeItem> newParentItem = findItemForValue(treeView, item); - if (newParentItem == null) return; + if (newParentItem == null) { + return; + } item.accept(changeConsumer, dragItem.getElement(), isCopy); @@ -426,10 +479,13 @@ private void dragDropped(@NotNull final DragEvent dragEvent) { /** * Handle entering a dragged element. */ + @FxThread private void dragOver(@NotNull final DragEvent dragEvent) { final TreeNode item = getItem(); - if (item == null) return; + if (item == null) { + return; + } final Dragboard dragboard = dragEvent.getDragboard(); final Long objectId = (Long) dragboard.getContent(DATA_FORMAT); @@ -457,6 +513,7 @@ private void dragOver(@NotNull final DragEvent dragEvent) { /** * Handle exiting a dragged element. */ + @FxThread private void dragExited(@NotNull final DragEvent dragEvent) { dropAvailable.setValue(false); } diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/AbstractNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/AbstractNodeAction.java index 61819a82..cd9cb88d 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/AbstractNodeAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/AbstractNodeAction.java @@ -1,6 +1,7 @@ package com.ss.editor.ui.control.tree.action; import static com.ss.rlib.util.ClassUtils.unsafeCast; +import static com.ss.rlib.util.ObjectUtils.notNull; import com.ss.editor.analytics.google.GAEvent; import com.ss.editor.analytics.google.GAnalytics; import com.ss.editor.annotation.FxThread; @@ -10,6 +11,8 @@ import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.rlib.logging.Logger; import com.ss.rlib.logging.LoggerManager; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; import javafx.scene.control.MenuItem; import javafx.scene.image.Image; import javafx.scene.image.ImageView; @@ -19,7 +22,7 @@ /** * The base implementation of an action for an element in a node tree. * - * @param the type parameter + * @param the change consumer's type. * @author JavaSaBr */ public abstract class AbstractNodeAction extends MenuItem implements Comparable { @@ -36,6 +39,9 @@ public abstract class AbstractNodeAction extends MenuI @NotNull protected static final ExecutorManager EXECUTOR_MANAGER = ExecutorManager.getInstance(); + @NotNull + private static final Array> EMPTY_NODES = ArrayFactory.newArray(TreeNode.class); + /** * The component of the node tree. */ @@ -48,9 +54,24 @@ public abstract class AbstractNodeAction extends MenuI @NotNull private final TreeNode node; + /** + * The nodes. + */ + @NotNull + private final Array> nodes; + public AbstractNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + this(nodeTree, node, EMPTY_NODES); + } + + public AbstractNodeAction(@NotNull final NodeTree nodeTree, @NotNull final Array> nodes) { + this(nodeTree, notNull(nodes.first()), nodes); + } + + AbstractNodeAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node, @NotNull final Array> nodes) { this.nodeTree = unsafeCast(nodeTree); this.node = node; + this.nodes = nodes; setOnAction(event -> process()); setText(getName()); @@ -62,9 +83,9 @@ public AbstractNodeAction(@NotNull final NodeTree nodeTree, @NotNull final Tr } /** - * Gets name. + * Get the action's name. * - * @return the name of this action. + * @return the action's name. */ @FxThread protected abstract @NotNull String getName(); @@ -80,7 +101,7 @@ protected void process() { /** * The icon of this action. * - * @return he icon or null. + * @return the icon or null. */ @FxThread protected @Nullable Image getIcon() { @@ -98,15 +119,25 @@ protected void process() { } /** - * Gets node. + * Get the node. * - * @return the node of the model. + * @return the node. */ @FxThread protected @NotNull TreeNode getNode() { return node; } + /** + * Get the nodes. + * + * @return the nodes. + */ + @FxThread + protected @NotNull Array> getNodes() { + return nodes; + } + /** * Get the order. * diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateNodeAction.java index 88b1af02..aa4d023e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateNodeAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/CreateNodeAction.java @@ -9,7 +9,7 @@ import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/DisableAllControlsAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/DisableAllControlsAction.java new file mode 100644 index 00000000..e2ab3da9 --- /dev/null +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/DisableAllControlsAction.java @@ -0,0 +1,57 @@ +package com.ss.editor.ui.control.tree.action.impl; + +import static com.ss.rlib.util.ObjectUtils.notNull; +import static com.ss.rlib.util.array.ArrayCollectors.toArray; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.editor.Messages; +import com.ss.editor.annotation.FxThread; +import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.model.undo.impl.DisableControlsOperation; +import com.ss.editor.ui.Icons; +import com.ss.editor.ui.control.tree.NodeTree; +import com.ss.editor.ui.control.tree.action.AbstractNodeAction; +import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.editor.util.ControlUtils; +import com.ss.editor.util.NodeUtils; +import com.ss.rlib.util.array.Array; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to disable all controls in a selected node. + * + * @author JavaSaBr + */ +public class DisableAllControlsAction extends AbstractNodeAction { + + public DisableAllControlsAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.STOP_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_DISABLE_ALL_CONTROLS; + } + + @Override + @FxThread + protected void process() { + + final Array controls = NodeUtils.children((Spatial) getNode().getElement()) + .flatMap(ControlUtils::controls) + .filter(ControlUtils::isEnabled) + .collect(toArray(Control.class)); + + final ModelChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); + changeConsumer.execute(new DisableControlsOperation(controls)); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/EnableAllControlsAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/EnableAllControlsAction.java new file mode 100644 index 00000000..6d8ee425 --- /dev/null +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/EnableAllControlsAction.java @@ -0,0 +1,57 @@ +package com.ss.editor.ui.control.tree.action.impl; + +import static com.ss.rlib.util.ObjectUtils.notNull; +import static com.ss.rlib.util.array.ArrayCollectors.toArray; +import com.jme3.scene.Spatial; +import com.jme3.scene.control.Control; +import com.ss.editor.Messages; +import com.ss.editor.annotation.FxThread; +import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.model.undo.impl.EnableControlsOperation; +import com.ss.editor.ui.Icons; +import com.ss.editor.ui.control.tree.NodeTree; +import com.ss.editor.ui.control.tree.action.AbstractNodeAction; +import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.editor.util.ControlUtils; +import com.ss.editor.util.NodeUtils; +import com.ss.rlib.util.array.Array; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * The action to enable all controls in a selected node. + * + * @author JavaSaBr + */ +public class EnableAllControlsAction extends AbstractNodeAction { + + public EnableAllControlsAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + super(nodeTree, node); + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.PLAY_16; + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_ENABLE_ALL_CONTROLS; + } + + @Override + @FxThread + protected void process() { + + final Array controls = NodeUtils.children((Spatial) getNode().getElement()) + .flatMap(ControlUtils::controls) + .filter(control -> !ControlUtils.isEnabled(control)) + .collect(toArray(Control.class)); + + final ModelChangeConsumer changeConsumer = notNull(getNodeTree().getChangeConsumer()); + changeConsumer.execute(new EnableControlsOperation(controls)); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/LinkModelAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/LinkModelAction.java index ded32e13..f48fb56e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/LinkModelAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/LinkModelAction.java @@ -1,6 +1,6 @@ package com.ss.editor.ui.control.tree.action.impl; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.LOADED_MODEL_KEY; +import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; import static com.ss.editor.util.EditorUtil.getAssetFile; import static com.ss.editor.util.EditorUtil.toAssetPath; import static com.ss.rlib.util.ObjectUtils.notNull; @@ -19,7 +19,7 @@ import com.ss.editor.ui.component.asset.tree.context.menu.action.DeleteFileAction; import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; import com.ss.editor.ui.component.asset.tree.context.menu.action.RenameFileAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; @@ -98,7 +98,7 @@ protected void processOpen(@NotNull final Path file) { final AssetLinkNode assetLinkNode = new AssetLinkNode(modelKey); assetLinkNode.attachLinkedChild(loadedModel, modelKey); - assetLinkNode.setUserData(LOADED_MODEL_KEY, true); + assetLinkNode.setUserData(KEY_LOADED_MODEL, true); if (defaultLayer != null) { SceneLayer.setLayer(defaultLayer, assetLinkNode); diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/LoadModelAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/LoadModelAction.java index 01f77238..c227b869 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/LoadModelAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/LoadModelAction.java @@ -1,6 +1,6 @@ package com.ss.editor.ui.control.tree.action.impl; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.LOADED_MODEL_KEY; +import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; import static com.ss.editor.util.EditorUtil.*; import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.asset.AssetManager; @@ -17,7 +17,7 @@ import com.ss.editor.ui.component.asset.tree.context.menu.action.DeleteFileAction; import com.ss.editor.ui.component.asset.tree.context.menu.action.NewFileAction; import com.ss.editor.ui.component.asset.tree.context.menu.action.RenameFileAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; @@ -93,7 +93,7 @@ protected void processOpen(@NotNull final Path file) { final AssetManager assetManager = EditorUtil.getAssetManager(); final Spatial loadedModel = assetManager.loadModel(modelKey); - loadedModel.setUserData(LOADED_MODEL_KEY, true); + loadedModel.setUserData(KEY_LOADED_MODEL, true); if (defaultLayer != null) { SceneLayer.setLayer(defaultLayer, loadedModel); diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/OptimizeGeometryAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/OptimizeGeometryAction.java index de23fb27..37847e12 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/OptimizeGeometryAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/OptimizeGeometryAction.java @@ -9,7 +9,7 @@ import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.OptimizeGeometryOperation; +import com.ss.editor.model.undo.impl.OptimizeGeometryOperation; import com.ss.editor.ui.control.tree.node.TreeNode; import javafx.scene.image.Image; import jme3tools.optimize.GeometryBatchFactory; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveControlAction.java index cd2712a5..503ebb6e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveControlAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveControlAction.java @@ -7,7 +7,7 @@ import com.ss.editor.annotation.FxThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.operation.RemoveControlOperation; +import com.ss.editor.model.undo.impl.RemoveControlOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveLightAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveLightAction.java index f7918599..27d4006f 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveLightAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveLightAction.java @@ -7,7 +7,7 @@ import com.ss.editor.annotation.FxThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.operation.RemoveLightOperation; +import com.ss.editor.model.undo.impl.RemoveLightOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveNodeAction.java index 616a4c64..0644769e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveNodeAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/RemoveNodeAction.java @@ -7,7 +7,7 @@ import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.operation.RemoveChildOperation; +import com.ss.editor.model.undo.impl.RemoveChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; @@ -45,7 +45,9 @@ protected void process() { final TreeNode node = getNode(); final Object element = node.getElement(); - if (!(element instanceof Spatial)) return; + if (!(element instanceof Spatial)) { + return; + } final Spatial spatial = (Spatial) element; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/RemoveAnimationAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/RemoveAnimationAction.java index b2a880fa..6e1dbe5c 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/RemoveAnimationAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/animation/RemoveAnimationAction.java @@ -8,7 +8,7 @@ import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.animation.RemoveAnimationNodeOperation; +import com.ss.editor.model.undo.impl.animation.RemoveAnimationNodeOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import javafx.scene.image.Image; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/CreateAudioNodeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/CreateAudioNodeAction.java index fd68faac..dc7b23d8 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/CreateAudioNodeAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/audio/CreateAudioNodeAction.java @@ -9,7 +9,7 @@ import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/AbstractCreateControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/AbstractCreateControlAction.java index 10ee1669..fe47c72b 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/AbstractCreateControlAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/AbstractCreateControlAction.java @@ -5,9 +5,9 @@ import com.jme3.scene.control.Control; import com.ss.editor.annotation.FxThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddControlOperation; +import com.ss.editor.model.undo.impl.AddControlOperation; import com.ss.editor.ui.control.tree.NodeTree; +import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; import org.jetbrains.annotations.NotNull; @@ -27,6 +27,10 @@ public AbstractCreateControlAction(@NotNull final NodeTree nodeTree, @NotNull protected void process() { super.process(); + if (isRequiredDialog()) { + return; + } + final TreeNode treeNode = getNode(); final Spatial parent = (Spatial) treeNode.getElement(); @@ -38,11 +42,23 @@ protected void process() { } /** - * Create control control. + * Return true if need a dialog to create a control. + * + * @return true if need a dialog to create a control. + */ + @FxThread + protected boolean isRequiredDialog() { + return false; + } + + /** + * Create a control. * - * @param parent the parent - * @return the control + * @param parent the parent. + * @return the control. */ @FxThread - protected abstract @NotNull Control createControl(@NotNull final Spatial parent); + protected @NotNull Control createControl(@NotNull final Spatial parent) { + throw new UnsupportedOperationException(); + } } \ No newline at end of file diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateCharacterControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateCharacterControlAction.java index 0a599301..0dad78cc 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateCharacterControlAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateCharacterControlAction.java @@ -1,15 +1,22 @@ package com.ss.editor.ui.control.tree.action.impl.control.physics; -import com.jme3.bullet.collision.shapes.CapsuleCollisionShape; +import static com.ss.editor.extension.property.EditablePropertyType.FLOAT; +import static com.ss.rlib.util.ObjectUtils.notNull; +import com.jme3.bullet.control.BetterCharacterControl; import com.jme3.bullet.control.CharacterControl; import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; import com.ss.editor.Messages; import com.ss.editor.annotation.FxThread; +import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.model.undo.impl.AddControlOperation; +import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; +import com.ss.editor.plugin.api.property.PropertyDefinition; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.control.AbstractCreateControlAction; import com.ss.editor.ui.control.tree.NodeTree; +import com.ss.editor.ui.control.tree.action.impl.control.AbstractCreateControlAction; import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; import javafx.scene.image.Image; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,6 +28,10 @@ */ public class CreateCharacterControlAction extends AbstractCreateControlAction { + private static final String PROPERTY_RADIUS = "radius"; + private static final String PROPERTY_HEIGHT = "height"; + private static final String PROPERTY_MASS = "mass"; + public CreateCharacterControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { super(nodeTree, node); } @@ -39,8 +50,26 @@ public CreateCharacterControlAction(@NotNull final NodeTree nodeTree, @NotNul } @Override - @FxThread - protected @NotNull Control createControl(@NotNull final Spatial parent) { - return new CharacterControl(new CapsuleCollisionShape(0.6f, 1.8f), 0.03f); + protected void process() { + + final Array definitions = ArrayFactory.newArray(PropertyDefinition.class); + definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_RADIUS, PROPERTY_RADIUS, 1F)); + definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_HEIGHT, PROPERTY_HEIGHT, 1F)); + definitions.add(new PropertyDefinition(FLOAT, Messages.MODEL_PROPERTY_MASS, PROPERTY_MASS, 1F)); + + final GenericFactoryDialog dialog = new GenericFactoryDialog(definitions, vars -> { + + final float radius = vars.getFloat(PROPERTY_RADIUS); + final float height = vars.getFloat(PROPERTY_HEIGHT); + final float mass = vars.getFloat(PROPERTY_MASS); + + final TreeNode treeNode = getNode(); + final Spatial parent = (Spatial) treeNode.getElement(); + + final NodeTree nodeTree = getNodeTree(); + final ModelChangeConsumer consumer = notNull(nodeTree.getChangeConsumer()); + consumer.execute(new AddControlOperation(new BetterCharacterControl(radius, height, mass), parent)); + }); + dialog.show(); } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java index d4103de5..9cbc300c 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateRigidBodyControlAction.java @@ -8,6 +8,7 @@ import com.ss.editor.ui.control.tree.action.impl.control.AbstractCreateControlAction; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.editor.util.ControlUtils; import javafx.scene.image.Image; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,6 +41,7 @@ public CreateRigidBodyControlAction(@NotNull final NodeTree nodeTree, @NotNul protected @NotNull RigidBodyControl createControl(@NotNull final Spatial parent) { final RigidBodyControl rigidBodyControl = new RigidBodyControl(); rigidBodyControl.setEnabled(false); + ControlUtils.applyScale(parent, parent.getWorldScale(), rigidBodyControl); return rigidBodyControl; } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java index 9a81f5ab..4cafe118 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/CreateStaticRigidBodyControlAction.java @@ -7,6 +7,7 @@ import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.editor.util.ControlUtils; import javafx.scene.image.Image; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,12 +36,13 @@ public CreateStaticRigidBodyControlAction(@NotNull final NodeTree nodeTree, return Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL_STATIC_RIGID_BODY; } - @Override @FxThread protected @NotNull RigidBodyControl createControl(@NotNull final Spatial parent) { - final RigidBodyControl rigidBodyControl = super.createControl(parent); + final RigidBodyControl rigidBodyControl = new RigidBodyControl(); + rigidBodyControl.setEnabled(false); rigidBodyControl.setMass(0F); + ControlUtils.applyScale(parent, parent.getWorldScale(), rigidBodyControl); return rigidBodyControl; } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControl.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java similarity index 85% rename from src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControl.java rename to src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java index 93b93bb8..676cd489 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControl.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/ReactivatePhysicsControlAction.java @@ -17,9 +17,9 @@ * * @author JavaSaBr */ -public class ReactivatePhysicsControl extends AbstractNodeAction { +public class ReactivatePhysicsControlAction extends AbstractNodeAction { - public ReactivatePhysicsControl(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { + public ReactivatePhysicsControlAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { super(nodeTree, node); } diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java index 3ba3f7f2..69c49c2b 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/CreateVehicleWheelAction.java @@ -13,7 +13,7 @@ import com.ss.editor.plugin.api.property.PropertyDefinition; import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddVehicleWheelOperation; +import com.ss.editor.model.undo.impl.AddVehicleWheelOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.rlib.util.VarTable; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java index c4b57d85..ce9ce8c6 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/control/physics/vehicle/RemoveVehicleWheelAction.java @@ -9,7 +9,7 @@ import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.RemoveVehicleWheelOperation; +import com.ss.editor.model.undo.impl.RemoveVehicleWheelOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import javafx.scene.image.Image; @@ -23,32 +23,24 @@ */ public class RemoveVehicleWheelAction extends AbstractNodeAction { - /** - * Instantiates a new Remove vehicle wheel action. - * - * @param nodeTree the node tree - * @param node the node - */ public RemoveVehicleWheelAction(@NotNull final NodeTree nodeTree, @NotNull final TreeNode node) { super(nodeTree, node); } - @FxThread - @NotNull @Override - protected String getName() { + @FxThread + protected @NotNull String getName() { return Messages.MODEL_NODE_TREE_ACTION_REMOVE; } - @FxThread - @Nullable @Override - protected Image getIcon() { + @FxThread + protected @Nullable Image getIcon() { return Icons.REMOVE_12; } - @FxThread @Override + @FxThread protected void process() { final TreeNode node = getNode(); diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java index 4d57df5b..84a00b7a 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/geometry/AbstractCreateGeometryAction.java @@ -10,7 +10,7 @@ import com.ss.editor.extension.scene.SceneLayer; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.util.EditorUtil; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/AbstractCreateLightAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/AbstractCreateLightAction.java index bdae9797..a59c33c8 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/AbstractCreateLightAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/light/AbstractCreateLightAction.java @@ -6,7 +6,7 @@ import com.ss.editor.annotation.FxThread; import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.tree.action.impl.operation.AddLightOperation; +import com.ss.editor.model.undo.impl.AddLightOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/multi/RemoveElementsAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/multi/RemoveElementsAction.java new file mode 100644 index 00000000..aedecfc5 --- /dev/null +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/multi/RemoveElementsAction.java @@ -0,0 +1,95 @@ +package com.ss.editor.ui.control.tree.action.impl.multi; + +import static com.ss.rlib.util.ObjectUtils.notNull; +import com.ss.editor.Messages; +import com.ss.editor.annotation.FxThread; +import com.ss.editor.model.undo.editor.ChangeConsumer; +import com.ss.editor.model.undo.editor.ModelChangeConsumer; +import com.ss.editor.ui.Icons; +import com.ss.editor.ui.control.tree.NodeTree; +import com.ss.editor.ui.control.tree.action.AbstractNodeAction; +import com.ss.editor.model.undo.impl.RemoveElementsOperation; +import com.ss.editor.model.undo.impl.RemoveElementsOperation.Element; +import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; +import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationTreeNode; +import com.ss.editor.ui.control.tree.node.impl.light.LightTreeNode; +import com.ss.editor.ui.control.tree.node.impl.spatial.SpatialTreeNode; +import com.ss.rlib.function.TripleConsumer; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayCollectors; +import com.ss.rlib.util.array.ArrayFactory; +import javafx.scene.control.MenuItem; +import javafx.scene.image.Image; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * The action to remove some elements from a scene/model. + * + * @author JavaSaBr + */ +public class RemoveElementsAction extends AbstractNodeAction { + + private static final Array> AVAILABLE_TYPES = ArrayFactory.newArray(Class.class); + + static { + AVAILABLE_TYPES.add(SpatialTreeNode.class); + AVAILABLE_TYPES.add(ControlTreeNode.class); + AVAILABLE_TYPES.add(LightTreeNode.class); + AVAILABLE_TYPES.add(AnimationTreeNode.class); + } + + public static final TripleConsumer, List, Array>> ACTION_FILLER = (nodeTree, menuItems, treeNodes) -> { + + final TreeNode unexpectedItem = treeNodes.search(treeNode -> + AVAILABLE_TYPES.search(treeNode, Class::isInstance) == null || !treeNode.canRemove()); + + if (unexpectedItem == null) { + menuItems.add(new RemoveElementsAction(nodeTree, treeNodes)); + } + }; + + public RemoveElementsAction(@NotNull final NodeTree nodeTree, @NotNull final Array> nodes) { + super(nodeTree, nodes); + } + + @Override + @FxThread + protected @NotNull String getName() { + return Messages.MODEL_NODE_TREE_ACTION_REMOVE; + } + + @Override + @FxThread + protected @Nullable Image getIcon() { + return Icons.REMOVE_12; + } + + @Override + @FxThread + public void process() { + super.process(); + + final Array> nodes = getNodes(); + final Array toRemove = nodes.stream() + .filter(treeNode -> treeNode.getParent() != null) + .map(this::convert) + .collect(ArrayCollectors.toArray(Element.class)); + + + final NodeTree nodeTree = getNodeTree(); + final ChangeConsumer changeConsumer = notNull(nodeTree.getChangeConsumer()); + changeConsumer.execute(new RemoveElementsOperation(toRemove)); + } + + @FxThread + private @NotNull Element convert(@NotNull final TreeNode treeNode) { + final Object value = treeNode.getElement(); + final TreeNode parentNode = notNull(treeNode.getParent()); + final Object parent = parentNode.getElement(); + return new Element(value, parent); + } +} diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java index ba0f6c48..9914118e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/CreateParticleEmitterAction.java @@ -16,7 +16,7 @@ import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.util.EditorUtil; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java index 6e337783..75e3e1e9 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/influencer/AbstractCreateParticleInfluencerAction.java @@ -6,7 +6,7 @@ import com.ss.editor.annotation.FxThread; import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.operation.particle.emitter.ChangeParticleInfluencerOperation; +import com.ss.editor.model.undo.impl.emitter.ChangeParticleInfluencerOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java index 6d12c5ba..ae06bbcf 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/particle/emitter/shape/AbstractCreateShapeEmitterAction.java @@ -9,7 +9,7 @@ import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; import com.ss.editor.plugin.api.property.PropertyDefinition; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.operation.particle.emitter.ChangeEmitterShapeOperation; +import com.ss.editor.model.undo.impl.emitter.ChangeEmitterShapeOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java index 200b9498..4dbd0978 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/AbstractCreateShapeAction.java @@ -9,7 +9,7 @@ import com.ss.editor.plugin.api.dialog.GenericFactoryDialog; import com.ss.editor.plugin.api.property.PropertyDefinition; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.operation.ChangeCollisionShapeOperation; +import com.ss.editor.model.undo.impl.ChangeCollisionShapeOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java index 9c711028..abf7b77b 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/physics/shape/GenerateCollisionShapeAction.java @@ -19,7 +19,7 @@ import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.plugin.api.property.PropertyDefinition; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.operation.ChangeCollisionShapeOperation; +import com.ss.editor.model.undo.impl.ChangeCollisionShapeOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.rlib.util.VarTable; @@ -75,7 +75,6 @@ protected void process() { final Box box = (Box) mesh; shape = new BoxCollisionShape(new Vector3f(box.getXExtent(), box.getYExtent(), box.getZExtent())); } - } if (shape == null) { diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/CreateSceneLayerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/CreateSceneLayerAction.java index 70da3a34..3c285a47 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/CreateSceneLayerAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/CreateSceneLayerAction.java @@ -9,7 +9,7 @@ import com.ss.editor.ui.Icons; import com.ss.editor.model.node.layer.LayersRoot; import com.ss.editor.ui.control.tree.node.impl.layer.LayersRootTreeNode; -import com.ss.editor.ui.control.tree.action.impl.operation.scene.AddSceneLayerOperation; +import com.ss.editor.model.undo.impl.scene.AddSceneLayerOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/RemoveSceneLayerAction.java b/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/RemoveSceneLayerAction.java index 92a7d01d..bd93f13e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/RemoveSceneLayerAction.java +++ b/src/main/java/com/ss/editor/ui/control/tree/action/impl/scene/RemoveSceneLayerAction.java @@ -9,7 +9,7 @@ import com.ss.editor.ui.Icons; import com.ss.editor.model.node.layer.LayersRoot; import com.ss.editor.ui.control.tree.node.impl.layer.SceneLayerTreeNode; -import com.ss.editor.ui.control.tree.action.impl.operation.scene.RemoveSceneLayerOperation; +import com.ss.editor.model.undo.impl.scene.RemoveSceneLayerOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.AbstractNodeAction; import com.ss.editor.ui.control.tree.node.TreeNode; diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactory.java index cd72c424..285b8560 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactory.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactory.java @@ -30,12 +30,12 @@ public interface TreeNodeFactory extends Comparable { * @return the order. */ @FxThread - default int getOrder() { + default int getPriority() { return 0; } @Override default int compareTo(@NotNull final TreeNodeFactory another) { - return getOrder() - another.getOrder(); + return another.getPriority() - getPriority(); } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactoryRegistry.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactoryRegistry.java index 1a043b18..846de224 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactoryRegistry.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/factory/TreeNodeFactoryRegistry.java @@ -59,7 +59,7 @@ private TreeNodeFactoryRegistry() { @FxThread public void register(@NotNull final TreeNodeFactory factory) { this.factories.add(factory); - this.factories.sort((first, second) -> second.getOrder() - first.getOrder()); + this.factories.sort(TreeNodeFactory::compareTo); } /** diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/AnimationTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/AnimationTreeNodeFactory.java index f95ea951..76e735e4 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/AnimationTreeNodeFactory.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/AnimationTreeNodeFactory.java @@ -15,6 +15,8 @@ */ public class AnimationTreeNodeFactory implements TreeNodeFactory { + public static final int PRIORITY = 1; + @Override @FxThread public > @Nullable V createFor(@Nullable final T element, final long objectId) { @@ -38,7 +40,7 @@ public class AnimationTreeNodeFactory implements TreeNodeFactory { @Override @FxThread - public int getOrder() { - return 1; + public int getPriority() { + return PRIORITY; } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/ControlTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/ControlTreeNodeFactory.java index f56f31a3..c68571b9 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/ControlTreeNodeFactory.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/ControlTreeNodeFactory.java @@ -2,10 +2,7 @@ import static com.ss.rlib.util.ClassUtils.unsafeCast; import com.jme3.animation.SkeletonControl; -import com.jme3.bullet.control.CharacterControl; -import com.jme3.bullet.control.KinematicRagdollControl; -import com.jme3.bullet.control.RigidBodyControl; -import com.jme3.bullet.control.VehicleControl; +import com.jme3.bullet.control.*; import com.jme3.cinematic.events.MotionEvent; import com.jme3.scene.control.Control; import com.jme3.scene.control.LightControl; @@ -14,7 +11,7 @@ import com.ss.editor.ui.control.tree.node.impl.control.LightControlTreeNode; import com.ss.editor.ui.control.tree.node.impl.control.SkeletonControlTreeNode; import com.ss.editor.ui.control.tree.node.impl.control.motion.MotionEventTreeNode; -import com.ss.editor.ui.control.tree.node.impl.control.physics.CharacterControlTreeNode; +import com.ss.editor.ui.control.tree.node.impl.control.physics.BetterCharacterControlTreeNode; import com.ss.editor.ui.control.tree.node.impl.control.physics.RagdollControlTreeNode; import com.ss.editor.ui.control.tree.node.impl.control.physics.RigidBodyControlTreeNode; import com.ss.editor.ui.control.tree.node.impl.control.physics.vehicle.VehicleControlTreeNode; @@ -41,8 +38,8 @@ public class ControlTreeNodeFactory implements TreeNodeFactory { return unsafeCast(new VehicleControlTreeNode((VehicleControl) element, objectId)); } else if (element instanceof SkeletonControl) { return unsafeCast(new SkeletonControlTreeNode((SkeletonControl) element, objectId)); - } else if (element instanceof CharacterControl) { - return unsafeCast(new CharacterControlTreeNode((CharacterControl) element, objectId)); + } else if (element instanceof BetterCharacterControl) { + return unsafeCast(new BetterCharacterControlTreeNode((BetterCharacterControl) element, objectId)); } else if (element instanceof RigidBodyControl) { return unsafeCast(new RigidBodyControlTreeNode((RigidBodyControl) element, objectId)); } else if (element instanceof LightControl) { diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java index 269061f1..25acbc44 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultParticlesTreeNodeFactory.java @@ -25,6 +25,8 @@ */ public class DefaultParticlesTreeNodeFactory implements TreeNodeFactory { + public static final int PRIORITY = 1; + @Override @FxThread public > @Nullable V createFor(@Nullable final T element, final long objectId) { @@ -67,7 +69,7 @@ public class DefaultParticlesTreeNodeFactory implements TreeNodeFactory { @Override @FxThread - public int getOrder() { - return 1; + public int getPriority() { + return PRIORITY; } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultTreeNodeFactory.java index 5f1aa304..77976fb8 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultTreeNodeFactory.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/DefaultTreeNodeFactory.java @@ -34,6 +34,8 @@ */ public class DefaultTreeNodeFactory implements TreeNodeFactory { + public static final int PRIORITY = 0; + @Override @FxThread public > @Nullable V createFor(@Nullable final T element, final long objectId) { @@ -72,4 +74,9 @@ public class DefaultTreeNodeFactory implements TreeNodeFactory { return null; } + + @Override + public int getPriority() { + return PRIORITY; + } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java index 411751cd..f7ce1586 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/factory/impl/PrimitiveTreeNodeFactory.java @@ -24,6 +24,8 @@ */ public class PrimitiveTreeNodeFactory implements TreeNodeFactory { + public static final int PRIORITY = 1; + @Override @FxThread public > @Nullable V createFor(@Nullable final T element, final long objectId) { @@ -45,7 +47,7 @@ public class PrimitiveTreeNodeFactory implements TreeNodeFactory { @Override @FxThread - public int getOrder() { - return 1; + public int getPriority() { + return PRIORITY; } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTreeNode.java index c8445ea0..fc05907a 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/anim/AnimationTreeNode.java @@ -11,7 +11,7 @@ import com.ss.editor.ui.control.model.ModelNodeTree; import com.ss.editor.ui.control.tree.action.impl.RenameNodeAction; import com.ss.editor.ui.control.tree.action.impl.animation.*; -import com.ss.editor.ui.control.tree.action.impl.operation.animation.RenameAnimationNodeOperation; +import com.ss.editor.model.undo.impl.animation.RenameAnimationNodeOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.util.AnimationUtils; diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/CharacterControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java similarity index 74% rename from src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/CharacterControlTreeNode.java rename to src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java index d4f13872..7f71a091 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/CharacterControlTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/BetterCharacterControlTreeNode.java @@ -1,5 +1,6 @@ package com.ss.editor.ui.control.tree.node.impl.control.physics; +import com.jme3.bullet.control.BetterCharacterControl; import com.jme3.bullet.control.CharacterControl; import com.ss.editor.Messages; import com.ss.editor.annotation.FxThread; @@ -14,9 +15,9 @@ * * @author JavaSaBr */ -public class CharacterControlTreeNode extends PhysicsObjectTreeNode { +public class BetterCharacterControlTreeNode extends PhysicsControlTreeNode { - public CharacterControlTreeNode(@NotNull final CharacterControl element, final long objectId) { + public BetterCharacterControlTreeNode(@NotNull final BetterCharacterControl element, final long objectId) { super(element, objectId); } diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsObjectTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java similarity index 51% rename from src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsObjectTreeNode.java rename to src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java index 52c2a650..2aecac7f 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsObjectTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/PhysicsControlTreeNode.java @@ -2,13 +2,16 @@ import com.jme3.bullet.collision.PhysicsCollisionObject; import com.jme3.bullet.collision.shapes.CollisionShape; -import com.jme3.scene.control.Control; +import com.jme3.bullet.control.PhysicsControl; import com.ss.editor.Messages; +import com.ss.editor.annotation.FxThread; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; -import com.ss.editor.ui.control.tree.action.impl.physics.shape.*; import com.ss.editor.ui.control.tree.NodeTree; +import com.ss.editor.ui.control.tree.action.impl.physics.shape.*; import com.ss.editor.ui.control.tree.node.TreeNode; +import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; import javafx.collections.ObservableList; import javafx.scene.control.Menu; import javafx.scene.control.MenuItem; @@ -16,35 +19,27 @@ import javafx.scene.image.ImageView; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import com.ss.rlib.util.array.Array; -import com.ss.rlib.util.array.ArrayFactory; /** - * The implementation of the {@link TreeNode} to show a {@link PhysicsCollisionObject} in the tree. + * The implementation of the {@link TreeNode} to show {@link PhysicsControl} in the tree. * - * @param the type parameter + * @param the physics control's type. * @author JavaSaBr */ @SuppressWarnings("WeakerAccess") -public class PhysicsObjectTreeNode extends ControlTreeNode { +public class PhysicsControlTreeNode extends ControlTreeNode { + - /** - * Instantiates a new Physics object model node. - * - * @param element the element - * @param objectId the object id - */ - public PhysicsObjectTreeNode(@NotNull final T element, final long objectId) { + public PhysicsControlTreeNode(@NotNull final T element, final long objectId) { super(element, objectId); } - @NotNull @Override - public Array> getChildren(@NotNull final NodeTree nodeTree) { + @FxThread + public @NotNull Array> getChildren(@NotNull final NodeTree nodeTree) { final T element = getElement(); - final CollisionShape collisionShape = element.getCollisionShape(); - + final CollisionShape collisionShape = ((PhysicsCollisionObject) element).getCollisionShape(); final Array> result = ArrayFactory.newArray(TreeNode.class, 1); result.add(FACTORY_REGISTRY.createFor(collisionShape)); @@ -52,30 +47,36 @@ public Array> getChildren(@NotNull final NodeTree nodeTree) { } @Override + @FxThread public boolean hasChildren(@NotNull final NodeTree nodeTree) { - return true; + return getElement() instanceof PhysicsCollisionObject; } @Override + @FxThread public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - final Menu changeShapeMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_CHANGE_COLLISION_SHAPE, new ImageView(Icons.ADD_12)); - changeShapeMenu.getItems().addAll(new GenerateCollisionShapeAction(nodeTree, this), - new CreateBoxCollisionShapeAction(nodeTree, this), - new CreateCapsuleCollisionShapeAction(nodeTree, this), - new CreateConeCollisionShapeAction(nodeTree, this), - new CreateCylinderCollisionShapeAction(nodeTree, this), - new CreateSphereCollisionShapeAction(nodeTree, this)); + if (getElement() instanceof PhysicsCollisionObject) { + + final Menu changeShapeMenu = new Menu(Messages.MODEL_NODE_TREE_ACTION_CHANGE_COLLISION_SHAPE, new ImageView(Icons.ADD_12)); + changeShapeMenu.getItems().addAll(new GenerateCollisionShapeAction(nodeTree, this), + new CreateBoxCollisionShapeAction(nodeTree, this), + new CreateCapsuleCollisionShapeAction(nodeTree, this), + new CreateConeCollisionShapeAction(nodeTree, this), + new CreateCylinderCollisionShapeAction(nodeTree, this), + new CreateSphereCollisionShapeAction(nodeTree, this)); - items.add(changeShapeMenu); + items.add(changeShapeMenu); + } super.fillContextMenu(nodeTree, items); } - @Nullable + @Override - public Image getIcon() { + @FxThread + public @Nullable Image getIcon() { return Icons.PHYSICS_16; } } diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java index 5108b80a..4e1775f0 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/RigidBodyControlTreeNode.java @@ -5,7 +5,7 @@ import com.ss.editor.annotation.FxThread; import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.action.impl.control.physics.ReactivatePhysicsControl; +import com.ss.editor.ui.control.tree.action.impl.control.physics.ReactivatePhysicsControlAction; import com.ss.editor.ui.control.tree.NodeTree; import javafx.collections.ObservableList; import javafx.scene.control.MenuItem; @@ -18,7 +18,7 @@ * * @author JavaSaBr */ -public class RigidBodyControlTreeNode extends PhysicsObjectTreeNode { +public class RigidBodyControlTreeNode extends PhysicsControlTreeNode { public RigidBodyControlTreeNode(@NotNull final RigidBodyControl element, final long objectId) { super(element, objectId); @@ -58,7 +58,7 @@ public void fillContextMenu(@NotNull final NodeTree nodeTree, final RigidBodyControl element = getElement(); if (!element.isActive()) { - items.add(new ReactivatePhysicsControl(nodeTree, this)); + items.add(new ReactivatePhysicsControlAction(nodeTree, this)); } super.fillContextMenu(nodeTree, items); diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java index 605c0b24..77f64266 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/control/physics/vehicle/VehicleControlTreeNode.java @@ -5,7 +5,7 @@ import com.ss.editor.annotation.FxThread; import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.ui.Icons; -import com.ss.editor.ui.control.tree.node.impl.control.physics.PhysicsObjectTreeNode; +import com.ss.editor.ui.control.tree.node.impl.control.physics.PhysicsControlTreeNode; import com.ss.editor.ui.control.tree.action.impl.control.physics.vehicle.CreateVehicleWheelAction; import com.ss.editor.ui.control.tree.NodeTree; import javafx.collections.ObservableList; @@ -19,7 +19,7 @@ * * @author JavaSaBr */ -public class VehicleControlTreeNode extends PhysicsObjectTreeNode { +public class VehicleControlTreeNode extends PhysicsControlTreeNode { public VehicleControlTreeNode(@NotNull final VehicleControl element, final long objectId) { super(element, objectId); diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/SceneLayerTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/SceneLayerTreeNode.java index 74da5300..7ba46a84 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/SceneLayerTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/layer/SceneLayerTreeNode.java @@ -11,8 +11,8 @@ import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.node.impl.spatial.NodeTreeNode; import com.ss.editor.ui.control.tree.action.impl.RenameNodeAction; -import com.ss.editor.ui.control.tree.action.impl.operation.RenameNodeOperation; -import com.ss.editor.ui.control.tree.action.impl.operation.scene.ChangeVisibleSceneLayerOperation; +import com.ss.editor.model.undo.impl.RenameNodeOperation; +import com.ss.editor.model.undo.impl.scene.ChangeVisibleSceneLayerOperation; import com.ss.editor.ui.control.tree.action.impl.scene.RemoveSceneLayerAction; import com.ss.editor.ui.control.property.operation.PropertyOperation; import com.ss.editor.ui.control.tree.NodeTree; diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightTreeNode.java index d14f4140..7adb8241 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/light/LightTreeNode.java @@ -8,7 +8,7 @@ import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.impl.RemoveLightAction; -import com.ss.editor.ui.control.tree.action.impl.operation.RenameLightOperation; +import com.ss.editor.model.undo.impl.RenameLightOperation; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.rlib.util.StringUtils; import javafx.collections.ObservableList; diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/NodeTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/NodeTreeNode.java index 803d6732..d5dad40e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/NodeTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/NodeTreeNode.java @@ -25,8 +25,8 @@ import com.ss.editor.ui.control.tree.action.impl.light.CreateDirectionLightAction; import com.ss.editor.ui.control.tree.action.impl.light.CreatePointLightAction; import com.ss.editor.ui.control.tree.action.impl.light.CreateSpotLightAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; -import com.ss.editor.ui.control.tree.action.impl.operation.MoveChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; +import com.ss.editor.model.undo.impl.MoveChildOperation; import com.ss.editor.ui.control.tree.action.impl.particle.emitter.CreateParticleEmitterAction; import com.ss.editor.ui.control.tree.action.impl.particle.emitter.ResetParticleEmittersAction; import com.ss.editor.ui.control.tree.action.impl.terrain.CreateTerrainAction; @@ -143,7 +143,10 @@ public NodeTreeNode(@NotNull final T element, final long objectId) { @FxThread public void fillContextMenu(@NotNull final NodeTree nodeTree, @NotNull final ObservableList items) { - if (!(nodeTree instanceof ModelNodeTree)) return; + + if (!(nodeTree instanceof ModelNodeTree)) { + return; + } final T element = getElement(); final Spatial emitter = NodeUtils.findSpatial(element, ParticleEmitter.class::isInstance); diff --git a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/SpatialTreeNode.java b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/SpatialTreeNode.java index 26f93e25..a698856e 100644 --- a/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/SpatialTreeNode.java +++ b/src/main/java/com/ss/editor/ui/control/tree/node/impl/spatial/SpatialTreeNode.java @@ -2,6 +2,7 @@ import static com.ss.editor.Messages.MODEL_NODE_TREE_ACTION_ADD_CONTROL; import static com.ss.editor.Messages.MODEL_NODE_TREE_ACTION_CREATE; +import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_MODEL_NODE; import static com.ss.editor.util.NodeUtils.findParent; import static com.ss.rlib.util.ObjectUtils.notNull; import com.jme3.bullet.control.CharacterControl; @@ -17,13 +18,14 @@ import com.jme3.scene.control.Control; import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.annotation.FxThread; -import com.ss.editor.control.transform.EditorTransformSupport; import com.ss.editor.extension.scene.InvisibleObject; import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.ui.Icons; import com.ss.editor.ui.control.model.ModelNodeTree; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.action.impl.AddUserDataAction; +import com.ss.editor.ui.control.tree.action.impl.DisableAllControlsAction; +import com.ss.editor.ui.control.tree.action.impl.EnableAllControlsAction; import com.ss.editor.ui.control.tree.action.impl.RemoveNodeAction; import com.ss.editor.ui.control.tree.action.impl.control.CreateCustomControlAction; import com.ss.editor.ui.control.tree.action.impl.control.CreateLightControlAction; @@ -32,12 +34,14 @@ import com.ss.editor.ui.control.tree.action.impl.control.physics.CreateRigidBodyControlAction; import com.ss.editor.ui.control.tree.action.impl.control.physics.CreateStaticRigidBodyControlAction; import com.ss.editor.ui.control.tree.action.impl.control.physics.vehicle.CreateVehicleControlAction; -import com.ss.editor.ui.control.tree.action.impl.operation.AddControlOperation; -import com.ss.editor.ui.control.tree.action.impl.operation.MoveControlOperation; -import com.ss.editor.ui.control.tree.action.impl.operation.RenameNodeOperation; +import com.ss.editor.model.undo.impl.AddControlOperation; +import com.ss.editor.model.undo.impl.MoveControlOperation; +import com.ss.editor.model.undo.impl.RenameNodeOperation; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.ui.control.tree.node.impl.control.ControlTreeNode; import com.ss.editor.ui.control.tree.node.impl.light.LightTreeNode; +import com.ss.editor.util.ControlUtils; +import com.ss.editor.util.NodeUtils; import com.ss.rlib.util.StringUtils; import com.ss.rlib.util.array.Array; import com.ss.rlib.util.array.ArrayFactory; @@ -130,6 +134,18 @@ public void fillContextMenu(@NotNull final NodeTree nodeTree, items.add(new RemoveNodeAction(nodeTree, this)); } + NodeUtils.children(element) + .flatMap(ControlUtils::controls) + .filter(control -> !ControlUtils.isEnabled(control)) + .findAny() + .ifPresent(c -> items.add(new EnableAllControlsAction(nodeTree, this))); + + NodeUtils.children(element) + .flatMap(ControlUtils::controls) + .filter(ControlUtils::isEnabled) + .findAny() + .ifPresent(c -> items.add(new DisableAllControlsAction(nodeTree, this))); + super.fillContextMenu(nodeTree, items); } @@ -180,7 +196,7 @@ public void accept(@NotNull final ChangeConsumer changeConsumer, @NotNull final @FxThread public boolean canRemove() { final Node parent = getElement().getParent(); - return parent != null && parent.getUserData(EditorTransformSupport.class.getName()) != Boolean.TRUE; + return parent != null && parent.getUserData(KEY_MODEL_NODE) != Boolean.TRUE; } /** @@ -278,7 +294,10 @@ public boolean hasChildren(@NotNull final NodeTree nodeTree) { @Override @FxThread public void changeName(@NotNull final NodeTree nodeTree, @NotNull final String newName) { - if (StringUtils.equals(getName(), newName)) return; + + if (StringUtils.equals(getName(), newName)){ + return; + } super.changeName(nodeTree, newName); diff --git a/src/main/java/com/ss/editor/ui/dialog/CreateCustomControlDialog.java b/src/main/java/com/ss/editor/ui/dialog/CreateCustomControlDialog.java index 50b2fd3d..1b7db3f1 100644 --- a/src/main/java/com/ss/editor/ui/dialog/CreateCustomControlDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/CreateCustomControlDialog.java @@ -12,7 +12,7 @@ import com.ss.editor.manager.ClasspathManager; import com.ss.editor.manager.ClasspathManager.Scope; import com.ss.editor.model.undo.editor.ModelChangeConsumer; -import com.ss.editor.ui.control.tree.action.impl.operation.AddControlOperation; +import com.ss.editor.model.undo.impl.AddControlOperation; import com.ss.editor.ui.css.CssClasses; import com.ss.rlib.ui.util.FXUtils; import com.ss.rlib.util.ClassUtils; diff --git a/src/main/java/com/ss/editor/ui/dialog/CreateSceneAppStateDialog.java b/src/main/java/com/ss/editor/ui/dialog/CreateSceneAppStateDialog.java index d26ae122..6da4c05e 100644 --- a/src/main/java/com/ss/editor/ui/dialog/CreateSceneAppStateDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/CreateSceneAppStateDialog.java @@ -9,8 +9,6 @@ import com.ss.editor.extension.scene.SceneNode; import com.ss.editor.extension.scene.app.state.EditableSceneAppState; import com.ss.editor.extension.scene.app.state.SceneAppState; -import com.ss.editor.extension.scene.app.state.impl.EditableLightingSceneAppState; -import com.ss.editor.extension.scene.app.state.impl.EditableSkySceneAppState; import com.ss.editor.extension.scene.app.state.impl.bullet.EditableBulletSceneAppState; import com.ss.editor.extension.scene.app.state.impl.pbr.StaticLightProbeSceneAppState; import com.ss.editor.extension.scene.filter.SceneFilter; @@ -49,8 +47,6 @@ public class CreateSceneAppStateDialog extends AbstractSimpleEditorDialog { private static final Array BUILT_IN_NAMES = ArrayFactory.newArray(String.class); static { - register(new EditableLightingSceneAppState()); - register(new EditableSkySceneAppState()); register(new EditableBulletSceneAppState()); register(new StaticLightProbeSceneAppState()); } diff --git a/src/main/java/com/ss/editor/ui/dialog/CreateSceneFilterDialog.java b/src/main/java/com/ss/editor/ui/dialog/CreateSceneFilterDialog.java index bac79fc4..57b77d3d 100644 --- a/src/main/java/com/ss/editor/ui/dialog/CreateSceneFilterDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/CreateSceneFilterDialog.java @@ -47,6 +47,7 @@ public class CreateSceneFilterDialog extends AbstractSimpleEditorDialog { static { register(new EditableDirectionLightFromSceneShadowFilter()); + register(new EditableHqDirectionalLightFromSceneShadowFilter()); register(new EditablePointLightFromSceneShadowFilter()); register(new EditableCartoonEdgeFilter()); register(new EditableColorOverlayFilter()); @@ -59,13 +60,10 @@ public class CreateSceneFilterDialog extends AbstractSimpleEditorDialog { register(new EditableSceneBloomFilter()); register(new EditableObjectsBloomFilter()); register(new EditableSceneAndObjectsBloomFilter()); - register(new EditableLightingStateShadowFilter()); register(new EditableWaterFilter()); register(new EditableWaterWithDirectionLightFilter()); - register(new EditableWaterWithLightingStateFilter()); register(new EditableLocalWaterFilter()); register(new EditableLocalWaterWithDirectionLightFilter()); - register(new EditableLocalWaterWithLightingStateFilter()); } private static void register(@NotNull final SceneFilter sceneFilter) { diff --git a/src/main/java/com/ss/editor/ui/dialog/EditorDialog.java b/src/main/java/com/ss/editor/ui/dialog/EditorDialog.java index 629b04e0..8da00307 100644 --- a/src/main/java/com/ss/editor/ui/dialog/EditorDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/EditorDialog.java @@ -10,8 +10,8 @@ import com.ss.editor.annotation.FxThread; import com.ss.editor.config.EditorConfig; import com.ss.editor.ui.css.CssClasses; -import com.ss.editor.ui.css.CssRegistry; import com.ss.editor.ui.css.CssColorTheme; +import com.ss.editor.ui.css.CssRegistry; import com.ss.editor.ui.event.FxEventManager; import com.ss.editor.ui.scene.EditorFxScene; import com.ss.editor.util.EditorUtil; @@ -24,6 +24,7 @@ import javafx.collections.ObservableList; import javafx.scene.Node; import javafx.scene.Scene; +import javafx.scene.image.Image; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.GridPane; @@ -118,6 +119,10 @@ public EditorDialog() { dialog.setResizable(isResizable()); dialog.setScene(scene); + final Stage fxStage = EditorUtil.getFxStage(); + final ObservableList icons = dialog.getIcons(); + icons.addAll(fxStage.getIcons()); + configureSize(container); } diff --git a/src/main/java/com/ss/editor/ui/dialog/GenerateTangentsDialog.java b/src/main/java/com/ss/editor/ui/dialog/GenerateTangentsDialog.java index d876f7a3..ffa628c1 100644 --- a/src/main/java/com/ss/editor/ui/dialog/GenerateTangentsDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/GenerateTangentsDialog.java @@ -9,7 +9,7 @@ import com.ss.editor.annotation.FromAnyThread; import com.ss.editor.util.TangentGenerator; import com.ss.editor.model.undo.editor.ChangeConsumer; -import com.ss.editor.ui.control.tree.action.impl.operation.ChangeMeshOperation; +import com.ss.editor.model.undo.impl.ChangeMeshOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.ui.css.CssClasses; diff --git a/src/main/java/com/ss/editor/ui/dialog/SettingsDialog.java b/src/main/java/com/ss/editor/ui/dialog/SettingsDialog.java index 09462143..abc9408f 100644 --- a/src/main/java/com/ss/editor/ui/dialog/SettingsDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/SettingsDialog.java @@ -19,6 +19,7 @@ import com.ss.editor.manager.ClasspathManager; import com.ss.editor.manager.ExecutorManager; import com.ss.editor.manager.ResourceManager; +import com.ss.editor.part3d.editor.impl.scene.SceneEditor3DPart; import com.ss.editor.plugin.api.property.control.PropertyEditorControl; import com.ss.editor.plugin.api.settings.SettingsCategory; import com.ss.editor.plugin.api.settings.SettingsPropertyDefinition; @@ -80,6 +81,7 @@ public class SettingsDialog extends EditorDialog { public SettingsDialog() { FXUtils.addClassTo(getContainer(), CssClasses.SETTINGS_DIALOG); + validate(); } @Override @@ -257,12 +259,20 @@ private void processOk() { EXECUTOR_MANAGER.addJmeTask(() -> { final JmeApplication jmeApplication = JmeApplication.getInstance(); - final FXAAFilter fxaaFilter = jmeApplication.getFXAAFilter(); - fxaaFilter.setEnabled(editorConfig.getBoolean(PREF_FILTER_FXAA, PREF_DEFAULT_FXAA_FILTER)); + final SceneEditor3DPart sceneEditor3DPart = jmeApplication.getStateManager() + .getState(SceneEditor3DPart.class); final ToneMapFilter filter = jmeApplication.getToneMapFilter(); - filter.setEnabled(editorConfig.getBoolean(PREF_FILTER_TONEMAP, PREF_DEFAULT_TONEMAP_FILTER)); filter.setWhitePoint(editorConfig.getVector3f(PREF_FILTER_TONEMAP_WHITE_POINT, PREF_DEFAULT_TONEMAP_WHITE_POINT)); + + if (sceneEditor3DPart != null) { + return; + } + + filter.setEnabled(editorConfig.getBoolean(PREF_FILTER_TONEMAP, PREF_DEFAULT_TONEMAP_FILTER)); + + final FXAAFilter fxaaFilter = jmeApplication.getFXAAFilter(); + fxaaFilter.setEnabled(editorConfig.getBoolean(PREF_FILTER_FXAA, PREF_DEFAULT_FXAA_FILTER)); }); if (requiredUpdateClasspath != null) { diff --git a/src/main/java/com/ss/editor/ui/dialog/animation/ExtractSubAnimationDialog.java b/src/main/java/com/ss/editor/ui/dialog/animation/ExtractSubAnimationDialog.java index 16c9495a..5a661990 100644 --- a/src/main/java/com/ss/editor/ui/dialog/animation/ExtractSubAnimationDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/animation/ExtractSubAnimationDialog.java @@ -11,7 +11,7 @@ import com.ss.editor.manager.ExecutorManager; import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.ui.control.tree.NodeTree; -import com.ss.editor.ui.control.tree.action.impl.operation.animation.AddAnimationNodeOperation; +import com.ss.editor.model.undo.impl.animation.AddAnimationNodeOperation; import com.ss.editor.ui.control.tree.node.impl.control.anim.AnimationTreeNode; import com.ss.editor.ui.css.CssClasses; import com.ss.editor.ui.dialog.AbstractSimpleEditorDialog; diff --git a/src/main/java/com/ss/editor/ui/dialog/sky/CreateSkyDialog.java b/src/main/java/com/ss/editor/ui/dialog/sky/CreateSkyDialog.java index 14e1b566..a19b986a 100644 --- a/src/main/java/com/ss/editor/ui/dialog/sky/CreateSkyDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/sky/CreateSkyDialog.java @@ -25,7 +25,7 @@ import com.ss.editor.model.undo.editor.ModelChangeConsumer; import com.ss.editor.ui.control.choose.ChooseFolderControl; import com.ss.editor.ui.control.choose.ChooseTextureControl; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.ui.css.CssClasses; diff --git a/src/main/java/com/ss/editor/ui/dialog/terrain/CreateTerrainDialog.java b/src/main/java/com/ss/editor/ui/dialog/terrain/CreateTerrainDialog.java index c685f3bd..d38b685f 100644 --- a/src/main/java/com/ss/editor/ui/dialog/terrain/CreateTerrainDialog.java +++ b/src/main/java/com/ss/editor/ui/dialog/terrain/CreateTerrainDialog.java @@ -1,6 +1,6 @@ package com.ss.editor.ui.dialog.terrain; -import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.LOADED_MODEL_KEY; +import static com.ss.editor.part3d.editor.impl.scene.AbstractSceneEditor3DPart.KEY_LOADED_MODEL; import static com.ss.editor.util.EditorUtil.getAssetFile; import static com.ss.editor.util.EditorUtil.toAssetPath; import static com.ss.rlib.util.ObjectUtils.notNull; @@ -26,7 +26,7 @@ import com.ss.editor.model.undo.editor.ChangeConsumer; import com.ss.editor.ui.control.choose.ChooseFolderControl; import com.ss.editor.ui.control.choose.ChooseTextureControl; -import com.ss.editor.ui.control.tree.action.impl.operation.AddChildOperation; +import com.ss.editor.model.undo.impl.AddChildOperation; import com.ss.editor.ui.control.tree.NodeTree; import com.ss.editor.ui.control.tree.node.TreeNode; import com.ss.editor.ui.css.CssClasses; @@ -458,6 +458,8 @@ private void updatePathSizeValues() { } /** + * Get the total size combo box. + * * @return the total size combo box. */ @FxThread @@ -466,6 +468,8 @@ private void updatePathSizeValues() { } /** + * Get the patch size combo box. + * * @return the patch size combo box. */ @FxThread @@ -474,6 +478,8 @@ private void updatePathSizeValues() { } /** + * Get the alpha blend texture size combo box. + * * @return the alpha blend texture size combo box. */ @FxThread @@ -482,6 +488,8 @@ private void updatePathSizeValues() { } /** + * Get the min radius field. + * * @return the min radius field. */ @FxThread @@ -490,6 +498,8 @@ private void updatePathSizeValues() { } /** + * Get the max radius field. + * * @return the max radius field. */ @FxThread @@ -498,7 +508,9 @@ private void updatePathSizeValues() { } /** - * @return the settingsRoot. + * Get the settings root. + * + * @return the settings root. */ @FxThread private @NotNull VBox getSettingsRoot() { @@ -506,6 +518,8 @@ private void updatePathSizeValues() { } /** + * Get the base texture control. + * * @return the base texture control. */ @FxThread @@ -514,6 +528,8 @@ private void updatePathSizeValues() { } /** + * Get the base image control. + * * @return the base image control. */ @FxThread @@ -522,6 +538,8 @@ private void updatePathSizeValues() { } /** + * Get the type of height map. + * * @return the type of height map. */ @FxThread @@ -530,6 +548,8 @@ private void updatePathSizeValues() { } /** + * Get the height map scale field. + * * @return the height map scale field. */ @FxThread @@ -538,6 +558,8 @@ private void updatePathSizeValues() { } /** + * Get the height map smooth field. + * * @return the height map smooth field. */ @FxThread @@ -546,6 +568,8 @@ private void updatePathSizeValues() { } /** + * Get the flattening field. + * * @return the flattening field. */ @FxThread @@ -554,6 +578,8 @@ private void updatePathSizeValues() { } /** + * Get the iterations field. + * * @return the iterations field. */ @FxThread @@ -562,6 +588,8 @@ private void updatePathSizeValues() { } /** + * Get the alpha texture folder control. + * * @return the alpha texture folder control. */ @FxThread @@ -779,7 +807,7 @@ private void createTerrainInBackground() throws Exception { terrainMaterial.setBoolean("WardIso", true); final com.jme3.scene.Node terrainNode = (com.jme3.scene.Node) terrain; - terrainNode.setUserData(LOADED_MODEL_KEY, true); + terrainNode.setUserData(KEY_LOADED_MODEL, true); terrainNode.setMaterial(terrainMaterial); terrainNode.setModelBound(new BoundingBox()); terrainNode.updateModelBound(); @@ -808,6 +836,8 @@ private void createTerrainInBackground() throws Exception { } /** + * Get the node tree. + * * @return the node tree. */ @FxThread @@ -816,6 +846,8 @@ private void createTerrainInBackground() throws Exception { } /** + * Get the parent node. + * * @return the parent node. */ @FxThread diff --git a/src/main/java/com/ss/editor/ui/util/UiUtils.java b/src/main/java/com/ss/editor/ui/util/UiUtils.java index 2dbaf40e..2f4cc800 100644 --- a/src/main/java/com/ss/editor/ui/util/UiUtils.java +++ b/src/main/java/com/ss/editor/ui/util/UiUtils.java @@ -986,6 +986,34 @@ public static boolean hasFileInClipboard() { return !(files == null || files.isEmpty()); } + /** + * Find a menu item by the item's type. + * + * @param items the item list. + * @param type the item's type. + * @param the item's type. + * @return the found item or null. + */ + @FxThread + public static @Nullable T findMenuItem(@NotNull final List items, + @NotNull final Class type) { + for (final MenuItem item : items) { + + if (type.isInstance(item)) { + return type.cast(item); + } + + if (item instanceof Menu) { + final T result = findMenuItem(((Menu) item).getItems(), type); + if (result != null) { + return result; + } + } + } + + return null; + } + private UiUtils() { throw new RuntimeException(); } diff --git a/src/main/java/com/ss/editor/util/ControlUtils.java b/src/main/java/com/ss/editor/util/ControlUtils.java index 5d815ce4..0772c5bd 100644 --- a/src/main/java/com/ss/editor/util/ControlUtils.java +++ b/src/main/java/com/ss/editor/util/ControlUtils.java @@ -1,10 +1,23 @@ package com.ss.editor.util; +import static com.jme3.bullet.util.CollisionShapeFactory.createDynamicMeshShape; +import static com.jme3.bullet.util.CollisionShapeFactory.createMeshShape; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.collision.shapes.BoxCollisionShape; +import com.jme3.bullet.collision.shapes.CollisionShape; +import com.jme3.bullet.collision.shapes.SphereCollisionShape; import com.jme3.bullet.control.PhysicsControl; +import com.jme3.bullet.objects.PhysicsRigidBody; +import com.jme3.math.Vector3f; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; import com.jme3.scene.Spatial; import com.jme3.scene.control.AbstractControl; import com.jme3.scene.control.Control; +import com.jme3.scene.shape.Box; +import com.jme3.scene.shape.Sphere; import com.ss.editor.annotation.FromAnyThread; +import com.ss.editor.annotation.JmeThread; import org.jetbrains.annotations.NotNull; import java.util.Arrays; @@ -17,6 +30,29 @@ */ public class ControlUtils { + /** + * Create control's stream by the spatial. + * + * @param spatial the spatial. + * @return the control's stream. + */ + @FromAnyThread + public static boolean has(@NotNull final Spatial spatial, @NotNull final Class type) { + + final int numControls = spatial.getNumControls(); + if (numControls < 1) { + return false; + } + + for (int i = 0; i < numControls; i++) { + if (type.isInstance(spatial.getControl(i))) { + return true; + } + } + + return false; + } + /** * Create control's stream by the spatial. * @@ -32,7 +68,7 @@ public class ControlUtils { } final Control[] controls = new Control[numControls]; - for (int i = 0; i < controls.length; i++) { + for (int i = 0; i < numControls; i++) { controls[i] = spatial.getControl(i); } @@ -70,4 +106,53 @@ public static void setEnabled(@NotNull final Control control, final boolean enab ((PhysicsControl) control).setEnabled(enabled); } } + + /** + * Apply the new scale. + * + * @param spatial the spatial. + * @param currentScale the current scale. + * @param object the collision object. + */ + @JmeThread + public static void applyScale(@NotNull Spatial spatial, + @NotNull final Vector3f currentScale, + @NotNull final PhysicsCollisionObject object) { + + final float mass = object instanceof PhysicsRigidBody ? ((PhysicsRigidBody) object).getMass() : 1F; + + CollisionShape shape = null; + + if (spatial instanceof Geometry) { + + final Geometry geom = (Geometry) spatial; + final Mesh mesh = geom.getMesh(); + + if (mesh instanceof Sphere) { + + final float x = currentScale.getX(); + if (Float.compare(x, currentScale.getY()) == 0 && Float.compare(x, currentScale.getZ()) == 0) { + shape = new SphereCollisionShape(((Sphere) mesh).getRadius() * x); + } + + } else if (mesh instanceof Box) { + + final Box box = (Box) mesh; + final Vector3f halfExtents = new Vector3f(box.getXExtent(), box.getYExtent(), box.getZExtent()); + halfExtents.multLocal(currentScale); + + shape = new BoxCollisionShape(halfExtents); + } + } + + if (shape == null) { + if (mass > 0) { + shape = createDynamicMeshShape(spatial); + } else { + shape = createMeshShape(spatial); + } + } + + object.setCollisionShape(shape); + } } diff --git a/src/main/java/com/ss/editor/util/EditorUtil.java b/src/main/java/com/ss/editor/util/EditorUtil.java index ff065717..f2f3b709 100644 --- a/src/main/java/com/ss/editor/util/EditorUtil.java +++ b/src/main/java/com/ss/editor/util/EditorUtil.java @@ -717,6 +717,7 @@ public static void openFileInSystemExplorer(@NotNull Path path) { commands.add("nautilus"); } else if (isAppExists("dolphin -v")) { commands.add("dolphin"); + commands.add("--select"); } else { commands.add("xdg-open"); if (!Files.isDirectory(path)) { @@ -725,7 +726,9 @@ public static void openFileInSystemExplorer(@NotNull Path path) { } } - if (commands.isEmpty()) return; + if (commands.isEmpty()) { + return; + } final String url; try { diff --git a/src/main/java/com/ss/editor/util/GeomUtils.java b/src/main/java/com/ss/editor/util/GeomUtils.java index 6c9348b8..ed9c5054 100644 --- a/src/main/java/com/ss/editor/util/GeomUtils.java +++ b/src/main/java/com/ss/editor/util/GeomUtils.java @@ -214,7 +214,7 @@ public static boolean canAttach(@NotNull final Node node, @NotNull final Spatial } /** - * Get a context point on spatial from cursor position. + * Get a contact point on the spatial from cursor position. * * @param spatial the spatial. * @param camera the camera. @@ -227,6 +227,36 @@ public static boolean canAttach(@NotNull final Node node, @NotNull final Spatial return getContactPointFromScreenPos(spatial, camera, cursor.getX(), cursor.getY()); } + /** + * Get a collision result on the spatial from cursor position. + * + * @param spatial the spatial. + * @param camera the camera. + * @return the collision result or null. + */ + @FromAnyThread + public static @Nullable CollisionResult getCollisionFromCursor(@NotNull final Spatial spatial, + @NotNull final Camera camera) { + final InputManager inputManager = EditorUtil.getInputManager(); + final Vector2f cursor = inputManager.getCursorPosition(); + return getCollisionFromScreenPos(spatial, camera, cursor.getX(), cursor.getY()); + } + + /** + * Get a collisions result on the spatial from cursor position. + * + * @param spatial the spatial. + * @param camera the camera. + * @return the collisions result. + */ + @FromAnyThread + public static @NotNull CollisionResults getCollisionsFromCursor(@NotNull final Spatial spatial, + @NotNull final Camera camera) { + final InputManager inputManager = EditorUtil.getInputManager(); + final Vector2f cursor = inputManager.getCursorPosition(); + return getCollisionsFromScreenPos(spatial, camera, cursor.getX(), cursor.getY()); + } + /** * Get a contact point on spatial from screen position. * @@ -244,6 +274,23 @@ public static boolean canAttach(@NotNull final Node node, @NotNull final Spatial return collision == null ? null : collision.getContactPoint(); } + /** + * Get a contact normal on spatial from screen position. + * + * @param spatial the spatial. + * @param camera the camera. + * @param screenX the screen X coord. + * @param screenY the screen Y coord. + * @return the contact normal or null. + */ + @FromAnyThread + public static @Nullable Vector3f getContactNormalFromScreenPos(@NotNull final Spatial spatial, + @NotNull final Camera camera, final float screenX, + final float screenY) { + final CollisionResult collision = getCollisionFromScreenPos(spatial, camera, screenX, screenY); + return collision == null ? null : collision.getContactNormal(); + } + /** * Get a geometry on spatial from cursor position. * @@ -289,6 +336,28 @@ public static boolean canAttach(@NotNull final Node node, @NotNull final Spatial @NotNull final Camera camera, final float screenX, final float screenY) { + final CollisionResults results = getCollisionsFromScreenPos(spatial, camera, screenX, screenY); + if (results.size() < 1) { + return null; + } + + return results.getClosestCollision(); + } + + /** + * Get a collision on spatial from screen position. + * + * @param spatial the spatial. + * @param camera the camera. + * @param screenX the screen X coord. + * @param screenY the screen Y coord. + * @return the collisions . + */ + @FromAnyThread + public static @NotNull CollisionResults getCollisionsFromScreenPos(@NotNull final Spatial spatial, + @NotNull final Camera camera, + final float screenX, final float screenY) { + final LocalObjects local = LocalObjects.get(); final Vector2f cursor = local.nextVector(screenX, screenY); @@ -306,10 +375,6 @@ public static boolean canAttach(@NotNull final Node node, @NotNull final Spatial spatial.updateModelBound(); spatial.collideWith(ray, results); - if (results.size() < 1) { - return null; - } - - return results.getClosestCollision(); + return results; } } diff --git a/src/main/java/com/ss/editor/util/LocalObjects.java b/src/main/java/com/ss/editor/util/LocalObjects.java index 11310577..07550ce1 100644 --- a/src/main/java/com/ss/editor/util/LocalObjects.java +++ b/src/main/java/com/ss/editor/util/LocalObjects.java @@ -3,12 +3,17 @@ import static java.lang.Thread.currentThread; import com.jme3.collision.CollisionResults; import com.jme3.math.*; +import com.jme3.scene.Spatial; import com.ss.editor.EditorThread; import com.ss.editor.annotation.FromAnyThread; import com.ss.rlib.util.CycleBuffer; +import com.ss.rlib.util.array.Array; +import com.ss.rlib.util.array.ArrayFactory; import com.ss.rlib.util.pools.Reusable; import org.jetbrains.annotations.NotNull; +import java.util.Collection; + /** * The container with local objects. * @@ -18,13 +23,22 @@ public class LocalObjects { private static final int SIZE = 50; + @NotNull + private static final ThreadLocal THREAD_LOCAL = ThreadLocal.withInitial(LocalObjects::new); + /** * Get the local objects. * * @return the local objects */ public static @NotNull LocalObjects get() { - return ((EditorThread) currentThread()).getLocal(); + + final Thread currentThread = currentThread(); + if (currentThread instanceof EditorThread) { + ((EditorThread) currentThread).getLocal(); + } + + return THREAD_LOCAL.get(); } /** @@ -81,6 +95,18 @@ public class LocalObjects { @NotNull private final CycleBuffer matrixFloatBuffer; + /** + * The buffer of object arrays. + */ + @NotNull + private final CycleBuffer> objectArrayBuffer; + + /** + * The buffer of spatial's arrays. + */ + @NotNull + private final CycleBuffer> spatialArrayBuffer; + @SuppressWarnings("unchecked") public LocalObjects() { this.vectorBuffer = new CycleBuffer<>(Vector3f.class, SIZE, Vector3f::new); @@ -91,10 +117,32 @@ public LocalObjects() { this.matrix3fBuffer = new CycleBuffer<>(Matrix3f.class, SIZE, Matrix3f::new); this.matrixFloatBuffer = new CycleBuffer<>(float[].class, SIZE, () -> new float[16]); this.colorBuffer = new CycleBuffer<>(ColorRGBA.class, SIZE, ColorRGBA::new); + this.objectArrayBuffer = new CycleBuffer<>(Array.class, SIZE, () -> ArrayFactory.newArray(Object.class), Collection::clear); + this.spatialArrayBuffer = new CycleBuffer<>(Array.class, SIZE, () -> ArrayFactory.newArray(Spatial.class), Collection::clear); this.collisionResultsBuffer = new CycleBuffer<>(ReusableCollisionResults.class, SIZE, ReusableCollisionResults::new, Reusable::free); } + /** + * Get the next free objects array. + * + * @return the next free objects array. + */ + @FromAnyThread + public @NotNull Array nextObjectArray() { + return objectArrayBuffer.next(); + } + + /** + * Get the next free spatial's array. + * + * @return the next free spatial's array. + */ + @FromAnyThread + public @NotNull Array nextSpatialArray() { + return spatialArrayBuffer.next(); + } + /** * Get next free matrix. * diff --git a/src/main/java/com/ss/editor/util/NodeUtils.java b/src/main/java/com/ss/editor/util/NodeUtils.java index 4efe0f43..c9a498ad 100644 --- a/src/main/java/com/ss/editor/util/NodeUtils.java +++ b/src/main/java/com/ss/editor/util/NodeUtils.java @@ -9,15 +9,15 @@ import com.jme3.scene.Geometry; import com.jme3.scene.Node; import com.jme3.scene.Spatial; -import com.jme3.scene.control.Control; import com.ss.editor.annotation.FromAnyThread; +import com.ss.editor.annotation.JmeThread; import com.ss.rlib.util.StringUtils; import com.ss.rlib.util.array.Array; import com.ss.rlib.util.array.ArrayFactory; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; +import java.lang.reflect.Field; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; @@ -29,6 +29,18 @@ */ public class NodeUtils { + @NotNull + private static final Field FIELD_WORLD_BOUND; + + static { + try { + FIELD_WORLD_BOUND = Spatial.class.getDeclaredField("worldBound"); + FIELD_WORLD_BOUND.setAccessible(true); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + /** * Find a parent of the model. * @@ -80,7 +92,10 @@ public class NodeUtils { */ @FromAnyThread public static @Nullable Geometry findGeometry(@NotNull final Spatial spatial) { - if (!(spatial instanceof Node)) { + + if (spatial instanceof Geometry) { + return (Geometry) spatial; + } else if (!(spatial instanceof Node)) { return null; } @@ -389,6 +404,19 @@ public static void visitSpatial(@NotNull final Spatial spati } } + /** + * Collect all geometries. + * + * @param spatial the spatial. + * @return the list of all geometries. + */ + @FromAnyThread + public static @NotNull Array getGeometries(@NotNull final Spatial spatial) { + final Array result = ArrayFactory.newArray(Geometry.class); + addGeometry(spatial, result); + return result; + } + /** * Collect all geometries. * @@ -477,5 +505,14 @@ public static Stream children(@NotNull final Spatial spatial) { return result.stream(); } - + /** + * Force update world bound of the spatial. + * + * @param spatial the spatial. + */ + @JmeThread + public static void updateWorldBound(@NotNull final Spatial spatial) { + children(spatial).forEach(sp -> sp.forceRefresh(true, true, false)); + children(spatial).forEach(Spatial::getWorldBound); + } } diff --git a/src/main/java/com/ss/editor/util/PaintingUtils.java b/src/main/java/com/ss/editor/util/PaintingUtils.java index 3c51b996..9fd9b2fb 100644 --- a/src/main/java/com/ss/editor/util/PaintingUtils.java +++ b/src/main/java/com/ss/editor/util/PaintingUtils.java @@ -39,7 +39,8 @@ public class PaintingUtils { @FromAnyThread public static @Nullable Spatial getPaintedModel(@NotNull final Node cursorNode) { final PaintingControl control = getPaintingControl(cursorNode); - return control == null ? null : control.getPaintedModel(); + final Object paintedModel = control == null ? null : control.getPaintedModel(); + return paintedModel instanceof Spatial ? (Spatial) paintedModel : null; } /** @@ -50,7 +51,8 @@ public class PaintingUtils { */ @FromAnyThread public static @Nullable Spatial getPaintedModel(@Nullable final PaintingControl control) { - return control == null ? null : control.getPaintedModel(); + final Object paintedModel = control == null ? null : control.getPaintedModel(); + return paintedModel instanceof Spatial ? (Spatial) paintedModel : null; } /** diff --git a/src/main/java/com/ss/editor/util/ReusableCollisionResults.java b/src/main/java/com/ss/editor/util/ReusableCollisionResults.java index f31cd67b..3d39e844 100644 --- a/src/main/java/com/ss/editor/util/ReusableCollisionResults.java +++ b/src/main/java/com/ss/editor/util/ReusableCollisionResults.java @@ -9,6 +9,8 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Iterator; + /** * The reusable implementation of collision result. * @@ -40,6 +42,11 @@ public void addCollision(@NotNull final CollisionResult result) { original.add(result); } + @Override + public Iterator iterator() { + return collisions.iterator(); + } + @Override @JmeThread public CollisionResult getCollisionDirect(final int index) { diff --git a/src/main/resources/credits/icons.txt b/src/main/resources/credits/icons.txt index 2a84d0c3..df33a036 100644 --- a/src/main/resources/credits/icons.txt +++ b/src/main/resources/credits/icons.txt @@ -83,4 +83,5 @@ ui/icons/svg/debug.svg icon made by http://www.flaticon.com/authors/freepik from ui/icons/filetypes/vector.svg icon made by https://www.flaticon.com/authors/freepik from www.flaticon.com ui/icons/svg/import.svg icon made by https://www.flaticon.com/authors/anatoly from www.flaticon.com ui/icons/svg/filter-filled-tool-symbol.svg icon made by https://www.flaticon.com/authors/freepik from www.flaticon.com -ui/icons/svg/bar-chart-reload.svg icon made by https://www.flaticon.com/authors/freepik from www.flaticon.com \ No newline at end of file +ui/icons/svg/bar-chart-reload.svg icon made by https://www.flaticon.com/authors/freepik from www.flaticon.com +ui/icons/svg/forest.svg icon made by https://www.flaticon.com/authors/freepik from www.flaticon.com \ No newline at end of file diff --git a/src/main/resources/credits/libraries.txt b/src/main/resources/credits/libraries.txt index 8143ace6..c62c4b25 100644 --- a/src/main/resources/credits/libraries.txt +++ b/src/main/resources/credits/libraries.txt @@ -15,9 +15,9 @@ batik-script-1.8 batik-svg-dom-1.8 batik-svggen-1.8 log4j-1.2.6 javafxsvg-1.2.1 core-0.27 dense64-0.27 denseC64-0.27 eventbus-1.4 stack-alloc simple-0.27 jutils-1.0.0 lwjgl j-ogg-all-1.0.0 jbullet jglfont-core-1.4 xpp3-1.1.4c retrace lwjgl-stb lwjgl-glfw -jinput-2.0.5 jme3-blender-3.2.0 jme3-bullet-3.2.0 vecmath-1.3.1 lwjgl-opengl jsr305-2.0.2 -jme3-bullet-native-3.2.0 jme3-core-3.2.0 jme3-desktop-3.2.0 lwjgl-opencl jme3-terrain-3.2.0 -jme3-effects-3.2.0 jme3-jogg-3.2.0 jme3-lwjgl3-3.2.0 lwjgl-openal lwjgl-jemalloc jme3-plugins-3.2.0 +jinput-2.0.5 jme3-blender-3.3.0 jme3-bullet-3.3.0 vecmath-1.3.1 lwjgl-opengl jsr305-2.0.2 +jme3-bullet-native-3.3.0 jme3-core-3.3.0 jme3-desktop-3.3.0 lwjgl-opencl jme3-terrain-3.3.0 +jme3-effects-3.3.0 jme3-jogg-3.3.0 jme3-lwjgl3-3.3.0 lwjgl-openal lwjgl-jemalloc jme3-plugins-3.3.0 ## http @@ -25,17 +25,9 @@ commons-codec-1.9 commons-logging-1.2 httpclient-4.5.2 httpcore-4.4.4 ## extensions -jmonkeybuilder-extension-1.9.7 groovy-all-2.5.0-beta-1 annotations-15.0 +jmonkeybuilder-extension-2.1.1 groovy-all-2.5.0-beta-1 annotations-15.0 ## extensions ## xbuf guava-18.0 jme3_physicsloader-0.5 jme3_xbuf_loader-0.9.1 xbuf-0.9.1 slf4j-api-1.7.7 -jme3_xbuf_rt-0.9.1 protobuf-java-3.0.0 protobuf-java-util-3.0.0 - -## extensions ## t0neg0d - -toneg0d.emitter-2.4.1 - -## extensions ## simsilica - -iso-surface.1.0.0 lemur-1.9.1 sim-fx-1.3.0 +jme3_xbuf_rt-0.9.1 protobuf-java-3.0.0 protobuf-java-util-3.0.0 \ No newline at end of file diff --git a/src/main/resources/messages/messages.properties b/src/main/resources/messages/messages.properties index ca18a548..5370c0cb 100644 --- a/src/main/resources/messages/messages.properties +++ b/src/main/resources/messages/messages.properties @@ -275,6 +275,8 @@ ModelNodeTreeActionCylinderCollisionShape=Cylinder ModelNodeTreeActionSphereCollisionShape=Sphere ModelNodeTreeActionAddWheel=Add wheel ModelNodeTreeActionAddTerrain=Terrain +ModelNodeTreeActionEnableAllControls=Enable all controls +ModelNodeTreeActionDisableAllControls=Disable all controls ModelPropertyCullHint=Cull Hint ModelPropertyShadowMode=Shadow mode @@ -282,6 +284,7 @@ ModelPropertyQueueBucket=Queue bucket ModelPropertyLocation=Location ModelPropertyScale=Scale ModelPropertyRotation=Rotation +ModelPropertyTransformation=Transformation ModelPropertyMaterial=Material ModelPropertyDirection=Direction ModelPropertyRadius=Radius @@ -329,6 +332,8 @@ ModelPropertyWalkDirection=Walk direction ModelPropertyFallSpeed=Fall speed ModelPropertyGravity=Gravity ModelPropertyJumpSpeed=Jump speed +ModelPropertyJumpForce=Jump force +ModelPropertyPhysicsDamping=Physics damping ModelPropertyMaxSlope=Max slope ModelPropertyIsApplyPhysicsLocal=Apply physics local ModelPropertyIsUseViewDirection=Use view direction @@ -611,20 +616,22 @@ CreateParticleEmitterQuadShapeDialogTitle=Creating a quad shape CreateParticleEmitterTorusShapeDialogTitle=Creating a torus shape CreateParticleEmitterTriangleShapeDialogTitle=Creating a triangle shape -EditingComponentBrushSize=Brush size -EditingComponentBrushPower=Brush power -EditingComponentSmoothly=Smoothly -EditingComponentLimited=Limited -EditingComponentUseMarker=User marker -EditingComponentLevel=Level -EditingComponentRoughness=Roughness -EditingComponentFrequency=Frequency -EditingComponentLacunarity=Lacunarity -EditingComponentOctaves=Octaves -EditingComponentScale=Scale -EditingComponentTriPlanar=Tri-planar -EditingComponentShininess=Shininess -EditingComponentLayer=Layer +PaintingComponentBrushSize=Brush size +PaintingComponentBrushPower=Brush power +PaintingComponentSmoothly=Smoothly +PaintingComponentLimited=Limited +PaintingComponentUseMarker=User marker +PaintingComponentLevel=Level +PaintingComponentRoughness=Roughness +PaintingComponentFrequency=Frequency +PaintingComponentLacunarity=Lacunarity +PaintingComponentOctaves=Octaves +PaintingComponentScale=Scale +PaintingComponentTriPlanar=Tri-planar +PaintingComponentShininess=Shininess +PaintingComponentLayer=Layer +PaintingComponentModel=Model +PaintingComponentMethod=Method ModelConverterDialogTitle=Model converting ModelConverterDialogResultName=Result name @@ -667,4 +674,8 @@ PluginsDialogUsedDependencies=Used dependencies PaintingComponentContainerTool=Tool PaintingComponentContainerNoTools=No tools -PaintingComponentTerrainEditor=Terrain editor \ No newline at end of file +PaintingComponentTerrainEditor=Terrain editor +PaintingComponentSpawnModels=Spawn models +PaintingComponentSpawnModelsMethodAsIs=As Is +PaintingComponentSpawnModelsMethodLink=Using links +PaintingComponentSpawnModelsMethodBatch=Using batches \ No newline at end of file diff --git a/src/main/resources/messages/messages_de.properties b/src/main/resources/messages/messages_de.properties index 7cbfd944..94ad9ad6 100644 --- a/src/main/resources/messages/messages_de.properties +++ b/src/main/resources/messages/messages_de.properties @@ -275,6 +275,8 @@ ModelNodeTreeActionCylinderCollisionShape=Zylinder ModelNodeTreeActionSphereCollisionShape=Kugel ModelNodeTreeActionAddWheel=Rad ModelNodeTreeActionAddTerrain=Gelände +ModelNodeTreeActionEnableAllControls=Enable all controls +ModelNodeTreeActionDisableAllControls=Disable all controls ModelPropertyCullHint=Cull Hint ModelPropertyShadowMode=Schattenmodus @@ -283,6 +285,7 @@ ModelPropertyLocation=Ort ModelPropertyScale=Skalierung ModelPropertyRotation=Drehung ModelPropertyMaterial=Material +ModelPropertyTransformation=Transformation ModelPropertyDirection=Ausrichtung ModelPropertyRadius=Radius ModelPropertyColor=Farbe @@ -329,6 +332,8 @@ ModelPropertyWalkDirection=Bewegungsrichtung ModelPropertyFallSpeed=Fallgeschwindigkeit ModelPropertyGravity=Gravitation ModelPropertyJumpSpeed=Sprunggeschwindigkeit +ModelPropertyJumpForce=Jump force +ModelPropertyPhysicsDamping=Physics damping ModelPropertyMaxSlope=Maximale Neigung ModelPropertyIsApplyPhysicsLocal=Lokale Physik ModelPropertyIsUseViewDirection=Benutze Ansichtrichtung @@ -611,20 +616,22 @@ CreateParticleEmitterQuadShapeDialogTitle=Viereck-Form erstellen CreateParticleEmitterTorusShapeDialogTitle=Torus-Form erstellen CreateParticleEmitterTriangleShapeDialogTitle=Dreieck-Form erstellen -EditingComponentBrushSize=Pinselgröße -EditingComponentBrushPower=Pinselstärke -EditingComponentSmoothly=Weich -EditingComponentLimited=Begrenzt -EditingComponentUseMarker=Benutze Marker -EditingComponentLevel=Stufe -EditingComponentRoughness=Rauheit -EditingComponentFrequency=Frequenz -EditingComponentLacunarity=Lakunarität -EditingComponentOctaves=Oktaven -EditingComponentScale=Maßstab -EditingComponentTriPlanar=Dreiflächig -EditingComponentShininess=Glänzend -EditingComponentLayer=Schicht +PaintingComponentBrushSize=Pinselgröße +PaintingComponentBrushPower=Pinselstärke +PaintingComponentSmoothly=Weich +PaintingComponentLimited=Begrenzt +PaintingComponentUseMarker=Benutze Marker +PaintingComponentLevel=Stufe +PaintingComponentRoughness=Rauheit +PaintingComponentFrequency=Frequenz +PaintingComponentLacunarity=Lakunarität +PaintingComponentOctaves=Oktaven +PaintingComponentScale=Maßstab +PaintingComponentTriPlanar=Dreiflächig +PaintingComponentShininess=Glänzend +PaintingComponentLayer=Schicht +PaintingComponentModel=Model +PaintingComponentMethod=Method ModelConverterDialogTitle=Modellkonvertierung ModelConverterDialogResultName=Resultierender Name @@ -667,4 +674,8 @@ PluginsDialogUsedDependencies=Used dependencies PaintingComponentContainerTool=Tool PaintingComponentContainerNoTools=No tools -PaintingComponentTerrainEditor=Terrain editor \ No newline at end of file +PaintingComponentTerrainEditor=Terrain editor +PaintingComponentSpawnModels=Spawn models +PaintingComponentSpawnModelsMethodAsIs=As Is +PaintingComponentSpawnModelsMethodLink=Using links +PaintingComponentSpawnModelsMethodBatch=Using batches \ No newline at end of file diff --git a/src/main/resources/messages/messages_fr.properties b/src/main/resources/messages/messages_fr.properties index 97c96b8c..bf0622b8 100644 --- a/src/main/resources/messages/messages_fr.properties +++ b/src/main/resources/messages/messages_fr.properties @@ -275,6 +275,8 @@ ModelNodeTreeActionCylinderCollisionShape=Cylindre ModelNodeTreeActionSphereCollisionShape=Sphère ModelNodeTreeActionAddWheel=Ajouter une roue ModelNodeTreeActionAddTerrain=Terrain +ModelNodeTreeActionEnableAllControls=Enable all controls +ModelNodeTreeActionDisableAllControls=Disable all controls ModelPropertyCullHint=Cull hint ModelPropertyShadowMode=Mode Shadow @@ -282,6 +284,7 @@ ModelPropertyQueueBucket=Tâche de file d'attente ModelPropertyLocation=Emplacement ModelPropertyScale=Echelle ModelPropertyRotation=Rotation +ModelPropertyTransformation=Transformation ModelPropertyMaterial=Matériel ModelPropertyDirection=Direction ModelPropertyRadius=Rayon @@ -329,6 +332,8 @@ ModelPropertyWalkDirection=Direction de la marche ModelPropertyFallSpeed ??= Vitesse de chute ModelPropertyGravity=Gravité ModelPropertyJumpSpeed ??= Vitesse de saut +ModelPropertyJumpForce=Jump force +ModelPropertyPhysicsDamping=Physics damping ModelPropertyMaxSlope=Pente maximale ModelPropertyIsApplyPhysicsLocal=Appliquer la physique locale ModelPropertyIsUseViewDirection=Utiliser la direction de la vue @@ -613,20 +618,22 @@ CreateParticleEmitterQuadShapeDialogTitle=Création d'une forme de quad CreateParticleEmitterTorusShapeDialogTitle=Création d'une forme de tore CreateParticleEmitterTriangleShapeDialogTitle=Création d'une forme de triangle -EditingComponentBrushSize=Taille du pinceau -EditingComponentBrushPower=Force du pincen (Intensité) -EditingComponentSmoothly=En douceur -EditingComponentLimited=Limité -EditingComponentUseMarker=Marqueur de l'utilisateur -EditingComponentLevel=Niveau -EditingComponentRoughness=Rugosité -EditingComponentFrequency=Fréquence -EditingComponentLacunarity=Lacunarité -EditingComponentOctaves=Octaves -EditingComponentScale=Echelle -EditingComponentTriPlanar=Tri-planaire -EditingComponentShininess=Brillance -EditingComponentLayer=Couche +PaintingComponentBrushSize=Taille du pinceau +PaintingComponentBrushPower=Force du pincen (Intensité) +PaintingComponentSmoothly=En douceur +PaintingComponentLimited=Limité +PaintingComponentUseMarker=Marqueur de l'utilisateur +PaintingComponentLevel=Niveau +PaintingComponentRoughness=Rugosité +PaintingComponentFrequency=Fréquence +PaintingComponentLacunarity=Lacunarité +PaintingComponentOctaves=Octaves +PaintingComponentScale=Echelle +PaintingComponentTriPlanar=Tri-planaire +PaintingComponentShininess=Brillance +PaintingComponentLayer=Couche +PaintingComponentModel=Model +PaintingComponentMethod=Method ModelConverterDialogTitle=Conversion de modèle ModelConverterDialogResultName=Nom du résultat @@ -669,4 +676,8 @@ PluginsDialogUsedDependencies=Used dependencies PaintingComponentContainerTool=Tool PaintingComponentContainerNoTools=No tools -PaintingComponentTerrainEditor=Terrain editor \ No newline at end of file +PaintingComponentTerrainEditor=Terrain editor +PaintingComponentSpawnModels=Spawn models +PaintingComponentSpawnModelsMethodAsIs=As Is +PaintingComponentSpawnModelsMethodLink=Using links +PaintingComponentSpawnModelsMethodBatch=Using batches \ No newline at end of file diff --git a/src/main/resources/messages/messages_ru.properties b/src/main/resources/messages/messages_ru.properties index 06b44e7f..058c948d 100644 --- a/src/main/resources/messages/messages_ru.properties +++ b/src/main/resources/messages/messages_ru.properties @@ -277,6 +277,8 @@ ModelNodeTreeActionCylinderCollisionShape=Цилиндр ModelNodeTreeActionSphereCollisionShape=Сфера ModelNodeTreeActionAddWheel=Добавить колесо ModelNodeTreeActionAddTerrain=Местность +ModelNodeTreeActionEnableAllControls=Включить все контролы +ModelNodeTreeActionDisableAllControls=Выключить все контролы ModelPropertyCullHint=Cull Hint ModelPropertyShadowMode=Режим теней @@ -284,6 +286,7 @@ ModelPropertyQueueBucket=Порядок рендера ModelPropertyLocation=Положение ModelPropertyScale=Маштаб ModelPropertyRotation=Вращение +ModelPropertyTransformation=Трансформация ModelPropertyMaterial=Материал ModelPropertyDirection=Направление ModelPropertyRadius=Радиус @@ -331,6 +334,8 @@ ModelPropertyWalkDirection=Направление движения ModelPropertyFallSpeed=Скорость падения ModelPropertyGravity=Гравитация ModelPropertyJumpSpeed=Скорость прыжка +ModelPropertyJumpForce=Сила прыжка +ModelPropertyPhysicsDamping=Гашение физики ModelPropertyMaxSlope=Макс. наклон ModelPropertyIsApplyPhysicsLocal=Местная физика ModelPropertyIsUseViewDirection=Исп. напр. просмотра @@ -613,20 +618,22 @@ CreateParticleEmitterQuadShapeDialogTitle=Создание формы квадр CreateParticleEmitterTorusShapeDialogTitle=Создание формы торуса CreateParticleEmitterTriangleShapeDialogTitle=Создание формы треугольника -EditingComponentBrushSize=Размер кисти -EditingComponentBrushPower=Сила кисти -EditingComponentSmoothly=Плавно -EditingComponentLimited=Ограничено -EditingComponentUseMarker=Использовать маркер -EditingComponentLevel=Уровень -EditingComponentRoughness=Шершавость -EditingComponentFrequency=Частота -EditingComponentLacunarity=Лакунарность -EditingComponentOctaves=Октав -EditingComponentScale=Маштаб -EditingComponentTriPlanar=Три-плоскостной -EditingComponentShininess=Блеск -EditingComponentLayer=Слой +PaintingComponentBrushSize=Размер кисти +PaintingComponentBrushPower=Сила кисти +PaintingComponentSmoothly=Плавно +PaintingComponentLimited=Ограничено +PaintingComponentUseMarker=Использовать маркер +PaintingComponentLevel=Уровень +PaintingComponentRoughness=Шершавость +PaintingComponentFrequency=Частота +PaintingComponentLacunarity=Лакунарность +PaintingComponentOctaves=Октав +PaintingComponentScale=Маштаб +PaintingComponentTriPlanar=Три-плоскостной +PaintingComponentShininess=Блеск +PaintingComponentLayer=Слой +PaintingComponentModel=Модель +PaintingComponentMethod=Метод ModelConverterDialogTitle=Конвертирование модели ModelConverterDialogResultName=Итоговое имя @@ -669,4 +676,8 @@ PluginsDialogUsedDependencies=Используемые зависимости PaintingComponentContainerTool=Инструмент PaintingComponentContainerNoTools=Нет инструментов -PaintingComponentTerrainEditor=Редактирование местности \ No newline at end of file +PaintingComponentTerrainEditor=Редактирование местности +PaintingComponentSpawnModels=Размещение моделей +PaintingComponentSpawnModelsMethodAsIs=Как есть +PaintingComponentSpawnModelsMethodLink=Использ. ссылки +PaintingComponentSpawnModelsMethodBatch=Использ. упаковку \ No newline at end of file diff --git a/src/main/resources/messages/messages_zh_CN.properties b/src/main/resources/messages/messages_zh_CN.properties index e8b5a7d0..0a0b8b6e 100644 --- a/src/main/resources/messages/messages_zh_CN.properties +++ b/src/main/resources/messages/messages_zh_CN.properties @@ -277,6 +277,8 @@ ModelNodeTreeActionCylinderCollisionShape=\u5706\u67f1\u4f53 ModelNodeTreeActionSphereCollisionShape=\u7403\u4f53 ModelNodeTreeActionAddWheel=\u6dfb\u52a0\u8f66\u8f6e ModelNodeTreeActionAddTerrain=\u6dfb\u52a0\u5730\u5f62 +ModelNodeTreeActionEnableAllControls=Enable all controls +ModelNodeTreeActionDisableAllControls=Disable all controls ModelPropertyCullHint=\u9762\u5254\u9664 ModelPropertyShadowMode=\u9634\u5f71\u6a21\u5f0f @@ -284,6 +286,7 @@ ModelPropertyQueueBucket=Queue bucket ModelPropertyLocation=\u4f4d\u7f6e ModelPropertyScale=\u7f29\u653e ModelPropertyRotation=\u65cb\u8f6c +ModelPropertyTransformation=Transformation ModelPropertyMaterial=\u6750\u8d28 ModelPropertyDirection=\u5b9a\u5411\u58f0\u6e90\u7684\u4f20\u64ad\u65b9\u5411 ModelPropertyRadius=\u534a\u5f84 @@ -331,6 +334,8 @@ ModelPropertyWalkDirection=\u884c\u8d70\u65b9\u5411 ModelPropertyFallSpeed=\u6389\u843d\u901f\u5ea6 ModelPropertyGravity=\u91cd\u529b\u52a0\u901f\u5ea6 ModelPropertyJumpSpeed=\u8df3\u8dc3\u901f\u5ea6 +ModelPropertyJumpForce=Jump force +ModelPropertyPhysicsDamping=Physics damping ModelPropertyMaxSlope=\u6700\u5927\u659c\u7387 ModelPropertyIsApplyPhysicsLocal=\u662f\u5426\u542f\u7528\u672c\u5730\u7269\u7406 ModelPropertyIsUseViewDirection=\u662f\u5426\u4f7f\u7528\u9762\u671d\u65b9\u5411 @@ -613,20 +618,22 @@ CreateParticleEmitterQuadShapeDialogTitle=\u521b\u5efa\u56db\u8fb9\u5f62\u72b6\u CreateParticleEmitterTorusShapeDialogTitle=\u521b\u5efa\u5706\u73af\u72b6\u53d1\u751f\u5668 CreateParticleEmitterTriangleShapeDialogTitle=\u521b\u5efa\u4e09\u89d2\u5f62\u53d1\u751f\u5668 -EditingComponentBrushSize=\u7b14\u5237\u5c3a\u5bf8 -EditingComponentBrushPower=\u7b14\u5237\u529b\u5ea6 -EditingComponentSmoothly=\u5e73\u6ed1\u7684 -EditingComponentLimited=\u53d7\u9650\u7684 -EditingComponentUseMarker=\u7528\u6237\u6807\u8bb0 -EditingComponentLevel=\u7b49\u7ea7 -EditingComponentRoughness=\u7c97\u7cd9\u5ea6 -EditingComponentFrequency=\u9891\u7387 -EditingComponentLacunarity=\u5b54\u9699\u5ea6 -EditingComponentOctaves=\u516b\u8fb9\u5f62 -EditingComponentScale=\u7f29\u653e -EditingComponentTriPlanar=\u4e09\u5e73\u9762 -EditingComponentShininess=\u5149\u4eae\u5ea6 -EditingComponentLayer=\u5c42\u6b21 +PaintingComponentBrushSize=\u7b14\u5237\u5c3a\u5bf8 +PaintingComponentBrushPower=\u7b14\u5237\u529b\u5ea6 +PaintingComponentSmoothly=\u5e73\u6ed1\u7684 +PaintingComponentLimited=\u53d7\u9650\u7684 +PaintingComponentUseMarker=\u7528\u6237\u6807\u8bb0 +PaintingComponentLevel=\u7b49\u7ea7 +PaintingComponentRoughness=\u7c97\u7cd9\u5ea6 +PaintingComponentFrequency=\u9891\u7387 +PaintingComponentLacunarity=\u5b54\u9699\u5ea6 +PaintingComponentOctaves=\u516b\u8fb9\u5f62 +PaintingComponentScale=\u7f29\u653e +PaintingComponentTriPlanar=\u4e09\u5e73\u9762 +PaintingComponentShininess=\u5149\u4eae\u5ea6 +PaintingComponentLayer=\u5c42\u6b21 +PaintingComponentModel=Model +PaintingComponentMethod=Method ModelConverterDialogTitle=\u6a21\u578b\u8f6c\u6362 ModelConverterDialogResultName=\u6587\u4ef6\u540d @@ -669,4 +676,8 @@ PluginsDialogUsedDependencies=Used dependencies PaintingComponentContainerTool=Tool PaintingComponentContainerNoTools=No tools -PaintingComponentTerrainEditor=Terrain editor \ No newline at end of file +PaintingComponentTerrainEditor=Terrain editor +PaintingComponentSpawnModels=Spawn models +PaintingComponentSpawnModelsMethodAsIs=As Is +PaintingComponentSpawnModelsMethodLink=Using links +PaintingComponentSpawnModelsMethodBatch=Using batches \ No newline at end of file diff --git a/src/main/resources/ui/icons/svg/forest.svg b/src/main/resources/ui/icons/svg/forest.svg new file mode 100644 index 00000000..7f87efda --- /dev/null +++ b/src/main/resources/ui/icons/svg/forest.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/com/ss/editor/test/external/BOSceneTest.java b/src/test/java/com/ss/editor/test/external/BOSceneTest.java new file mode 100644 index 00000000..8ba9d7bf --- /dev/null +++ b/src/test/java/com/ss/editor/test/external/BOSceneTest.java @@ -0,0 +1,125 @@ +package com.ss.editor.test.external; + +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; +import com.jme3.material.Material; +import com.jme3.math.*; +import com.jme3.scene.Geometry; +import com.jme3.scene.shape.Box; + +import java.util.concurrent.ThreadLocalRandom; + +/** + * The simple test of j3s scenes. + * + * @author JavaSaBr + */ +public class BOSceneTest extends BaseExternalTest { + + public static void main(String[] args) { + run(BOSceneTest.class); + } + + /*private BufferObject ssbo; + private BufferObject ssbo2; + private BufferObject ubo; + @Override + public void simpleInitApp() { + super.simpleInitApp(); + + getFlyByCamera().setEnabled(false); + getInputManager().setCursorVisible(true); + + final Box box = new Box(1, 1, 1); + + Geometry geometry = new Geometry("Geom", box); + + ssbo = new BufferObject(3); + ssbo.setFieldValue("light_1", ColorRGBA.Red); + ssbo.setFieldValue("light_2", ColorRGBA.Green); + + ubo = new BufferObject(2); + ubo.setFieldValue("light_1", ColorRGBA.Yellow); + ubo.setFieldValue("light_2", ColorRGBA.Red); + + final Matrix3f matrix3f = new Matrix3f(); + matrix3f.setColumn(0, new Vector3f(0, 0, 1)); + matrix3f.setColumn(1, new Vector3f(0, 1, 0)); + matrix3f.setColumn(2, new Vector3f(0, 1, 0)); + + final Matrix4f matrix4f = new Matrix4f(); + matrix4f.setColumn(1, new float[]{0, 1, 0, 0}); + + ssbo2 = new BufferObject(4); + ssbo2.setFieldValue("index", 1); + ssbo2.setFieldValue("colors", new ColorRGBA[]{ColorRGBA.Green, ColorRGBA.Red, ColorRGBA.Blue}); + ssbo2.setFieldValue("alp", 1F); + ssbo2.setFieldValue("matrix3", matrix3f); + ssbo2.setFieldValue("matrix4", matrix4f); + ssbo2.setFieldValue("positions", new Vector3f[]{Vector3f.UNIT_X, new Vector3f(0.3F, 0.3f, 0.3F), Vector3f.UNIT_Z}); + ssbo2.setFieldValue("index2", 1); + ssbo2.setFieldValue("matrixes", new Matrix3f[] {new Matrix3f(), matrix3f}); + ssbo2.setFieldValue("vector2", new Vector2f(0, 0)); + ssbo2.setFieldValue("fvalue", 0.4F); + + final Material materialSSBO = new Material(assetManager, "MatDefs/UnshadedSSBO.j3md"); + materialSSBO.setShaderStorageBufferObject("TestSSBO", ssbo); + materialSSBO.setColor("Color", ColorRGBA.DarkGray); + + geometry.setMaterial(materialSSBO); + geometry.setLocalTranslation(1, 0, 0); + + rootNode.attachChild(geometry); + + final Material materialUBO = new Material(assetManager, "MatDefs/UnshadedUBO.j3md"); + materialUBO.setUniformBufferObject("TestUBO", ubo); + materialUBO.setColor("Color", ColorRGBA.DarkGray); + + geometry = geometry.clone(); + geometry.setMaterial(materialUBO); + geometry.setLocalTranslation(-1, 0, 0); + + rootNode.attachChild(geometry); + + final Material materialSSBO2 = new Material(assetManager, "MatDefs/UnshadedSSBO2.j3md"); + materialSSBO2.setShaderStorageBufferObject("TestSSBO", ssbo2); + materialSSBO2.setColor("Color", ColorRGBA.DarkGray); + + geometry = geometry.clone(); + geometry.setMaterial(materialSSBO2); + geometry.setLocalTranslation(-3, 0, 0); + + rootNode.attachChild(geometry); + + getFlyByCamera().setMoveSpeed(5); + getInputManager().addMapping("mouse", new KeyTrigger(KeyInput.KEY_SPACE)); + getInputManager().addListener((ActionListener) (name, isPressed, tpf) -> { + if (isPressed) { + getFlyByCamera().setEnabled(!getFlyByCamera().isEnabled()); + } + }, "mouse"); + } + + @Override + public void simpleUpdate(final float tpf) { + super.simpleUpdate(tpf); + + final ThreadLocalRandom random = ThreadLocalRandom.current(); + + ColorRGBA randomColor = new ColorRGBA(random.nextFloat(), + random.nextFloat(), + random.nextFloat(), + 1F); + + ssbo.setFieldValue("light_2", randomColor); + + randomColor = new ColorRGBA(random.nextFloat(), + random.nextFloat(), + random.nextFloat(), + 1F); + + ubo.setFieldValue("light_2", randomColor); + } +*/ +} diff --git a/src/test/java/com/ss/editor/test/external/BaseExternalTest.java b/src/test/java/com/ss/editor/test/external/BaseExternalTest.java index 4890663c..a4647dab 100644 --- a/src/test/java/com/ss/editor/test/external/BaseExternalTest.java +++ b/src/test/java/com/ss/editor/test/external/BaseExternalTest.java @@ -21,7 +21,7 @@ public class BaseExternalTest extends SimpleApplication { settings.setHeight(768); settings.setWidth(1024); settings.setGammaCorrection(true); - settings.setRenderer(AppSettings.LWJGL_OPENGL33); + settings.setRenderer(AppSettings.LWJGL_OPENGL43); return settings; } diff --git a/src/test/java/com/ss/editor/test/external/PbrSceneTest.java b/src/test/java/com/ss/editor/test/external/PbrSceneTest.java index 665567f1..f717c66e 100644 --- a/src/test/java/com/ss/editor/test/external/PbrSceneTest.java +++ b/src/test/java/com/ss/editor/test/external/PbrSceneTest.java @@ -1,5 +1,8 @@ package com.ss.editor.test.external; +import com.jme3.input.KeyInput; +import com.jme3.input.controls.ActionListener; +import com.jme3.input.controls.KeyTrigger; import com.ss.editor.extension.loader.SceneLoader; /** @@ -19,5 +22,14 @@ public void simpleInitApp() { SceneLoader.install(this, postProcessor); rootNode.attachChild(assetManager.loadModel("Scene/TestPbrScene.j3s")); getFlyByCamera().setMoveSpeed(5); + getInputManager().addMapping("mouse", new KeyTrigger(KeyInput.KEY_SPACE)); + getInputManager().addListener(new ActionListener() { + @Override + public void onAction(final String name, final boolean isPressed, final float tpf) { + if (isPressed) { + getFlyByCamera().setEnabled(!getFlyByCamera().isEnabled()); + } + } + }, "mouse"); } } diff --git a/src/test/resources/MatDefs/UnshadedSSBO.frag b/src/test/resources/MatDefs/UnshadedSSBO.frag new file mode 100644 index 00000000..5894d4a0 --- /dev/null +++ b/src/test/resources/MatDefs/UnshadedSSBO.frag @@ -0,0 +1,57 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD)) + #define NEED_TEXCOORD1 +#endif + +#if defined(DISCARD_ALPHA) + uniform float m_AlphaDiscardThreshold; +#endif + +uniform vec4 m_Color; +uniform sampler2D m_ColorMap; +uniform sampler2D m_LightMap; + +layout (std140, binding = 3) buffer m_TestSSBO +{ + vec4 light_1; + vec4 light_2; +}; + +varying vec2 texCoord1; +varying vec2 texCoord2; + +varying vec4 vertColor; + + +void main(){ + vec4 color = vec4(1.0); + + #ifdef HAS_COLORMAP + color *= texture2D(m_ColorMap, texCoord1); + #endif + + #ifdef HAS_VERTEXCOLOR + color *= vertColor; + #endif + + #ifdef HAS_COLOR + color *= m_Color; + #endif + + #ifdef HAS_LIGHTMAP + #ifdef SEPARATE_TEXCOORD + color.rgb *= texture2D(m_LightMap, texCoord2).rgb; + #else + color.rgb *= texture2D(m_LightMap, texCoord1).rgb; + #endif + #endif + + #if defined(DISCARD_ALPHA) + if(color.a < m_AlphaDiscardThreshold){ + discard; + } + #endif + + gl_FragColor = light_2; +} \ No newline at end of file diff --git a/src/test/resources/MatDefs/UnshadedSSBO.j3md b/src/test/resources/MatDefs/UnshadedSSBO.j3md new file mode 100644 index 00000000..391b989b --- /dev/null +++ b/src/test/resources/MatDefs/UnshadedSSBO.j3md @@ -0,0 +1,186 @@ +MaterialDef Unshaded { + + MaterialParameters { + Texture2D ColorMap + Texture2D LightMap + Color Color (Color) + Boolean VertexColor (UseVertexColor) + Float PointSize : 1.0 + Boolean SeparateTexCoord + + // Texture of the glowing parts of the material + Texture2D GlowMap + // The glow color of the object + Color GlowColor + + // For instancing + Boolean UseInstancing + + // For hardware skinning + Int NumberOfBones + Matrix4Array BoneMatrices + + // Alpha threshold for fragment discarding + Float AlphaDiscardThreshold (AlphaTestFallOff) + + //Shadows + Int FilterMode + Boolean HardwareShadows + + Texture2D ShadowMap0 + Texture2D ShadowMap1 + Texture2D ShadowMap2 + Texture2D ShadowMap3 + //pointLights + Texture2D ShadowMap4 + Texture2D ShadowMap5 + + Float ShadowIntensity + Vector4 Splits + Vector2 FadeInfo + + Matrix4 LightViewProjectionMatrix0 + Matrix4 LightViewProjectionMatrix1 + Matrix4 LightViewProjectionMatrix2 + Matrix4 LightViewProjectionMatrix3 + //pointLight + Matrix4 LightViewProjectionMatrix4 + Matrix4 LightViewProjectionMatrix5 + Vector3 LightPos + Vector3 LightDir + + BufferObject TestSSBO + + Float PCFEdge + + Float ShadowMapSize + + Boolean BackfaceShadows: true + } + + Technique { + VertexShader GLSL430: Common/MatDefs/Misc/Unshaded.vert + FragmentShader GLSL430: MatDefs/UnshadedSSBO.frag + + WorldParameters { + WorldViewProjectionMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + INSTANCING : UseInstancing + SEPARATE_TEXCOORD : SeparateTexCoord + HAS_COLORMAP : ColorMap + HAS_LIGHTMAP : LightMap + HAS_VERTEXCOLOR : VertexColor + HAS_POINTSIZE : PointSize + HAS_COLOR : Color + NUM_BONES : NumberOfBones + DISCARD_ALPHA : AlphaDiscardThreshold + } + } + + Technique PreNormalPass { + + VertexShader GLSL100 GLSL150 : Common/MatDefs/SSAO/normal.vert + FragmentShader GLSL100 GLSL150 : Common/MatDefs/SSAO/normal.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + NormalMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + } + + Technique PreShadow { + + VertexShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.vert + FragmentShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + COLOR_MAP : ColorMap + DISCARD_ALPHA : AlphaDiscardThreshold + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + + ForcedRenderState { + FaceCull Off + DepthTest On + DepthWrite On + PolyOffset 5 3 + ColorWrite Off + } + + } + + + Technique PostShadow { + VertexShader GLSL100 GLSL150: Common/MatDefs/Shadow/PostShadow.vert + FragmentShader GLSL100 GLSL150: Common/MatDefs/Shadow/PostShadow.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + HARDWARE_SHADOWS : HardwareShadows + FILTER_MODE : FilterMode + PCFEDGE : PCFEdge + DISCARD_ALPHA : AlphaDiscardThreshold + COLOR_MAP : ColorMap + SHADOWMAP_SIZE : ShadowMapSize + FADE : FadeInfo + PSSM : Splits + POINTLIGHT : LightViewProjectionMatrix5 + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + BACKFACE_SHADOWS: BackfaceShadows + } + + ForcedRenderState { + Blend Modulate + DepthWrite Off + PolyOffset -0.1 0 + } + } + + Technique Glow { + + VertexShader GLSL100 GLSL150: Common/MatDefs/Misc/Unshaded.vert + FragmentShader GLSL100 GLSL150: Common/MatDefs/Light/Glow.frag + + WorldParameters { + WorldViewProjectionMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + NEED_TEXCOORD1 + HAS_GLOWMAP : GlowMap + HAS_GLOWCOLOR : GlowColor + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + HAS_POINTSIZE : PointSize + } + } +} \ No newline at end of file diff --git a/src/test/resources/MatDefs/UnshadedSSBO2.frag b/src/test/resources/MatDefs/UnshadedSSBO2.frag new file mode 100644 index 00000000..b9974adf --- /dev/null +++ b/src/test/resources/MatDefs/UnshadedSSBO2.frag @@ -0,0 +1,81 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD)) + #define NEED_TEXCOORD1 +#endif + +#if defined(DISCARD_ALPHA) + uniform float m_AlphaDiscardThreshold; +#endif + +uniform vec4 m_Color; +uniform sampler2D m_ColorMap; +uniform sampler2D m_LightMap; + +layout (std140, binding = 4) buffer m_TestSSBO +{ + int index; + vec4 colors[3]; + float alp; + mat3 matrix3; + mat4 matrix4; + vec3 positions[3]; + int index2; + mat3 matrixes[2]; + vec2 vector2; + float fvalue; +}; + +varying vec2 texCoord1; +varying vec2 texCoord2; + +varying vec4 vertColor; + + +void main(){ + + vec4 color = vec4(1.0); + + #ifdef HAS_COLORMAP + color *= texture2D(m_ColorMap, texCoord1); + #endif + + #ifdef HAS_VERTEXCOLOR + color *= vertColor; + #endif + + #ifdef HAS_COLOR + color *= m_Color; + #endif + + #ifdef HAS_LIGHTMAP + #ifdef SEPARATE_TEXCOORD + color.rgb *= texture2D(m_LightMap, texCoord2).rgb; + #else + color.rgb *= texture2D(m_LightMap, texCoord1).rgb; + #endif + #endif + + #if defined(DISCARD_ALPHA) + if(color.a < m_AlphaDiscardThreshold){ + discard; + } + #endif + + float m00 = matrix3[0][0]; + float m01 = matrix3[0][1]; + float m02 = matrix3[0][2]; + + float m10 = matrix3[1][0]; + float m11 = matrix3[1][1]; + float m12 = matrix3[1][2]; + + float m20 = matrix3[2][0]; + float m21 = matrix3[2][1]; + float m22 = matrix3[2][2]; + + // gl_FragColor = vec4(positions[index2], 1.0) * alp; + // gl_FragColor = vec4(m20, m21, m22, 1.0) * alp; + // gl_FragColor = vec4(matrixes[1][1][0], matrixes[1][1][1], matrixes[1][1][2], 1.0) * alp; + gl_FragColor = vec4(vector2.x, vector2.y, fvalue, 1.0) * alp; +} \ No newline at end of file diff --git a/src/test/resources/MatDefs/UnshadedSSBO2.j3md b/src/test/resources/MatDefs/UnshadedSSBO2.j3md new file mode 100644 index 00000000..c97474ac --- /dev/null +++ b/src/test/resources/MatDefs/UnshadedSSBO2.j3md @@ -0,0 +1,186 @@ +MaterialDef Unshaded { + + MaterialParameters { + Texture2D ColorMap + Texture2D LightMap + Color Color (Color) + Boolean VertexColor (UseVertexColor) + Float PointSize : 1.0 + Boolean SeparateTexCoord + + // Texture of the glowing parts of the material + Texture2D GlowMap + // The glow color of the object + Color GlowColor + + // For instancing + Boolean UseInstancing + + // For hardware skinning + Int NumberOfBones + Matrix4Array BoneMatrices + + // Alpha threshold for fragment discarding + Float AlphaDiscardThreshold (AlphaTestFallOff) + + //Shadows + Int FilterMode + Boolean HardwareShadows + + Texture2D ShadowMap0 + Texture2D ShadowMap1 + Texture2D ShadowMap2 + Texture2D ShadowMap3 + //pointLights + Texture2D ShadowMap4 + Texture2D ShadowMap5 + + Float ShadowIntensity + Vector4 Splits + Vector2 FadeInfo + + Matrix4 LightViewProjectionMatrix0 + Matrix4 LightViewProjectionMatrix1 + Matrix4 LightViewProjectionMatrix2 + Matrix4 LightViewProjectionMatrix3 + //pointLight + Matrix4 LightViewProjectionMatrix4 + Matrix4 LightViewProjectionMatrix5 + Vector3 LightPos + Vector3 LightDir + + BufferObject TestSSBO + + Float PCFEdge + + Float ShadowMapSize + + Boolean BackfaceShadows: true + } + + Technique { + VertexShader GLSL430: Common/MatDefs/Misc/Unshaded.vert + FragmentShader GLSL430: MatDefs/UnshadedSSBO2.frag + + WorldParameters { + WorldViewProjectionMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + INSTANCING : UseInstancing + SEPARATE_TEXCOORD : SeparateTexCoord + HAS_COLORMAP : ColorMap + HAS_LIGHTMAP : LightMap + HAS_VERTEXCOLOR : VertexColor + HAS_POINTSIZE : PointSize + HAS_COLOR : Color + NUM_BONES : NumberOfBones + DISCARD_ALPHA : AlphaDiscardThreshold + } + } + + Technique PreNormalPass { + + VertexShader GLSL100 GLSL150 : Common/MatDefs/SSAO/normal.vert + FragmentShader GLSL100 GLSL150 : Common/MatDefs/SSAO/normal.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + NormalMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + } + + Technique PreShadow { + + VertexShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.vert + FragmentShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + COLOR_MAP : ColorMap + DISCARD_ALPHA : AlphaDiscardThreshold + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + + ForcedRenderState { + FaceCull Off + DepthTest On + DepthWrite On + PolyOffset 5 3 + ColorWrite Off + } + + } + + + Technique PostShadow { + VertexShader GLSL100 GLSL150: Common/MatDefs/Shadow/PostShadow.vert + FragmentShader GLSL100 GLSL150: Common/MatDefs/Shadow/PostShadow.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + HARDWARE_SHADOWS : HardwareShadows + FILTER_MODE : FilterMode + PCFEDGE : PCFEdge + DISCARD_ALPHA : AlphaDiscardThreshold + COLOR_MAP : ColorMap + SHADOWMAP_SIZE : ShadowMapSize + FADE : FadeInfo + PSSM : Splits + POINTLIGHT : LightViewProjectionMatrix5 + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + BACKFACE_SHADOWS: BackfaceShadows + } + + ForcedRenderState { + Blend Modulate + DepthWrite Off + PolyOffset -0.1 0 + } + } + + Technique Glow { + + VertexShader GLSL100 GLSL150: Common/MatDefs/Misc/Unshaded.vert + FragmentShader GLSL100 GLSL150: Common/MatDefs/Light/Glow.frag + + WorldParameters { + WorldViewProjectionMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + NEED_TEXCOORD1 + HAS_GLOWMAP : GlowMap + HAS_GLOWCOLOR : GlowColor + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + HAS_POINTSIZE : PointSize + } + } +} \ No newline at end of file diff --git a/src/test/resources/MatDefs/UnshadedUBO.frag b/src/test/resources/MatDefs/UnshadedUBO.frag new file mode 100644 index 00000000..c04881d7 --- /dev/null +++ b/src/test/resources/MatDefs/UnshadedUBO.frag @@ -0,0 +1,57 @@ +#import "Common/ShaderLib/GLSLCompat.glsllib" + +#if defined(HAS_GLOWMAP) || defined(HAS_COLORMAP) || (defined(HAS_LIGHTMAP) && !defined(SEPARATE_TEXCOORD)) + #define NEED_TEXCOORD1 +#endif + +#if defined(DISCARD_ALPHA) + uniform float m_AlphaDiscardThreshold; +#endif + +uniform vec4 m_Color; +uniform sampler2D m_ColorMap; +uniform sampler2D m_LightMap; + +layout (std140, binding = 2) uniform m_TestUBO +{ + vec4 light_1; + vec4 light_2; +}; + +varying vec2 texCoord1; +varying vec2 texCoord2; + +varying vec4 vertColor; + + +void main(){ + vec4 color = vec4(1.0); + + #ifdef HAS_COLORMAP + color *= texture2D(m_ColorMap, texCoord1); + #endif + + #ifdef HAS_VERTEXCOLOR + color *= vertColor; + #endif + + #ifdef HAS_COLOR + color *= m_Color; + #endif + + #ifdef HAS_LIGHTMAP + #ifdef SEPARATE_TEXCOORD + color.rgb *= texture2D(m_LightMap, texCoord2).rgb; + #else + color.rgb *= texture2D(m_LightMap, texCoord1).rgb; + #endif + #endif + + #if defined(DISCARD_ALPHA) + if(color.a < m_AlphaDiscardThreshold){ + discard; + } + #endif + + gl_FragColor = light_2; +} \ No newline at end of file diff --git a/src/test/resources/MatDefs/UnshadedUBO.j3md b/src/test/resources/MatDefs/UnshadedUBO.j3md new file mode 100644 index 00000000..2bb5c149 --- /dev/null +++ b/src/test/resources/MatDefs/UnshadedUBO.j3md @@ -0,0 +1,186 @@ +MaterialDef Unshaded { + + MaterialParameters { + Texture2D ColorMap + Texture2D LightMap + Color Color (Color) + Boolean VertexColor (UseVertexColor) + Float PointSize : 1.0 + Boolean SeparateTexCoord + + // Texture of the glowing parts of the material + Texture2D GlowMap + // The glow color of the object + Color GlowColor + + // For instancing + Boolean UseInstancing + + // For hardware skinning + Int NumberOfBones + Matrix4Array BoneMatrices + + // Alpha threshold for fragment discarding + Float AlphaDiscardThreshold (AlphaTestFallOff) + + //Shadows + Int FilterMode + Boolean HardwareShadows + + Texture2D ShadowMap0 + Texture2D ShadowMap1 + Texture2D ShadowMap2 + Texture2D ShadowMap3 + //pointLights + Texture2D ShadowMap4 + Texture2D ShadowMap5 + + Float ShadowIntensity + Vector4 Splits + Vector2 FadeInfo + + Matrix4 LightViewProjectionMatrix0 + Matrix4 LightViewProjectionMatrix1 + Matrix4 LightViewProjectionMatrix2 + Matrix4 LightViewProjectionMatrix3 + //pointLight + Matrix4 LightViewProjectionMatrix4 + Matrix4 LightViewProjectionMatrix5 + Vector3 LightPos + Vector3 LightDir + + BufferObject TestUBO + + Float PCFEdge + + Float ShadowMapSize + + Boolean BackfaceShadows: true + } + + Technique { + VertexShader GLSL430: Common/MatDefs/Misc/Unshaded.vert + FragmentShader GLSL430: MatDefs/UnshadedUBO.frag + + WorldParameters { + WorldViewProjectionMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + INSTANCING : UseInstancing + SEPARATE_TEXCOORD : SeparateTexCoord + HAS_COLORMAP : ColorMap + HAS_LIGHTMAP : LightMap + HAS_VERTEXCOLOR : VertexColor + HAS_POINTSIZE : PointSize + HAS_COLOR : Color + NUM_BONES : NumberOfBones + DISCARD_ALPHA : AlphaDiscardThreshold + } + } + + Technique PreNormalPass { + + VertexShader GLSL100 GLSL150 : Common/MatDefs/SSAO/normal.vert + FragmentShader GLSL100 GLSL150 : Common/MatDefs/SSAO/normal.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + NormalMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + } + + Technique PreShadow { + + VertexShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.vert + FragmentShader GLSL100 GLSL150 : Common/MatDefs/Shadow/PreShadow.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldViewMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + COLOR_MAP : ColorMap + DISCARD_ALPHA : AlphaDiscardThreshold + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + } + + ForcedRenderState { + FaceCull Off + DepthTest On + DepthWrite On + PolyOffset 5 3 + ColorWrite Off + } + + } + + + Technique PostShadow { + VertexShader GLSL100 GLSL150: Common/MatDefs/Shadow/PostShadow.vert + FragmentShader GLSL100 GLSL150: Common/MatDefs/Shadow/PostShadow.frag + + WorldParameters { + WorldViewProjectionMatrix + WorldMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + HARDWARE_SHADOWS : HardwareShadows + FILTER_MODE : FilterMode + PCFEDGE : PCFEdge + DISCARD_ALPHA : AlphaDiscardThreshold + COLOR_MAP : ColorMap + SHADOWMAP_SIZE : ShadowMapSize + FADE : FadeInfo + PSSM : Splits + POINTLIGHT : LightViewProjectionMatrix5 + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + BACKFACE_SHADOWS: BackfaceShadows + } + + ForcedRenderState { + Blend Modulate + DepthWrite Off + PolyOffset -0.1 0 + } + } + + Technique Glow { + + VertexShader GLSL100 GLSL150: Common/MatDefs/Misc/Unshaded.vert + FragmentShader GLSL100 GLSL150: Common/MatDefs/Light/Glow.frag + + WorldParameters { + WorldViewProjectionMatrix + ViewProjectionMatrix + ViewMatrix + } + + Defines { + NEED_TEXCOORD1 + HAS_GLOWMAP : GlowMap + HAS_GLOWCOLOR : GlowColor + NUM_BONES : NumberOfBones + INSTANCING : UseInstancing + HAS_POINTSIZE : PointSize + } + } +} \ No newline at end of file