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