From 3e50486a96b74a82b80f377229e2d16a010cd0b7 Mon Sep 17 00:00:00 2001 From: stephengold Date: Sun, 9 Jun 2024 09:52:11 -0700 Subject: [PATCH] convert the DacWizard subproject to a separate project --- .gitignore | 5 +- DacWizard/build.gradle | 43 - .../jme3utilities/minie/wizard/Action.java | 191 --- .../jme3utilities/minie/wizard/AngleMode.java | 46 - .../jme3utilities/minie/wizard/BoneValue.java | 96 -- .../jme3utilities/minie/wizard/BonesMode.java | 165 -- .../minie/wizard/BonesScreen.java | 231 --- .../jme3utilities/minie/wizard/DacWizard.java | 834 ---------- .../minie/wizard/FilePathMode.java | 161 -- .../minie/wizard/FilePathScreen.java | 326 ---- .../jme3utilities/minie/wizard/LinkValue.java | 103 -- .../jme3utilities/minie/wizard/LinksMode.java | 251 --- .../minie/wizard/LinksScreen.java | 663 -------- .../jme3utilities/minie/wizard/LoadMode.java | 234 --- .../minie/wizard/LoadScreen.java | 325 ---- .../jme3utilities/minie/wizard/Model.java | 1405 ----------------- .../minie/wizard/RomCallable.java | 369 ----- .../jme3utilities/minie/wizard/TestMode.java | 651 -------- .../minie/wizard/TestScreen.java | 452 ------ .../jme3utilities/minie/wizard/TorsoMode.java | 180 --- .../minie/wizard/TorsoScreen.java | 227 --- .../minie/wizard/package-info.java | 30 - .../Interface/Nifty/screens/wizard/bones.xml | 73 - .../Nifty/screens/wizard/filePath.xml | 77 - .../Interface/Nifty/screens/wizard/links.xml | 151 -- .../Interface/Nifty/screens/wizard/load.xml | 130 -- .../Interface/Nifty/screens/wizard/test.xml | 138 -- .../Interface/Nifty/screens/wizard/torso.xml | 69 - .../resources/Textures/icons/ellipsis.png | Bin 856 -> 0 bytes .../main/resources/Textures/icons/folder.png | Bin 1621 -> 0 bytes .../src/main/resources/Textures/icons/jme.png | Bin 1815 -> 0 bytes .../main/resources/Textures/icons/license.txt | 21 - LICENSE | 3 +- MinieLibrary/release-notes.md | 2 +- .../minie-library-tutorials/pages/dac.adoc | 2 +- README.md | 18 +- build.gradle | 2 +- 37 files changed, 15 insertions(+), 7659 deletions(-) delete mode 100644 DacWizard/build.gradle delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/Action.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/AngleMode.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/BoneValue.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/BonesMode.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/BonesScreen.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/DacWizard.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/FilePathMode.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/FilePathScreen.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/LinkValue.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/LinksMode.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/LinksScreen.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/LoadMode.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/LoadScreen.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/Model.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/RomCallable.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/TestMode.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/TestScreen.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/TorsoMode.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/TorsoScreen.java delete mode 100644 DacWizard/src/main/java/jme3utilities/minie/wizard/package-info.java delete mode 100644 DacWizard/src/main/resources/Interface/Nifty/screens/wizard/bones.xml delete mode 100644 DacWizard/src/main/resources/Interface/Nifty/screens/wizard/filePath.xml delete mode 100644 DacWizard/src/main/resources/Interface/Nifty/screens/wizard/links.xml delete mode 100644 DacWizard/src/main/resources/Interface/Nifty/screens/wizard/load.xml delete mode 100644 DacWizard/src/main/resources/Interface/Nifty/screens/wizard/test.xml delete mode 100644 DacWizard/src/main/resources/Interface/Nifty/screens/wizard/torso.xml delete mode 100644 DacWizard/src/main/resources/Textures/icons/ellipsis.png delete mode 100644 DacWizard/src/main/resources/Textures/icons/folder.png delete mode 100644 DacWizard/src/main/resources/Textures/icons/jme.png delete mode 100644 DacWizard/src/main/resources/Textures/icons/license.txt diff --git a/.gitignore b/.gitignore index 04848898e..20af68d3e 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,6 @@ # Ignore Gradle's build output directories: /build/ -/DacWizard/build/ /Jme3Examples/build/ /MinieAssets/build/ /MinieDump/build/ @@ -29,10 +28,8 @@ # Ignore IDE-specific directories: /.idea/ /.nb-gradle/ -/DacWizard/private/ -# Ignore the Acorus sandboxes: -/DacWizard/Written Assets/ +# Ignore the Acorus sandbox: /MinieExamples/Written Assets/ # Ignore extracted native libraries: diff --git a/DacWizard/build.gradle b/DacWizard/build.gradle deleted file mode 100644 index 2e5ead911..000000000 --- a/DacWizard/build.gradle +++ /dev/null @@ -1,43 +0,0 @@ -// Gradle script to build the DacWizard subproject of Minie - -// Note: "common.gradle" in the root project contains additional initialization -// for this project. This initialization is applied in the "build.gradle" -// of the root project. - -plugins { - id 'application' // to build JVM applications -} - -tasks.withType(JavaExec).configureEach { // Java runtime options: - args '--openGL3' -} - -application { - mainClass = 'jme3utilities.minie.wizard.DacWizard' -} -if (!hasProperty('mainClass')) { - ext.mainClass = application.mainClass -} -jar.manifest.attributes('Main-Class': application.mainClass) - -dependencies { - runtimeOnly(libs.jme3.desktop) - implementation(libs.heart) - runtimeOnly(libs.lwjgl) - implementation(libs.jme3.utilities.nifty) - runtimeOnly(libs.jme3.plugins) - runtimeOnly(libs.nifty.style.black) - implementation(libs.wes) - - // DacWizard doesn't use jme3-jogg - // -- it is included solely to avoid warnings from AssetConfig. - runtimeOnly(libs.jme3.jogg) - - //implementation 'com.github.stephengold:Minie:' + minieVersion // for published library - implementation project(':MinieLibrary') // for latest sourcecode -} - -tasks.register('runForceDialog', JavaExec) { - args '--forceDialog' - mainClass = application.mainClass -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/Action.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/Action.java deleted file mode 100644 index e6a9149cf..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/Action.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.state.AppStateManager; -import com.jme3.bullet.BulletAppState; -import com.jme3.bullet.PhysicsSpace; -import com.jme3.renderer.RenderManager; -import java.util.logging.Logger; -import jme3utilities.nifty.bind.BindScreen; -import jme3utilities.nifty.displaysettings.DsScreen; -import jme3utilities.ui.InputMode; - -/** - * Action strings for the DacWizard application. Each String describes a - * user-interface action. By convention, action strings begin with a verb in all - * lowercase and never end with a space (' '). - * - * @author Stephen Gold sgold@sonic.net - */ -final class Action { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(Action.class.getName()); - - final static String browse = "browse"; - final static String dumpAppStates = "dump appStates"; - final static String dumpPhysicsSpace = "dump physicsSpace"; - final static String dumpRenderer = "dump renderer"; - final static String editBindings = "edit bindings"; - final static String editDisplaySettings = "edit displaySettings"; - final static String editLinks = "edit links"; - final static String load = "load"; - final static String morePath = "more path"; - final static String moreRoot = "more root"; - final static String nextAnimation = "next animation"; - final static String nextMassHeuristic = "next massHeuristic"; - final static String nextScreen = "next screen"; - final static String pickLink = "pick link"; - final static String previousAnimation = "previous animation"; - final static String previousScreen = "previous screen"; - final static String rebuild = "rebuild"; - final static String save = "save"; - final static String saveJ3o = "saveJ3o"; - final static String selectCenterHeuristic = "select centerHeuristic"; - final static String selectRotationOrder = "select rotationOrder"; - final static String selectShapeHeuristic = "select shapeHeuristic"; - final static String setAnimationTime = "set animationTime"; - final static String setMargin = "set margin"; - final static String setMassParameter = "set massParameter"; - final static String setShapeScale = "set shapeScale"; - final static String toggleAngleMode = "toggle angleMode"; - final static String toggleAxes = "toggle axes"; - final static String toggleMesh = "toggle mesh"; - final static String togglePhysicsDebug = "toggle physicsDebug"; - final static String toggleRagdoll = "toggle ragdoll"; - final static String toggleSkeleton = "toggle skeleton"; - // ************************************************************************* - // constructors - - /** - * A private constructor to inhibit instantiation of this class. - */ - private Action() { - // do nothing - } - // ************************************************************************* - // new methods exposed - - /** - * Process an ongoing action from the GUI or keyboard that wasn't handled by - * the active InputMode. - * - * @param actionString textual description of the action (not null) - * @return true if the action has been handled, otherwise false - */ - static boolean processOngoing(String actionString) { - boolean handled = true; - - Model model = DacWizard.getModel(); - switch (actionString) { - case dumpAppStates: - dumpAppStates(); - break; - - case dumpPhysicsSpace: - dumpPhysicsSpace(); - break; - - case dumpRenderer: - dumpRenderer(); - break; - - case editBindings: - editBindings(); - break; - - case editDisplaySettings: - editDisplaySettings(); - break; - - case nextAnimation: - model.nextAnimation(); - break; - - case previousAnimation: - model.previousAnimation(); - break; - - default: - handled = false; - } - - return handled; - } - // ************************************************************************* - // private methods - - /** - * Process a "dump appStates" action. - */ - private static void dumpAppStates() { - DacWizard app = DacWizard.getApplication(); - AppStateManager stateManager = app.getStateManager(); - DacWizard.dumper.dump(stateManager); - } - - /** - * Process a "dump physicsSpace" action. - */ - private static void dumpPhysicsSpace() { - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - DacWizard.dumper.dump(physicsSpace); - } - - /** - * Process a "dump renderer" action. - */ - private static void dumpRenderer() { - DacWizard app = DacWizard.getApplication(); - RenderManager renderManager = app.getRenderManager(); - DacWizard.dumper.dump(renderManager); - } - - /** - * Process an "edit bindings" action. - */ - private static void editBindings() { - BindScreen bindScreen = DacWizard.findAppState(BindScreen.class); - InputMode active = InputMode.getActiveMode(); - bindScreen.activate(active); - } - - /** - * Process an "edit displaySettings" action. - */ - private static void editDisplaySettings() { - DsScreen dss = DacWizard.findAppState(DsScreen.class); - dss.activate(); - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/AngleMode.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/AngleMode.java deleted file mode 100644 index 97099d44f..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/AngleMode.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - Copyright (c) 2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -/** - * Enumerate modes for angle display/input. - * - * @author Stephen Gold sgold@sonic.net - */ -enum AngleMode { - // ************************************************************************* - // values - - /** - * angles in degrees - */ - Degrees, - /** - * angles in radians - */ - Radians -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/BoneValue.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/BoneValue.java deleted file mode 100644 index 9a425abd1..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/BoneValue.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - Copyright (c) 2019, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import java.util.logging.Logger; -import jme3utilities.MyString; - -/** - * The value of an item in the TreeBox of the "bones" screen. - * - * @author Stephen Gold sgold@sonic.net - */ -class BoneValue { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(BoneValue.class.getName()); - // ************************************************************************* - // fields - - /** - * index of the bone (≥0) - */ - final private int boneIndex; - // ************************************************************************* - // constructors - - /** - * Instantiate a value from a bone index. - * - * @param boneIndex the index of the bone (≥0) - */ - BoneValue(int boneIndex) { - assert boneIndex >= 0 : boneIndex; - this.boneIndex = boneIndex; - } - // ************************************************************************* - // new methods exposed - - /** - * Read the bone index. - * - * @return the bone index (≥0) - */ - int boneIndex() { - assert boneIndex >= 0 : boneIndex; - return boneIndex; - } - // ************************************************************************* - // Object methods - - /** - * Convert the value to text for TreeBox display. - * - * @return display text for the item (not null, not empty) - */ - @Override - public String toString() { - Model model = DacWizard.getModel(); - String boneName = model.boneName(boneIndex); - int numTracks = model.countTracks(boneIndex); - String influence = model.describeBoneInfluence(boneIndex); - String result = String.format("%s: used in %d track%s, %s", - MyString.quote(boneName), numTracks, numTracks == 1 ? "" : "s", - influence); - - return result; - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/BonesMode.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/BonesMode.java deleted file mode 100644 index 6e4836ad8..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/BonesMode.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.SimpleApplication; -import com.jme3.app.state.AppStateManager; -import com.jme3.asset.AssetManager; -import com.jme3.cursors.plugins.JmeCursor; -import com.jme3.input.KeyInput; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3utilities.MyString; -import jme3utilities.Validate; -import jme3utilities.ui.InputMode; - -/** - * Input mode for the "bones" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class BonesMode extends InputMode { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(BonesMode.class.getName()); - /** - * asset path to the cursor for this mode - */ - final private static String assetPath = "Textures/cursors/default.cur"; - // ************************************************************************* - // constructors - - /** - * Instantiate a disabled, uninitialized input mode. - */ - BonesMode() { - super("bones"); - } - // ************************************************************************* - // InputMode methods - - /** - * Add default hotkey bindings. These bindings will be used if no custom - * bindings are found. - */ - @Override - protected void defaultBindings() { - bind(SimpleApplication.INPUT_MAPPING_EXIT, KeyInput.KEY_ESCAPE); - bind(Action.editBindings, KeyInput.KEY_F1); - bind(Action.editDisplaySettings, KeyInput.KEY_F2); - - bind(Action.previousScreen, KeyInput.KEY_PGUP); - - bind(Action.dumpPhysicsSpace, KeyInput.KEY_O); - bind(Action.dumpRenderer, KeyInput.KEY_P); - bind(Action.nextScreen, KeyInput.KEY_PGDN); - - bind(Action.previousScreen, KeyInput.KEY_B); - bind(Action.nextScreen, KeyInput.KEY_N); - } - - /** - * Initialize this (disabled) mode prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - // Set the mouse cursor for this mode. - AssetManager manager = application.getAssetManager(); - JmeCursor cursor = (JmeCursor) manager.loadAsset(assetPath); - setCursor(cursor); - - super.initialize(stateManager, application); - } - - /** - * Process an action from the keyboard or mouse. - * - * @param actionString textual description of the action (not null) - * @param ongoing true if the action is ongoing, otherwise false - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void onAction(String actionString, boolean ongoing, float tpf) { - Validate.nonNull(actionString, "action string"); - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "Got action {0} ongoing={1}", - new Object[]{MyString.quote(actionString), ongoing}); - } - - boolean handled = false; - if (ongoing) { - switch (actionString) { - case Action.nextScreen: - nextScreen(); - handled = true; - break; - - case Action.previousScreen: - previousScreen(); - handled = true; - break; - - default: - } - } - if (!handled) { - getActionApplication().onAction(actionString, ongoing, tpf); - } - } - // ************************************************************************* - // private methods - - /** - * Proceed to the "torso" screen if possible. - */ - private void nextScreen() { - String feedback = BonesScreen.feedback(); - if (feedback.isEmpty()) { - setEnabled(false); - InputMode load = InputMode.findMode("torso"); - load.setEnabled(true); - } - } - - /** - * Go back to the "load" screen. - */ - private void previousScreen() { - setEnabled(false); - InputMode load = InputMode.findMode("load"); - load.setEnabled(true); - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/BonesScreen.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/BonesScreen.java deleted file mode 100644 index 5bcfa058d..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/BonesScreen.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.bullet.animation.DacConfiguration; -import de.lessvoid.nifty.controls.Button; -import de.lessvoid.nifty.controls.TreeBox; -import de.lessvoid.nifty.controls.TreeItem; -import de.lessvoid.nifty.elements.Element; -import java.util.BitSet; -import java.util.List; -import java.util.logging.Logger; -import jme3utilities.InitialState; -import jme3utilities.MyString; -import jme3utilities.nifty.GuiScreenController; -import jme3utilities.ui.InputMode; - -/** - * The screen controller for the "bones" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class BonesScreen extends GuiScreenController { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(BonesScreen.class.getName()); - // ************************************************************************* - // fields - - /** - * element of the GUI button to proceed to the "torso" screen - */ - private Element nextElement; - /** - * TreeBox to display all bones in the skeleton - */ - private TreeBox treeBox; - // ************************************************************************* - // constructors - - /** - * Instantiate an uninitialized, disabled screen that will not be enabled - * during initialization. - */ - BonesScreen() { - super("bones", "Interface/Nifty/screens/wizard/bones.xml", - InitialState.Disabled); - } - // ************************************************************************* - // new methods exposed - - /** - * Determine user feedback (if any) regarding the "next screen" action. - * - * @return "" if ready to proceed, otherwise an explanatory message - */ - static String feedback() { - Model model = DacWizard.getModel(); - int numBones = model.countBones(); - - String result = ""; - if (model.listLinkedBones().length == 0) { - result = "No bones are linked."; - } else if (model.countVertices(DacConfiguration.torsoName) == 0) { - result = "No mesh vertices for the torso."; - } else { - for (int i = 0; i < numBones; ++i) { - if (model.isBoneLinked(i)) { - String name = model.boneName(i); - if (model.countVertices(name) == 0) { - result = "No mesh vertices for " + MyString.quote(name); - } - } - } - } - - return result; - } - // ************************************************************************* - // GuiScreenController methods - - /** - * Initialize this (disabled) screen prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - super.initialize(stateManager, application); - - InputMode inputMode = InputMode.findMode("bones"); - assert inputMode != null; - setListener(inputMode); - inputMode.influence(this); - } - - /** - * A callback from Nifty, invoked each time the screen shuts down. - */ - @Override - public void onEndScreen() { - treeBox.clear(); - super.onEndScreen(); - } - - /** - * A callback from Nifty, invoked each time this screen starts up. - */ - @Override - @SuppressWarnings("unchecked") - public void onStartScreen() { - super.onStartScreen(); - - Button nextButton = getButton("next"); - if (nextButton == null) { - throw new RuntimeException("missing GUI control: nextButton"); - } - this.nextElement = nextButton.getElement(); - - this.treeBox = getScreen().findNiftyControl("skeleton", TreeBox.class); - if (treeBox == null) { - throw new RuntimeException("missing GUI control: skeleton"); - } - - TreeItem rootItem = new TreeItem<>(); - rootItem.setExpanded(true); - Model model = DacWizard.getModel(); - int numBones = model.countBones(); - - // Create an item for each bone in the model's skeleton. - TreeItem[] boneItems = new TreeItem[numBones]; - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - BoneValue value = new BoneValue(boneIndex); - boneItems[boneIndex] = new TreeItem<>(value); - boneItems[boneIndex].setExpanded(true); - } - - // Parent each item. - for (int childIndex = 0; childIndex < numBones; ++childIndex) { - TreeItem childItem = boneItems[childIndex]; - int parentIndex = model.parentIndex(childIndex); - if (parentIndex == -1) { - rootItem.addTreeItem(childItem); - } else { - boneItems[parentIndex].addTreeItem(childItem); - } - } - treeBox.setTree(rootItem); - - // Pre-select items. - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - TreeItem item = boneItems[boneIndex]; - if (model.isBoneLinked(boneIndex)) { - treeBox.selectItem(item); - } - } - } - - /** - * Update this ScreenController prior to rendering. (Invoked once per - * frame.) - * - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void update(float tpf) { - super.update(tpf); - - if (!hasStarted()) { - return; - } - - List> selectedBones = treeBox.getSelection(); - int numSelected = selectedBones.size(); - - Model model = DacWizard.getModel(); - int numBones = model.countBones(); - - String numText = String.format("Selected %d of %d bone%s", - numSelected, numBones, numBones == 1 ? "" : "s"); - setStatusText("numSelected", numText); - - BitSet linkedBones = new BitSet(numBones); - for (TreeItem treeItem : selectedBones) { - BoneValue value = treeItem.getValue(); - int boneIndex = value.boneIndex(); - linkedBones.set(boneIndex); - } - model.setLinkedBones(linkedBones); - - String feedback = feedback(); - setStatusText("feedback", feedback); - if (feedback.isEmpty()) { - nextElement.show(); - } else { - nextElement.hide(); - } - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/DacWizard.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/DacWizard.java deleted file mode 100644 index bbd322707..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/DacWizard.java +++ /dev/null @@ -1,834 +0,0 @@ -/* - Copyright (c) 2019-2024 Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.anim.AnimClip; -import com.jme3.anim.AnimComposer; -import com.jme3.anim.Armature; -import com.jme3.anim.SkinningControl; -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.jme3.animation.Skeleton; -import com.jme3.animation.SkeletonControl; -import com.jme3.app.DebugKeysAppState; -import com.jme3.app.state.AppState; -import com.jme3.app.state.AppStateManager; -import com.jme3.bullet.BulletAppState; -import com.jme3.bullet.PhysicsSpace; -import com.jme3.bullet.animation.DacLinks; -import com.jme3.bullet.animation.DynamicAnimControl; -import com.jme3.bullet.animation.RagUtils; -import com.jme3.light.AmbientLight; -import com.jme3.light.DirectionalLight; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Quaternion; -import com.jme3.math.Vector3f; -import com.jme3.scene.Node; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.AbstractControl; -import com.jme3.scene.control.Control; -import com.jme3.system.AppSettings; -import com.jme3.system.JmeVersion; -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3utilities.Heart; -import jme3utilities.InfluenceUtil; -import jme3utilities.MyCamera; -import jme3utilities.MySkeleton; -import jme3utilities.MySpatial; -import jme3utilities.MyString; -import jme3utilities.debug.AxesVisualizer; -import jme3utilities.debug.SkeletonVisualizer; -import jme3utilities.math.MyMath; -import jme3utilities.math.MyVector3f; -import jme3utilities.math.RectSizeLimits; -import jme3utilities.minie.DumpFlags; -import jme3utilities.minie.PhysicsDumper; -import jme3utilities.nifty.GuiApplication; -import jme3utilities.nifty.LibraryVersion; -import jme3utilities.nifty.bind.BindScreen; -import jme3utilities.nifty.displaysettings.DsScreen; -import jme3utilities.ui.ActionApplication; -import jme3utilities.ui.CameraOrbitAppState; -import jme3utilities.ui.DisplaySettings; -import jme3utilities.ui.InputMode; -import jme3utilities.ui.ShowDialog; -import jme3utilities.wes.AnimationEdit; -import jme3utilities.wes.Pose; -import jme3utilities.wes.TweenTransforms; - -/** - * A GuiApplication to configure a DynamicAnimControl for a C-G model. The - * application's main entry point is in this class. The scene graph is also - * managed here. - *

- * Seen in the April 2019 walkthru video: - * https://www.youtube.com/watch?v=iWyrzZe45jA - * - * @author Stephen Gold sgold@sonic.net - */ -public class DacWizard extends GuiApplication { - // ************************************************************************* - // constants and loggers - - /** - * desired height of the C-G model (for visualization, in world units) - */ - final private static float cgmHeight = 10f; - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(DacWizard.class.getName()); - /** - * application name (for the title bar of the app's window) - */ - final private static String applicationName - = DacWizard.class.getSimpleName(); - /** - * magic clip/animation name used to denote a C-G model's bind pose - */ - final public static String bindPoseName = "( bind pose )"; - // ************************************************************************* - // fields - - /** - * true once {@link #startup1()} has completed, until then false - */ - private static boolean didStartup1 = false; - /** - * application instance - */ - private static DacWizard application; - /** - * Nifty screen for editing display settings - */ - private static DsScreen displaySettingsScreen; - /** - * state information - */ - final private static Model model = new Model(); - /** - * node controlled by the AxesVisualizer - */ - private static Node axesNode = null; - /** - * parent of the loaded C-G model in the scene - */ - private static Node cgmParent = null; - /** - * dump debugging information to {@code System.out} - */ - final static PhysicsDumper dumper = new PhysicsDumper(); - // ************************************************************************* - // constructors - - /** - * Instantiate the DacWizard application. - *

- * This no-arg constructor was made explicit to avoid javadoc warnings from - * JDK 18+. - */ - public DacWizard() { - } - // ************************************************************************* - // new methods exposed - - /** - * Clear the default scene. - */ - void clearScene() { - BulletAppState bulletAppState = findAppState(BulletAppState.class); - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - DacLinks ragdoll = findDac(); - if (ragdoll != null) { - ragdoll.setPhysicsSpace(null); - } - if (!physicsSpace.isEmpty()) { - dumper.dump(physicsSpace); - } - assert physicsSpace.isEmpty(); - - int numControls = rootNode.getNumControls(); - for (int controlI = numControls - 1; controlI >= 0; --controlI) { - Control control = rootNode.getControl(controlI); - rootNode.removeControl(control); - } - - List children = rootNode.getChildren(); - for (Spatial child : children) { - child.removeFromParent(); - } - - if (axesNode != null) { - axesNode = null; - } - if (cgmParent != null) { - cgmParent = null; - } - } - - /** - * Find the first attached AppState that's an instance of the specified - * class. - * - * @param type of subclass - * @param subclass the kind of AppState to search for (not null) - * @return the pre-existing instance (not null) - */ - static T findAppState(Class subclass) { - AppStateManager manager = application.getStateManager(); - T appState = manager.getState(subclass); - - assert appState != null; - return appState; - } - - /** - * Find the AxesVisualizer in the scene. - * - * @return the pre-existing Control, or null if none/multiple - */ - static AxesVisualizer findAxesVisualizer() { - AxesVisualizer result = null; - if (axesNode != null) { - List controls = MySpatial.listControls( - axesNode, AxesVisualizer.class, null); - if (controls.size() == 1) { - result = controls.get(0); - } - } - - return result; - } - - /** - * Find the DynamicAnimControl in the scene. - * - * @return the pre-existing Control, or null if none/multiple - */ - static DynamicAnimControl findDac() { - DynamicAnimControl result = null; - if (cgmParent != null) { - List controls = MySpatial.listControls( - cgmParent, DynamicAnimControl.class, null); - if (controls.size() == 1) { - result = controls.get(0); - } - } - - return result; - } - - /** - * Find the SkeletonVisualizer in the scene. - * - * @return the pre-existing control, or null if none/multiple - */ - SkeletonVisualizer findSkeletonVisualizer() { - SkeletonVisualizer result = null; - List controls = MySpatial.listControls( - rootNode, SkeletonVisualizer.class, null); - if (controls.size() == 1) { - result = controls.get(0); - } - - return result; - } - - /** - * Access the application instance from a static context. - * - * @return the pre-existing instance (not null) - */ - static DacWizard getApplication() { - assert application != null; - return application; - } - - /** - * Access the state information. - * - * @return the pre-existing instance (not null) - */ - static Model getModel() { - assert model != null; - return model; - } - - /** - * Main entry point for the DacWizard application. - * - * @param arguments array of command-line arguments (not null) - */ - public static void main(String[] arguments) { - // Mute the chatty loggers found in certain packages. - Heart.setLoggingLevels(Level.WARNING); - - String renderer = AppSettings.LWJGL_OPENGL2; - ShowDialog showDialog = ShowDialog.Never; - - // Process any command-line arguments. - for (String arg : arguments) { - switch (arg) { - case "-3": - case "--openGL3": - renderer = AppSettings.LWJGL_OPENGL33; - break; - - case "-f": - case "--forceDialog": - showDialog = ShowDialog.Always; - break; - - case "--showSettingsDialog": - showDialog = ShowDialog.FirstTime; - break; - - case "-v": - case "--verbose": - Heart.setLoggingLevels(Level.INFO); - break; - - default: - logger.log( - Level.WARNING, "Unknown command-line argument {0}", - MyString.quote(arg)); - } - } - - String title = applicationName + " " + MyString.join(arguments); - mainStartup(showDialog, renderer, title); - } - - /** - * Add a C-G model to the (cleared) scene, pose the model, transform the - * model, and reset the camera. - * - * @param cgModel the root spatial of model to add (not null, alias created) - * @param animationName the clip/animation name for the desired pose or - * {@link #bindPoseName} (not null) - * @param animationTime the animation time for the desired pose (in seconds, - * ≥0) - */ - void makeScene(Spatial cgModel, String animationName, float animationTime) { - assert cgModel != null; - assert animationName != null; - assert animationTime >= 0f : animationTime; - assert axesNode == null; - assert cgmParent == null; - - // Add a disabled visualizer for axes, with its own controlled Node. - axesNode = new Node("axesNode"); - rootNode.attachChild(axesNode); - float arrowLength = 0.2f * cgmHeight; - AxesVisualizer axes = new AxesVisualizer(assetManager, arrowLength); - axes.setLineWidth(AxesVisualizer.widthForSolid); - axesNode.addControl(axes); - - // Add the C-G model, with its own parent Node. - cgmParent = new Node("cgmParent"); - if (model.isShowingMeshes()) { - cgmParent.setCullHint(Spatial.CullHint.Never); - } else { - cgmParent.setCullHint(Spatial.CullHint.Always); - } - rootNode.attachChild(cgmParent); - cgmParent.attachChild(cgModel); - /* - * Normalize all quaternions in the model's animations, - * since Pose.applyTo() is sensitive to such flaws. - */ - List animControls = MySpatial.listControls( - cgmParent, AnimControl.class, null); - normalizeAnimControls(animControls); - - List composers = MySpatial.listControls( - cgmParent, AnimComposer.class, null); - normalizeComposers(composers); - - // Apply the specified animation pose. - AbstractControl sc = RagUtils.findSControl(cgModel); - if (sc instanceof SkeletonControl && animControls.size() == 1) { - // old animation system - SkeletonControl skeletonControl = (SkeletonControl) sc; - Skeleton skeleton = skeletonControl.getSkeleton(); - AnimControl animControl = animControls.get(0); - poseSkeleton(skeleton, animControl, animationName, animationTime); - - // Update mesh position buffer(s): - skeletonControl.setHardwareSkinningPreferred(false); - skeletonControl.render(renderManager, viewPort); - - } else if (sc instanceof SkinningControl && composers.size() == 1) { - // new animation system - SkinningControl skinningControl = (SkinningControl) sc; - Armature armature = skinningControl.getArmature(); - AnimComposer composer = composers.get(0); - poseArmature(armature, composer, animationName, animationTime); - - // Update mesh position buffer(s): - skinningControl.setHardwareSkinningPreferred(false); - skinningControl.render(renderManager, viewPort); - } - - // Translate and scale the C-G model. - setParentTransform(cgmHeight); - - if (sc != null && findSkeletonVisualizer() == null) { - // Add a SkeletonVisualizer. - SkeletonVisualizer sv = new SkeletonVisualizer(assetManager, sc); - sv.setLineColor(ColorRGBA.Yellow); - if (sc instanceof SkeletonControl) { // old animation system - InfluenceUtil.hideNonInfluencers(sv, (SkeletonControl) sc); - } else { // new animation system - InfluenceUtil.hideNonInfluencers(sv, (SkinningControl) sc); - } - rootNode.addControl(sv); - } - - DacLinks dac = findDac(); - if (dac != null) { // Configure the DAC. - float gravity = 6f * cgmHeight; - Vector3f gravityVector = new Vector3f(0f, -gravity, 0f); - dac.setGravity(gravityVector); - } - - resetCamera(); - } - - /** - * Toggle rendering of C-G model meshes on/off. - */ - static void toggleMesh() { - boolean oldShow = model.isShowingMeshes(); - boolean newShow = !oldShow; - model.setShowingMeshes(newShow); - - if (cgmParent != null) { - Spatial.CullHint cull; - if (newShow) { - cull = Spatial.CullHint.Never; - } else { - cull = Spatial.CullHint.Always; - } - cgmParent.setCullHint(cull); - } - } - - /** - * Toggle the skeleton visualizer on/off. - */ - static void toggleSkeletonVisualizer() { - DacWizard app = getApplication(); - SkeletonVisualizer sv = app.findSkeletonVisualizer(); - if (sv != null) { - boolean newState = !sv.isEnabled(); - sv.setEnabled(newState); - } - } - // ************************************************************************* - // GuiApplication methods - - /** - * Initialize the DacWizard application. - */ - @Override - public void guiInitializeApplication() { - logger.info(""); - logger.setLevel(Level.INFO); - - if (!Heart.areAssertionsEnabled()) { - logger.warning("Assertions are disabled!"); - } - - // Log version strings. - logger.log(Level.INFO, "jme3-core version is {0}", - MyString.quote(JmeVersion.FULL_NAME)); - logger.log(Level.INFO, "Heart version is {0}", - MyString.quote(Heart.versionShort())); - logger.log(Level.INFO, "jme3-utilities-nifty version is {0}", - MyString.quote(LibraryVersion.versionShort())); - - // Detach an app state created by SimpleApplication. - DebugKeysAppState debugKeys = findAppState(DebugKeysAppState.class); - stateManager.detach(debugKeys); - - configureDumper(); - addLighting(); - - getSignals().add("orbitLeft"); - getSignals().add("orbitRight"); - - attachAppStates(); - } - - /** - * Process an action from the GUI or keyboard that wasn't handled by the - * active InputMode. - * - * @param actionString textual description of the action (not null) - * @param ongoing true if the action is ongoing, otherwise false - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void onAction(String actionString, boolean ongoing, float tpf) { - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "Got action {0} ongoing={1}", - new Object[]{MyString.quote(actionString), ongoing}); - } - - boolean handled = false; - if (ongoing) { - handled = Action.processOngoing(actionString); - } - if (!handled) { // Forward unhandled action to the superclass. - super.onAction(actionString, ongoing, tpf); - } - } - - /** - * Callback invoked once per frame. - * - * @param tpf the time interval between frames (in seconds, ≥0) - */ - @Override - public void simpleUpdate(float tpf) { - super.simpleUpdate(tpf); - - if (!didStartup1) { - startup1(); - didStartup1 = true; - } - model.pollForTaskCompletion(); - } - // ************************************************************************* - // private methods - - /** - * Add lighting and background color to the scene. - */ - private void addLighting() { - ColorRGBA ambientColor = new ColorRGBA(1f, 1f, 1f, 1f); - AmbientLight ambient = new AmbientLight(ambientColor); - rootNode.addLight(ambient); - ambient.setName("ambient"); - - Vector3f direction = new Vector3f(1f, -2f, -1f).normalizeLocal(); - DirectionalLight sun = new DirectionalLight(direction); - rootNode.addLight(sun); - sun.setName("sun"); - - ColorRGBA bgColor = new ColorRGBA(0.2f, 0.2f, 0.2f, 1f); - viewPort.setBackgroundColor(bgColor); - } - - /** - * Attach app states during initialization. - */ - private void attachAppStates() { - boolean success; - - success = stateManager.attach(new BindScreen()); - assert success; - - success = stateManager.attach(new BulletAppState()); - assert success; - - success = stateManager.attach(displaySettingsScreen); - assert success; - - CameraOrbitAppState cameraOrbitAppState - = new CameraOrbitAppState(cam, "orbitLeft", "orbitRight"); - stateManager.attach(cameraOrbitAppState); - /* - * Create and attach an input mode and screen controller - * for the "filePath" screen. - */ - success = stateManager.attach(new FilePathMode()); - assert success; - success = stateManager.attach(new FilePathScreen()); - assert success; - /* - * Create and attach an input mode and screen controller - * for the "load" screen. - */ - success = stateManager.attach(new LoadMode()); - assert success; - success = stateManager.attach(new LoadScreen()); - assert success; - /* - * Create and attach an input mode and screen controller - * for the "bones" screen. - */ - success = stateManager.attach(new BonesMode()); - assert success; - success = stateManager.attach(new BonesScreen()); - assert success; - /* - * Create and attach an input mode and screen controller - * for the "torso" screen. - */ - success = stateManager.attach(new TorsoMode()); - assert success; - success = stateManager.attach(new TorsoScreen()); - assert success; - /* - * Create and attach an input mode and screen controller - * for the "links" screen. - */ - success = stateManager.attach(new LinksMode()); - assert success; - success = stateManager.attach(new LinksScreen()); - assert success; - /* - * Create and attach an input mode and screen controller - * for the "test" screen. - */ - success = stateManager.attach(new TestMode()); - assert success; - success = stateManager.attach(new TestScreen()); - assert success; - } - - /** - * Configure the PhysicsDumper during startup. - */ - private static void configureDumper() { - dumper.setEnabled(DumpFlags.CullHints, true); - dumper.setEnabled(DumpFlags.JointsInBodies, true); - dumper.setEnabled(DumpFlags.JointsInSpaces, true); - dumper.setEnabled(DumpFlags.Transforms, true); - } - - /** - * Normalize all quaternions in the specified animation controls. - * - * @param animControls the controls to modify (not null) - */ - private static void normalizeAnimControls(List animControls) { - for (AnimControl animControl : animControls) { - Collection names = animControl.getAnimationNames(); - for (String name : names) { - Animation animation = animControl.getAnim(name); - AnimationEdit.normalizeQuaternions(animation, 0.00005f); - } - } - } - - /** - * Normalize all quaternions in the specified anim composers. - * - * @param composers the anim composers to modify (not null) - */ - private static void normalizeComposers(List composers) { - for (AnimComposer composer : composers) { - Collection names = composer.getAnimClipsNames(); - for (String clipName : names) { - AnimClip animClip = composer.getAnimClip(clipName); - AnimationEdit.normalizeQuaternions(animClip, 0.00005f); - } - } - } - - /** - * Initialization performed immediately after parsing the command-line - * arguments. - * - * @param showDialog when to show the JME settings dialog (not null) - * @param renderer the value passed to - * {@link com.jme3.system.AppSettings#setRenderer(java.lang.String)} - * @param title for the title bar of the app's window - */ - private static void mainStartup(final ShowDialog showDialog, - final String renderer, final String title) { - // Instantiate the application. - application = new DacWizard(); - - // Instantiate the display-settings screen. - RectSizeLimits dsl = new RectSizeLimits( - 640, 480, // minimum width and height - 2_048, 1_080 // maximum width and height - ); - DisplaySettings displaySettings - = new DisplaySettings(application, applicationName, dsl) { - @Override - protected void applyOverrides(AppSettings settings) { - super.applyOverrides(settings); - - setShowDialog(showDialog); - settings.setAudioRenderer(null); - settings.setRenderer(renderer); - settings.setResizable(true); - settings.setSamples(4); - settings.setTitle(title); - settings.setVSync(true); - } - }; - displaySettingsScreen = new DsScreen(displaySettings); - - AppSettings appSettings = displaySettings.initialize(); - if (appSettings != null) { - application.setSettings(appSettings); - /* - * Don't pause on lost focus. This simplifies debugging by - * permitting the application to run while minimized. - */ - application.setPauseOnLostFocus(false); - /* - * If the settings dialog should be shown, it has already been shown - * by DisplaySettings.initialize(). - */ - application.setShowSettings(false); - /* - * Designate a sandbox directory. - * This must be done *prior to* initialization. - */ - try { - ActionApplication.designateSandbox("Written Assets"); - } catch (IOException exception) { - // do nothing - } - application.start(); - // ... and onward to DacWizard.guiInitializeApplication()! - } - } - - /** - * Apply the specified animation pose to the specified Armature. - * - * @param armature the armature to modify (not null) - * @param composer the composer containing the named clip, unless it's - * {@link #bindPoseName} - * @param clipName the name of the clip containing the desired pose, or - * {@link #bindPoseName} - * @param animationTime the animation time of the desired pose in the clip - * (in seconds, ≥0) - */ - private static void poseArmature(Armature armature, AnimComposer composer, - String clipName, float animationTime) { - Pose pose = new Pose(armature); - if (!clipName.equals(bindPoseName)) { - AnimClip clip = composer.getAnimClip(clipName); - pose.setToClip(clip, animationTime); - } - pose.applyTo(armature); - armature.update(); - } - - /** - * Apply the specified animation pose to the specified Skeleton. - * - * @param skeleton the skeleton to modify (not null) - * @param animControl the control containing the named animation, unless - * it's {@link #bindPoseName} - * @param animationName the name of the animation containing the desired - * pose, or {@link #bindPoseName} - * @param time the animation time of the desired pose in the animation (in - * seconds, ≥0) - */ - private static void poseSkeleton(Skeleton skeleton, AnimControl animControl, - String animationName, float time) { - MySkeleton.setUserControl(skeleton, true); - Pose pose = new Pose(skeleton); - if (!animationName.equals(bindPoseName)) { - Animation animation = animControl.getAnim(animationName); - pose.setToAnimation(animation, time, new TweenTransforms()); - } - pose.applyTo(skeleton); - skeleton.updateWorldVectors(); - } - - /** - * Reset the default camera. - */ - private void resetCamera() { - flyCam.setDragToRotate(true); - flyCam.setMoveSpeed(20f); - - Vector3f location = new Vector3f(0f, 0.93f, 2.7f); - location.multLocal(cgmHeight); - cam.setLocation(location); - - cam.setName("cam"); - cam.setRotation(new Quaternion(0f, 0.995268f, -0.094f, 0.0253f)); - - float near = 0.01f * cgmHeight; - float far = 25f * cgmHeight; - MyCamera.setNearFar(cam, near, far); - } - - /** - * Configure the parent transform so that the C-G model has the specified - * size and the center of its base is located at the world origin. - * - * @param desiredSize the desired size (in world units, >0) - */ - private static void setParentTransform(float desiredSize) { - assert desiredSize > 0f : desiredSize; - - // Scale the model uniformly to the desired size. - Vector3f[] minMax = MySpatial.findMinMaxCoords(cgmParent); - Vector3f min = minMax[0]; // alias - Vector3f max = minMax[1]; // alias - Vector3f dimensions = max.subtract(min); - float oldSize = MyMath.max(dimensions.x, dimensions.y, dimensions.z); - if (oldSize > 0f) { - cgmParent.scale(desiredSize / oldSize); - } - /* - * Translate the model so that its base rests on the X-Z plane and its - * center lies on the Y axis. - */ - minMax = MySpatial.findMinMaxCoords(cgmParent); - min = minMax[0]; // alias - max = minMax[1]; // alias - Vector3f center = MyVector3f.midpoint(min, max, null); - cgmParent.move(-center.x, -min.y, -center.z); - } - - /** - * Initialization performed during the first invocation of - * {@link #simpleUpdate(float)}. - */ - private void startup1() { - logger.info(""); - /* - * Disable the render statistics. - * These can be re-enabled by pressing the F5 hotkey. - */ - setDisplayFps(false); - setDisplayStatView(false); - - // Enable the initial InputMode. - InputMode.getActiveMode().setEnabled(false); - InputMode initialInputMode = InputMode.findMode("filePath"); - initialInputMode.setEnabled(true); - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/FilePathMode.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/FilePathMode.java deleted file mode 100644 index 517eb3493..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/FilePathMode.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.SimpleApplication; -import com.jme3.app.state.AppStateManager; -import com.jme3.asset.AssetManager; -import com.jme3.cursors.plugins.JmeCursor; -import com.jme3.input.KeyInput; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3utilities.MyString; -import jme3utilities.Validate; -import jme3utilities.ui.InputMode; - -/** - * Input mode for the "filePath" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class FilePathMode extends InputMode { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(FilePathMode.class.getName()); - /** - * asset path to the cursor for this mode - */ - final private static String assetPath = "Textures/cursors/default.cur"; - /** - * action-string prefix to alter the filesystem path prefix - */ - final private static String setPathPrefix = "set pathPrefix "; - // ************************************************************************* - // constructors - - /** - * Instantiate a disabled, uninitialized input mode. - */ - FilePathMode() { - super("filePath"); - } - // ************************************************************************* - // InputMode methods - - /** - * Add default hotkey bindings. These bindings will be used if no custom - * bindings are found. - */ - @Override - protected void defaultBindings() { - bind(SimpleApplication.INPUT_MAPPING_EXIT, KeyInput.KEY_ESCAPE); - bind(Action.editBindings, KeyInput.KEY_F1); - bind(Action.editDisplaySettings, KeyInput.KEY_F2); - - bind(Action.dumpPhysicsSpace, KeyInput.KEY_O); - bind(Action.dumpRenderer, KeyInput.KEY_P); - bind(Action.nextScreen, KeyInput.KEY_PGDN); - - bind(Action.nextScreen, KeyInput.KEY_N); - } - - /** - * Initialize this (disabled) mode prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - // Configure the mouse cursor for this mode. - AssetManager manager = application.getAssetManager(); - JmeCursor cursor = (JmeCursor) manager.loadAsset(assetPath); - setCursor(cursor); - - super.initialize(stateManager, application); - } - - /** - * Process an action from the keyboard or mouse. - * - * @param actionString textual description of the action (not null) - * @param ongoing true if the action is ongoing, otherwise false - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void onAction(String actionString, boolean ongoing, float tpf) { - Validate.nonNull(actionString, "action string"); - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "Got action {0} ongoing={1}", - new Object[]{MyString.quote(actionString), ongoing}); - } - - boolean handled = false; - if (ongoing) { - FilePathScreen screen - = DacWizard.findAppState(FilePathScreen.class); - - if (Action.browse.equals(actionString)) { - screen.browse(); - handled = true; - - } else if (actionString.startsWith(setPathPrefix)) { - String pathPrefix - = MyString.remainder(actionString, setPathPrefix); - screen.setPathPrefix(pathPrefix); - handled = true; - - } else if (Action.nextScreen.equals(actionString)) { - nextScreen(); - handled = true; - } - } - if (!handled) { - getActionApplication().onAction(actionString, ongoing, tpf); - } - } - // ************************************************************************* - // private methods - - /** - * Proceed to the "load" screen if possible. - */ - private void nextScreen() { - String feedback = FilePathScreen.feedback(); - if (feedback.isEmpty()) { - setEnabled(false); - InputMode load = InputMode.findMode("load"); - load.setEnabled(true); - } - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/FilePathScreen.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/FilePathScreen.java deleted file mode 100644 index e38ef13df..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/FilePathScreen.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import de.lessvoid.nifty.controls.Button; -import de.lessvoid.nifty.elements.Element; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.logging.Logger; -import jme3utilities.Heart; -import jme3utilities.InitialState; -import jme3utilities.MyString; -import jme3utilities.nifty.GuiScreenController; -import jme3utilities.nifty.PopupMenuBuilder; -import jme3utilities.ui.InputMode; - -/** - * The screen controller for the "filePath" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class FilePathScreen extends GuiScreenController { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger - = Logger.getLogger(FilePathScreen.class.getName()); - // ************************************************************************* - // fields - - /** - * element of GUI button to proceed to the "load" screen - */ - private Element nextElement; - // ************************************************************************* - // constructors - - /** - * Instantiate an uninitialized, disabled screen that will not be enabled - * during initialization. - */ - FilePathScreen() { - super("filePath", "Interface/Nifty/screens/wizard/filePath.xml", - InitialState.Disabled); - setSubmenuWarp(0.5f, 0.5f); - } - // ************************************************************************* - // new methods exposed - - /** - * Handle a "browse" action to begin browsing the file system. - */ - void browse() { - Map fileMap = Heart.driveMap(); - - // Add the current working directory to the file map. - String workPath = System.getProperty("user.dir"); - File work = new File(workPath); - if (work.isDirectory()) { - String absolutePath = Heart.fixPath(workPath); - fileMap.put(absolutePath, work); - } - - // Add the user's home directory to the file map. - String homePath = System.getProperty("user.home"); - File home = new File(homePath); - if (home.isDirectory()) { - String absolutePath = Heart.fixPath(homePath); - fileMap.put(absolutePath, home); - } - /* - * If a filesystem path is selected, add its parent directory - * to the file map. - */ - Model model = DacWizard.getModel(); - String filePath = model.filePath(); - if (!filePath.isEmpty()) { - File file = new File(filePath); - File parent = file.getParentFile(); - String parentPath = parent.getPath(); - String absolutePath = Heart.fixPath(parentPath); - fileMap.put(absolutePath, parent); - } - - // Build and show a popup menu. - String actionPrefix = "set pathPrefix "; - PopupMenuBuilder builder = buildFileMenu(fileMap); - showPopupMenu(actionPrefix, builder); - } - - /** - * Determine user feedback (if any) regarding the "next screen" action. - * - * @return "" if ready to proceed, otherwise an explanatory message - */ - static String feedback() { - Model model = DacWizard.getModel(); - String filePath = model.filePath(); - - String result = ""; - if (!filePath.contains("/")) { - result = "No model is selected yet."; - } - - return result; - } - - /** - * Handle a "set pathPrefix" action. - * - * @param pathPrefix the user-selected filesystem-path prefix (not null, not - * empty) - */ - void setPathPrefix(String pathPrefix) { - assert pathPrefix != null; - - String absPathPrefix = Heart.fixPath(pathPrefix); - File file = new File(absPathPrefix); - - boolean isDirectory = file.isDirectory(); - if (!isDirectory && file.canRead()) { // complete path to readable file - Model model = DacWizard.getModel(); - model.setFilePath(absPathPrefix); - - } else { - Map fileMap; - String actionPrefix; - if (isDirectory) { - fileMap = directoryMap(absPathPrefix, ""); - actionPrefix = "set pathPrefix " + absPathPrefix; - - } else { // an incomplete path - File parent = file.getParentFile(); - String parentPath = parent.getPath(); - parentPath = Heart.fixPath(parentPath); - - String name = file.getName(); - fileMap = directoryMap(parentPath, name); - actionPrefix = "set pathPrefix " + parentPath; - } - if (!actionPrefix.endsWith("/")) { - actionPrefix += "/"; - } - - // Build and show a popup menu. - PopupMenuBuilder builder = buildFileMenu(fileMap); - showPopupMenu(actionPrefix, builder); - } - } - // ************************************************************************* - // GuiScreenController methods - - /** - * Initialize this (disabled) screen prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - super.initialize(stateManager, application); - - InputMode inputMode = InputMode.findMode("filePath"); - assert inputMode != null; - setListener(inputMode); - inputMode.influence(this); - } - - /** - * A callback from Nifty, invoked each time this screen starts up. - */ - @Override - public void onStartScreen() { - super.onStartScreen(); - - Button nextButton = getButton("next"); - if (nextButton == null) { - throw new RuntimeException("missing GUI control: nextButton"); - } - this.nextElement = nextButton.getElement(); - } - - /** - * Update this ScreenController prior to rendering. (Invoked once per - * frame.) - * - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void update(float tpf) { - super.update(tpf); - - Model model = DacWizard.getModel(); - String filePath = model.filePath(); - setStatusText("filePath", " " + filePath); - - String feedback = feedback(); - setStatusText("feedback", feedback); - if (feedback.isEmpty()) { - nextElement.show(); - } else { - nextElement.hide(); - } - } - // ************************************************************************* - // private methods - - /** - * Build a file-selection popup menu based on the specified file map. - * - * @param fileMap the map of files to include (not null) - * @return a new instance (not null) - */ - private PopupMenuBuilder buildFileMenu(Map fileMap) { - assert fileMap != null; - - // Generate a list of file names (and prefixes) to display in the menu. - Set nameSet = fileMap.keySet(); - assert !nameSet.contains("."); - List nameList = new ArrayList<>(nameSet); - - // Reduce the list as necessary to fit on the screen. - int height = cam.getHeight(); - int maxMenuItems = height / 26; - MyString.reduce(nameList, maxMenuItems); - - // Sort the list and build the menu. - Collections.sort(nameList); - PopupMenuBuilder result = new PopupMenuBuilder(); - for (String name : nameList) { - if (fileMap.containsKey(name)) { - File file = fileMap.get(name); - if (file.isDirectory()) { - result.add(name, "Textures/icons/folder.png"); - } else if (name.endsWith(".j3o")) { - result.add(name, "Textures/icons/jme.png"); - } else if (name.endsWith(".glb")) { - result.add(name, "Textures/icons/jme.png"); - } else if (name.endsWith(".gltf")) { - result.add(name, "Textures/icons/jme.png"); - } - } else { // prefix - result.add(name, "Textures/icons/ellipsis.png"); - } - } - - return result; - } - - /** - * Build a map of files, in the specified directory, whose names have the - * specified prefix. - * - * @param dirPath the filesystem path to the directory (not null) - * @param namePrefix required name prefix (not null) - * @return a new instance (not null) - */ - private static Map directoryMap( - String dirPath, String namePrefix) { - assert dirPath != null; - assert namePrefix != null; - - Map fileMap = new TreeMap<>(); - /* - * Initialize the map with subdirectories and readable files. - * Exclude names that start with ".". - */ - File directory = new File(dirPath); - File[] files = directory.listFiles(); - if (files != null) { - for (File file : files) { - if (file.isDirectory() || file.canRead()) { - String name = file.getName(); - if (name.startsWith(namePrefix) && !name.startsWith(".")) { - fileMap.put(name, file); - } - } - } - } - - // Add ".." if a parent directory exists. - File parent = directory.getParentFile(); - if (parent != null) { - if ("..".startsWith(namePrefix)) { - fileMap.put("..", parent); - } - } - - return fileMap; - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/LinkValue.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/LinkValue.java deleted file mode 100644 index 9ab7630a9..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/LinkValue.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright (c) 2019-2022, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.bullet.animation.DacConfiguration; -import java.util.logging.Logger; - -/** - * The value of an item in the TreeBox of the "links" screen. - * - * @author Stephen Gold sgold@sonic.net - */ -class LinkValue { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final private static Logger logger - = Logger.getLogger(LinkValue.class.getName()); - // ************************************************************************* - // fields - - /** - * name of the bone/torso (not null) - */ - final private String boneName; - // ************************************************************************* - // constructors - - /** - * Instantiate a value from a bone name or torsoName. - * - * @param boneName the name of the bone/torso (not null) - */ - LinkValue(String boneName) { - assert boneName != null; - this.boneName = boneName; - } - // ************************************************************************* - // new methods exposed - - /** - * Read the name of the bone/torso. - * - * @return the bone name (not null) - */ - String boneName() { - assert boneName != null; - return boneName; - } - // ************************************************************************* - // Object methods - - /** - * Convert the value to text for TreeBox display. - * - * @return display text for the item (not null, not empty) - */ - @Override - public String toString() { - String result; - if (boneName.equals(DacConfiguration.torsoName)) { - result = "Torso:"; - } else { - result = "Bone:" + boneName; - } - - Model model = DacWizard.getModel(); - int numBones = model.countManagedBones(boneName); - int numVertices = model.countVertices(boneName); - result += String.format( - " (%d bone%s, %d vert%s)", numBones, (numBones == 1) ? "" : "s", - numVertices, (numVertices == 1) ? "ex" : "ices"); - - return result; - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/LinksMode.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/LinksMode.java deleted file mode 100644 index b2d4deadc..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/LinksMode.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.SimpleApplication; -import com.jme3.app.state.AppStateManager; -import com.jme3.asset.AssetManager; -import com.jme3.bullet.RotationOrder; -import com.jme3.bullet.animation.CenterHeuristic; -import com.jme3.bullet.animation.ShapeHeuristic; -import com.jme3.cursors.plugins.JmeCursor; -import com.jme3.input.KeyInput; -import com.jme3.math.Vector3f; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3utilities.MyString; -import jme3utilities.Validate; -import jme3utilities.math.MyVector3f; -import jme3utilities.ui.InputMode; - -/** - * Input mode for the "links" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class LinksMode extends InputMode { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(LinksMode.class.getName()); - /** - * asset path to the cursor for this mode - */ - final private static String assetPath = "Textures/cursors/default.cur"; - // ************************************************************************* - // constructors - - /** - * Instantiate a disabled, uninitialized input mode. - */ - LinksMode() { - super("links"); - } - // ************************************************************************* - // InputMode methods - - /** - * Add default hotkey bindings. These bindings will be used if no custom - * bindings are found. - */ - @Override - protected void defaultBindings() { - bind(SimpleApplication.INPUT_MAPPING_EXIT, KeyInput.KEY_ESCAPE); - bind(Action.editBindings, KeyInput.KEY_F1); - bind(Action.editDisplaySettings, KeyInput.KEY_F2); - - bind(Action.previousScreen, KeyInput.KEY_PGUP); - - bind(Action.dumpPhysicsSpace, KeyInput.KEY_O); - bind(Action.dumpRenderer, KeyInput.KEY_P); - bind(Action.nextScreen, KeyInput.KEY_PGDN); - - bind(Action.previousScreen, KeyInput.KEY_B); - bind(Action.nextScreen, KeyInput.KEY_N); - } - - /** - * Initialize this (disabled) mode prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - // Set the mouse cursor for this mode. - AssetManager manager = application.getAssetManager(); - JmeCursor cursor = (JmeCursor) manager.loadAsset(assetPath); - setCursor(cursor); - - super.initialize(stateManager, application); - } - - /** - * Process an action from the keyboard or mouse. - * - * @param actionString textual description of the action (not null) - * @param ongoing true if the action is ongoing, otherwise false - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void onAction(String actionString, boolean ongoing, float tpf) { - Validate.nonNull(actionString, "action string"); - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "Got action {0} ongoing={1}", - new Object[]{MyString.quote(actionString), ongoing}); - } - - boolean handled = true; - if (ongoing) { - LinksScreen screen = DacWizard.findAppState(LinksScreen.class); - switch (actionString) { - case Action.nextMassHeuristic: - screen.nextMassHeuristic(); - break; - - case Action.nextScreen: - nextScreen(); - break; - - case Action.previousScreen: - previousScreen(); - break; - - case Action.selectCenterHeuristic: - screen.selectCenterHeuristic(); - break; - - case Action.selectRotationOrder: - screen.selectRotationOrder(); - break; - - case Action.selectShapeHeuristic: - screen.selectShapeHeuristic(); - break; - - case Action.setMassParameter: - screen.setMassParameter(); - break; - - case Action.setShapeScale: - screen.setShapeScale(); - break; - - case Action.toggleAngleMode: - DacWizard.getModel().toggleAngleMode(); - break; - - default: - handled = false; - } - if (!handled) { - handled = testForPrefixes(actionString); - } - } - if (!handled) { - getActionApplication().onAction(actionString, ongoing, tpf); - } - } - // ************************************************************************* - // private methods - - /** - * Proceed to the "test" screen if possible. - */ - private void nextScreen() { - String feedback = LinksScreen.feedback(); - if (feedback.isEmpty()) { - setEnabled(false); - InputMode test = InputMode.findMode("test"); - test.setEnabled(true); - } - } - - /** - * Go back to the "torso" screen. - */ - private void previousScreen() { - setEnabled(false); - InputMode bones = InputMode.findMode("torso"); - bones.setEnabled(true); - } - - /** - * Test an ongoing action for prefixes. - * - * @param actionString textual description of the action (not null) - * @return true if the action is handled, otherwise false - */ - private static boolean testForPrefixes(String actionString) { - boolean handled = true; - LinksScreen screen = DacWizard.findAppState(LinksScreen.class); - String arg; - - if (actionString.startsWith("select centerHeuristic ")) { - arg = MyString.remainder(actionString, "select centerHeuristic "); - CenterHeuristic heuristic = CenterHeuristic.valueOf(arg); - screen.selectCenterHeuristic(heuristic); - - } else if (actionString.startsWith("select rotationOrder ")) { - arg = MyString.remainder(actionString, "select rotationOrder "); - RotationOrder axisOrder; - if (arg.equals("sixdof")) { - axisOrder = null; - } else { - axisOrder = RotationOrder.valueOf(arg); - } - screen.selectRotationOrder(axisOrder); - - } else if (actionString.startsWith("select shapeHeuristic ")) { - arg = MyString.remainder(actionString, "select shapeHeuristic "); - ShapeHeuristic heuristic = ShapeHeuristic.valueOf(arg); - screen.selectShapeHeuristic(heuristic); - - } else if (actionString.startsWith("set massParameter ")) { - arg = MyString.remainder(actionString, "set massParameter "); - float value = Float.parseFloat(arg); - screen.setMassParameter(value); - - } else if (actionString.startsWith("set shapeScale ")) { - arg = MyString.remainder(actionString, "set shapeScale "); - Vector3f factors = MyVector3f.parse(arg); - if (factors != null && MyVector3f.isAllPositive(factors)) { - screen.setShapeScale(factors); - } - - } else { - handled = false; - } - - return handled; - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/LinksScreen.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/LinksScreen.java deleted file mode 100644 index f10b9cde9..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/LinksScreen.java +++ /dev/null @@ -1,663 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.bullet.PhysicsSpace; -import com.jme3.bullet.RotationOrder; -import com.jme3.bullet.animation.CenterHeuristic; -import com.jme3.bullet.animation.DacConfiguration; -import com.jme3.bullet.animation.LinkConfig; -import com.jme3.bullet.animation.MassHeuristic; -import com.jme3.bullet.animation.RangeOfMotion; -import com.jme3.bullet.animation.ShapeHeuristic; -import com.jme3.math.Vector3f; -import de.lessvoid.nifty.NiftyEventSubscriber; -import de.lessvoid.nifty.controls.Button; -import de.lessvoid.nifty.controls.SliderChangedEvent; -import de.lessvoid.nifty.controls.TreeBox; -import de.lessvoid.nifty.controls.TreeItem; -import de.lessvoid.nifty.elements.Element; -import java.util.List; -import java.util.logging.Logger; -import jme3utilities.InitialState; -import jme3utilities.MyString; -import jme3utilities.Validate; -import jme3utilities.math.MyMath; -import jme3utilities.math.MyVector3f; -import jme3utilities.nifty.GuiScreenController; -import jme3utilities.nifty.PopupMenuBuilder; -import jme3utilities.nifty.SliderTransform; -import jme3utilities.nifty.dialog.AllowNull; -import jme3utilities.nifty.dialog.DialogController; -import jme3utilities.nifty.dialog.FloatDialog; -import jme3utilities.nifty.dialog.VectorDialog; -import jme3utilities.ui.InputMode; - -/** - * The screen controller for the "links" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -public class LinksScreen extends GuiScreenController { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(LinksScreen.class.getName()); - // ************************************************************************* - // fields - - /** - * element of GUI button to proceed to the "test" screen - */ - private Element nextElement; - /** - * TreeBox to display links in the hierarchy - */ - private TreeBox treeBox; - // ************************************************************************* - // constructors - - /** - * Instantiate an uninitialized, disabled screen that will not be enabled - * during initialization. - */ - LinksScreen() { - super("links", "Interface/Nifty/screens/wizard/links.xml", - InitialState.Disabled); - } - // ************************************************************************* - // new methods exposed - - /** - * Determine user feedback (if any) regarding the "next screen" action. - * - * @return "" if ready to proceed, otherwise an explanatory message - */ - static String feedback() { - return ""; - } - - /** - * Callback handler that Nifty invokes after a slider changes. - * - * @param sliderId Nifty element ID of the slider (not null) - * @param event details of the event (not null, ignored) - */ - @NiftyEventSubscriber(pattern = ".*Slider") - public void linksScreenSliderChanged( - final String sliderId, final SliderChangedEvent event) { - Validate.nonNull(sliderId, "slider ID"); - assert sliderId.endsWith("Slider") : sliderId; - Validate.nonNull(event, "event"); - - if (!isIgnoreGuiChanges() && hasStarted()) { - readSliders(); - } - } - - /** - * Handle a "next massHeuristic" action. - */ - void nextMassHeuristic() { - LinkConfig config = config(); - float massParameter = config.massParameter(); - MassHeuristic massHeuristic = config.massHeuristic(); - if (massHeuristic == MassHeuristic.Mass) { - massHeuristic = MassHeuristic.Density; - } else { - massHeuristic = MassHeuristic.Mass; - } - ShapeHeuristic shapeHeuristic = config.shapeHeuristic(); - Vector3f shapeScale = config.shapeScale(null); - CenterHeuristic centerHeuristic = config.centerHeuristic(); - RotationOrder axisOrder = config.rotationOrder(); - - config = new LinkConfig(massParameter, massHeuristic, shapeHeuristic, - shapeScale, centerHeuristic, axisOrder); - setConfig(config); - } - - /** - * Handle a "select centerHeuristic" action with no argument. - */ - void selectCenterHeuristic() { - PopupMenuBuilder builder = new PopupMenuBuilder(); - - LinkConfig config = config(); - String boneName = selectedLink(); - CenterHeuristic selected = config.centerHeuristic(); - for (CenterHeuristic heuristic : CenterHeuristic.values()) { - if (boneName.equals(DacConfiguration.torsoName) - && heuristic == CenterHeuristic.Joint) { - continue; - } - if (heuristic != selected) { - String name = heuristic.toString(); - builder.add(name); - } - } - - showPopupMenu("select centerHeuristic ", builder); - } - - /** - * Handle a "select centerHeuristic" action with an argument. - * - * @param heuristic the desired heuristic (not null) - */ - void selectCenterHeuristic(CenterHeuristic heuristic) { - LinkConfig config = config(); - float massParameter = config.massParameter(); - MassHeuristic massHeuristic = config.massHeuristic(); - ShapeHeuristic shapeHeuristic = config.shapeHeuristic(); - Vector3f shapeScale = config.shapeScale(null); - RotationOrder axisOrder = config.rotationOrder(); - - config = new LinkConfig(massParameter, massHeuristic, shapeHeuristic, - shapeScale, heuristic, axisOrder); - setConfig(config); - } - - /** - * Determine which PhysicsLink is currently selected. - * - * @return the bone/torso name, or null if none selected - */ - String selectedLink() { - String result = null; - List> selectedLinks = treeBox.getSelection(); - if (!selectedLinks.isEmpty()) { - assert selectedLinks.size() == 1; - TreeItem selectedItem = selectedLinks.get(0); - LinkValue value = selectedItem.getValue(); - result = value.boneName(); - } - - return result; - } - - /** - * Handle a "select rotationOrder" action without an argument. - */ - void selectRotationOrder() { - PopupMenuBuilder builder = new PopupMenuBuilder(); - - LinkConfig config = config(); - RotationOrder selected = config.rotationOrder(); - if (selected != null) { - builder.add("sixdof"); - } - for (RotationOrder axisOrder : RotationOrder.values()) { - if (axisOrder != selected) { - String name = axisOrder.toString(); - builder.add(name); - } - } - - showPopupMenu("select rotationOrder ", builder); - } - - /** - * Handle a "select rotationOrder" action with an argument. - * - * @param axisOrder may be null - */ - void selectRotationOrder(RotationOrder axisOrder) { - LinkConfig config = config(); - float massParameter = config.massParameter(); - MassHeuristic massHeuristic = config.massHeuristic(); - ShapeHeuristic shapeHeuristic = config.shapeHeuristic(); - Vector3f shapeScale = config.shapeScale(null); - CenterHeuristic centerHeuristic = config.centerHeuristic(); - - config = new LinkConfig(massParameter, massHeuristic, shapeHeuristic, - shapeScale, centerHeuristic, axisOrder); - setConfig(config); - } - - /** - * Handle a "select shapeHeuristic" action without an argument. - */ - void selectShapeHeuristic() { - PopupMenuBuilder builder = new PopupMenuBuilder(); - - LinkConfig config = config(); - ShapeHeuristic selected = config.shapeHeuristic(); - for (ShapeHeuristic heuristic : ShapeHeuristic.values()) { - if (heuristic != selected) { - String name = heuristic.toString(); - builder.add(name); - } - } - - showPopupMenu("select shapeHeuristic ", builder); - } - - /** - * Handle a "select shapeHeuristic" action with an argument. - * - * @param heuristic the desired heuristic (not null) - */ - void selectShapeHeuristic(ShapeHeuristic heuristic) { - LinkConfig config = config(); - float massParameter = config.massParameter(); - MassHeuristic massHeuristic = config.massHeuristic(); - Vector3f shapeScale = config.shapeScale(null); - CenterHeuristic centerHeuristic = config.centerHeuristic(); - RotationOrder axisOrder = config.rotationOrder(); - - config = new LinkConfig(massParameter, massHeuristic, heuristic, - shapeScale, centerHeuristic, axisOrder); - setConfig(config); - } - - /** - * Handle a "set massParameter" action without an argument. - */ - void setMassParameter() { - LinkConfig config = config(); - float oldParameter = config.massParameter(); - String defaultText = Float.toString(oldParameter); - String actionPrefix = "set massParameter "; - DialogController controller = new FloatDialog( - "Set", Float.MIN_VALUE, Float.MAX_VALUE, AllowNull.No); - showTextEntryDialog("Enter the mass-parameter value:", defaultText, - actionPrefix, controller); - } - - /** - * Handle a "set massParameter" action with an argument. - * - * @param value the desired parameter value (>0) - */ - void setMassParameter(float value) { - LinkConfig config = config(); - MassHeuristic massHeuristic = config.massHeuristic(); - ShapeHeuristic shapeHeuristic = config.shapeHeuristic(); - Vector3f shapeScale = config.shapeScale(null); - CenterHeuristic centerHeuristic = config.centerHeuristic(); - RotationOrder axisOrder = config.rotationOrder(); - - config = new LinkConfig(value, massHeuristic, shapeHeuristic, - shapeScale, centerHeuristic, axisOrder); - setConfig(config); - } - - /** - * Handle a "set shapeScale" action without an argument. - */ - void setShapeScale() { - LinkConfig config = config(); - Vector3f oldParameter = config.shapeScale(null); - String defaultText = oldParameter.toString(); - String actionPrefix = "set shapeScale "; - DialogController controller = new VectorDialog("Set", 3, AllowNull.No); - showTextEntryDialog("Enter the shapeScale value:", defaultText, - actionPrefix, controller); - } - - /** - * Handle a "set shapeScale" action with an argument. - * - * @param scaleFactors the desired scale factors (not null, no negative - * component, unaffected) - */ - void setShapeScale(Vector3f scaleFactors) { - LinkConfig config = config(); - MassHeuristic massHeuristic = config.massHeuristic(); - float massParameter = config.massParameter(); - ShapeHeuristic shapeHeuristic = config.shapeHeuristic(); - CenterHeuristic centerHeuristic = config.centerHeuristic(); - RotationOrder axisOrder = config.rotationOrder(); - - config = new LinkConfig(massParameter, massHeuristic, shapeHeuristic, - scaleFactors, centerHeuristic, axisOrder); - setConfig(config); - } - // ************************************************************************* - // GuiScreenController methods - - /** - * Initialize this (disabled) screen prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - super.initialize(stateManager, application); - - InputMode inputMode = InputMode.findMode("links"); - assert inputMode != null; - setListener(inputMode); - inputMode.influence(this); - } - - /** - * A callback from Nifty, invoked each time this screen starts up. - */ - @Override - @SuppressWarnings("unchecked") - public void onStartScreen() { - super.onStartScreen(); - - Button nextButton = getButton("next"); - if (nextButton == null) { - throw new RuntimeException("missing GUI control: nextButton"); - } - this.nextElement = nextButton.getElement(); - - this.treeBox = getScreen().findNiftyControl("hierarchy", TreeBox.class); - if (treeBox == null) { - throw new RuntimeException("missing GUI control: hierarchy"); - } - - TreeItem rootItem = new TreeItem<>(); - rootItem.setExpanded(true); - - // Create an item for the torso. - LinkValue linkItem = new LinkValue(DacConfiguration.torsoName); - TreeItem torsoItem = new TreeItem<>(linkItem); - torsoItem.setExpanded(true); - - // Create an item for each linked bone in the hierarchy. - Model model = DacWizard.getModel(); - int[] linkedBoneIndices = model.listLinkedBones(); - int numLinkedBones = linkedBoneIndices.length; - TreeItem[] lbItems = new TreeItem[numLinkedBones]; - for (int lbIndex = 0; lbIndex < numLinkedBones; ++lbIndex) { - int boneIndex = linkedBoneIndices[lbIndex]; - String boneName = model.boneName(boneIndex); - linkItem = new LinkValue(boneName); - lbItems[lbIndex] = new TreeItem<>(linkItem); - lbItems[lbIndex].setExpanded(true); - } - - // Parent each item. - for (int childLbi = 0; childLbi < numLinkedBones; ++childLbi) { - TreeItem childItem = lbItems[childLbi]; - LinkValue childValue = childItem.getValue(); - String childName = childValue.boneName(); - String parentName = model.linkedBoneParentName(childName); - if (parentName.equals(DacConfiguration.torsoName)) { - torsoItem.addTreeItem(childItem); - } else { // parent is a BoneLink - TreeItem parentItem - = findLinkedBoneItem(parentName, lbItems); - parentItem.addTreeItem(childItem); - } - } - rootItem.addTreeItem(torsoItem); - treeBox.setTree(rootItem); - - // Initialize the selection. - String selected = model.selectedLink(); - if (selected.equals(DacConfiguration.torsoName)) { - treeBox.selectItem(torsoItem); - } else { // a BoneLink is selected - TreeItem item = findLinkedBoneItem(selected, lbItems); - treeBox.selectItem(item); - } - } - - /** - * Update this ScreenController prior to rendering. (Invoked once per - * frame.) - * - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void update(float tpf) { - super.update(tpf); - - if (!hasStarted()) { - return; - } - - Model model = DacWizard.getModel(); - List> selectedLinks = treeBox.getSelection(); - String boneName; - if (selectedLinks.isEmpty()) { - boneName = model.selectedLink(); - } else { // an item is selected - assert selectedLinks.size() == 1 : selectedLinks.size(); - TreeItem selectedItem = selectedLinks.get(0); - LinkValue value = selectedItem.getValue(); - boneName = value.boneName(); - model.selectLink(boneName); - } - - String xRangeStatus = ""; - String yRangeStatus = ""; - String zRangeStatus = ""; - if (boneName.equals(DacConfiguration.torsoName)) { - setSliderEnabled("minX", false); - setSliderEnabled("maxX", false); - setSliderEnabled("minY", false); - setSliderEnabled("maxY", false); - setSliderEnabled("minZ", false); - setSliderEnabled("maxZ", false); - } else { // a BoneLink is selected - RangeOfMotion rom = model.rom(boneName); - xRangeStatus = describe(rom, PhysicsSpace.AXIS_X); - yRangeStatus = describe(rom, PhysicsSpace.AXIS_Y); - zRangeStatus = describe(rom, PhysicsSpace.AXIS_Z); - setAxisSliders("minX", "maxX", rom, PhysicsSpace.AXIS_X); - setAxisSliders("minY", "maxY", rom, PhysicsSpace.AXIS_Y); - setAxisSliders("minZ", "maxZ", rom, PhysicsSpace.AXIS_Z); - } - setStatusText("xRangeStatus", xRangeStatus); - setStatusText("yRangeStatus", yRangeStatus); - setStatusText("zRangeStatus", zRangeStatus); - - LinkConfig config = model.config(boneName); - String centerHeuristicButton = config.centerHeuristic().toString(); - setButtonText("centerHeuristic", centerHeuristicButton); - - MassHeuristic massHeuristic = config.massHeuristic(); - String massHeuristicButton = massHeuristic.toString().toLowerCase(); - setButtonText("massHeuristic", massHeuristicButton); - - float massParameter = config.massParameter(); - String massParameterButton = MyString.describe(massParameter); - setButtonText("massParameter", massParameterButton); - - String shapeHeuristicButton = config.shapeHeuristic().toString(); - setButtonText("shapeHeuristic", shapeHeuristicButton); - - Vector3f shapeScale = config.shapeScale(null); - String shapeScaleButton = MyVector3f.describe(shapeScale); - setButtonText("shapeScale", shapeScaleButton); - - RotationOrder order = config.rotationOrder(); - String rotationOrderButtonText; - if (order == null) { - rotationOrderButtonText = "sixdof"; - } else { - rotationOrderButtonText = order.toString(); - } - setButtonText("rotationOrder", rotationOrderButtonText); - - String feedback = feedback(); - setStatusText("feedback", feedback); - if (feedback.isEmpty()) { - nextElement.show(); - } else { - nextElement.hide(); - } - - AngleMode angleMode = model.angleMode(); - String angleModeText = angleMode.toString(); - setButtonText("angleMode", angleModeText); - } - // ************************************************************************* - // private methods - - /** - * Read the configuration of the selected link. - * - * @return the configuration (not null) - */ - private LinkConfig config() { - Model model = DacWizard.getModel(); - String boneName = selectedLink(); - LinkConfig result = model.config(boneName); - - return result; - } - - /** - * Describe one axis of a joint's range of motion. - * - * @param rom (not null) - * @param axisIndex axisIndex which axis: 0→X, 1→Y, 2→Z - * @return descriptive text (not null, not empty) - */ - private static String describe(RangeOfMotion rom, int axisIndex) { - float maxRadians = rom.getMaxRotation(axisIndex); - float minRadians = rom.getMinRotation(axisIndex); - - String text; - AngleMode angleMode = DacWizard.getModel().angleMode(); - switch (angleMode) { - case Degrees: - float maxDegrees = MyMath.toDegrees(maxRadians); - float minDegrees = MyMath.toDegrees(minRadians); - int max = Math.round(maxDegrees); - int min = Math.round(minDegrees); - text = String.format("%+d to %+d degrees", min, max); - break; - - case Radians: - text = String.format( - "%+.2f to %+.2f rad", minRadians, maxRadians); - break; - - default: - throw new IllegalStateException("angleMode = " + angleMode); - } - - return text; - } - - /** - * Find the item for the named BoneLink. - * - * @param boneName the bone name of the link (not null, not empty) - * @param linkedBoneItems the array of items (not null, not empty, - * unaffected) - * @return the pre-existing item, or null if not found - */ - private static TreeItem findLinkedBoneItem( - String boneName, TreeItem[] linkedBoneItems) { - assert boneName != null; - assert !boneName.isEmpty(); - - TreeItem result; - for (TreeItem linkedBoneItem : linkedBoneItems) { - result = linkedBoneItem; - LinkValue value = result.getValue(); - if (boneName.equals(value.boneName())) { - return result; - } - } - - return null; - } - - /** - * Update the RangeOfMotion of the selected BoneLink based on slider - * positions. - */ - private void readSliders() { - float maxX = readSlider("maxX", SliderTransform.None); - maxX = MyMath.toRadians(maxX); - - float minX = readSlider("minX", SliderTransform.None); - minX = MyMath.toRadians(minX); - - float maxY = readSlider("maxY", SliderTransform.None); - maxY = MyMath.toRadians(maxY); - - float minY = readSlider("minY", SliderTransform.None); - minY = MyMath.toRadians(minY); - - float maxZ = readSlider("maxZ", SliderTransform.None); - maxZ = MyMath.toRadians(maxZ); - - float minZ = readSlider("minZ", SliderTransform.None); - minZ = MyMath.toRadians(minZ); - - RangeOfMotion rom - = new RangeOfMotion(maxX, minX, maxY, minY, maxZ, minZ); - - Model model = DacWizard.getModel(); - String boneName = model.selectedLink(); - model.setRom(boneName, rom); - } - - /** - * Reposition and enable the named sliders to reflect the indexed axis of - * the specified RangeOfMotion. - * - * @param minSliderName the name of the slider for the minimum rotation (not - * null, not empty) - * @param maxSliderName the name of the slider for the maximum rotation (not - * null, not empty) - * @param rom (not null) - * @param axisIndex which axis: 0→X, 1→Y, 2→Z - */ - private void setAxisSliders(String minSliderName, String maxSliderName, - RangeOfMotion rom, int axisIndex) { - float maxRadians = rom.getMaxRotation(axisIndex); - float maxDegrees = MyMath.toDegrees(maxRadians); - setSliderEnabled(maxSliderName, true); - setSlider(maxSliderName, SliderTransform.None, maxDegrees); - - float minRadians = rom.getMinRotation(axisIndex); - float minDegrees = MyMath.toDegrees(minRadians); - setSliderEnabled(minSliderName, true); - setSlider(minSliderName, SliderTransform.None, minDegrees); - } - - /** - * Alter the configuration of the selected link. - * - * @param config the desired configuration (not null) - */ - private void setConfig(LinkConfig config) { - Model model = DacWizard.getModel(); - String boneName = selectedLink(); - model.setConfig(boneName, config); - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/LoadMode.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/LoadMode.java deleted file mode 100644 index d882880e4..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/LoadMode.java +++ /dev/null @@ -1,234 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.SimpleApplication; -import com.jme3.app.state.AppStateManager; -import com.jme3.asset.AssetManager; -import com.jme3.cursors.plugins.JmeCursor; -import com.jme3.input.CameraInput; -import com.jme3.input.KeyInput; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3utilities.MyString; -import jme3utilities.Validate; -import jme3utilities.nifty.dialog.AllowNull; -import jme3utilities.nifty.dialog.DialogController; -import jme3utilities.nifty.dialog.FloatDialog; -import jme3utilities.ui.InputMode; - -/** - * Input mode for the "load" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class LoadMode extends InputMode { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(LoadMode.class.getName()); - /** - * asset path to the cursor for this mode - */ - final private static String assetPath = "Textures/cursors/default.cur"; - // ************************************************************************* - // constructors - - /** - * Instantiate a disabled, uninitialized input mode. - */ - LoadMode() { - super("load"); - } - // ************************************************************************* - // InputMode methods - - /** - * Add default hotkey bindings. These bindings will be used if no custom - * bindings are found. - */ - @Override - protected void defaultBindings() { - bind(SimpleApplication.INPUT_MAPPING_EXIT, KeyInput.KEY_ESCAPE); - bind(Action.editBindings, KeyInput.KEY_F1); - bind(Action.editDisplaySettings, KeyInput.KEY_F2); - - bind(Action.previousScreen, KeyInput.KEY_PGUP, KeyInput.KEY_B); - bind(Action.nextScreen, KeyInput.KEY_PGDN, KeyInput.KEY_N); - - bindSignal(CameraInput.FLYCAM_BACKWARD, KeyInput.KEY_S); - bindSignal(CameraInput.FLYCAM_FORWARD, KeyInput.KEY_W); - bindSignal(CameraInput.FLYCAM_LOWER, KeyInput.KEY_Z); - bindSignal(CameraInput.FLYCAM_RISE, KeyInput.KEY_Q); - bindSignal("orbitLeft", KeyInput.KEY_A); - bindSignal("orbitRight", KeyInput.KEY_D); - - bind(Action.dumpPhysicsSpace, KeyInput.KEY_O); - bind(Action.dumpRenderer, KeyInput.KEY_P); - - bind(SimpleApplication.INPUT_MAPPING_CAMERA_POS, KeyInput.KEY_C); - bind(Action.toggleSkeleton, KeyInput.KEY_V); - } - - /** - * Initialize this (disabled) mode prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - // Configure the mouse cursor for this mode. - AssetManager manager = application.getAssetManager(); - JmeCursor cursor = (JmeCursor) manager.loadAsset(assetPath); - setCursor(cursor); - - super.initialize(stateManager, application); - } - - /** - * Process an action from the keyboard or mouse. - * - * @param actionString textual description of the action (not null) - * @param ongoing true if the action is ongoing, otherwise false - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void onAction(String actionString, boolean ongoing, float tpf) { - Validate.nonNull(actionString, "action string"); - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "Got action {0} ongoing={1}", - new Object[]{MyString.quote(actionString), ongoing}); - } - - boolean handled = false; - if (ongoing) { - Model model = DacWizard.getModel(); - handled = true; - switch (actionString) { - case Action.load: - model.load(); - break; - - case Action.morePath: - model.morePath(); - break; - - case Action.moreRoot: - model.moreRoot(); - break; - - case Action.nextAnimation: - model.nextAnimation(); - break; - - case Action.nextScreen: - nextScreen(); - break; - - case Action.previousAnimation: - model.previousAnimation(); - break; - - case Action.previousScreen: - model.unload(); - previousScreen(); - break; - - case Action.setAnimationTime: - setAnimationTime(); - break; - - case Action.toggleSkeleton: - model.toggleShowingSkeleton(); - break; - - default: - handled = false; - } - - String prefix = Action.setAnimationTime + " "; - if (!handled && actionString.startsWith(prefix)) { - String argument = MyString.remainder(actionString, prefix); - float time = Float.parseFloat(argument); - model.setAnimationTime(time); - handled = true; - } - } - - if (!handled) { - getActionApplication().onAction(actionString, ongoing, tpf); - } - } - // ************************************************************************* - // private methods - - /** - * Proceed to the "bones" screen if possible. - */ - private void nextScreen() { - String feedback = LoadScreen.feedback(); - if (feedback.isEmpty()) { - setEnabled(false); - InputMode bones = InputMode.findMode("bones"); - bones.setEnabled(true); - } - } - - /** - * Go back to the "filePath" screen. - */ - private void previousScreen() { - setEnabled(false); - InputMode filePath = InputMode.findMode("filePath"); - filePath.setEnabled(true); - } - - /** - * Process a "set animationTime" action: display a dialog to enter a new - * animation time. - */ - private static void setAnimationTime() { - Model model = DacWizard.getModel(); - float duration = model.animationDuration(); - DialogController controller - = new FloatDialog("Set", 0f, duration, AllowNull.No); - - float oldTime = model.animationTime(); - String defaultText = Float.toString(oldTime); - - LoadScreen screen = DacWizard.findAppState(LoadScreen.class); - screen.closeAllPopups(); - screen.showTextEntryDialog("Enter the animation time (in seconds):", - defaultText, Action.setAnimationTime + " ", controller); - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/LoadScreen.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/LoadScreen.java deleted file mode 100644 index f122533cf..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/LoadScreen.java +++ /dev/null @@ -1,325 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.animation.Skeleton; -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.scene.Spatial; -import de.lessvoid.nifty.controls.Button; -import de.lessvoid.nifty.elements.Element; -import java.util.logging.Logger; -import jme3utilities.Heart; -import jme3utilities.InitialState; -import jme3utilities.MyString; -import jme3utilities.debug.SkeletonVisualizer; -import jme3utilities.nifty.GuiScreenController; -import jme3utilities.ui.InputMode; - -/** - * The screen controller for the "load" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class LoadScreen extends GuiScreenController { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(LoadScreen.class.getName()); - // ************************************************************************* - // fields - - /** - * element of the GUI button to proceed to the "bones" screen - */ - private Element nextElement; - /** - * animation time of the pose being viewed (in seconds) - */ - private float viewedAnimationTime; - /** - * root spatial of the C-G model being viewed, or null for none - */ - private Spatial viewedSpatial; - /** - * clip/animation name of the pose being viewed - */ - private String viewedAnimationName; - // ************************************************************************* - // constructors - - /** - * Instantiate an uninitialized, disabled screen that will not be enabled - * during initialization. - */ - LoadScreen() { - super("load", "Interface/Nifty/screens/wizard/load.xml", - InitialState.Disabled); - } - // ************************************************************************* - // new methods exposed - - /** - * Determine user feedback (if any) regarding the "next screen" action. - * - * @return an empty string if ready to proceed, otherwise an explanatory - * message - */ - static String feedback() { - Model model = DacWizard.getModel(); - int numDacs = model.countDacs(); - int numSkeletonControls = model.countSControls(); - Spatial nextSpatial = model.getRootSpatial(); - String loadException = model.loadExceptionString(); - - String result; - if (!loadException.isEmpty()) { - result = loadException; - } else if (nextSpatial == null) { - result = "The model hasn't been loaded yet."; - } else if (numSkeletonControls == 0) { - result = "The model lacks a skinning/skeleton control."; - } else if (numSkeletonControls > 1) { - result = String.format( - "The model has %d skinning/skeleton controls.", - numSkeletonControls); - - } else if (model.countBones() < 1) { - if (model.findSkeleton() == null) { // new animation system - result = "The model's Armature lacks joints."; - } else { // old animation system - result = "The model's Skeleton lacks bones."; - } - - } else if (numDacs > 1) { - result = String.format("The model has %d DACs.", numDacs); - } else { - result = model.validationFeedback(); - } - - return result; - } - // ************************************************************************* - // GuiScreenController methods - - /** - * Initialize this (disabled) screen prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - super.initialize(stateManager, application); - - InputMode inputMode = InputMode.findMode("load"); - assert inputMode != null; - setListener(inputMode); - inputMode.influence(this); - } - - /** - * A callback from Nifty, invoked each time this screen starts up. - */ - @Override - public void onStartScreen() { - super.onStartScreen(); - - Button nextButton = getButton("next"); - if (nextButton == null) { - throw new RuntimeException("missing GUI control: nextButton"); - } - this.nextElement = nextButton.getElement(); - - DacWizard wizard = DacWizard.getApplication(); - wizard.clearScene(); - this.viewedSpatial = null; - this.viewedAnimationName = null; - this.viewedAnimationTime = Float.NaN; - - Model model = DacWizard.getModel(); - model.setShowingMeshes(true); - } - - /** - * Update this ScreenController prior to rendering. (Invoked once per - * frame.) - * - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void update(float tpf) { - super.update(tpf); - - if (!hasStarted()) { - return; - } - - updateFeedback(); - updatePath(); - updateToggleButton(); - - // Update the 3-D scene. - Model model = DacWizard.getModel(); - Spatial nextSpatial = model.getRootSpatial(); - String nextAnimationName = model.animationName(); - float nextAnimationTime = model.animationTime(); - if (nextSpatial != viewedSpatial - || !nextAnimationName.equals(viewedAnimationName) - || nextAnimationTime != viewedAnimationTime) { - DacWizard wizard = DacWizard.getApplication(); - wizard.clearScene(); - - this.viewedSpatial = nextSpatial; - this.viewedAnimationName = nextAnimationName; - this.viewedAnimationTime = nextAnimationTime; - - if (nextSpatial != null) { - Spatial cgModel = Heart.deepCopy(nextSpatial); - wizard.makeScene(cgModel, nextAnimationName, nextAnimationTime); - } - } - - updatePosingControls(); - } - // ************************************************************************* - // private methods - - /** - * Update the feedback line and the load/next buttons. - */ - private void updateFeedback() { - Model model = DacWizard.getModel(); - Spatial nextSpatial = model.getRootSpatial(); - String loadException = model.loadExceptionString(); - - String loadButton = ""; - if (loadException.isEmpty() && nextSpatial == null) { - loadButton = "Load and preview"; - } - setButtonText("load", loadButton); - - String feedback = feedback(); - setStatusText("feedback", feedback); - if (feedback.isEmpty()) { - nextElement.show(); - } else { - nextElement.hide(); - } - } - - /** - * Update the posing controls. - */ - private void updatePosingControls() { - String anText = ""; - String atText = ""; - String naText = ""; - String paText = ""; - - if (viewedSpatial != null) { - Model model = DacWizard.getModel(); - int numAnimations = model.countAnimations(); - if (numAnimations > 0) { - paText = "-"; - naText = "+"; - } - - float duration = model.animationDuration(); - if (duration > 0f) { - atText = Float.toString(viewedAnimationTime) + " seconds"; - } - - anText = viewedAnimationName; - if (!anText.equals(DacWizard.bindPoseName)) { - anText = MyString.quote(anText); - } - } - - setStatusText("animationName", anText); - setButtonText("animationTime", atText); - setButtonText("nextAnimation", naText); - setButtonText("previousAnimation", paText); - } - - /** - * Update the path status and "+" buttons. - */ - private void updatePath() { - Model model = DacWizard.getModel(); - - String assetPath = model.assetPath(); - String assetRoot = model.assetRoot(); - String[] pathComponents = assetPath.split("/"); - String[] rootComponents = assetRoot.split("/"); - - String morePathButton = ""; - String moreRootButton = ""; - if (pathComponents.length > 2) { - moreRootButton = "+"; - } - if (rootComponents.length > 1) { - morePathButton = "+"; - } - - setButtonText("morePath", morePathButton); - setButtonText("moreRoot", moreRootButton); - - setStatusText("assetPath", " " + assetPath); - setStatusText("assetRoot", " " + assetRoot); - } - - /** - * Update the button to toggle skeleton visualization. - */ - private void updateToggleButton() { - String buttonText = ""; - - DacWizard app = DacWizard.getApplication(); - SkeletonVisualizer sv = app.findSkeletonVisualizer(); - Model model = DacWizard.getModel(); - Spatial root = model.getRootSpatial(); - if (sv != null && root != null) { - boolean isShown = model.isShowingSkeleton(); - sv.setEnabled(isShown); - - Skeleton skeleton = model.findSkeleton(); - String armature = (skeleton == null) ? "armature" : "skeleton"; - if (isShown) { - buttonText = "Hide " + armature; - } else { - buttonText = "Show " + armature; - } - } - - setButtonText("skeleton", buttonText); - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/Model.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/Model.java deleted file mode 100644 index d14ae0185..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/Model.java +++ /dev/null @@ -1,1405 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.anim.AnimClip; -import com.jme3.anim.AnimComposer; -import com.jme3.anim.Armature; -import com.jme3.anim.Joint; -import com.jme3.anim.SkinningControl; -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.jme3.animation.Bone; -import com.jme3.animation.Skeleton; -import com.jme3.animation.SkeletonControl; -import com.jme3.asset.AssetManager; -import com.jme3.bullet.animation.CenterHeuristic; -import com.jme3.bullet.animation.DacConfiguration; -import com.jme3.bullet.animation.DynamicAnimControl; -import com.jme3.bullet.animation.LinkConfig; -import com.jme3.bullet.animation.MassHeuristic; -import com.jme3.bullet.animation.RagUtils; -import com.jme3.bullet.animation.RangeOfMotion; -import com.jme3.bullet.animation.ShapeHeuristic; -import com.jme3.math.Vector3f; -import com.jme3.scene.Mesh; -import com.jme3.scene.Spatial; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.FutureTask; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3utilities.Heart; -import jme3utilities.InfluenceUtil; -import jme3utilities.MyAnimation; -import jme3utilities.MySkeleton; -import jme3utilities.MySpatial; -import jme3utilities.MyString; -import jme3utilities.math.VectorSet; -import jme3utilities.ui.InputMode; -import jme3utilities.ui.Locators; - -/** - * The state information (MVC model) in the DacWizard application. - * - * @author Stephen Gold sgold@sonic.net - */ -class Model { - // ************************************************************************* - // constants and loggers - - /** - * magic clip/animation index used to denote bind pose - */ - final private static int bindPoseIndex = -1; - /** - * message logger for this class - */ - final static Logger logger - = Logger.getLogger(Model.class.getName()); - // ************************************************************************* - // fields - - /** - * mode for displaying angles - */ - private AngleMode angleMode = AngleMode.Degrees; - /** - * bones that influence the Mesh in any way - */ - private BitSet anyInfluenceBones; - /** - * bones that directly influence the Mesh - */ - private BitSet directInfluenceBones; - /** - * bones that will be linked - */ - private BitSet linkedBones; - /** - * whether to visualize PhysicsJoint axes in the TestScreen - */ - private boolean isShowingAxes = false; - /** - * whether to render model meshes in the TestScreen - */ - private boolean isShowingMeshes = true; - /** - * whether to visualize the skeleton/armature - */ - private boolean isShowingSkeleton = true; - /** - * PhysicsControl that will be added to the C-G model - */ - private DynamicAnimControl ragdoll; - /** - * Exception that occurred during load - */ - private Exception loadException; - /** - * animation time for the selected pose (in seconds, ≥0) - */ - private float animationTime = 0f; - /** - * task for estimating ranges of motion - */ - private FutureTask romTask; - /** - * index of the selected clip/animation, or {@link #bindPoseIndex} for bind - * pose - */ - private int animationIndex = bindPoseIndex; - /** - * index of the torso's main bone, or -1 for the default - */ - private int mainBoneIndex; - /** - * number of components in the filesystem path to the asset root - */ - private int numComponentsInRoot; - /** - * list of all clip/animation names in the loaded C-G model - */ - final private List animationNames = new ArrayList<>(32); - /** - * map manager names to sets of vertices - */ - private Map coordsMap; - /** - * callable for estimating ranges of motion - */ - private RomCallable romCallable; - /** - * root spatial of the loaded C-G model - */ - private Spatial rootSpatial; - /** - * bone/torso name of the selected PhysicsLink - */ - private String selectedLink; - /** - * components of the filesystem path to the C-G model (not null) - */ - private String[] filePathComponents = new String[0]; - // ************************************************************************* - // new methods exposed - - /** - * Return the mode for displaying angles. - * - * @return an enum value (not null) - */ - AngleMode angleMode() { - assert angleMode != null; - return angleMode; - } - - /** - * Return the duration of the selected clip/animation. - * - * @return the duration (in seconds, ≥0) - */ - float animationDuration() { - float result; - if (animationIndex == bindPoseIndex) { - result = 0f; - - } else { - result = Float.NaN; - String name = animationNames.get(animationIndex); - int skipNames = animationIndex; - - List animControls = MySpatial.listControls( - rootSpatial, AnimControl.class, null); - for (AnimControl animControl : animControls) { - Collection names = animControl.getAnimationNames(); - if (skipNames < names.size()) { - Animation animation = animControl.getAnim(name); - result = animation.getLength(); - break; - } else { - skipNames -= names.size(); - } - } - - List composers = MySpatial.listControls( - rootSpatial, AnimComposer.class, null); - for (AnimComposer composer : composers) { - Collection names = composer.getAnimClipsNames(); - if (skipNames < names.size()) { - AnimClip animClip = composer.getAnimClip(name); - result = (float) animClip.getLength(); - break; - } else { - skipNames -= names.size(); - } - } - - if (Float.isNaN(result)) { - throw new RuntimeException( - "clip/animation not found: " + MyString.quote(name)); - } - } - - assert result >= 0f : result; - return result; - } - - /** - * Return the clip/animation name for the selected pose. - * - * @return the name of the clip/animation or {@code bindPoseName} for bind - * pose (not null) - */ - String animationName() { - String result; - if (animationIndex == bindPoseIndex) { - result = DacWizard.bindPoseName; - } else { - result = animationNames.get(animationIndex); - } - - assert result != null; - return result; - } - - /** - * Return the animation time for the selected pose. - * - * @return the animation time (in seconds, ≥0) - */ - float animationTime() { - assert animationTime >= 0f : animationTime; - return animationTime; - } - - /** - * Determine the asset path to the J3O/glTF asset. The filesystem path must - * be set. - * - * @return the path (not null, not empty) - */ - String assetPath() { - int numComponents = filePathComponents.length; - if (numComponents == 0) { - throw new RuntimeException("Filesystem path not set."); - } - assert numComponentsInRoot < numComponents : numComponents; - String[] resultComponents = Arrays.copyOfRange( - filePathComponents, numComponentsInRoot, numComponents); - String result = String.join("/", resultComponents); - result = "/" + result; - - return result; - } - - /** - * Determine the filesystem path to the asset root. The filesystem path must - * be set. - * - * @return the path (not null, not empty) - */ - String assetRoot() { - int numComponents = filePathComponents.length; - if (numComponents == 0) { - throw new RuntimeException("Filesystem path not set."); - } - assert numComponentsInRoot < numComponents : numComponents; - String[] resultComponents = Arrays.copyOfRange( - filePathComponents, 0, numComponentsInRoot); - String result = String.join("/", resultComponents); - result += "/"; - - assert result != null; - assert !result.isEmpty(); - return result; - } - - /** - * Return the name of the indexed bone. A C-G model must be loaded. - * - * @param boneIndex which bone (≥0) - * @return the name (may be null) - */ - String boneName(int boneIndex) { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - String result; - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - Joint joint = armature.getJoint(boneIndex); - result = joint.getName(); - - } else { // old animation system - Bone bone = skeleton.getBone(boneIndex); - result = bone.getName(); - } - - return result; - } - - /** - * Return the configuration of the named bone/torso link. - * - * @param boneName the name of the bone/torso (not null) - * @return the pre-existing configuration (not null) - */ - LinkConfig config(String boneName) { - LinkConfig result = ragdoll.config(boneName); - return result; - } - - /** - * Copy the configured DynamicAnimControl. - * - * @return a new Control, or null if no model loaded - */ - DynamicAnimControl copyRagdoll() { - DynamicAnimControl clone = Heart.deepCopy(ragdoll); - return clone; - } - - /** - * Count how many clip/animations are in the loaded C-G model. - * - * @return the count (≥0) - */ - int countAnimations() { - int result = animationNames.size(); - return result; - } - - /** - * Count how many bones are in the skeleton. A C-G model must be loaded. - * - * @return the count (≥0) - */ - int countBones() { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - int count = 0; - Skeleton skeleton = findSkeleton(); - if (skeleton != null) { // old animation system - count = skeleton.getBoneCount(); - } else { // new animation system - Armature armature = findArmature(); - if (armature != null) { - count = armature.getJointCount(); - } - } - - assert count >= 0 : count; - return count; - } - - /** - * Count how many dynamic anim controls are in the model. - * - * @return the count (≥0) or 0 if no model loaded - */ - int countDacs() { - int count = MySpatial.countControls( - rootSpatial, DynamicAnimControl.class); - - assert count >= 0 : count; - return count; - } - - /** - * Count how many bones are managed by the specified bone/torso link. A C-G - * model must be loaded. - * - * @param managerName the bone/torso name of the manager (not null) - * @return the count (≥0) - */ - int countManagedBones(String managerName) { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - int count = 0; - - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - int numJoints = armature.getJointCount(); - for (int boneIndex = 0; boneIndex < numJoints; ++boneIndex) { - Joint joint = armature.getJoint(boneIndex); - String name = findManager(joint); - if (managerName.equals(name)) { - ++count; - } - } - - } else { // old animation system - int numBones = skeleton.getBoneCount(); - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - Bone bone = skeleton.getBone(boneIndex); - String name = findManager(bone, skeleton); - if (managerName.equals(name)) { - ++count; - } - } - } - - assert count >= 0 : count; - return count; - } - - /** - * Count how many skeleton/skinning controls are in the model. - * - * @return the count (≥0) or 0 if no model loaded - */ - int countSControls() { - int count = MySpatial.countControls(rootSpatial, SkeletonControl.class); - count += MySpatial.countControls(rootSpatial, SkinningControl.class); - - assert count >= 0 : count; - return count; - } - - /** - * Count how many tracks in the C-G model use the indexed bone. A C-G model - * must be loaded. - * - * @param boneIndex which bone (≥0) - * @return the count (≥0) - */ - int countTracks(int boneIndex) { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - int count = 0; - - List composers - = MySpatial.listControls(rootSpatial, AnimComposer.class, null); - for (AnimComposer composer : composers) { - Collection clipNames = composer.getAnimClipsNames(); - for (String clipName : clipNames) { - AnimClip clip = composer.getAnimClip(clipName); - if (MyAnimation.findTransformTrack(clip, boneIndex) != null) { - ++count; - } - } - } - - List animControls - = MySpatial.listControls(rootSpatial, AnimControl.class, null); - for (AnimControl animControl : animControls) { - Collection names = animControl.getAnimationNames(); - for (String animName : names) { - Animation animation = animControl.getAnim(animName); - if (MyAnimation.hasTrackForBone(animation, boneIndex)) { - ++count; - } - } - } - - return count; - } - - /** - * Count how many vertices would be assigned to the named bone/torso. - * - * @param boneName (not null) - * @return the count (≥0) - */ - int countVertices(String boneName) { - int count; - VectorSet vertices = coordsMap.get(boneName); - if (vertices == null) { - count = 0; - } else { - count = vertices.numVectors(); - } - - return count; - } - - /** - * Describe the influence of the indexed bone in the loaded C-G model. - * - * @param boneIndex which bone (≥0) - * @return descriptive text (not null, not empty) - */ - String describeBoneInfluence(int boneIndex) { - String result; - if (directInfluenceBones.get(boneIndex)) { - result = "has direct mesh influence"; - } else if (anyInfluenceBones.get(boneIndex)) { - result = "mesh influence (indirect only)"; - } else { - result = "NO mesh influence"; - } - - return result; - } - - /** - * Return the filesystem path to the J3O/glTF file. - * - * @return the path (not null, may be empty) - */ - String filePath() { - String result = String.join("/", filePathComponents); - assert result != null; - return result; - } - - /** - * Access the model's Skeleton, assuming it has no more than one. A C-G - * model must be loaded. - * - * @return the pre-existing instance, or null if none or multiple - */ - Skeleton findSkeleton() { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - List list = MySkeleton.listSkeletons(rootSpatial, null); - - Skeleton result = null; - if (list.size() == 1) { - result = list.get(0); - } - - return result; - } - - /** - * Access the root spatial of the loaded C-G model. - * - * @return the pre-existing Spatial, or null if no model loaded - */ - Spatial getRootSpatial() { - return rootSpatial; - } - - /** - * Test whether there's a pre-existing DynamicAnimControl with the exact - * same set of linked bones. - * - * @return true if a matching Control exists, otherwise false - */ - boolean hasConfiguredRagdoll() { - if (ragdoll == null) { - return false; - } - - int numBones = countBones(); - boolean result = true; - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - String name = boneName(boneIndex); - boolean isLinked = ragdoll.hasBoneLink(name); - if (isLinked != linkedBones.get(boneIndex)) { - result = false; - break; - } - } - - return result; - } - - /** - * Test whether the indexed bone will be linked. - * - * @param boneIndex which bone (≥0) - * @return true if linked, otherwise false - */ - boolean isBoneLinked(int boneIndex) { - boolean result = linkedBones.get(boneIndex); - return result; - } - - /** - * Test whether the PhysicsJoint axes will be visualized. - * - * @return true if visualized, otherwise false - */ - boolean isShowingAxes() { - return isShowingAxes; - } - - /** - * Test whether the model meshes will be rendered. - * - * @return true if rendered, otherwise false - */ - boolean isShowingMeshes() { - return isShowingMeshes; - } - - /** - * Test whether the skeleton/armature will be visualized. - * - * @return true if visualized, otherwise false - */ - boolean isShowingSkeleton() { - return isShowingSkeleton; - } - - /** - * Determine the parent (in the link hierarchy) of the named linked bone. A - * C-G model must be loaded. - * - * @param childName the bone name of the child (not null, not empty) - * @return the bone/torso name of the parent - */ - String linkedBoneParentName(String childName) { - assert childName != null; - assert !childName.isEmpty(); - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - String name; - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - Joint child = armature.getJoint(childName); - Joint parent = child.getParent(); - if (parent == null) { // the named Joint was a root joint - name = DacConfiguration.torsoName; - } else { - name = findManager(parent); - } - - } else { // old animation system - Bone child = skeleton.getBone(childName); - Bone parent = child.getParent(); - if (parent == null) { // the named Bone was a root bone - name = DacConfiguration.torsoName; - } else { - name = findManager(parent, skeleton); - } - } - - return name; - } - - /** - * Enumerate the indices of all bones that will be linked. A C-G model must - * be loaded. - * - * @return a new array of indices (not null) - */ - int[] listLinkedBones() { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - int numBones = countBones(); - int numLinkedBones = linkedBones.cardinality(); - int[] result = new int[numLinkedBones]; - int linkedBoneIndex = 0; - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - if (linkedBones.get(boneIndex)) { - result[linkedBoneIndex] = boneIndex; - ++linkedBoneIndex; - } - } - - return result; - } - - /** - * Enumerate the indices of all bones managed by the torso. A C-G model must - * be loaded. - * - * @return a new array of indices (not null) - */ - int[] listTorsoManagedBones() { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - int numManaged = countManagedBones(DacConfiguration.torsoName); - int[] result = new int[numManaged]; - - int managedIndex = 0; - int numBones = countBones(); - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - String managerName = findManager(boneIndex); - if (managerName.equals(DacConfiguration.torsoName)) { - result[managedIndex] = boneIndex; - ++managedIndex; - } - } - - return result; - } - - /** - * Attempt to load a C-G model. The filesystem path must have been - * previously set. If successful, rootSpatial, animNames, ragdoll, - * mainBoneIndex, and linkedBones are initialized. Otherwise, - * {@code rootSpatial==null} and loadException is set. - */ - void load() { - int numComponents = filePathComponents.length; - if (numComponents == 0) { - throw new RuntimeException("Filesystem path not set."); - } - - unload(); - String assetRoot = assetRoot(); - String assetPath = assetPath(); - - Locators.save(); - Locators.unregisterAll(); - Locators.registerFilesystem(assetRoot); - Locators.registerDefault(); - AssetManager assetManager = Locators.getAssetManager(); - assetManager.clearCache(); - try { - this.rootSpatial = assetManager.loadModel(assetPath); - this.loadException = null; - } catch (RuntimeException exception) { - this.rootSpatial = null; - this.loadException = exception; - } - Locators.restore(); - - animationNames.clear(); - if (rootSpatial != null) { - this.ragdoll = removeDac(); - recalculateInfluence(); - updateAnimationNames(); - - int mbIndex = -1; - if (ragdoll != null) { - String mbName = ragdoll.mainBoneName(); - mbIndex = findBoneIndex(mbName); - } - setMainBoneIndex(mbIndex); - - int numBones = countBones(); - BitSet bitset = new BitSet(numBones); // empty set - if (ragdoll != null) { - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - String name = boneName(boneIndex); - if (ragdoll.hasBoneLink(name)) { - bitset.set(boneIndex); - } - } - } - setLinkedBones(bitset); - } - } - - /** - * Return the exception that occurred during the most recent load attempt. - * - * @return the exception message, or "" if none - */ - String loadExceptionString() { - String result = ""; - if (loadException != null) { - result = loadException.toString(); - } - - return result; - } - - /** - * Return the index of the torso's main bone. - * - * @return the bone index (≥0) - */ - int mainBoneIndex() { - int result = mainBoneIndex; - if (mainBoneIndex == -1) { - List targetList = RagUtils.listDacMeshes(rootSpatial, null); - Mesh[] meshes = new Mesh[targetList.size()]; - targetList.toArray(meshes); - - Skeleton skeleton = findSkeleton(); - if (skeleton != null) { // old animation system - Bone bone = RagUtils.findMainBone(skeleton, meshes); - result = skeleton.getBoneIndex(bone); - - } else { // new animation system - Armature armature = findArmature(); - Joint armatureJoint = RagUtils.findMainJoint(armature, meshes); - result = armatureJoint.getId(); - } - } - - assert result >= 0 : result; - return result; - } - - /** - * Shift one component of the filesystem path from the asset root to the - * asset path. - */ - void morePath() { - unload(); - --numComponentsInRoot; - } - - /** - * Shift one component of the filesystem path from the asset path to the - * asset root. - */ - void moreRoot() { - unload(); - ++numComponentsInRoot; - } - - /** - * Select the next clip/animation in the loaded C-G model. - */ - void nextAnimation() { - int numAnimations = countAnimations(); - if (animationIndex < numAnimations - 1) { - ++animationIndex; - } else { - this.animationIndex = bindPoseIndex; - } - - this.animationTime = 0f; - } - - /** - * Determine the index of the parent of the indexed bone. - * - * @param boneIndex which bone (≥0) - * @return the index of the parent (≥0) or -1 for a root bone - */ - int parentIndex(int boneIndex) { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - int result; - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - Joint joint = armature.getJoint(boneIndex); - Joint parent = joint.getParent(); - - if (parent == null) { - result = -1; - } else { - result = parent.getId(); - } - - } else { // old animation system - Bone bone = skeleton.getBone(boneIndex); - Bone parent = bone.getParent(); - - if (parent == null) { - result = -1; - } else { - result = skeleton.getBoneIndex(parent); - } - } - - return result; - } - - /** - * If the range-of-motion task is done, instantiate the DynamicAnimControl - * and proceed to the "links" screen. - */ - void pollForTaskCompletion() { - if (romTask == null || !romTask.isDone()) { - return; - } - logger.log(Level.INFO, "The range-of-motion task is done."); - - RangeOfMotion[] roms; - try { - roms = romTask.get(); - } catch (ExecutionException | InterruptedException exception) { - System.out.print(exception); - return; - } - this.romCallable.cleanup(); - this.romTask = null; - - this.ragdoll = new DynamicAnimControl(); - float massParameter = 1f; - LinkConfig linkConfig = new LinkConfig( - massParameter, MassHeuristic.Density, ShapeHeuristic.VertexHull, - new Vector3f(1f, 1f, 1f), CenterHeuristic.Mean); - - ragdoll.setConfig(DacConfiguration.torsoName, linkConfig); - - int mbIndex = mainBoneIndex(); - String mbName = boneName(mbIndex); - ragdoll.setMainBoneName(mbName); - - int numBones = countBones(); - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - if (linkedBones.get(boneIndex)) { - String boneName = boneName(boneIndex); - ragdoll.link(boneName, linkConfig, roms[boneIndex]); - } - } - - selectLink(DacConfiguration.torsoName); - InputMode links = InputMode.findMode("links"); - links.setEnabled(true); - } - - /** - * Select the previous clip/animation in the loaded C-G model. - */ - void previousAnimation() { - int numAnimations = countAnimations(); - if (animationIndex == bindPoseIndex) { - this.animationIndex = numAnimations - 1; - } else { - --animationIndex; - } - - this.animationTime = 0f; - } - - /** - * Access the joint limits of the named BoneLink. - * - * @param boneName the name of the bone (not null, not empty) - * @return the pre-existing limits (not null) - */ - RangeOfMotion rom(String boneName) { - assert boneName != null; - assert !boneName.isEmpty(); - - RangeOfMotion result = ragdoll.getJointLimits(boneName); - return result; - } - - /** - * Determine which physics link is selected. - * - * @return the bone/torso name of the link, or null if no selection - */ - String selectedLink() { - return selectedLink; - } - - /** - * Select the named physics link. - * - * @param boneName the bone/torso name of the desired link (not null) - */ - void selectLink(String boneName) { - assert boneName != null; - this.selectedLink = boneName; - } - - /** - * Alter the animation time for the selected pose. - * - * @param time the desired animation time (≥0, ≤duration) - */ - void setAnimationTime(float time) { - assert time >= 0f : time; - assert time <= animationDuration() : time; - - this.animationTime = time; - } - - /** - * Reconfigure the named bone/torso. - * - * @param boneName the name of the bone, or torsoName (not null) - * @param config the desired configuration (not null) - */ - void setConfig(String boneName, LinkConfig config) { - assert boneName != null; - assert config != null; - - ragdoll.setConfig(boneName, config); - } - - /** - * Alter the model's filesystem path. - * - * @param path the desired filesystem path (not null, contains a "/") - */ - void setFilePath(String path) { - assert path != null; - assert path.contains("/"); - - this.filePathComponents = path.split("/"); - this.numComponentsInRoot = 1; - this.loadException = null; - unload(); - /* - * Use heuristics to guess how many components there are - * in the filesystem path to the asset root. - */ - int numComponents = filePathComponents.length; - assert numComponents > 0 : numComponents; - for (int componentI = 0; componentI < numComponents; ++componentI) { - String component = filePathComponents[componentI]; - switch (component) { - case "assets": - case "resources": - case "Written Assets": - if (componentI > 1) { - numComponentsInRoot = componentI - 1; - } - break; - case "Models": - if (componentI > 0 && componentI < numComponents) { - numComponentsInRoot = componentI; - } - break; - default: - } - } - } - - /** - * Alter which bones will be linked. A C-G model must be loaded. - * - * @param linkedBones the desired set of linked bones (not null) - */ - void setLinkedBones(BitSet linkedBones) { - assert linkedBones != null; - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - if (!linkedBones.equals(this.linkedBones)) { - this.linkedBones = linkedBones; - int numBones = countBones(); - String[] managerMap = new String[numBones]; - - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - for (int jointIndex = 0; jointIndex < numBones; ++jointIndex) { - Joint joint = armature.getJoint(jointIndex); - managerMap[jointIndex] = findManager(joint); - } - - } else { // old animation system - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - Bone bone = skeleton.getBone(boneIndex); - managerMap[boneIndex] = findManager(bone, skeleton); - } - } - - List targetList = RagUtils.listDacMeshes(rootSpatial, null); - Mesh[] targets = new Mesh[targetList.size()]; - targetList.toArray(targets); - - // Enumerate mesh-vertex coordinates and assign them to managers. - this.coordsMap = RagUtils.coordsMap(targets, managerMap); - } - } - - /** - * Alter the index for the main bone in the torso. - * - * @param desiredIndex the desired index (≥0) or -1 to use the default - */ - void setMainBoneIndex(int desiredIndex) { - assert desiredIndex >= -1 : desiredIndex; - this.mainBoneIndex = desiredIndex; - } - - /** - * Replace the RangeOfMotion of the named BoneLink. - * - * @param boneName the name of the bone (not null, not empty) - * @param rom the desired RangeOfMotion (not null) - */ - void setRom(String boneName, RangeOfMotion rom) { - assert boneName != null; - assert !boneName.isEmpty(); - assert rom != null; - - ragdoll.setJointLimits(boneName, rom); - } - - /** - * Alter whether model meshes will be rendered. - * - * @param setting true to render meshes, false to hide them - */ - void setShowingMeshes(boolean setting) { - this.isShowingMeshes = setting; - } - - /** - * Start a thread to estimate the range of motion for each linked bone. - */ - void startRomTask() { - this.romCallable = new RomCallable(this); - assert romTask == null; - this.romTask = new FutureTask<>(romCallable); - Thread romThread = new Thread(romTask); - romThread.start(); - } - - /** - * Toggle the mode for displaying angles. - */ - void toggleAngleMode() { - switch (angleMode) { - case Degrees: - this.angleMode = AngleMode.Radians; - break; - case Radians: - this.angleMode = AngleMode.Degrees; - break; - default: - throw new IllegalStateException("angleMode = " + angleMode); - } - } - - /** - * Toggle the visibility of PhysicsJoint axes in TestScreen. - */ - void toggleShowingAxes() { - this.isShowingAxes = !isShowingAxes; - } - - /** - * Toggle the visibility of the skeleton. - */ - void toggleShowingSkeleton() { - this.isShowingSkeleton = !isShowingSkeleton; - } - - /** - * Unload the loaded C-G model, if any. - */ - void unload() { - this.animationIndex = bindPoseIndex; - animationNames.clear(); - this.animationTime = 0f; - this.mainBoneIndex = -1; - this.rootSpatial = null; - this.ragdoll = null; - } - - /** - * Validate the loaded C-G model for use with DynamicAnimControl. - * - * @return a feedback message (not null, not empty) or an empty string if - * none - */ - String validationFeedback() { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - String result = ""; - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - try { - RagUtils.validate(rootSpatial); - RagUtils.validate(armature); - } catch (IllegalArgumentException exception) { - result = exception.getMessage(); - } - - } else { // old animation system - try { - RagUtils.validate(rootSpatial); - RagUtils.validate(skeleton); - } catch (IllegalArgumentException exception) { - result = exception.getMessage(); - } - } - - return result; - } - // ************************************************************************* - // private methods - - /** - * Access the model's Armature, assuming it doesn't have more than one - * SkinningControl. A C-G model must be loaded. - * - * @return the pre-existing instance, or null if none or multiple - */ - private Armature findArmature() { - if (rootSpatial == null) { - throw new RuntimeException("No model loaded."); - } - - List skinners = MySpatial.listControls( - rootSpatial, SkinningControl.class, null); - - Armature result = null; - if (skinners.size() == 1) { - SkinningControl control = skinners.get(0); - result = control.getArmature(); - } - - return result; - } - - /** - * Return the index of the named bone. A C-G model must be loaded. - * - * @param boneName the name of the bone to find - * @return the index (≥0) or -1 if not found - */ - private int findBoneIndex(String boneName) { - int result; - - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - result = armature.getJointIndex(boneName); - - } else { // old animation system - result = skeleton.getBoneIndex(boneName); - } - - return result; - } - - /** - * Find the manager of the indexed bone. - * - * @param startBoneIndex the index of the bone to analyze (≥0) - * @return the bone/torso name (not null) - */ - private String findManager(int startBoneIndex) { - String result; - - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - Joint startJoint = armature.getJoint(startBoneIndex); - result = findManager(startJoint); - - } else { // old animation system - Bone startBone = skeleton.getBone(startBoneIndex); - result = findManager(startBone, skeleton); - } - - return result; - } - - /** - * Find the link that manages the specified Bone. - * - * @param startBone which Bone to analyze (not null, unaffected) - * @param skeleton the Skeleton containing the Bone - * @return a bone/torso name (not null) - */ - private String findManager(Bone startBone, Skeleton skeleton) { - assert startBone != null; - - String managerName; - Bone bone = startBone; - while (true) { - int boneIndex = skeleton.getBoneIndex(bone); - if (linkedBones.get(boneIndex)) { - managerName = bone.getName(); - break; - } - bone = bone.getParent(); - if (bone == null) { - managerName = DacConfiguration.torsoName; - break; - } - } - - assert managerName != null; - return managerName; - } - - /** - * Find the link that manages the specified armature joint. - * - * @param startJoint which Joint to analyze (not null, unaffected) - * @return a bone/torso name (not null) - */ - private String findManager(Joint startJoint) { - assert startJoint != null; - - String managerName; - Joint joint = startJoint; - while (true) { - int jointIndex = joint.getId(); - if (linkedBones.get(jointIndex)) { - managerName = joint.getName(); - break; - } - joint = joint.getParent(); - if (joint == null) { - managerName = DacConfiguration.torsoName; - break; - } - } - - assert managerName != null; - return managerName; - } - - /** - * Recalculate the influence of each bone. - */ - private void recalculateInfluence() { - Skeleton skeleton = findSkeleton(); - if (skeleton == null) { // new animation system - Armature armature = findArmature(); - if (armature != null) { - this.anyInfluenceBones = InfluenceUtil.addAllInfluencers( - rootSpatial, armature); - armature.applyBindPose(); - } - } else { // old animation system - this.anyInfluenceBones = InfluenceUtil.addAllInfluencers( - rootSpatial, skeleton); - } - - int numBones = countBones(); - this.directInfluenceBones = new BitSet(numBones); - InfluenceUtil.addDirectInfluencers(rootSpatial, directInfluenceBones); - } - - /** - * Remove any DynamicAnimControl from the C-G model. - * - * @return the pre-existing control that was removed, or null if none - */ - private DynamicAnimControl removeDac() { - List list = MySpatial.listControls( - rootSpatial, DynamicAnimControl.class, null); - DynamicAnimControl result = null; - if (!list.isEmpty()) { - assert list.size() == 1 : list.size(); - result = list.get(0); - Spatial controlled = result.getSpatial(); - controlled.removeControl(result); - } - - return result; - } - - /** - * Update the list of all clips/animations in the loaded C-G model. - */ - private void updateAnimationNames() { - animationNames.clear(); - - List animControls - = MySpatial.listControls(rootSpatial, AnimControl.class, null); - for (AnimControl animControl : animControls) { - Collection names = animControl.getAnimationNames(); - animationNames.addAll(names); - } - - List composers - = MySpatial.listControls(rootSpatial, AnimComposer.class, null); - for (AnimComposer composer : composers) { - Collection names = composer.getAnimClipsNames(); - animationNames.addAll(names); - } - - this.animationIndex = bindPoseIndex; - this.animationTime = 0f; - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/RomCallable.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/RomCallable.java deleted file mode 100644 index cb843fa28..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/RomCallable.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - Copyright (c) 2019-2024 Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.anim.AnimClip; -import com.jme3.anim.AnimComposer; -import com.jme3.anim.Armature; -import com.jme3.anim.Joint; -import com.jme3.anim.SkinningControl; -import com.jme3.animation.AnimControl; -import com.jme3.animation.Animation; -import com.jme3.animation.Bone; -import com.jme3.animation.Skeleton; -import com.jme3.animation.SkeletonControl; -import com.jme3.bullet.BulletAppState; -import com.jme3.bullet.PhysicsSpace; -import com.jme3.bullet.PhysicsTickListener; -import com.jme3.bullet.animation.BoneLink; -import com.jme3.bullet.animation.DynamicAnimControl; -import com.jme3.bullet.animation.RagUtils; -import com.jme3.bullet.animation.RangeOfMotion; -import com.jme3.bullet.joints.PhysicsJoint; -import com.jme3.bullet.joints.SixDofJoint; -import com.jme3.bullet.objects.PhysicsRigidBody; -import com.jme3.math.FastMath; -import com.jme3.math.Vector3f; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.AbstractControl; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.logging.Logger; -import jme3utilities.Heart; -import jme3utilities.MySpatial; -import jme3utilities.math.MyVector3f; -import jme3utilities.math.noise.Generator; -import jme3utilities.wes.Pose; -import jme3utilities.wes.TweenTransforms; - -/** - * A Callable for asynchronously estimating the ranges of motion of the loaded - * C-G model, based on a pseudo-random sample its animations. - * - * @author Stephen Gold sgold@sonic.net - */ -class RomCallable implements Callable, PhysicsTickListener { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger - = Logger.getLogger(RomCallable.class.getName()); - // ************************************************************************* - // fields - - /** - * initial state of physics debug visualization - */ - final private boolean wasDebugEnabled; - /** - * temporary DynamicAnimationControl for use with the temporary model - */ - final private DynamicAnimControl tempDac; - /** - * pseudo-random generator for skeleton poses - */ - final private Generator generator = new Generator(); - /** - * information about the subject C-G model - */ - final private Model model; - /** - * root of the temporary C-G model - */ - final private Spatial tempModelRoot; - /** - * interpolation techniques used when calculating skeleton poses - */ - final private TweenTransforms techniques = new TweenTransforms(); - /** - * maximum angles seen for each rotational axis of each physics joint - */ - final private Vector3f[] maxima; - /** - * minimum angles seen for each rotational axis of each physics joint - */ - final private Vector3f[] minima; - // ************************************************************************* - // constructors - - /** - * Instantiate a callable to analyze the specified model. - * - * @param subjectModel the model to analyze (not null) - */ - RomCallable(Model subjectModel) { - this.model = subjectModel; - - // Initialize accumulators for maximum and minimum rotation angles. - int numBones = model.countBones(); - this.maxima = new Vector3f[numBones]; - this.minima = new Vector3f[numBones]; - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - if (model.isBoneLinked(boneIndex)) { - maxima[boneIndex] = new Vector3f(0f, 0f, 0f); - minima[boneIndex] = new Vector3f(0f, 0f, 0f); - } - } - - // Temporarily enable physics-debug visualization. - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - this.wasDebugEnabled = bulletAppState.isDebugEnabled(); - if (!wasDebugEnabled) { - bulletAppState.setDebugEnabled(true); - } - /* - * Create a temporary copy of the C-G model and attach it - * to the scene graph. - */ - Spatial cgModel = model.getRootSpatial(); - - DacWizard wizard = DacWizard.getApplication(); - wizard.clearScene(); - - this.tempModelRoot = Heart.deepCopy(cgModel); - String animationName = model.animationName(); - float animationTime = model.animationTime(); - wizard.makeScene(tempModelRoot, animationName, animationTime); - /* - * Add a DynamicAnimControl to the copy. Since the control will - * stay in kinematic mode, its masses and ranges of motion - * don't matter. - */ - float mass = 1f; - RangeOfMotion stiffRom = new RangeOfMotion(); - AbstractControl sControl = RagUtils.findSControl(tempModelRoot); - if (sControl instanceof SkinningControl) { // new animation system - Armature armature = ((SkinningControl) sControl).getArmature(); - this.tempDac = new DynamicAnimControl() { - @Override - public void update(float tpf) { - applyRandomPose(); - super.update(tpf); - } - }; - for (int jointIndex = 0; jointIndex < numBones; ++jointIndex) { - if (model.isBoneLinked(jointIndex)) { - Joint joint = armature.getJoint(jointIndex); - String boneName = joint.getName(); - tempDac.link(boneName, mass, stiffRom); - } - } - - } else { // old animation system - Skeleton skeleton = ((SkeletonControl) sControl).getSkeleton(); - this.tempDac = new DynamicAnimControl() { - @Override - public void update(float tpf) { - applyRandomPose(); - super.update(tpf); - } - }; - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - if (model.isBoneLinked(boneIndex)) { - Bone bone = skeleton.getBone(boneIndex); - String boneName = bone.getName(); - tempDac.link(boneName, mass, stiffRom); - } - } - } - - int mbIndex = model.mainBoneIndex(); - String mbName = model.boneName(mbIndex); - tempDac.setMainBoneName(mbName); - - Spatial controlledSpatial = sControl.getSpatial(); - controlledSpatial.addControl(tempDac); - - // Disable contact response for all rigid bodies in the ragdoll. - PhysicsRigidBody[] bodies = tempDac.listRigidBodies(); - for (PhysicsRigidBody body : bodies) { - body.setContactResponse(false); - } - - // Add the ragdoll to physics space. - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - assert physicsSpace.isEmpty(); - tempDac.setPhysicsSpace(physicsSpace); - physicsSpace.addTickListener(this); - } - // ************************************************************************* - // new methods exposed - - /** - * Clean up the scene graph and the physics. - */ - void cleanup() { - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - - tempModelRoot.removeFromParent(); - physicsSpace.removeTickListener(this); - tempDac.setPhysicsSpace(null); - assert physicsSpace.isEmpty(); - - if (!wasDebugEnabled) { - bulletAppState.setDebugEnabled(false); - } - } - // ************************************************************************* - // Callable methods - - /** - * Estimate the range of motion of each linked bone in the loaded C-G model. - * - * @return a new map from bone indices to ranges of motion - */ - @Override - public RangeOfMotion[] call() throws InterruptedException { - // Accumulate joint-angle statistics for 10 seconds. - Thread.sleep(10_000); - - // Convert the statistics into ranges of motion. - int numBones = model.countBones(); - RangeOfMotion[] roms = new RangeOfMotion[numBones]; - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - if (model.isBoneLinked(boneIndex)) { - Vector3f max = maxima[boneIndex]; - Vector3f min = minima[boneIndex]; - roms[boneIndex] = new RangeOfMotion( - max.x, min.x, max.y, min.y, max.z, min.z); - } - } - - return roms; - } - // ************************************************************************* - // PhysicsTickListener methods - - /** - * Callback from Bullet, invoked just after the simulation has been stepped. - * - * @param space the space that was just stepped (not null) - * @param timeStep the duration of the simulation step (in seconds, ≥0) - */ - @Override - public void physicsTick(PhysicsSpace space, float timeStep) { - // Read joint angles from the ragdoll and update statistics. - Vector3f angles = new Vector3f(); - int numBones = model.countBones(); - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - String boneName = model.boneName(boneIndex); - BoneLink link = tempDac.findBoneLink(boneName); - if (link != null) { - PhysicsJoint joint = link.getJoint(); - SixDofJoint sixDof = (SixDofJoint) joint; - sixDof.getAngles(angles); - assert angles.x >= -FastMath.PI : angles; - assert angles.x <= FastMath.PI : angles; - assert angles.y >= -FastMath.PI : angles; - assert angles.y <= FastMath.PI : angles; - assert angles.z >= -FastMath.PI : angles; - assert angles.z <= FastMath.PI : angles; - MyVector3f.accumulateMaxima(maxima[boneIndex], angles); - MyVector3f.accumulateMinima(minima[boneIndex], angles); - } - } - } - - /** - * Callback from Bullet, invoked just before the simulation is stepped. - * - * @param space the space that's about to be stepped (not null) - * @param timeStep the duration of the simulation step (in seconds, ≥0) - */ - @Override - public void prePhysicsTick(PhysicsSpace space, float timeStep) { - // do nothing - } - // ************************************************************************* - // private methods - - /** - * Apply a pseudo-random Pose to the Armature or Skeleton of the temporary - * C-G model. - */ - @SuppressWarnings("unchecked") - private void applyRandomPose() { - // Choose an AnimComposer or AnimControl. - List controls = MySpatial.listControls( - tempModelRoot, AnimControl.class, null); - MySpatial.listControls(tempModelRoot, AnimComposer.class, controls); - AbstractControl control = (AbstractControl) generator.pick(controls); - - if (control instanceof AnimControl) { - AnimControl animControl = (AnimControl) control; - - // Choose an Animation. - Collection nameCollection = animControl.getAnimationNames(); - int numAnimations = nameCollection.size(); - String[] nameArray = new String[numAnimations]; - nameCollection.toArray(nameArray); - String animationName = generator.pick(nameArray); - if (animationName == null) { - return; - } - Animation animation = animControl.getAnim(animationName); - - // Choose an animation time. - float duration = animation.getLength(); - float animationTime = generator.nextFloat(0f, duration); - - Skeleton skeleton = tempDac.getSkeleton(); - Pose pose = new Pose(skeleton); - pose.setToAnimation(animation, animationTime, techniques); - pose.applyTo(skeleton); - - } else if (control instanceof AnimComposer) { - AnimComposer composer = (AnimComposer) control; - - // Choose an AnimClip. - Collection clips = composer.getAnimClips(); - int numClips = clips.size(); - AnimClip[] clipArray = new AnimClip[numClips]; - clips.toArray(clipArray); - AnimClip clip = generator.pick(clipArray); - if (clip == null) { - return; - } - - // Choose an animation time. - double duration = clip.getLength(); - double animationTime = duration * generator.nextDouble(); - - Armature armature = tempDac.getArmature(); - Pose pose = new Pose(armature); - pose.setToClip(clip, animationTime); - pose.applyTo(armature); - } - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/TestMode.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/TestMode.java deleted file mode 100644 index b010c46b6..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/TestMode.java +++ /dev/null @@ -1,651 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.SimpleApplication; -import com.jme3.app.state.AppStateManager; -import com.jme3.asset.AssetManager; -import com.jme3.bullet.BulletAppState; -import com.jme3.bullet.PhysicsSpace; -import com.jme3.bullet.RotationOrder; -import com.jme3.bullet.animation.BoneLink; -import com.jme3.bullet.animation.DacConfiguration; -import com.jme3.bullet.animation.DacLinks; -import com.jme3.bullet.animation.DynamicAnimControl; -import com.jme3.bullet.animation.KinematicSubmode; -import com.jme3.bullet.animation.LinkConfig; -import com.jme3.bullet.animation.PhysicsLink; -import com.jme3.bullet.animation.RagUtils; -import com.jme3.bullet.animation.RangeOfMotion; -import com.jme3.bullet.animation.TorsoLink; -import com.jme3.bullet.collision.PhysicsCollisionObject; -import com.jme3.bullet.collision.PhysicsRayTestResult; -import com.jme3.bullet.collision.shapes.CollisionShape; -import com.jme3.cursors.plugins.JmeCursor; -import com.jme3.export.JmeExporter; -import com.jme3.export.binary.BinaryExporter; -import com.jme3.input.CameraInput; -import com.jme3.input.KeyInput; -import com.jme3.math.Transform; -import com.jme3.math.Vector2f; -import com.jme3.math.Vector3f; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.AbstractControl; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3utilities.Heart; -import jme3utilities.MyString; -import jme3utilities.Validate; -import jme3utilities.nifty.dialog.AllowNull; -import jme3utilities.nifty.dialog.DialogController; -import jme3utilities.nifty.dialog.FloatDialog; -import jme3utilities.ui.ActionApplication; -import jme3utilities.ui.InputMode; - -/** - * Input mode for the "test" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class TestMode extends InputMode { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(TestMode.class.getName()); - /** - * asset path to the cursor for this mode - */ - final private static String assetPath = "Textures/cursors/default.cur"; - // ************************************************************************* - // fields - - /** - * local transform of the controlled spatial when entering/exiting ragdoll - * mode - */ - final private Transform resetTransform = new Transform(); - // ************************************************************************* - // constructors - - /** - * Instantiate a disabled, uninitialized input mode. - */ - TestMode() { - super("test"); - } - // ************************************************************************* - // InputMode methods - - /** - * Add default hotkey bindings. These bindings will be used if no custom - * bindings are found. - */ - @Override - protected void defaultBindings() { - bind(SimpleApplication.INPUT_MAPPING_EXIT, KeyInput.KEY_ESCAPE); - bind(Action.editBindings, KeyInput.KEY_F1); - bind(Action.editDisplaySettings, KeyInput.KEY_F2); - bind(Action.rebuild, KeyInput.KEY_F3); - - bind(Action.previousScreen, KeyInput.KEY_PGUP, KeyInput.KEY_B); - - bind(Action.dumpPhysicsSpace, KeyInput.KEY_O); - bind(Action.dumpRenderer, KeyInput.KEY_P); - - bindSignal(CameraInput.FLYCAM_BACKWARD, KeyInput.KEY_S); - bindSignal(CameraInput.FLYCAM_FORWARD, KeyInput.KEY_W); - bindSignal(CameraInput.FLYCAM_LOWER, KeyInput.KEY_Z); - bindSignal(CameraInput.FLYCAM_RISE, KeyInput.KEY_Q); - bindSignal("orbitLeft", KeyInput.KEY_A); - bindSignal("orbitRight", KeyInput.KEY_D); - - bind(SimpleApplication.INPUT_MAPPING_CAMERA_POS, KeyInput.KEY_C); - bind(Action.toggleSkeleton, KeyInput.KEY_V); - bind(Action.togglePhysicsDebug, KeyInput.KEY_SLASH); - - bind(Action.pickLink, "RMB"); - } - - /** - * Initialize this (disabled) mode prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - // Configure the mouse cursor for this mode. - AssetManager manager = application.getAssetManager(); - JmeCursor cursor = (JmeCursor) manager.loadAsset(assetPath); - setCursor(cursor); - - super.initialize(stateManager, application); - } - - /** - * Process an action from the keyboard or mouse. - * - * @param actionString textual description of the action (not null) - * @param ongoing true if the action is ongoing, otherwise false - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void onAction(String actionString, boolean ongoing, float tpf) { - Validate.nonNull(actionString, "action string"); - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "Got action {0} ongoing={1}", - new Object[]{MyString.quote(actionString), ongoing}); - } - - boolean handled = false; - if (ongoing) { - handled = true; - Model model = DacWizard.getModel(); - switch (actionString) { - case Action.pickLink: - pickLink(); - break; - - case Action.previousScreen: - previousScreen(); - break; - - case Action.rebuild: - DacLinks dac = DacWizard.findDac(); - if (dac != null) { - dac.rebuild(); - } - break; - - case Action.save: - saveJava(); - break; - - case Action.saveJ3o: - saveJ3o(); - break; - - case Action.setAnimationTime: - setAnimationTime(); - break; - - case Action.setMargin: - setMargin(); - break; - - case Action.toggleAxes: - model.toggleShowingAxes(); - break; - - case Action.toggleMesh: - DacWizard.toggleMesh(); - break; - - case Action.togglePhysicsDebug: - togglePhysicsDebug(); - break; - - case Action.toggleRagdoll: - toggleRagdoll(); - break; - - case Action.toggleSkeleton: - model.toggleShowingSkeleton(); - break; - - default: - handled = false; - } - - String prefix = Action.setAnimationTime + " "; - if (!handled && actionString.startsWith(prefix)) { - String argument = MyString.remainder(actionString, prefix); - float time = Float.parseFloat(argument); - model.setAnimationTime(time); - handled = true; - } - - prefix = Action.setMargin + " "; - if (!handled && actionString.startsWith(prefix)) { - String arg = MyString.remainder(actionString, prefix); - float newMargin = Float.parseFloat(arg); - setMargin(newMargin); - handled = true; - } - } - - if (!handled) { - getActionApplication().onAction(actionString, ongoing, tpf); - } - } - // ************************************************************************* - // private methods - - /** - * Format a LinkConfig as Java source code. - * - * @param config (not null, unaffected) - * @return formatted text (not null, not empty) - */ - private static String format(LinkConfig config) { - Vector3f scale = config.shapeScale(null); - String scaleXString = MyString.describe(scale.x); - String scaleYString = MyString.describe(scale.y); - String scaleZString = MyString.describe(scale.z); - - float massP = config.massParameter(); - String massPString = MyString.describe(massP); - - RotationOrder ro = config.rotationOrder(); - String orderString = (ro == null) ? "null" : "RotationOrder." + ro; - - String code = String.format( - "new LinkConfig(%sf, MassHeuristic.%s,%n" - + " ShapeHeuristic.%s, " - + "new Vector3f(%sf, %sf, %sf),%n" - + " CenterHeuristic.%s, %s)", - massPString, config.massHeuristic(), - config.shapeHeuristic(), - scaleXString, scaleYString, scaleZString, - config.centerHeuristic(), orderString); - - return code; - } - - /** - * Cast a physics ray from the mouse pointer. If the nearest hit is a - * PhysicsLink, select that link. - */ - private void pickLink() { - Vector2f screenXY = inputManager.getCursorPosition(); - Vector3f from = cam.getWorldCoordinates(screenXY, 0f); - Vector3f to = cam.getWorldCoordinates(screenXY, 1f); - - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - - List rayTest = physicsSpace.rayTest(from, to); - if (!rayTest.isEmpty()) { - PhysicsRayTestResult nearestHit = rayTest.get(0); - PhysicsCollisionObject pco = nearestHit.getCollisionObject(); - Object user = pco.getUserObject(); - if (user instanceof PhysicsLink) { - PhysicsLink link = (PhysicsLink) user; - Model model = DacWizard.getModel(); - - if (link instanceof BoneLink) { - String boneName = link.boneName(); - model.selectLink(boneName); - } else { - assert link instanceof TorsoLink; - model.selectLink(DacConfiguration.torsoName); - } - } - } - } - - /** - * Go back to the "links" screen. - */ - private void previousScreen() { - setEnabled(false); - InputMode links = InputMode.findMode("links"); - links.setEnabled(true); - } - - /** - * Write the model to a file, along with a configured control. - */ - private static void saveJ3o() { - Model model = DacWizard.getModel(); - - String originalPath = model.filePath(); - File originalFile = new File(originalPath); - String modelName = originalFile.getName(); - if (modelName.endsWith(".j3o")) { - modelName = MyString.removeSuffix(modelName, ".j3o"); - } - String hhmmss = ActionApplication.hhmmss(); - String outputFileName = String.format("%s-%s.j3o", modelName, hhmmss); - String outputFilePath = ActionApplication.filePath(outputFileName); - - Spatial modelRoot = model.getRootSpatial(); - modelRoot = Heart.deepCopy(modelRoot); - AbstractControl sControl = RagUtils.findSControl(modelRoot); - Spatial controlledSpatial = sControl.getSpatial(); - DynamicAnimControl dac = model.copyRagdoll(); - controlledSpatial.addControl(dac); - - JmeExporter exporter = BinaryExporter.getInstance(); - File outputFile = new File(outputFilePath); - TestScreen screen = DacWizard.findAppState(TestScreen.class); - try { - exporter.save(modelRoot, outputFile); - } catch (IOException exception) { - screen.showInfoDialog("Exception", exception.toString()); - return; - } - - // Display a confirmation dialog. - String message = String.format( - "The model and configured control have been written to%n%s.", - MyString.quote(outputFilePath)); - screen.showInfoDialog("Success", message); - } - - /** - * Write the control configuration to a file. - */ - private static void saveJava() { - String hhmmss = ActionApplication.hhmmss(); - String className = "Dac" + hhmmss; - String fileName = className + ".java"; - - DynamicAnimControl dac = DacWizard.findDac(); - TestScreen screen = DacWizard.findAppState(TestScreen.class); - - String path = ActionApplication.filePath(fileName); - File file = new File(path); - try (PrintStream stream = new PrintStream(file)) { - write(dac, className, stream); - } catch (FileNotFoundException exception) { - screen.showInfoDialog("Exception", exception.toString()); - return; - } - - // Display a confirmation dialog. - String message = String.format( - "The configuration has been written to%n%s.", - MyString.quote(path)); - screen.showInfoDialog("Success", message); - } - - /** - * Process a "set animationTime" action: display a dialog to enter a new - * animation time. - */ - private static void setAnimationTime() { - Model model = DacWizard.getModel(); - float duration = model.animationDuration(); - DialogController controller - = new FloatDialog("Set", 0f, duration, AllowNull.No); - - float oldTime = model.animationTime(); - String defaultText = Float.toString(oldTime); - - TestScreen screen = DacWizard.findAppState(TestScreen.class); - screen.closeAllPopups(); - screen.showTextEntryDialog("Enter the animation time (in seconds):", - defaultText, Action.setAnimationTime + " ", controller); - } - - /** - * Process a "set margin" action: display a dialog to enter a new collision - * margin. - */ - private static void setMargin() { - float oldValue = CollisionShape.getDefaultMargin(); - String defaultValue = Float.toString(oldValue); - FloatDialog controller = new FloatDialog( - "Set", Float.MIN_VALUE, Float.MAX_VALUE, AllowNull.No); - - TestScreen screen = DacWizard.findAppState(TestScreen.class); - screen.closeAllPopups(); - screen.showTextEntryDialog("Enter new margin:", defaultValue, - Action.setMargin + " ", controller); - } - - /** - * Alter the default collision margin and also the margin of every shape. - * - * @param newMargin the desired value (>0) - */ - private static void setMargin(float newMargin) { - CollisionShape.setDefaultMargin(newMargin); - - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - Collection list - = physicsSpace.getPcoList(); - for (PhysicsCollisionObject pco : list) { - pco.getCollisionShape().setMargin(newMargin); - } - } - - /** - * Toggle physics-debug visualization on/off. - */ - private static void togglePhysicsDebug() { - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - boolean enabled = bulletAppState.isDebugEnabled(); - bulletAppState.setDebugEnabled(!enabled); - } - - /** - * Toggle ragdoll mode. - */ - private void toggleRagdoll() { - DynamicAnimControl dac = DacWizard.findDac(); - TorsoLink torso = dac.getTorsoLink(); - if (torso.isKinematic()) { - // Save the local transform of the controlled spatial. - Spatial controlledSpatial = dac.getSpatial(); - Transform local = controlledSpatial.getLocalTransform(); // alias - resetTransform.set(local); - dac.saveCurrentPose(); - dac.setRagdollMode(); - - } else { // Gradually blend to the saved local transform and pose. - float blendInterval = 1f; // in seconds - dac.blendToKinematicMode( - KinematicSubmode.Reset, blendInterval, resetTransform); - } - } - - /** - * Write the control configuration to a stream, as Java source code. - * - * @param dac a configured control to reproduce (not null, unaffected) - * @param className name for the Java class (not null, not empty) - * @param stream the output stream (not null) - */ - private static void write( - DacConfiguration dac, String className, PrintStream stream) { - stream.printf("import com.jme3.bullet.RotationOrder;%n" - + "import com.jme3.bullet.animation.CenterHeuristic;%n" - + "import com.jme3.bullet.animation.DacConfiguration;%n" - + "import com.jme3.bullet.animation.DynamicAnimControl;%n" - + "import com.jme3.bullet.animation.LinkConfig;%n" - + "import com.jme3.bullet.animation.MassHeuristic;%n" - + "import com.jme3.bullet.animation.RangeOfMotion;%n" - + "import com.jme3.bullet.animation.ShapeHeuristic;%n" - + "import com.jme3.math.Vector3f;%n%n"); - stream.printf("public class %s extends DynamicAnimControl ", className); - stream.printf("{%n%n public %s() {%n", className); - stream.println(" super();"); - - // Write each unique LinkConfig. - Map configs = writeLinkConfigs(dac, stream); - - // Configure the torso of the ragdoll. - String torsoName = DacConfiguration.torsoName; - LinkConfig config = dac.config(torsoName); - int configIndex = configs.get(config); - String code = String.format(" super.setConfig(%s, config%d);%n", - MyString.quote(torsoName), configIndex); - stream.print(code); - writeConfigureMainBone(dac, "super", stream); - - writeConfigureBoneLinks(dac, "super", configs, stream); - stream.printf(" }%n%n"); - - stream.println( - " public static void configure(DacConfiguration dac) {"); - - // Write each unique LinkConfig. - configs = writeLinkConfigs(dac, stream); - - // Configure the torso of the ragdoll. - config = dac.config(torsoName); - configIndex = configs.get(config); - code = String.format(" dac.setConfig(%s, config%d);%n", - MyString.quote(torsoName), configIndex); - stream.print(code); - writeConfigureMainBone(dac, "dac", stream); - - writeConfigureBoneLinks(dac, "dac", configs, stream); - stream.printf(" }%n}%n"); - } - - /** - * Write a LinkConfig definition to a stream, as Java source code. - * - * @param config a LinkConfig to use as a model (not null) - * @param configIndex the index into unique link configurations (>0) - * @param stream the output stream (not null) - */ - private static void writeConfig( - LinkConfig config, int configIndex, PrintStream stream) { - assert config != null; - assert configIndex > 0 : configIndex; - - String newValue = format(config); - stream.printf( - " LinkConfig config%d = %s;%n", configIndex, newValue); - } - - /** - * Write code to configure each linked bone in the ragdoll. - * - * @param dac a configured control to reproduce (not null, unaffected) - * @param varName the name of the Java variable to configure (not null, not - * empty) - * @param configs map from unique link configurations to indices (not null, - * unaffected) - * @param stream the output stream (not null) - */ - private static void writeConfigureBoneLinks( - DacConfiguration dac, String varName, - Map configs, PrintStream stream) { - String[] lbNames = dac.listLinkedBoneNames(); - - for (String lbName : lbNames) { - LinkConfig config = dac.config(lbName); - int configIndex = configs.get(config); - stream.printf(" %s.link(%s, config%d,%n", - varName, MyString.quote(lbName), configIndex); - - RangeOfMotion range = dac.getJointLimits(lbName); - - float maxX = range.getMaxRotation(PhysicsSpace.AXIS_X); - String maxXString = MyString.describeAngle(maxX); - float minX = range.getMinRotation(PhysicsSpace.AXIS_X); - String minXString = MyString.describeAngle(minX); - - float maxY = range.getMaxRotation(PhysicsSpace.AXIS_Y); - String maxYString = MyString.describeAngle(maxY); - float minY = range.getMinRotation(PhysicsSpace.AXIS_Y); - String minYString = MyString.describeAngle(minY); - - float maxZ = range.getMaxRotation(PhysicsSpace.AXIS_Z); - String maxZString = MyString.describeAngle(maxZ); - float minZ = range.getMinRotation(PhysicsSpace.AXIS_Z); - String minZString = MyString.describeAngle(minZ); - - String newRange = String.format("new RangeOfMotion(" - + "%sf, %sf, %sf, %sf, %sf, %sf)", - maxXString, minXString, - maxYString, minYString, - maxZString, minZString); - stream.printf(" %s);%n", newRange); - } - } - - /** - * Write code to configure the torso's main bone. - * - * @param dac a configured control to reproduce (not null, unaffected) - * @param varName the name of the Java variable to configure (not null, not - * empty) - * @param stream the output stream (not null) - */ - private static void writeConfigureMainBone( - DacConfiguration dac, String varName, PrintStream stream) { - String mbName = dac.mainBoneName(); - stream.printf(" %s.setMainBoneName(%s);%n", varName, - MyString.quote(mbName)); - } - - /** - * Assign an index to each unique link configuration in the specified - * control and write generative Java code to the specified stream. - * - * @param dac the control to analyze - * @param stream the output stream (not null) - * @return a new map from link configurations to indices (not null) - */ - private static Map writeLinkConfigs( - DacConfiguration dac, PrintStream stream) { - int nextConfigIndex = 1; - Map result = new TreeMap<>(); - - LinkConfig config = dac.config(DacConfiguration.torsoName); - if (!result.containsKey(config)) { - result.put(config, nextConfigIndex); - writeConfig(config, nextConfigIndex, stream); - ++nextConfigIndex; - } - - String[] lbNames = dac.listLinkedBoneNames(); - for (String lbName : lbNames) { - config = dac.config(lbName); - if (!result.containsKey(config)) { - result.put(config, nextConfigIndex); - writeConfig(config, nextConfigIndex, stream); - ++nextConfigIndex; - } - } - - return result; - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/TestScreen.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/TestScreen.java deleted file mode 100644 index 48fa008bb..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/TestScreen.java +++ /dev/null @@ -1,452 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.animation.Skeleton; -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import com.jme3.bullet.BulletAppState; -import com.jme3.bullet.PhysicsSpace; -import com.jme3.bullet.animation.BoneLink; -import com.jme3.bullet.animation.DacConfiguration; -import com.jme3.bullet.animation.DacLinks; -import com.jme3.bullet.animation.DynamicAnimControl; -import com.jme3.bullet.animation.PhysicsLink; -import com.jme3.bullet.animation.RagUtils; -import com.jme3.bullet.animation.TorsoLink; -import com.jme3.bullet.collision.shapes.CollisionShape; -import com.jme3.bullet.collision.shapes.PlaneCollisionShape; -import com.jme3.bullet.joints.Constraint; -import com.jme3.bullet.joints.JointEnd; -import com.jme3.bullet.joints.New6Dof; -import com.jme3.bullet.joints.SixDofJoint; -import com.jme3.bullet.objects.PhysicsBody; -import com.jme3.bullet.objects.PhysicsRigidBody; -import com.jme3.material.Material; -import com.jme3.math.ColorRGBA; -import com.jme3.math.Plane; -import com.jme3.math.Transform; -import com.jme3.math.Vector3f; -import com.jme3.scene.Spatial; -import com.jme3.scene.control.AbstractControl; -import java.util.List; -import java.util.logging.Logger; -import jme3utilities.Heart; -import jme3utilities.InitialState; -import jme3utilities.MyAsset; -import jme3utilities.MyString; -import jme3utilities.debug.AxesVisualizer; -import jme3utilities.debug.SkeletonVisualizer; -import jme3utilities.math.MyMath; -import jme3utilities.nifty.GuiScreenController; -import jme3utilities.ui.InputMode; - -/** - * The screen controller for the "test" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class TestScreen extends GuiScreenController { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(TestScreen.class.getName()); - // ************************************************************************* - // fields - - /** - * animation time of the pose being viewed (in seconds) - */ - private float viewedAnimationTime; - /** - * debug material for the selected PhysicsLink - */ - private Material selectMaterial; - /** - * horizontal plane added to physics space, or null if not added - */ - private PhysicsRigidBody groundPlane = null; - /** - * root spatial of the C-G model being viewed, or null for none - */ - private Spatial viewedSpatial = null; - /** - * clip/animation name of the pose being viewed - */ - private String viewedAnimationName; - // ************************************************************************* - // constructors - - /** - * Instantiate an uninitialized, disabled screen that will not be enabled - * during initialization. - */ - TestScreen() { - super("test", "Interface/Nifty/screens/wizard/test.xml", - InitialState.Disabled); - } - // ************************************************************************* - // GuiScreenController methods - - /** - * Initialize this (disabled) screen prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - super.initialize(stateManager, application); - - InputMode inputMode = InputMode.findMode("test"); - assert inputMode != null; - setListener(inputMode); - inputMode.influence(this); - - if (selectMaterial == null) { - this.selectMaterial = MyAsset.createWireframeMaterial( - assetManager, ColorRGBA.White); - } - } - - /** - * A callback from Nifty, invoked each time this screen shuts down. - */ - @Override - public void onEndScreen() { - super.onEndScreen(); - removeGroundPlane(); - } - - /** - * A callback from Nifty, invoked each time this screen starts up. - */ - @Override - public void onStartScreen() { - super.onStartScreen(); - - removeGroundPlane(); - DacWizard wizard = DacWizard.getApplication(); - wizard.clearScene(); - this.viewedSpatial = null; - this.viewedAnimationName = null; - this.viewedAnimationTime = Float.NaN; - - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - bulletAppState.setDebugEnabled(true); - } - - /** - * Update this ScreenController prior to rendering. (Invoked once per - * frame.) - * - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void update(float tpf) { - super.update(tpf); - - if (!hasStarted()) { - return; - } - - updateMarginButton(); - updateRagdollButton(); - updateViewButtons(); - - // Update the 3-D scene. - Model model = DacWizard.getModel(); - Spatial nextSpatial = model.getRootSpatial(); - String nextAnimationName = model.animationName(); - float nextAnimationTime = model.animationTime(); - if (nextSpatial != viewedSpatial - || !nextAnimationName.equals(viewedAnimationName) - || nextAnimationTime != viewedAnimationTime) { - DacWizard wizard = DacWizard.getApplication(); - - removeGroundPlane(); - wizard.clearScene(); - - this.viewedSpatial = nextSpatial; - this.viewedAnimationName = nextAnimationName; - this.viewedAnimationTime = nextAnimationTime; - - if (nextSpatial != null) { - Spatial cgModel = Heart.deepCopy(nextSpatial); - wizard.makeScene(cgModel, nextAnimationName, nextAnimationTime); - addGroundPlane(); - - AbstractControl sControl = RagUtils.findSControl(cgModel); - Spatial controlledSpatial = sControl.getSpatial(); - DynamicAnimControl dac = model.copyRagdoll(); - controlledSpatial.addControl(dac); - - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - dac.setPhysicsSpace(physicsSpace); - } - } - - updateAxes(); - updatePosingControls(); - updateSelectedLink(); - } - // ************************************************************************* - // private methods - - /** - * If there isn't a ground plane, create one and add it to the PhysicsSpace. - */ - private void addGroundPlane() { - if (groundPlane == null) { - Plane xzPlane = new Plane(Vector3f.UNIT_Y, 0f); - PlaneCollisionShape shape = new PlaneCollisionShape(xzPlane); - this.groundPlane - = new PhysicsRigidBody(shape, PhysicsBody.massForStatic); - - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - physicsSpace.addCollisionObject(groundPlane); - } - } - - /** - * Apply the pivot-to-PhysicsSpace transform of the specified Constraint to - * the specified Spatial. - * - * @param constraint the constraint to analyze (not null) - * @param spatial where to apply the transform (not null) - */ - private static void applyTransform(Constraint constraint, Spatial spatial) { - Transform frame = new Transform(); // TODO garbage - if (constraint instanceof New6Dof) { - New6Dof new6dof = (New6Dof) constraint; - new6dof.getFrameTransform(JointEnd.A, frame); - } else { - SixDofJoint sixDof = (SixDofJoint) constraint; - sixDof.getFrameTransform(JointEnd.A, frame); - } - - PhysicsRigidBody bodyA = constraint.getBodyA(); - Transform bodyTransform = bodyA.getTransform(null); - bodyTransform.setScale(1f); - MyMath.combine(frame, bodyTransform, frame); - - spatial.setLocalTransform(frame); - } - - /** - * Remove the ground plane (if any) from the PhysicsSpace. - */ - private void removeGroundPlane() { - if (groundPlane != null) { - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - PhysicsSpace physicsSpace = bulletAppState.getPhysicsSpace(); - physicsSpace.removeCollisionObject(groundPlane); - this.groundPlane = null; - } - } - - /** - * Update the AxesVisualizer. - */ - private void updateAxes() { - AxesVisualizer axesVisualizer = DacWizard.findAxesVisualizer(); - - Model model = DacWizard.getModel(); - boolean showingAxes = model.isShowingAxes(); - String btName = model.selectedLink(); - - if (!showingAxes - || viewedSpatial == null - || btName.equals(DacConfiguration.torsoName)) { - axesVisualizer.setEnabled(false); - - } else { - // Align the visualizer axes with the PhysicsJoint. - DacLinks dac = DacWizard.findDac(); - PhysicsLink selectedLink = dac.findBoneLink(btName); - Constraint constraint = (Constraint) selectedLink.getJoint(); - Spatial axesNode = axesVisualizer.getSpatial(); - applyTransform(constraint, axesNode); - - axesVisualizer.setEnabled(true); - } - } - - /** - * Update the collision-margin button. - */ - private void updateMarginButton() { - float margin = CollisionShape.getDefaultMargin(); - String marginButton = Float.toString(margin); - setButtonText("margin", marginButton); - } - - /** - * Update the posing controls. - */ - private void updatePosingControls() { - String anText = ""; - String atText = ""; - String naText = ""; - String paText = ""; - - if (viewedSpatial != null) { - Model model = DacWizard.getModel(); - int numAnimations = model.countAnimations(); - if (numAnimations > 0) { - paText = "-"; - naText = "+"; - } - - float duration = model.animationDuration(); - if (duration > 0f) { - atText = Float.toString(viewedAnimationTime) + " seconds"; - } - - anText = viewedAnimationName; - if (!anText.equals(DacWizard.bindPoseName)) { - anText = MyString.quote(anText); - } - } - - setStatusText("animationName", anText); - setButtonText("animationTime", atText); - setButtonText("nextAnimation", naText); - setButtonText("previousAnimation", paText); - } - - /** - * Update the "Go limp" button. - */ - private void updateRagdollButton() { - DacLinks dac = DacWizard.findDac(); - - String ragdollButton = ""; - if (dac != null && dac.isReady()) { - TorsoLink torso = dac.getTorsoLink(); - if (torso.isKinematic()) { - ragdollButton = "Go limp"; - } else { - ragdollButton = "Reset model"; - } - } - setButtonText("ragdoll", ragdollButton); - } - - /** - * Update the linkNameStatus and the custom materials of the DAC's bodies. - */ - private void updateSelectedLink() { - DacLinks dac = DacWizard.findDac(); - String linkName = ""; - if (dac != null) { - Model model = DacWizard.getModel(); - String selectedBtName = model.selectedLink(); - - if (selectedBtName.equals(DacConfiguration.torsoName)) { - linkName = "Torso:"; - } else { - linkName = "Bone:" + selectedBtName; - } - - List boneLinks = dac.listLinks(BoneLink.class); - for (BoneLink link : boneLinks) { - String boneName = link.boneName(); - PhysicsRigidBody body = link.getRigidBody(); - if (boneName.equals(selectedBtName)) { - body.setDebugMaterial(selectMaterial); - } else { - body.setDebugMaterial(null); - } - } - TorsoLink link = dac.getTorsoLink(); - PhysicsRigidBody body = link.getRigidBody(); - if (selectedBtName.equals(DacConfiguration.torsoName)) { - body.setDebugMaterial(selectMaterial); - } else { - body.setDebugMaterial(null); - } - } - setStatusText("linkNameStatus", linkName); - } - - /** - * Update the buttons that toggle view elements. - */ - private void updateViewButtons() { - BulletAppState bulletAppState - = DacWizard.findAppState(BulletAppState.class); - - String debugButton; - if (bulletAppState.isDebugEnabled()) { - debugButton = "Hide physics"; - } else { - debugButton = "Show physics"; - } - setButtonText("debug", debugButton); - - Model model = DacWizard.getModel(); - String meshButton; - if (model.isShowingMeshes()) { - meshButton = "Hide meshes"; - } else { - meshButton = "Show meshes"; - } - setButtonText("mesh", meshButton); - - String skeletonText = ""; - DacWizard app = DacWizard.getApplication(); - SkeletonVisualizer sv = app.findSkeletonVisualizer(); - Spatial root = model.getRootSpatial(); - if (sv != null && root != null) { - boolean isShown = model.isShowingSkeleton(); - sv.setEnabled(isShown); - - Skeleton skeleton = model.findSkeleton(); - String armature = (skeleton == null) ? "armature" : "skeleton"; - if (isShown) { - skeletonText = "Hide " + armature; - } else { - skeletonText = "Show " + armature; - } - } - setButtonText("skeleton", skeletonText); - - String axesText = model.isShowingAxes() ? "Hide axes" : "Show axes"; - setButtonText("axes", axesText); - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/TorsoMode.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/TorsoMode.java deleted file mode 100644 index d2e92e2ed..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/TorsoMode.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.SimpleApplication; -import com.jme3.app.state.AppStateManager; -import com.jme3.asset.AssetManager; -import com.jme3.bullet.animation.DacConfiguration; -import com.jme3.cursors.plugins.JmeCursor; -import com.jme3.input.KeyInput; -import java.util.logging.Level; -import java.util.logging.Logger; -import jme3utilities.MyString; -import jme3utilities.Validate; -import jme3utilities.ui.InputMode; - -/** - * Input mode for the "torso" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class TorsoMode extends InputMode { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(TorsoMode.class.getName()); - /** - * asset path to the cursor for this mode - */ - final private static String assetPath = "Textures/cursors/default.cur"; - // ************************************************************************* - // constructors - - /** - * Instantiate a disabled, uninitialized input mode. - */ - TorsoMode() { - super("torso"); - } - // ************************************************************************* - // InputMode methods - - /** - * Add default hotkey bindings. These bindings will be used if no custom - * bindings are found. - */ - @Override - protected void defaultBindings() { - bind(SimpleApplication.INPUT_MAPPING_EXIT, KeyInput.KEY_ESCAPE); - bind(Action.editBindings, KeyInput.KEY_F1); - bind(Action.editDisplaySettings, KeyInput.KEY_F2); - - bind(Action.previousScreen, KeyInput.KEY_PGUP); - - bind(Action.dumpPhysicsSpace, KeyInput.KEY_O); - bind(Action.dumpRenderer, KeyInput.KEY_P); - bind(Action.nextScreen, KeyInput.KEY_PGDN); - - bind(Action.previousScreen, KeyInput.KEY_B); - bind(Action.nextScreen, KeyInput.KEY_N); - } - - /** - * Initialize this (disabled) mode prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - // Set the mouse cursor for this mode. - AssetManager manager = application.getAssetManager(); - JmeCursor cursor = (JmeCursor) manager.loadAsset(assetPath); - setCursor(cursor); - - super.initialize(stateManager, application); - } - - /** - * Process an action from the keyboard or mouse. - * - * @param actionString textual description of the action (not null) - * @param ongoing true if the action is ongoing, otherwise false - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void onAction(String actionString, boolean ongoing, float tpf) { - Validate.nonNull(actionString, "action string"); - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "Got action {0} ongoing={1}", - new Object[]{MyString.quote(actionString), ongoing}); - } - - boolean handled = false; - if (ongoing) { - switch (actionString) { - case Action.editLinks: - goLinks(); - handled = true; - break; - - case Action.nextScreen: - goRomEstimation(); - handled = true; - break; - - case Action.previousScreen: - previousScreen(); - handled = true; - break; - - default: - } - } - if (!handled) { - getActionApplication().onAction(actionString, ongoing, tpf); - } - } - // ************************************************************************* - // private methods - - /** - * Bypass RoM estimation and go directly to the "links" screen. - */ - private void goLinks() { - setEnabled(false); - Model model = DacWizard.getModel(); - model.selectLink(DacConfiguration.torsoName); - InputMode links = InputMode.findMode("links"); - links.setEnabled(true); - } - - /** - * Initiate range-of-motion estimation before advancing to the "links" - * screen. - */ - private void goRomEstimation() { - setEnabled(false); - Model model = DacWizard.getModel(); - model.startRomTask(); - } - - /** - * Go back to the "bones" screen. - */ - private void previousScreen() { - setEnabled(false); - InputMode load = InputMode.findMode("bones"); - load.setEnabled(true); - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/TorsoScreen.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/TorsoScreen.java deleted file mode 100644 index b33ef500f..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/TorsoScreen.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - Copyright (c) 2019-2023, Stephen Gold - 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 the copyright holder 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 HOLDER 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 jme3utilities.minie.wizard; - -import com.jme3.app.Application; -import com.jme3.app.state.AppStateManager; -import de.lessvoid.nifty.controls.Button; -import de.lessvoid.nifty.controls.TreeBox; -import de.lessvoid.nifty.controls.TreeItem; -import de.lessvoid.nifty.elements.Element; -import java.util.List; -import java.util.logging.Logger; -import jme3utilities.InitialState; -import jme3utilities.nifty.GuiScreenController; -import jme3utilities.ui.InputMode; - -/** - * The screen controller for the "torso" screen of DacWizard. - * - * @author Stephen Gold sgold@sonic.net - */ -class TorsoScreen extends GuiScreenController { - // ************************************************************************* - // constants and loggers - - /** - * message logger for this class - */ - final static Logger logger = Logger.getLogger(TorsoScreen.class.getName()); - // ************************************************************************* - // fields - - /** - * element of the GUI button to proceed to the "links" screen - */ - private Element linksElement; - /** - * TreeBox to display bones managed by the torso - */ - private TreeBox treeBox; - // ************************************************************************* - // constructors - - /** - * Instantiate an uninitialized, disabled screen that will not be enabled - * during initialization. - */ - TorsoScreen() { - super("torso", "Interface/Nifty/screens/wizard/torso.xml", - InitialState.Disabled); - } - // ************************************************************************* - // GuiScreenController methods - - /** - * Initialize this (disabled) screen prior to its first update. - * - * @param stateManager (not null) - * @param application (not null) - */ - @Override - public void initialize( - AppStateManager stateManager, Application application) { - super.initialize(stateManager, application); - - InputMode inputMode = InputMode.findMode("torso"); - assert inputMode != null; - setListener(inputMode); - inputMode.influence(this); - } - - /** - * A callback from Nifty, invoked each time the screen shuts down. - */ - @Override - public void onEndScreen() { - treeBox.clear(); - super.onEndScreen(); - } - - /** - * A callback from Nifty, invoked each time this screen starts up. - */ - @Override - @SuppressWarnings("unchecked") - public void onStartScreen() { - super.onStartScreen(); - - Button linksButton = getButton("links"); - if (linksButton == null) { - throw new RuntimeException("missing GUI control: linksButton"); - } - this.linksElement = linksButton.getElement(); - - this.treeBox = getScreen().findNiftyControl("skeleton", TreeBox.class); - if (treeBox == null) { - throw new RuntimeException("missing GUI control: skeleton"); - } - - TreeItem rootItem = new TreeItem<>(); - rootItem.setExpanded(true); - Model model = DacWizard.getModel(); - int[] managedBones = model.listTorsoManagedBones(); - int numManaged = managedBones.length; - - // Create an item for each bone managed by the torso. - TreeItem[] boneItems = new TreeItem[numManaged]; - for (int managedIndex = 0; managedIndex < numManaged; ++managedIndex) { - int boneIndex = managedBones[managedIndex]; - BoneValue value = new BoneValue(boneIndex); - boneItems[managedIndex] = new TreeItem<>(value); - boneItems[managedIndex].setExpanded(true); - } - - // Generate a map from bone indices to managed-bone indices. - int numBones = model.countBones(); - int[] mbiArray = new int[numBones]; - for (int boneIndex = 0; boneIndex < numBones; ++boneIndex) { - mbiArray[boneIndex] = -1; - } - for (int managedIndex = 0; managedIndex < numManaged; ++managedIndex) { - int boneIndex = managedBones[managedIndex]; - mbiArray[boneIndex] = managedIndex; - } - - // Parent each item. - for (int managedIndex = 0; managedIndex < numManaged; ++managedIndex) { - TreeItem childItem = boneItems[managedIndex]; - int boneIndex = managedBones[managedIndex]; - int parentIndex = model.parentIndex(boneIndex); - if (parentIndex == -1) { - rootItem.addTreeItem(childItem); - } else { - int parentMbi = mbiArray[parentIndex]; - boneItems[parentMbi].addTreeItem(childItem); - } - } - treeBox.setTree(rootItem); - - // Pre-select the item for the main bone. - int mainBoneIndex = model.mainBoneIndex(); - selectItem(mainBoneIndex); - } - - /** - * Update this ScreenController prior to rendering. (Invoked once per - * frame.) - * - * @param tpf time interval between frames (in seconds, ≥0) - */ - @Override - public void update(float tpf) { - super.update(tpf); - - if (!hasStarted()) { - return; - } - - Model model = DacWizard.getModel(); - List> selectedItems = treeBox.getSelection(); - int numSelected = selectedItems.size(); - if (numSelected == 1) { // Update the main-bone index in the model. - TreeItem mbItem = selectedItems.get(0); - BoneValue mbValue = mbItem.getValue(); - int mbIndex = mbValue.boneIndex(); - model.setMainBoneIndex(mbIndex); - - } else { // empty selection: re-select the main bone - int mainBoneIndex = model.mainBoneIndex(); - selectItem(mainBoneIndex); - } - /* - * If there's a ragdoll already configured, allow the user to - * bypass range-of-motion estimation. - */ - boolean hasRagdoll = model.hasConfiguredRagdoll(); - if (hasRagdoll) { - linksElement.show(); - } else { - linksElement.hide(); - } - } - // ************************************************************************* - // private methods - - /** - * Select the tree item corresponding to the indexed bone. - * - * @param boneIndex the index of the bone to select (≥0) - */ - private void selectItem(int boneIndex) { - assert boneIndex >= 0 : boneIndex; - - List> itemList = treeBox.getItems(); - for (TreeItem item : itemList) { - BoneValue value = item.getValue(); - if (value.boneIndex() == boneIndex) { - treeBox.selectItem(item); - break; - } - } - } -} diff --git a/DacWizard/src/main/java/jme3utilities/minie/wizard/package-info.java b/DacWizard/src/main/java/jme3utilities/minie/wizard/package-info.java deleted file mode 100644 index 33345bd7e..000000000 --- a/DacWizard/src/main/java/jme3utilities/minie/wizard/package-info.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - Copyright (c) 2022, Stephen Gold - 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 the copyright holder 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 HOLDER 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. - */ -/** - * A GUI application to configure a DynamicAnimControl for a C-G model. - */ -package jme3utilities.minie.wizard; diff --git a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/bones.xml b/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/bones.xml deleted file mode 100644 index f98a1453a..000000000 --- a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/bones.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/filePath.xml b/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/filePath.xml deleted file mode 100644 index 350a2b7c7..000000000 --- a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/filePath.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/links.xml b/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/links.xml deleted file mode 100644 index 1cfa0f919..000000000 --- a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/links.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/load.xml b/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/load.xml deleted file mode 100644 index 327adcefd..000000000 --- a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/load.xml +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/test.xml b/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/test.xml deleted file mode 100644 index c4343735d..000000000 --- a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/test.xml +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/torso.xml b/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/torso.xml deleted file mode 100644 index ea6808e3a..000000000 --- a/DacWizard/src/main/resources/Interface/Nifty/screens/wizard/torso.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/DacWizard/src/main/resources/Textures/icons/ellipsis.png b/DacWizard/src/main/resources/Textures/icons/ellipsis.png deleted file mode 100644 index 4e71c4a1fa796242bb4683ffe48567eb08511692..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 856 zcmeAS@N?(olHy`uVBq!ia0vp^;vmey1|%P7U0DF6SkfJR9T^xl_SO6joDAeEBzpw; zGB8xBGB7kWGcf%852Rl(Fq9fFFuY1&V6d7F)So|n<;*J#3`~zbT^vIy<|O_3|KFZ@ zErSDt;l(p43Je?yv!wV09864Q6dE$JEF2gvUMXl`ShVsX1LKjVWBm+|L=>(uKZA9I9e%!5 zILyG*A*eaGoVk!wjJ<|c>fXP1cdh09{QS7n($Y3Ocz=JtW81m9zrVh&t^fbebi<}i zMa-FO3s@CChB~O8WME`5w&Ccw-Xy`!FP9RrB||VGu&BtWdFfJBW{=C$_2VVw#v#%wgvqX^K7e+ZAd=O$F{(g2Pnl;RaK>MTAGomz~Y!0LyLjH zZzCaAZCw1#g^#borXrob_f^y6`kwg z&|5y`P*nF`^Q~baQ>O@}xn=X(f0AWn=?-ufU@ZE0eSQ4HhaW#ac5hSlp4MR=7t6aiTIsGtq+g&N+%q@yR*2RQ6h!Mq1~|N#|OqWeXXsoz#va(Yks-E{(ln7 zkNNiX2e!qMnvBptC#H6XIiRZwEG=^O>7$x){EMV@`)Y5ADV#~~-@T{$kZ9<&6 zLKxG{JvBdz3M85t3^*jLtgR)VJb5DF;^HE)ul6@vnXb6FxU-)hU-Rb8#y1>1Jw4gv z?WH5KMD@hscxaM*DjlWLJ-KnTOf>VP6vDLy_u0clwV7J*$4Ls%IYT`q58#Yn0y f!G{@{co+`02WB6A9rF~JH5fcy{an^LB{Ts5?@>>I diff --git a/DacWizard/src/main/resources/Textures/icons/folder.png b/DacWizard/src/main/resources/Textures/icons/folder.png deleted file mode 100644 index 9b3468dc84d9e3072ff373710ba0179dfba735f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1621 zcmV-b2CDgqP)004R=004l4008;_004mK004C`008P>0026d000+nm#LZ5000Hx zNklxF?Ccf^@NqmB65xDeU}(5|&6+jLR#sLFM~)l;n+p&? zEFi@o1K8Qw!3O;N`AZBa#QyvDZ)T{^n1F0XAk7TLj1L|>WXa4fFj0~IA3M7<7^t6# zVZrJ%E?GH6b-#aoKm7IU*V90C9{~c05oAMDR1|}-urPz5ps>Q?g)@#yi*fQpEM;JX z*v-hm1SFW4AR-|4@85seLVffZl;uSj{sGN+`~EA#+HDsZ?mvFVprUD0v~Jznet-Z1 zyZpkr6WNZ3IPgz!K#RQTV&{|tZr{sW7P3UM>! zCD}5ZyZo48$(CCtAbEfQ0vrDD!QH9C{Qu;h+&e9)t1im0@7P_2-@pGdfYK4jXCOl$ zsfv-|@4tUw!x^D$pcKRJpMMyX6-5{fG$k1X`8gSwnHYIM<^lu|B+UQ3i#@X?kC%m= zh2hVyzhHww2EbD3e-H%Q!~hNgSn>r^OpFYlzW!wBopz8xQC5h7m4z7?Z$H4P5FmiS zhBLGAUIiLv!NtSD@c-v;uqGy;MIem~K+FCCy$%9QEI>V6>_81b@$bJG7(n7crX&wL zgRQv&!|S(S82EYF82DZ|%q zzZle$c`5FELgW&V$pA27suGCT&X9)4uW8ee^0mJuSK>UY66&NhL58Y-E65s#@ z3)ozM0Ahj|&UfwV%~!z0&CKBGsLqg-WDO3Mb=$81Q-csgLaYTtLWnU#dYlD=yNf2n ziuLCito)}i96xc7fq@(7lRtkMUVf*8)hb@|T2_y0jMTwH7n ze1hBzHl~W;pm_P_3j?np7Xu$32ZIPOML5{2GOSye$iM*%Hm~T}3@47=VPN231-h7% zffpD&U%!EZ^&dD`00IbXxSX8q^*fI~eEtvgG8h13UtLKQ%)D~*1;p#1$ODBj&~@y* z91MN6z6>8e{a{EfUBmG0!#4(YVQvOKpg1UU|NZ+7b~!)*fejZI6M6mo&7a#}KYa(M zV~{u1fQGXIg9&8#AE1G-Bo79_xG*!6Wzf}-WVmwU1;f5Ww-^{W*%)MjaRZ7I7G@@} z;Q#>yHXIm6e}DgFzx?3IJ77v+0=rNc7!+#2NV;|J4Z}O2%fRA@0*Qec7Y>fhQR&I>2k6o-ARmE>1z@mo0aFGqD7=B`8W00000NkvXXu0mjfh@RaW diff --git a/DacWizard/src/main/resources/Textures/icons/jme.png b/DacWizard/src/main/resources/Textures/icons/jme.png deleted file mode 100644 index 62f83c9be61461f3f6a62c0693f769990cfcddcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1815 zcmV+y2k7{TP)004R=004l4008;_004mK004C`008P>0026d000+nm#LZ5000J} zNklzs01ONa40H~;_00II60QB_q0KL7v08>*_ z00ssI0IaR80NC2wN9^h7M*{r%EeHh!3F+(X2=n{>5;izGgF87lpY!ta0QdLz0RH~| z00RR90ORB106RN70DOFW00IbXI3pt?3T9zpVfg*`FW`}>$*KT4Ki`OhH022=+O zK?NZFmXU$s@$o$~S3S5FY+zzqEhZv-@$cWiV8cOrK@I}}fB*s;4zih*m6hSgj~^_5 z{`}#)eC6uby?gh};(PHhTvrHWI|IXCXw(3i401qSavTh-Pha2j-naFcm4c>Dmxz$i zO`v|!H*ems^6>DS1S&fN5I|tVL0)?I?j6VimRGM{M^BzSDO~X53u{AR28KUCLy_Yg z#QX>4OY<-=u>ANTc;mvE_Dla5|8eo~9@W#+n|tlrwfi7>fB*tVD99V9PMu=l<>CEd zXkv1N>D>!!T|TJ6cp?ns8zFWegPDPWiG}rxva<4VUS8faz@U8#k_QMNu;J|N?7*P; z!SMd$M}`BtcQ&X3H2~umufZ^1umZzLhJ%6O*RNlEuU@})fAQkQ|0hqLfaL)K2plZu z&!2a^dhM#|>-QfXe7=3zSB)1M#{Yn>{{t}yWEm4PG|(9k;SUNT0iY@BTnr5FfBs~V zm6hdpbaVvE0|XG*@ZrThI6wq3&nWbGgupH zvG(@OVt9V>8Uv@4C_{O99)qfa48zASUm5=V{>|{}&3lGJdk-<}+I0XJ#>@;q|1&XI z*jX`H8)-A#y>W}--sZy$k}4{v1qB5`sf7U`fWU@-{r&Ih(rt%Coy_$ZD#|h#aA@b1%B1`ak>a5{GNac2-wRARVt<1T}J zeEI&9;SVD-!49-~aH4*Pc9i;xoux zfB*ug79};!g(t7x{Us$T$Z+-E6NbM)L!Uf+1av72!rV`O_Z()Jw`>c;&6l6grzEF*T(xS|KajZq0R%Q&K!E?) zqxatrKYR6-;nM9#44>Y;XSjI$48uI2i%wj<#~`R`#J~!)@XCdI3_Y_qFie;{kKs2k znS2B0Y&Jm&23-qFhCnA{h5%C)%dJ~BwMa=xgUtm9ATYtl%gewkAhPA&lNSuH-+f?s z{q{Wr1FtXxCkGpYpN#aZUz?=O4Z@Tn0K~$BD}fH!q)KD30}F zNC@|3NDp@A{PXH|b$&sC8OU6K00M{kCt&6g5Ej|~?CqP*Kzn1hd)IF;G!-T>Xer4u zyn6eAftTqILq?8!w@WMyOp z=Rbe|0=ryFN{YcyU;p;KSD!Ajv#~H38tXG?D#|c?|Ms2X(2W-im;TE!ykHb&kdu{W zFxFOLkP+o)5aQ)#5EtTS5E0~M`1$J(!yjO&c;?D2hT}J%9xydEJqt1yAb`LwS5Qy@ zl`sE3e*Dl>(7$vZ8!HRDudNZEwz4dPrW8NJcR@Y|MLQ>k=T9CooVtFV;m^Hi3_MJ~ z7(@kl8D75s!f@yDO9pYEnh7g*ybp_tt+cc-2j^>m0Ad7HbJwq52UixrB9o!Lqf^?* z#6)iY#+558V?AW;jI|ja0n_r$_x~9z{Z{NN#C@U)5{Nv;je)HBHlg6d{J^y_FY$`3xtIf;7#t*D*{=Rts z`NgZxzYcQn@NL&OwcPdU<%_={pCecJ00G2E%i13xzyNtvk%q4y@3#N|002ovPDHLk FV1j6+Rwe)d diff --git a/DacWizard/src/main/resources/Textures/icons/license.txt b/DacWizard/src/main/resources/Textures/icons/license.txt deleted file mode 100644 index 06e4cd8ba..000000000 --- a/DacWizard/src/main/resources/Textures/icons/license.txt +++ /dev/null @@ -1,21 +0,0 @@ -Licensing history for assets in src/main/resources/Textures/icons - -Stephen Gold authored "ellipsis.png", "folder.png", and "jme.png". -He makes them available under the Creative Commons -Attribution-Share Alike 3.0 Unported license -- see -https://creativecommons.org/licenses/by-sa/3.0/ for details. - -When sharing or reusing these files, please attribute them to "Stephen Gold's -Minie Project at https://github.com/stephengold/Minie" - -It is easier to ask permission than forgiveness. To request a custom license -granting rights not included in the CC-BY-SA terms, send an e-mail to -sgold@sonic.net with "custom license request" in the subject. Please -clearly indicate: - (1) your legal name - (2) which assets you want to license - (3) name and brief description of your project, if applicable - (4) the licensee (person or organization that will hold the custom license) - (5) what rights you are requesting (i.e. "non-exclusive and non-transferable - perpetual license to incorporate into proprietary software with worldwide - distribution") \ No newline at end of file diff --git a/LICENSE b/LICENSE index dbf004350..812948820 100644 --- a/LICENSE +++ b/LICENSE @@ -5,8 +5,7 @@ vhacd software package Copyright (c) 2016, Riccardo Balbo All rights reserved. Note: the following license does not apply to certain assets/resources -(3 files in DacWizard/src/main/resources/Textures/icons, - 1 file in MinieAssets/src/main/resources/Interface/Fonts, +(1 file in MinieAssets/src/main/resources/Interface/Fonts, 2 files in MinieAssets/src/main/resources/Models/Ankh, 2 files in MinieAssets/src/main/resources/Models/Banana, 2 files in MinieAssets/src/main/resources/Models/Barrel, diff --git a/MinieLibrary/release-notes.md b/MinieLibrary/release-notes.md index 9d165a347..b6bec66e7 100644 --- a/MinieLibrary/release-notes.md +++ b/MinieLibrary/release-notes.md @@ -1,4 +1,4 @@ -# Release log for the Minie library, DacWizard, MinieExamples, and VhacdTuner +# Release log for the Minie library and MinieExamples ## Version 8.1.0 released on 12 May 2024 diff --git a/MinieLibrary/src/site/antora/tutorials/modules/minie-library-tutorials/pages/dac.adoc b/MinieLibrary/src/site/antora/tutorials/modules/minie-library-tutorials/pages/dac.adoc index 796f984e7..20bca432e 100644 --- a/MinieLibrary/src/site/antora/tutorials/modules/minie-library-tutorials/pages/dac.adoc +++ b/MinieLibrary/src/site/antora/tutorials/modules/minie-library-tutorials/pages/dac.adoc @@ -91,7 +91,7 @@ stays rigid. As an alternative to hand-coding the control configuration, you can generate configuration code for a specific model using -https://github.com/stephengold/Minie/tree/master/DacWizard[the DacWizard application], +https://github.com/stephengold/DacWizard[the DacWizard application], which samples animation tracks to estimate the range of motion for each linked bone. diff --git a/README.md b/README.md index 10e55eab4..0aa9f0d2d 100644 --- a/README.md +++ b/README.md @@ -5,15 +5,17 @@ The [Minie Project][project] is about improving the integration of and [Khaled Mamou's V-HACD Library][vhacd] into [the jMonkeyEngine (JME) game engine][jme]. -It contains 7 subprojects: +It contains 6 subprojects: 1. MinieLibrary: the Minie runtime library and its automated tests - 2. [DacWizard]: a GUI application to configure a ragdoll - 3. TutorialApps: tutorial apps - 4. MinieExamples: demos, examples, and non-automated test software - 5. MinieAssets: generate assets used in MinieExamples - 6. MinieDump: a command-line utility to dump J3O assets - 7. Jme3Examples: physics examples from jme3-examples + 2. TutorialApps: tutorial apps + 3. MinieExamples: demos, examples, and non-automated test software + 4. MinieAssets: generate assets used in MinieExamples + 5. MinieDump: a command-line utility to dump J3O assets + 6. Jme3Examples: physics examples from jme3-examples + +The `DacWizard` application, formerly a subproject, +is now [a separate project at GitHub][dacwizard]. The `VhacdTuner` application, formerly a subproject, is now [a separate project at GitHub][vhacdTuner]. @@ -417,7 +419,7 @@ correct the situation: sgold@sonic.net [bullet]: https://pybullet.org/wordpress "Bullet Real-Time Physics Simulation" [checkstyle]: https://checkstyle.org "Checkstyle" [chrome]: https://www.google.com/chrome "Chrome" -[dacwizard]: https://github.com/stephengold/Minie/tree/master/DacWizard "DacWizard Application" +[dacwizard]: https://github.com/stephengold/DacWizard "DacWizard Project" [dokthar]: https://github.com/dokthar/jmonkeyengine "Dokthar's fork of JMonkeyEngine" [elements]: https://www.adobe.com/products/photoshop-elements.html "Photoshop Elements" [findbugs]: http://findbugs.sourceforge.net "FindBugs Project" diff --git a/build.gradle b/build.gradle index b9b242510..2fb804e4e 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ subprojects { } tasks.register('checkstyle') { - dependsOn ':DacWizard:checkstyleMain', ':Jme3Examples:checkstyleMain', \ + dependsOn ':Jme3Examples:checkstyleMain', \ ':MinieAssets:checkstyleMain', ':MinieDump:checkstyleMain', \ ':MinieExamples:checkstyleMain', ':MinieLibrary:checkstyleMain', \ ':MinieLibrary:checkstyleTest', ':TutorialApps:checkstyleMain'