From dda8ee2c384902bb6af2dbea19dd51db21bb0c60 Mon Sep 17 00:00:00 2001 From: "bre..ns" Date: Fri, 15 Jul 2011 17:20:39 +0000 Subject: [PATCH] * select and move tools added to sdk * ability to easily add other tools to scene composer * changed camera controller to handle more types of mouse events * much refactoring of sceneComposerToolController git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7863 75d07b2b-3a1a-0410-a2c5-0572b91ccdca --- .../gde/core/scene/SceneCameraController.java | 2 +- .../controller/AbstractCameraController.java | 186 ++++++- .../scene/controller/SceneToolController.java | 29 +- .../gde/core/util}/ToggleButtonGroup.java | 2 +- .../jme3/gde/scenecomposer/Bundle.properties | 8 + .../ComposerCameraController.java | 143 +++-- .../SceneComposerToolController.java | 179 ++++++ .../SceneComposerTopComponent.form | 104 +++- .../SceneComposerTopComponent.java | 98 +++- .../jme3/gde/scenecomposer/SceneEditTool.java | 508 ++++++++++++++++++ .../gde/scenecomposer/icon_arrow_inout.png | Bin 0 -> 570 bytes .../jme3/gde/scenecomposer/icon_arrow_out.png | Bin 0 -> 632 bytes .../icon_arrow_rotate_clockwise.png | Bin 0 -> 741 bytes .../jme3/gde/scenecomposer/icon_select.png | Bin 0 -> 3052 bytes .../gde/scenecomposer/tools/MoveTool.java | 160 ++++++ .../gde/scenecomposer/tools/SelectTool.java | 81 +++ .../TerrainCameraController.java | 6 +- .../TerrainEditorTopComponent.java | 6 +- .../terraineditor/TerrainToolController.java | 5 - .../VehicleCreatorCameraController.java | 2 +- 20 files changed, 1416 insertions(+), 103 deletions(-) rename sdk/{jme3-terrain-editor/src/com/jme3/gde/terraineditor => jme3-core/src/com/jme3/gde/core/util}/ToggleButtonGroup.java (98%) create mode 100644 sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerToolController.java create mode 100644 sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneEditTool.java create mode 100644 sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_arrow_inout.png create mode 100644 sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_arrow_out.png create mode 100644 sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_arrow_rotate_clockwise.png create mode 100644 sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_select.png create mode 100644 sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/MoveTool.java create mode 100644 sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/tools/SelectTool.java diff --git a/sdk/jme3-core/src/com/jme3/gde/core/scene/SceneCameraController.java b/sdk/jme3-core/src/com/jme3/gde/core/scene/SceneCameraController.java index 1d045c863..af2636b67 100644 --- a/sdk/jme3-core/src/com/jme3/gde/core/scene/SceneCameraController.java +++ b/sdk/jme3-core/src/com/jme3/gde/core/scene/SceneCameraController.java @@ -46,7 +46,7 @@ public class SceneCameraController extends AbstractCameraController { } @Override - protected void checkClick(int button) { + protected void checkClick(int button, boolean pressed) { } } diff --git a/sdk/jme3-core/src/com/jme3/gde/core/scene/controller/AbstractCameraController.java b/sdk/jme3-core/src/com/jme3/gde/core/scene/controller/AbstractCameraController.java index 7b2d01deb..0c2701648 100644 --- a/sdk/jme3-core/src/com/jme3/gde/core/scene/controller/AbstractCameraController.java +++ b/sdk/jme3-core/src/com/jme3/gde/core/scene/controller/AbstractCameraController.java @@ -51,6 +51,7 @@ import com.jme3.math.Vector3f; import com.jme3.renderer.Camera; import com.jme3.renderer.RenderManager; import java.util.concurrent.Callable; +import java.util.logging.Logger; /** * @@ -70,8 +71,16 @@ public abstract class AbstractCameraController extends AbstractAppState implemen protected Object master; protected boolean moved = false; protected boolean movedR = false; - protected boolean checkClick = false; + protected boolean buttonDownL = false; + protected boolean buttonDownR = false; + protected boolean checkClickL = false; protected boolean checkClickR = false; + protected boolean checkReleaseL = false; + protected boolean checkReleaseR = false; + protected boolean checkDragged = false; + protected boolean checkDraggedR = false; + protected boolean checkReleaseLeft = false; + protected boolean checkReleaseRight = false; public AbstractCameraController(Camera cam, InputManager inputManager) { this.cam = cam; @@ -151,15 +160,22 @@ public abstract class AbstractCameraController extends AbstractAppState implemen cam.setLocation(loc); } - public void onAction(String string, boolean bln, float f) { + /*public void onAction(String string, boolean bln, float f) { if ("MouseButtonLeft".equals(string)) { if (bln) { leftMouse = true; moved = false; } else { + if (leftMouse) + checkReleaseLeft = true; leftMouse = false; if (!moved) { - checkClick = true; + if (checkClick == false) + checkClick = true; + checkDragged = false; + } else { + checkDragged = true; + checkClick = false; } } } @@ -168,49 +184,56 @@ public abstract class AbstractCameraController extends AbstractAppState implemen rightMouse = true; movedR = false; } else { + if (rightMouse) + checkReleaseRight = true; rightMouse = false; if (!movedR) { - checkClickR = true; + if (checkClickR == false) + checkClickR = true; + checkDraggedR = false; + } else { + checkDraggedR = true; + checkClickR = false; } } } - } + }*/ public void onAnalog(String string, float f1, float f) { if ("MouseAxisX".equals(string)) { moved = true; movedR = true; - if (leftMouse) { + if (buttonDownL) { rotateCamera(Vector3f.UNIT_Y, -f1 * 2.5f); } - if (rightMouse) { + if (buttonDownR) { panCamera(f1 * 2.5f, 0); } } else if ("MouseAxisY".equals(string)) { moved = true; movedR = true; - if (leftMouse) { + if (buttonDownL) { rotateCamera(cam.getLeft(), -f1 * 2.5f); } - if (rightMouse) { + if (buttonDownR) { panCamera(0, -f1 * 2.5f); } } else if ("MouseAxisX-".equals(string)) { moved = true; movedR = true; - if (leftMouse) { + if (buttonDownL) { rotateCamera(Vector3f.UNIT_Y, f1 * 2.5f); } - if (rightMouse) { + if (buttonDownR) { panCamera(-f1 * 2.5f, 0); } } else if ("MouseAxisY-".equals(string)) { moved = true; movedR = true; - if (leftMouse) { + if (buttonDownL) { rotateCamera(cam.getLeft(), f1 * 2.5f); } - if (rightMouse) { + if (buttonDownR) { panCamera(0, f1 * 2.5f); } } else if ("MouseWheel".equals(string)) { @@ -219,6 +242,37 @@ public abstract class AbstractCameraController extends AbstractAppState implemen zoomCamera(-.1f); } } + + public void onAction(String string, boolean pressed, float f) { + if ("MouseButtonLeft".equals(string)) { + if (pressed) { + if (!buttonDownL) { // mouse clicked + checkClickL = true; + checkReleaseL = false; + } + } else { + if (buttonDownL) { // mouse released + checkReleaseL = true; + checkClickL = false; + } + } + buttonDownL = pressed; + } + if ("MouseButtonRight".equals(string)) { + if (pressed) { + if (!buttonDownR) { // mouse clicked + checkClickR = true; + checkReleaseR = false; + } + } else { + if (buttonDownR) { // mouse released + checkReleaseR = true; + checkClickR = false; + } + } + buttonDownR = pressed; + } + } public void onJoyAxisEvent(JoyAxisEvent jae) { } @@ -242,39 +296,129 @@ public abstract class AbstractCameraController extends AbstractAppState implemen /**APPSTATE**/ private boolean appInit = false; + + @Override public void initialize(AppStateManager asm, Application aplctn) { appInit = true; } + @Override public boolean isInitialized() { return appInit; } + @Override public void stateAttached(AppStateManager asm) { } + @Override public void stateDetached(AppStateManager asm) { } + @Override public void update(float f) { - if (checkClick) { - checkClick(0); - checkClick = false; - } - if (checkClickR) { - checkClick(1); - checkClickR = false; + if (moved) { + // moved, check for drags + if (checkReleaseL || checkReleaseR) { + // drag released + if (checkReleaseL) + checkDragged(0, false); + if (checkReleaseR) + checkDragged(1, false); + checkReleaseL = false; + checkReleaseR = false; + } else { + if (buttonDownL) + checkDragged(0, true); + else if (buttonDownR) + checkDragged(1, true); + else + checkMoved(); // no dragging, just moved + } + + moved = false; + } else { + // not moved, check for just clicks + if (checkClickL) { + checkClick(0, true); + checkClickL = false; + } + if (checkReleaseL) { + checkClick(0, false); + checkReleaseL = false; + } + if (checkClickR) { + checkClick(1, true); + checkClickR = false; + } + if (checkReleaseR) { + checkClick(1, false); + checkReleaseR = false; + } } + + /*if (checkDragged || checkDraggedR) { + if (checkDragged) { + checkDragged(0); + checkReleaseLeft = false; + checkDragged = false; + checkClick = false; + checkClickR = false; + } + if (checkDraggedR) { + checkDragged(1); + checkReleaseRight = false; + checkDraggedR = false; + checkClick = false; + checkClickR = false; + } + } else { + if (checkClick) { + checkClick(0, checkReleaseLeft); + checkReleaseLeft = false; + checkClick = false; + checkDragged = false; + checkDraggedR = false; + } + if (checkClickR) { + checkClick(1, checkReleaseRight); + checkReleaseRight = false; + checkClickR = false; + checkDragged = false; + checkDraggedR = false; + } + }*/ } - protected abstract void checkClick(int button); + /** + * mouse clicked, not dragged + * @param pressed true if pressed, false if released + */ + protected abstract void checkClick(int button, boolean pressed); + + /** + * Mouse dragged while button is depressed + */ + protected void checkDragged(int button, boolean pressed) { + // override in sub classes + } + + /** + * The mouse moved, no dragging or buttons pressed + */ + protected void checkMoved() { + // override in subclasses + } + @Override public void render(RenderManager rm) { } + @Override public void postRender() { } + @Override public void cleanup() { } diff --git a/sdk/jme3-core/src/com/jme3/gde/core/scene/controller/SceneToolController.java b/sdk/jme3-core/src/com/jme3/gde/core/scene/controller/SceneToolController.java index 4374622e0..c9d5714d9 100644 --- a/sdk/jme3-core/src/com/jme3/gde/core/scene/controller/SceneToolController.java +++ b/sdk/jme3-core/src/com/jme3/gde/core/scene/controller/SceneToolController.java @@ -61,33 +61,34 @@ public class SceneToolController implements AppState { } protected void initTools() { - Material redMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); - redMat.getAdditionalRenderState().setWireframe(true); - redMat.setColor("Color", ColorRGBA.Red); + //Material redMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + //redMat.getAdditionalRenderState().setWireframe(true); + //redMat.setColor("Color", ColorRGBA.Red); Material greenMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); greenMat.getAdditionalRenderState().setWireframe(true); greenMat.setColor("Color", ColorRGBA.Green); - Material blueMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); - blueMat.getAdditionalRenderState().setWireframe(true); - blueMat.setColor("Color", ColorRGBA.Blue); + //Material blueMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + //blueMat.getAdditionalRenderState().setWireframe(true); + //blueMat.setColor("Color", ColorRGBA.Blue); Material grayMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); grayMat.getAdditionalRenderState().setWireframe(true); grayMat.setColor("Color", ColorRGBA.Gray); - + //cursor if (cursor == null) { cursor = new Node(); } cursor.detachAllChildren(); - Geometry cursorArrowX = new Geometry("cursorArrowX", new Arrow(Vector3f.UNIT_X)); - Geometry cursorArrowY = new Geometry("cursorArrowY", new Arrow(Vector3f.UNIT_Y)); - Geometry cursorArrowZ = new Geometry("cursorArrowZ", new Arrow(Vector3f.UNIT_Z)); - cursorArrowX.setMaterial(redMat); + //Geometry cursorArrowX = new Geometry("cursorArrowX", new Arrow(Vector3f.UNIT_X)); + Geometry cursorArrowY = new Geometry("cursorArrowY", new Arrow(new Vector3f(0,-1,0))); + cursorArrowY.setLocalTranslation(0, 1, 0); + //Geometry cursorArrowZ = new Geometry("cursorArrowZ", new Arrow(Vector3f.UNIT_Z)); + //cursorArrowX.setMaterial(redMat); cursorArrowY.setMaterial(greenMat); - cursorArrowZ.setMaterial(blueMat); - cursor.attachChild(cursorArrowX); + //cursorArrowZ.setMaterial(blueMat); + //cursor.attachChild(cursorArrowX); cursor.attachChild(cursorArrowY); - cursor.attachChild(cursorArrowZ); + //cursor.attachChild(cursorArrowZ); toolsNode.attachChild(cursor); //grid diff --git a/sdk/jme3-terrain-editor/src/com/jme3/gde/terraineditor/ToggleButtonGroup.java b/sdk/jme3-core/src/com/jme3/gde/core/util/ToggleButtonGroup.java similarity index 98% rename from sdk/jme3-terrain-editor/src/com/jme3/gde/terraineditor/ToggleButtonGroup.java rename to sdk/jme3-core/src/com/jme3/gde/core/util/ToggleButtonGroup.java index d3048a02c..d30cc98d1 100644 --- a/sdk/jme3-terrain-editor/src/com/jme3/gde/terraineditor/ToggleButtonGroup.java +++ b/sdk/jme3-core/src/com/jme3/gde/core/util/ToggleButtonGroup.java @@ -30,7 +30,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package com.jme3.gde.terraineditor; +package com.jme3.gde.core.util; import javax.swing.AbstractButton; import javax.swing.ButtonGroup; diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/Bundle.properties b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/Bundle.properties index 74dd0b095..4898b7d08 100644 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/Bundle.properties +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/Bundle.properties @@ -44,3 +44,11 @@ SceneComposerTopComponent.jTextField1.text=10 SceneComposerTopComponent.jLabel4.text=kg SceneComposerTopComponent.jButton1.text=make character SceneComposerTopComponent.fixedCheckBox.text=radius/height +SceneComposerTopComponent.moveButton.text= +SceneComposerTopComponent.rotateButton.text= +SceneComposerTopComponent.scaleButton.text= +SceneComposerTopComponent.selectButton.text= +SceneComposerTopComponent.selectButton.toolTipText=Select +SceneComposerTopComponent.moveButton.toolTipText=Move +SceneComposerTopComponent.rotateButton.toolTipText=Rotate (in-development) +SceneComposerTopComponent.scaleButton.toolTipText=Scale (in-development) diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/ComposerCameraController.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/ComposerCameraController.java index d791d0268..7a889827d 100644 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/ComposerCameraController.java +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/ComposerCameraController.java @@ -36,6 +36,8 @@ import com.jme3.collision.CollisionResults; import com.jme3.gde.core.scene.SceneApplication; import com.jme3.gde.core.scene.controller.AbstractCameraController; import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; +import com.jme3.input.KeyInput; +import com.jme3.input.event.KeyInputEvent; import com.jme3.math.Ray; import com.jme3.math.Vector2f; import com.jme3.math.Vector3f; @@ -50,6 +52,8 @@ public class ComposerCameraController extends AbstractCameraController { private Node rootNode; private JmeNode jmeRootNode; + private SceneComposerToolController toolController; + private boolean forceCameraControls = false; // when user holds shift, this is true public ComposerCameraController(Camera cam, JmeNode rootNode) { super(cam, SceneApplication.getApplication().getInputManager()); @@ -57,49 +61,114 @@ public class ComposerCameraController extends AbstractCameraController { this.rootNode = rootNode.getLookup().lookup(Node.class); } - public void checkClick(int button) { + private boolean isEditButtonEnabled() { + return toolController.isEditToolEnabled(); + } + + public void setToolController(SceneComposerToolController toolController) { + this.toolController = toolController; + } + + public boolean isToolUsesCameraControls() { + return !toolController.isOverrideCameraControl(); + } + + public Camera getCamera() { + return cam; + } + + @Override + public void onKeyEvent(KeyInputEvent kie) { + if (kie.isPressed()) { + if ( KeyInput.KEY_LSHIFT == kie.getKeyCode() ) { + forceCameraControls = true; + } + } else if (kie.isReleased()){ + if ( KeyInput.KEY_LSHIFT == kie.getKeyCode() ) { + forceCameraControls = false; + } + } + } + + @Override + public void checkClick(int button, boolean pressed) { if (button == 0) { - CollisionResults results = new CollisionResults(); - Ray ray = new Ray(); - Vector3f pos = cam.getWorldCoordinates(new Vector2f(mouseX, mouseY), 0).clone(); - Vector3f dir = cam.getWorldCoordinates(new Vector2f(mouseX, mouseY), 0.3f).clone(); - dir.subtractLocal(pos).normalizeLocal(); - ray.setOrigin(pos); - ray.setDirection(dir); - rootNode.collideWith(ray, results); - if (results == null) { - return; + if (isEditButtonEnabled() && !forceCameraControls) { + toolController.doEditToolActivatedPrimary(new Vector2f(mouseX,mouseY), pressed, cam); } - final CollisionResult result = results.getClosestCollision(); - java.awt.EventQueue.invokeLater(new Runnable() { - - public void run() { - if (result != null && result.getGeometry() != null) { - SceneApplication.getApplication().setCurrentFileNode(jmeRootNode.getChild(result.getGeometry())); - } else { - SceneApplication.getApplication().setCurrentFileNode(jmeRootNode); - } - } - }); - checkClick = false; } if (button == 1) { - CollisionResults results = new CollisionResults(); - Ray ray = new Ray(); - Vector3f pos = cam.getWorldCoordinates(new Vector2f(mouseX, mouseY), 0).clone(); - Vector3f dir = cam.getWorldCoordinates(new Vector2f(mouseX, mouseY), 0.3f).clone(); - dir.subtractLocal(pos).normalizeLocal(); - ray.setOrigin(pos); - ray.setDirection(dir); - rootNode.collideWith(ray, results); - if (results == null) { - return; + if (isEditButtonEnabled() && !forceCameraControls) { + toolController.doEditToolActivatedSecondary(new Vector2f(mouseX,mouseY), pressed, cam); + } + } + } + + @Override + protected void checkDragged(int button, boolean pressed) { + if (button == 0) + toolController.doEditToolDraggedPrimary(new Vector2f(mouseX, mouseY), pressed, cam); + else if (button == 1) + toolController.doEditToolDraggedSecondary(new Vector2f(mouseX, mouseY), pressed, cam); + } + + @Override + protected void checkMoved() { + toolController.doEditToolMoved(new Vector2f(mouseX, mouseY), cam); + } + + @Override + public void onAnalog(String string, float f1, float f) { + if ("MouseAxisX".equals(string)) { + moved = true; + movedR = true; + if (isToolUsesCameraControls() || forceCameraControls) { + if (buttonDownL) { + rotateCamera(Vector3f.UNIT_Y, -f1 * 2.5f); + } + if (buttonDownR) { + panCamera(f1 * 2.5f, 0); + } } - CollisionResult result = results.getClosestCollision(); - if (result != null) { - ((SceneComposerTopComponent) master).doMoveCursor(result.getContactPoint());//getGeometry().getWorldTranslation().add(result.getGeometry().getWorldRotation().mult(result.getContactPoint()))); + } else if ("MouseAxisY".equals(string)) { + moved = true; + movedR = true; + if (isToolUsesCameraControls() || forceCameraControls) { + if (buttonDownL) { + rotateCamera(cam.getLeft(), -f1 * 2.5f); + } + if (buttonDownR) { + panCamera(0, -f1 * 2.5f); + } + } + } else if ("MouseAxisX-".equals(string)) { + moved = true; + movedR = true; + if (isToolUsesCameraControls() || forceCameraControls) { + if (buttonDownL) { + rotateCamera(Vector3f.UNIT_Y, f1 * 2.5f); + } + if (buttonDownR) { + panCamera(-f1 * 2.5f, 0); + } + } + } else if ("MouseAxisY-".equals(string)) { + moved = true; + movedR = true; + if (isToolUsesCameraControls() || forceCameraControls) { + if (buttonDownL) { + rotateCamera(cam.getLeft(), f1 * 2.5f); + } + if (buttonDownR) { + panCamera(0, f1 * 2.5f); + } } - checkClickR = false; + } else if ("MouseWheel".equals(string)) { + zoomCamera(.1f); + } else if ("MouseWheel-".equals(string)) { + zoomCamera(-.1f); } } + + } diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerToolController.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerToolController.java new file mode 100644 index 000000000..c17001042 --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerToolController.java @@ -0,0 +1,179 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer; + +import com.jme3.asset.AssetManager; +import com.jme3.gde.core.scene.SceneApplication; +import com.jme3.gde.core.scene.controller.SceneToolController; +import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.renderer.RenderManager; +import com.jme3.renderer.ViewPort; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import java.util.concurrent.Callable; + +/** + * + * @author Brent Owens + */ +public class SceneComposerToolController extends SceneToolController { + + private JmeNode rootNode; + private SceneEditTool editTool; + private SceneEditorController editorController; + private ComposerCameraController cameraController; + private Camera overlayCam; + private ViewPort overlayView; + private Node onTopToolsNode; + + public SceneComposerToolController(Node toolsNode, AssetManager manager, JmeNode rootNode) { + super(toolsNode, manager); + this.rootNode = rootNode; + } + + public SceneComposerToolController(AssetManager manager) { + super(manager); + } + + public void setEditorController(SceneEditorController editorController) { + this.editorController = editorController; + } + + public void setCameraController(ComposerCameraController cameraController) { + this.cameraController = cameraController; + + // a node in a viewport that will always render on top + onTopToolsNode = new Node("OverlayNode"); + overlayView = SceneApplication.getApplication().getRenderManager().createMainView("Overlay", this.cameraController.getCamera()); + overlayView.setClearFlags(false, true, false); + overlayView.attachScene( onTopToolsNode ); + } + + @Override + public void cleanup() { + super.cleanup(); + SceneApplication.getApplication().getRenderManager().removeMainView(overlayView); + cameraController = null; + editorController = null; + onTopToolsNode.detachAllChildren(); + } + + @Override + public void update(float tpf) { + super.update(tpf); + if (onTopToolsNode != null) { + onTopToolsNode.updateLogicalState(tpf); + onTopToolsNode.updateGeometricState(); + } + if (editTool != null) + editTool.updateToolsTransformation(selected); + + } + + @Override + public void render(RenderManager rm) { + super.render(rm); + } + + public boolean isEditToolEnabled() { + return editTool != null; + } + + /** + * If the current tool overrides camera zoom/pan controls + */ + public boolean isOverrideCameraControl() { + if (editTool != null) + return editTool.isOverrideCameraControl(); + else + return false; + } + + /** + * Scene composer edit tool activated. Pass in null to remove tools. + * + * @param sceneEditButton pass in null to hide any existing tool markers + */ + public void showEditTool(final SceneEditTool sceneEditTool) { + SceneApplication.getApplication().enqueue(new Callable() { + public Object call() throws Exception { + doEnableEditTool(sceneEditTool); + return null; + } + }); + } + + private void doEnableEditTool(SceneEditTool sceneEditTool) { + if (editTool != null) + editTool.hideMarker(); + editTool = sceneEditTool; + editTool.activate(manager, toolsNode, onTopToolsNode, selected, this); + } + + public void selectedSpatialTransformed() { + if (editTool != null) { + SceneApplication.getApplication().enqueue(new Callable() { + public Object call() throws Exception { + editTool.updateToolsTransformation(selected); + return null; + } + }); + } + } + + public void setSelected(Spatial selected) { + this.selected = selected; + } + + public void setNeedsSave(boolean needsSave) { + editorController.setNeedsSave(needsSave); + } + + /** + * Primary button activated, send command to the tool + * for appropriate action. + */ + public void doEditToolActivatedPrimary(Vector2f mouseLoc, boolean pressed, Camera camera) { + if (editTool != null){ + editTool.setCamera(camera); + editTool.actionPrimary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); + } + } + + /** + * Secondary button activated, send command to the tool + * for appropriate action. + */ + public void doEditToolActivatedSecondary(Vector2f mouseLoc, boolean pressed, Camera camera) { + if (editTool != null){ + editTool.setCamera(camera); + editTool.actionSecondary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); + } + } + + public void doEditToolMoved(Vector2f mouseLoc, Camera camera) { + if (editTool != null){ + editTool.setCamera(camera); + editTool.mouseMoved(mouseLoc); + } + } + + public void doEditToolDraggedPrimary(Vector2f mouseLoc, boolean pressed, Camera camera) { + if (editTool != null) { + editTool.setCamera(camera); + editTool.draggedPrimary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); + } + } + + public void doEditToolDraggedSecondary(Vector2f mouseLoc, boolean pressed, Camera camera) { + if (editTool != null){ + editTool.setCamera(camera); + editTool.draggedSecondary(mouseLoc, pressed, rootNode, editorController.getCurrentDataObject()); + } + } +} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.form b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.form index c8d7ccaca..71846046c 100644 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.form +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.form @@ -1,6 +1,13 @@
+ + + + + + + @@ -28,7 +35,7 @@ - + @@ -73,7 +80,7 @@ - + @@ -117,7 +124,7 @@ - + @@ -151,6 +158,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -332,12 +426,12 @@ - + - + diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java index 7cce546fe..4a9e97ec0 100644 --- a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneComposerTopComponent.java @@ -12,15 +12,17 @@ import com.jme3.gde.core.scene.PreviewRequest; import com.jme3.gde.core.scene.SceneApplication; import com.jme3.gde.core.scene.SceneListener; import com.jme3.gde.core.scene.SceneRequest; -import com.jme3.gde.core.scene.controller.SceneToolController; import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial; import com.jme3.gde.core.sceneexplorer.nodes.NodeUtility; +import com.jme3.gde.scenecomposer.tools.MoveTool; +import com.jme3.gde.scenecomposer.tools.SelectTool; import com.jme3.math.Vector3f; import com.jme3.scene.Node; import com.jme3.scene.Spatial; import java.util.Collection; import java.util.logging.Logger; +import javax.swing.ButtonGroup; import javax.swing.border.TitledBorder; import org.openide.util.Lookup.Result; import org.openide.util.LookupEvent; @@ -55,7 +57,7 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce private static final String PREFERRED_ID = "SceneComposerTopComponent"; private final Result result; ComposerCameraController camController; - SceneToolController toolController; + SceneComposerToolController toolController; SceneEditorController editorController; // private SaveCookie saveCookie = new SaveCookieImpl(); private SceneRequest currentRequest; @@ -77,6 +79,7 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce // //GEN-BEGIN:initComponents private void initComponents() { + spatialModButtonGroup = new ButtonGroup(); sceneInfoPanel = new javax.swing.JPanel(); sceneInfoLabel1 = new javax.swing.JLabel(); sceneInfoLabel2 = new javax.swing.JLabel(); @@ -84,6 +87,11 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce jScrollPane1 = new javax.swing.JScrollPane(); jList1 = new javax.swing.JList(); jToolBar1 = new javax.swing.JToolBar(); + selectButton = new javax.swing.JToggleButton(); + moveButton = new javax.swing.JToggleButton(); + rotateButton = new javax.swing.JToggleButton(); + scaleButton = new javax.swing.JToggleButton(); + jSeparator5 = new javax.swing.JToolBar.Separator(); addObjectButton = new javax.swing.JButton(); addCursorButton = new javax.swing.JButton(); moveToCursorButton = new javax.swing.JButton(); @@ -134,7 +142,7 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce .addComponent(sceneInfoLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(sceneInfoLabel2) - .addContainerGap(93, Short.MAX_VALUE)) + .addContainerGap(105, Short.MAX_VALUE)) ); palettePanel.setBackground(new java.awt.Color(204, 204, 204)); @@ -150,13 +158,63 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce ); palettePanelLayout.setVerticalGroup( palettePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 133, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 139, Short.MAX_VALUE) ); jToolBar1.setBackground(new java.awt.Color(204, 204, 204)); jToolBar1.setFloatable(false); jToolBar1.setRollover(true); + spatialModButtonGroup.add(selectButton); + selectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/scenecomposer/icon_select.png"))); // NOI18N + selectButton.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(selectButton, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.selectButton.text")); // NOI18N + selectButton.setToolTipText(org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.selectButton.toolTipText")); // NOI18N + selectButton.setFocusable(false); + selectButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectButtonActionPerformed(evt); + } + }); + jToolBar1.add(selectButton); + + spatialModButtonGroup.add(moveButton); + moveButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/scenecomposer/icon_arrow_out.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(moveButton, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.moveButton.text")); // NOI18N + moveButton.setToolTipText(org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.moveButton.toolTipText")); // NOI18N + moveButton.setFocusable(false); + moveButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + moveButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + moveButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + moveButtonActionPerformed(evt); + } + }); + jToolBar1.add(moveButton); + + spatialModButtonGroup.add(rotateButton); + rotateButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/scenecomposer/icon_arrow_rotate_clockwise.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(rotateButton, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.rotateButton.text")); // NOI18N + rotateButton.setToolTipText(org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.rotateButton.toolTipText")); // NOI18N + rotateButton.setEnabled(false); + rotateButton.setFocusable(false); + rotateButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + rotateButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + jToolBar1.add(rotateButton); + + spatialModButtonGroup.add(scaleButton); + scaleButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/scenecomposer/icon_arrow_inout.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(scaleButton, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.scaleButton.text")); // NOI18N + scaleButton.setToolTipText(org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.scaleButton.toolTipText")); // NOI18N + scaleButton.setEnabled(false); + scaleButton.setFocusable(false); + scaleButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + scaleButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + jToolBar1.add(scaleButton); + jToolBar1.add(jSeparator5); + addObjectButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/scenecomposer/add.gif"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(addObjectButton, org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.addObjectButton.text")); // NOI18N addObjectButton.setToolTipText(org.openide.util.NbBundle.getMessage(SceneComposerTopComponent.class, "SceneComposerTopComponent.addObjectButton.toolTipText")); // NOI18N @@ -274,11 +332,11 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce jPanel3.setLayout(jPanel3Layout); jPanel3Layout.setHorizontalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 190, Short.MAX_VALUE) + .addGap(0, 211, Short.MAX_VALUE) ); jPanel3Layout.setVerticalGroup( jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 21, Short.MAX_VALUE) + .addGap(0, 23, Short.MAX_VALUE) ); jToolBar1.add(jPanel3); @@ -357,7 +415,7 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(sceneInfoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 696, Short.MAX_VALUE) + .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 708, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -400,6 +458,7 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce private void moveToCursorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_moveToCursorButtonActionPerformed if (editorController != null) { editorController.moveSelectedSpatial(toolController.getCursorLocation()); + toolController.selectedSpatialTransformed(); } }//GEN-LAST:event_moveToCursorButtonActionPerformed @@ -442,6 +501,17 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce } }//GEN-LAST:event_jButton1ActionPerformed + + private void selectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectButtonActionPerformed + SelectTool tool = new SelectTool(); + toolController.showEditTool(tool); + }//GEN-LAST:event_selectButtonActionPerformed + + private void moveButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_moveButtonActionPerformed + MoveTool tool = new MoveTool(); + toolController.showEditTool(tool); + }//GEN-LAST:event_moveButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton addCursorButton; private javax.swing.JButton addObjectButton; @@ -464,19 +534,25 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce private javax.swing.JToolBar.Separator jSeparator2; private javax.swing.JToolBar.Separator jSeparator3; private javax.swing.JToolBar.Separator jSeparator4; + private javax.swing.JToolBar.Separator jSeparator5; private javax.swing.JTextField jTextField1; private javax.swing.JToolBar jToolBar1; private javax.swing.JToolBar jToolBar2; private javax.swing.JToolBar jToolBar3; + private javax.swing.JToggleButton moveButton; private javax.swing.JButton moveToCursorButton; private javax.swing.JPanel palettePanel; private javax.swing.JSpinner radiusSpinner; private javax.swing.JButton resetCursorButton; + private javax.swing.JToggleButton rotateButton; + private javax.swing.JToggleButton scaleButton; private javax.swing.JLabel sceneInfoLabel1; private javax.swing.JLabel sceneInfoLabel2; private javax.swing.JPanel sceneInfoPanel; + private javax.swing.JToggleButton selectButton; private javax.swing.JToggleButton showGridToggleButton; private javax.swing.JToggleButton showSelectionToggleButton; + private javax.swing.ButtonGroup spatialModButtonGroup; // End of variables declaration//GEN-END:variables /** @@ -811,10 +887,16 @@ public final class SceneComposerTopComponent extends TopComponent implements Sce if (toolController != null) { toolController.cleanup(); } - toolController = new SceneToolController(currentRequest.getToolNode(), currentRequest.getManager()); + toolController = new SceneComposerToolController(currentRequest.getToolNode(), currentRequest.getManager(), request.getJmeNode()); camController = new ComposerCameraController(SceneApplication.getApplication().getCamera(), request.getJmeNode()); + toolController.setEditorController(editorController); + camController.setToolController(toolController); camController.setMaster(this); camController.enable(); + + toolController.setCameraController(camController); + SelectTool tool = new SelectTool(); + toolController.showEditTool(tool); }/* else { SceneApplication.getApplication().removeSceneListener(this); currentRequest = null; diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneEditTool.java b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneEditTool.java new file mode 100644 index 000000000..8281527f8 --- /dev/null +++ b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/SceneEditTool.java @@ -0,0 +1,508 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package com.jme3.gde.scenecomposer; + + +import com.jme3.asset.AssetManager; +import com.jme3.bounding.BoundingBox; +import com.jme3.bounding.BoundingVolume; +import com.jme3.bullet.collision.PhysicsCollisionObject; +import com.jme3.bullet.control.CharacterControl; +import com.jme3.bullet.control.GhostControl; +import com.jme3.bullet.control.PhysicsControl; +import com.jme3.bullet.control.RigidBodyControl; +import com.jme3.bullet.control.VehicleControl; +import com.jme3.bullet.util.DebugShapeFactory; +import com.jme3.collision.CollisionResult; +import com.jme3.collision.CollisionResults; +import com.jme3.gde.core.scene.SceneApplication; +import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; +import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; +import com.jme3.gde.core.undoredo.SceneUndoRedoManager; +import com.jme3.material.Material; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.material.RenderState.FaceCullMode; +import com.jme3.math.ColorRGBA; +import com.jme3.math.FastMath; +import com.jme3.math.Matrix3f; +import com.jme3.math.Quaternion; +import com.jme3.math.Ray; +import com.jme3.math.Transform; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.Camera; +import com.jme3.scene.Geometry; +import com.jme3.scene.Mesh; +import com.jme3.scene.Node; +import com.jme3.scene.Spatial; +import com.jme3.scene.debug.Arrow; +import com.jme3.scene.debug.WireBox; +import com.jme3.scene.shape.Quad; +import java.util.concurrent.Callable; +import org.openide.loaders.DataObject; +import org.openide.util.Lookup; + +/** + * + * @author Brent Owens + */ +public abstract class SceneEditTool { + + protected SceneComposerToolController toolController; + protected AssetManager manager; + protected Camera camera; + private boolean overrideCameraControl = false; // if true, you cannot pan/zoom unless you hold SHIFT + + // the key to load the tool hint text from the resource bundle + protected String toolHintTextKey = "SceneComposerTopComponent.toolHint.default"; // not used yet + + protected Spatial selectedSpatial; + protected Spatial selectionShape; + protected Node toolNode; + protected Node onTopToolNode; + + protected Node axisMarker; + protected Material redMat, blueMat, greenMat, yellowMat, cyanMat, magentaMat, orangeMat; + + protected enum AxisMarkerPickType {axisOnly, planeOnly, axisAndPlane}; + protected AxisMarkerPickType axisPickType; + + + /** + * The tool was selected, start showing the marker. + * @param manager + * @param toolNode: parent node that the marker will attach to + */ + public void activate(AssetManager manager, Node toolNode, Node onTopToolNode, Spatial selectedSpatial, SceneComposerToolController toolController) { + this.manager = manager; + this.toolController = toolController; + this.selectedSpatial = selectedSpatial; + addMarker(toolNode, onTopToolNode); + } + + protected void addMarker(Node toolNode, Node onTopToolNode) { + this.toolNode = toolNode; + this.onTopToolNode = onTopToolNode; + + if (axisMarker == null) { + axisMarker = createAxisMarker(); + } + axisMarker.removeFromParent(); + this.onTopToolNode.attachChild(axisMarker); + setDefaultAxisMarkerColors(); + + // create and add the selection shape + if (selectionShape != null) + selectionShape.removeFromParent(); + + selectionShape = createSelectionShape(toolNode, selectedSpatial); + + if (selectionShape != null) { + setDefaultSelectionShapeColors(); + this.toolNode.attachChild(selectionShape); + axisMarker.setLocalTranslation(selectedSpatial.getWorldTranslation()); + selectionShape.setLocalTranslation(selectedSpatial.getWorldTranslation()); + } + + } + + protected void replaceSelectionShape(Spatial spatial) { + if (spatial != null) { + if (selectionShape != null) + selectionShape.removeFromParent(); + selectedSpatial = spatial; + toolController.setSelected(spatial); + selectionShape = createSelectionShape(toolNode, selectedSpatial); + setDefaultSelectionShapeColors(); + toolNode.attachChild(selectionShape); + } + else { + if (selectionShape != null) + selectionShape.removeFromParent(); + selectionShape = null; + } + } + + /** + * Remove the marker from it's parent (the tools node) + */ + public void hideMarker() { + if (axisMarker != null) + axisMarker.removeFromParent(); + if (selectionShape != null) + selectionShape.removeFromParent(); + } + + public boolean isOverrideCameraControl() { + return overrideCameraControl; + } + + public void setOverrideCameraControl(boolean overrideCameraControl) { + this.overrideCameraControl = overrideCameraControl; + } + + /** + * Called when the selected spatial has been modified + * outside of the tool. + */ + public void updateToolsTransformation(final Spatial spatial) { + + if (selectionShape == null) + return; + + // has anything changed? + if (!selectionShape.getLocalTranslation().equals(spatial.getWorldTranslation()) && + !selectionShape.getLocalRotation().equals(spatial.getWorldRotation()) && + !selectionShape.getLocalScale().equals(spatial.getWorldScale())) + return; + + // something has updated, so update the tools + selectionShape.setLocalTranslation(spatial.getWorldTranslation()); + selectionShape.setLocalRotation(spatial.getWorldRotation()); + selectionShape.setLocalScale(selectedSpatial.getWorldScale()); + + SceneApplication.getApplication().enqueue(new Callable() { + public Object call() throws Exception { + axisMarker.setLocalTranslation(spatial.getWorldTranslation()); + axisMarker.setLocalRotation(selectedSpatial.getWorldRotation()); + return null; + } + }); + } + + /** + * The primary action for the tool gets activated + */ + public abstract void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject); + + /** + * The secondary action for the tool gets activated + */ + public abstract void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject); + + /** + * Called when the mouse is moved but not dragged (ie no buttons are pressed) + */ + public abstract void mouseMoved(Vector2f screenCoord); + + /** + * Called when the mouse is moved while the primary button is down + */ + public abstract void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject); + + /** + * Called when the mouse is moved while the secondary button is down + */ + public abstract void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject); + + /** + * Call when an action is performed that requires the scene to be saved + * and an undo can be performed + * @param undoer your implementation, probably with a begin and end state for undoing + */ + protected void actionPerformed(AbstractUndoableSceneEdit undoer) { + Lookup.getDefault().lookup(SceneUndoRedoManager.class).addEdit(this, undoer); + toolController.setNeedsSave(true); + } + + + /** + * Given the mouse coordinates, pick the geometry that is closest to the camera. + * @param jmeRootNode to pick from + * @return the selected spatial, or null if nothing + */ + protected Spatial pickWorldSpatial(Camera cam, Vector2f mouseLoc, JmeNode jmeRootNode) { + Node rootNode = jmeRootNode.getLookup().lookup(Node.class); + CollisionResult cr = pick(cam, mouseLoc, rootNode); + if (cr != null) + return cr.getGeometry(); + else + return null; + } + + /** + * Given the mouse coordinate, pick the world location where the mouse intersects + * a geometry. + * @param jmeRootNode to pick from + * @return the location of the pick, or null if nothing collided with the mouse + */ + protected Vector3f pickWorldLocation(Camera cam, Vector2f mouseLoc, JmeNode jmeRootNode) { + Node rootNode = jmeRootNode.getLookup().lookup(Node.class); + return pickWorldLocation(cam, mouseLoc, rootNode); + } + + + protected Vector3f pickWorldLocation(Camera cam, Vector2f mouseLoc, Node rootNode) { + CollisionResult cr = pick(cam, mouseLoc, rootNode); + if (cr != null) + return cr.getContactPoint(); + else + return null; + } + + /** + * Pick a part of the axis marker. The result is a Vector3f that represents + * what part of the axis was selected. + * For example if (1,0,0) is returned, then the X-axis pole was selected. + * If (0,1,1) is returned, then the Y-Z plane was selected. + * + * @return null if it did not intersect the marker + */ + protected Vector3f pickAxisMarker(Camera cam, Vector2f mouseLoc, AxisMarkerPickType pickType) { + if (axisMarker == null) + return null; + + CollisionResult cr = pick(cam, mouseLoc, axisMarker); + if (cr == null || cr.getGeometry() == null) + return null; + + if (pickType == AxisMarkerPickType.planeOnly) { + if ("quadXY".equals(cr.getGeometry().getName()) ) { + return new Vector3f(1,1,0); + } else if ("quadXZ".equals(cr.getGeometry().getName()) ) { + return new Vector3f(1,0,1); + } else if ("quadYZ".equals(cr.getGeometry().getName()) ) { + return new Vector3f(0,1,1); + } + } + else if (pickType == AxisMarkerPickType.axisOnly) { + if ("arrowX".equals(cr.getGeometry().getName()) ) { + return new Vector3f(1,0,0); + } else if ("arrowY".equals(cr.getGeometry().getName()) ) { + return new Vector3f(0,1,0); + } else if ("arrowZ".equals(cr.getGeometry().getName()) ) { + return new Vector3f(0,1,0); + } + } else if (pickType == AxisMarkerPickType.axisAndPlane) { + if ("arrowX".equals(cr.getGeometry().getName()) ) { + return new Vector3f(1,0,0); + } else if ("arrowY".equals(cr.getGeometry().getName()) ) { + return new Vector3f(0,1,0); + } else if ("arrowZ".equals(cr.getGeometry().getName()) ) { + return new Vector3f(0,1,0); + } else if ("quadXY".equals(cr.getGeometry().getName()) ) { + return new Vector3f(1,1,0); + } else if ("quadXZ".equals(cr.getGeometry().getName()) ) { + return new Vector3f(1,0,1); + } else if ("quadYZ".equals(cr.getGeometry().getName()) ) { + return new Vector3f(0,1,1); + } + } + return null; + } + + private CollisionResult pick(Camera cam, Vector2f mouseLoc, Node node) { + CollisionResults results = new CollisionResults(); + Ray ray = new Ray(); + Vector3f pos = cam.getWorldCoordinates(mouseLoc, 0).clone(); + Vector3f dir = cam.getWorldCoordinates(mouseLoc, 0.1f).clone(); + dir.subtractLocal(pos).normalizeLocal(); + ray.setOrigin(pos); + ray.setDirection(dir); + node.collideWith(ray, results); + CollisionResult result = results.getClosestCollision(); + return result; + } + + /** + * Show what axis or plane the mouse is currently over and will affect. + * @param axisMarkerPickType + */ + protected void highlightAxisMarker(Camera camera, Vector2f screenCoord, AxisMarkerPickType axisMarkerPickType) { + setDefaultAxisMarkerColors(); + Vector3f picked = pickAxisMarker(camera, screenCoord, axisPickType); + if (picked == null) + return; + + if (picked.equals(new Vector3f(1,0,0))) + axisMarker.getChild("arrowX").setMaterial(orangeMat); + else if (picked.equals(new Vector3f(0,1,0))) + axisMarker.getChild("arrowY").setMaterial(orangeMat); + else if (picked.equals(new Vector3f(0,0,1))) + axisMarker.getChild("arrowZ").setMaterial(orangeMat); + else if (picked.equals(new Vector3f(1,1,0))) + axisMarker.getChild("quadXY").setMaterial(orangeMat); + else if (picked.equals(new Vector3f(1,0,1))) + axisMarker.getChild("quadXZ").setMaterial(orangeMat); + else if (picked.equals(new Vector3f(0,1,1))) + axisMarker.getChild("quadYZ").setMaterial(orangeMat); + } + + /** + * Create the axis marker that is selectable + */ + protected Node createAxisMarker() { + float size = 2; + float arrowSize = size; + float planeSize = size*0.7f; + + Quaternion YAW090 = new Quaternion().fromAngleAxis(-FastMath.PI/2, new Vector3f(0,1,0)); + Quaternion PITCH090 = new Quaternion().fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0)); + + redMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + redMat.getAdditionalRenderState().setWireframe(true); + redMat.setColor("Color", ColorRGBA.Red); + //redMat.getAdditionalRenderState().setDepthTest(false); + greenMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + greenMat.getAdditionalRenderState().setWireframe(true); + greenMat.setColor("Color", ColorRGBA.Green); + //greenMat.getAdditionalRenderState().setDepthTest(false); + blueMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + blueMat.getAdditionalRenderState().setWireframe(true); + blueMat.setColor("Color", ColorRGBA.Blue); + //blueMat.getAdditionalRenderState().setDepthTest(false); + yellowMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + yellowMat.getAdditionalRenderState().setWireframe(false); + yellowMat.setColor("Color", new ColorRGBA(1f, 1f, 0f, 0.25f)); + yellowMat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + yellowMat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); + //yellowMat.getAdditionalRenderState().setDepthTest(false); + cyanMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + cyanMat.getAdditionalRenderState().setWireframe(false); + cyanMat.setColor("Color", new ColorRGBA(0f, 1f, 1f, 0.25f)); + cyanMat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + cyanMat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); + //cyanMat.getAdditionalRenderState().setDepthTest(false); + magentaMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + magentaMat.getAdditionalRenderState().setWireframe(false); + magentaMat.setColor("Color", new ColorRGBA(1f, 0f, 1f, 0.25f)); + magentaMat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + magentaMat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); + //magentaMat.getAdditionalRenderState().setDepthTest(false); + + orangeMat = new Material(manager, "Common/MatDefs/Misc/Unshaded.j3md"); + orangeMat.getAdditionalRenderState().setWireframe(false); + orangeMat.setColor("Color", new ColorRGBA(251f/255f, 130f/255f, 0f, 0.4f)); + orangeMat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + orangeMat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); + + Node axis = new Node(); + + // create arrows + Geometry arrowX = new Geometry("arrowX", new Arrow(new Vector3f(arrowSize,0,0))); + Geometry arrowY = new Geometry("arrowY", new Arrow(new Vector3f(0,arrowSize,0))); + Geometry arrowZ = new Geometry("arrowZ", new Arrow(new Vector3f(0,0,arrowSize))); + axis.attachChild(arrowX); + axis.attachChild(arrowY); + axis.attachChild(arrowZ); + + // create planes + Geometry quadXY = new Geometry("quadXY", new Quad(planeSize, planeSize) ); + Geometry quadXZ = new Geometry("quadXZ", new Quad(planeSize, planeSize) ); + quadXZ.setLocalRotation(PITCH090); + Geometry quadYZ = new Geometry("quadYZ", new Quad(planeSize, planeSize) ); + quadYZ.setLocalRotation(YAW090); + axis.attachChild(quadXY); + axis.attachChild(quadXZ); + axis.attachChild(quadYZ); + + axis.setModelBound(new BoundingBox()); + return axis; + } + + protected void setDefaultAxisMarkerColors() { + axisMarker.getChild("arrowX").setMaterial(redMat); + axisMarker.getChild("arrowY").setMaterial(blueMat); + axisMarker.getChild("arrowZ").setMaterial(greenMat); + axisMarker.getChild("quadXY").setMaterial(yellowMat); + axisMarker.getChild("quadXZ").setMaterial(magentaMat); + axisMarker.getChild("quadYZ").setMaterial(cyanMat); + } + + protected void setDefaultSelectionShapeColors() { + if (selectionShape != null) { + Material mat = new Material(SceneApplication.getApplication().getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md"); + mat.getAdditionalRenderState().setWireframe(true); + mat.setColor("Color", new ColorRGBA(0.8f,0.8f,0.8f,0.3f)); + mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + selectionShape.setMaterial(mat); + } + } + + protected Spatial createSelectionShape(Node toolNode, Spatial spat) { + if (spat == null) + return null; + if (selectionShape != null) { + selectionShape.removeFromParent(); + selectionShape = null; + } + if (spat instanceof Geometry) { + return getGeometrySelection(toolNode, (Geometry) spat); + } else if (spat.getControl(PhysicsControl.class) != null) { + return getPhysicsSelection(toolNode, spat); + } else { + return getBoxSelection(toolNode, spat); + } + } + + protected Geometry getGeometrySelection(Node toolNode, Geometry geom) { + Mesh mesh = geom.getMesh(); + if (mesh == null) { + return null; + } + Geometry selectionGeometry = new Geometry("selection_geometry_sceneviewer", mesh); + selectionGeometry.setLocalTransform(geom.getWorldTransform()); + toolNode.attachChild(selectionGeometry); + return selectionGeometry; + } + + protected Geometry getBoxSelection(Node toolNode, Spatial geom) { + BoundingVolume bound = geom.getWorldBound(); + if (bound instanceof BoundingBox) { + BoundingBox bbox = (BoundingBox) bound; + Vector3f extent = new Vector3f(); + bbox.getExtent(extent); + WireBox wireBox=new WireBox(); + wireBox.fromBoundingBox(bbox); + Geometry selectionGeometry = new Geometry("selection_geometry_sceneviewer", wireBox); + selectionGeometry.setLocalTransform(geom.getWorldTransform()); + toolNode.attachChild(selectionGeometry); + return selectionGeometry; + } + return null; + } + + protected Spatial getPhysicsSelection(Node toolNode, Spatial geom) { + PhysicsCollisionObject control = geom.getControl(RigidBodyControl.class); + if (control == null) { + control = geom.getControl(VehicleControl.class); + } + if (control == null) { + control = geom.getControl(GhostControl.class); + } + if (control == null) { + control = geom.getControl(CharacterControl.class); + } + if (control == null) { + return null; + } + Spatial selectionGeometry = DebugShapeFactory.getDebugShape(control.getCollisionShape()); + if (selectionGeometry != null) { + selectionGeometry.setLocalTransform(geom.getWorldTransform()); + toolNode.attachChild(selectionGeometry); + return selectionGeometry; + } + return null; + } + + protected void detachSelectionShape() { + if (selectionShape != null) { + selectionShape.removeFromParent(); + selectionShape = null; + } + } + + + public Camera getCamera() { + return camera; + } + + public void setCamera(Camera camera) { + this.camera = camera; + } + + + +} diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_arrow_inout.png b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_arrow_inout.png new file mode 100644 index 0000000000000000000000000000000000000000..82ca9d58fd905fbd71a6ec68533d74abc08f68b4 GIT binary patch literal 570 zcmV-A0>%A_P)1 z9%>yrxV53U+2W=kI_p$Smp~PvYqMG?Hl>RPPD;mA>C~kaii3l0;viOXL7}9@ixCu? zTzsGOPA+M<7e3xE-}Aip{yj0K-r?f5hNM>qVg}F=6R#k*|E=bs{GrF zug||n)$>rk>BQn%#x@835yHj=BC#eT!RgKxwf;ruv)#TdrwFUxqslE+_5 zwr-@gDZO@_HqC%{z7Z3SRlR_{^A=fwY-4)WACgR%nZ(180Ph;#6TNs&?B){RR2QB# zdRC1s(Kk})Ad6o~*xcabU*BLsTrvy>*nI_UcKlf~&H7kg);-fsD>`DwGjV?o3=Xv7 zidL3FTG3HE4(whlCpi>LaGJCdwPO~*6KI7PIbp4+s2y_~hTk*ah!slBTG3HE4h9_7 z3VNEgVoa`};2E&m?YPxiwIZ!mNF0?DZ{hBvy*+OIhu;Y>0Ki`m(ok5G3jhEB07*qo IM6N<$f{Zu;vj6}9 literal 0 HcmV?d00001 diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_arrow_out.png b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_arrow_out.png new file mode 100644 index 0000000000000000000000000000000000000000..0609b3e1abe43c0455b3a05b3f98f52fd56ea941 GIT binary patch literal 632 zcmV-;0*C#HP)7U z1b;xM8w+Jag=mD4U?D;1LL?&fV`-~1T4LdMB4I~l7E-z?7B+ni3sxj0sfCR;L718M z?)80do|>6X6DK*j@165~=bn4dcg^k!=Ib#Ei3bdTzyi4-UG=+YiGyz>=?X6#vnxVW zLy_+uxsFDXz#5AmwH!ts4Z~V2R`AUNsFZGCb-n@T9XAPZ?Ea~t&@nro%;NQj3PO^e zOal`mDDJs}whD?_I~?up2Vxf6yx}aw4J|&nYsv{DtT^I^y0qu7=J1p)*6WB=b>bX~Lu3DlCW~>2)b_LU zD8{36QIOqJpFoFiVdmk9<~PYR-8!hAS&B8SJN=JoBE5Owd#$-Uo4{7jsN7|~oVg75 z*J;~A&UY#mhle2`4O1XS=j#v>sF{@4!+e~;3uCDtln>t2MfuxDui@VDt7r(=(uuwm zQ|=BiKYzoIk|VBFTW`LeL}?2!`SCQq#j|M}zT@0-<%HQkz%h~|ZrZ3{#q;$5o7U~a zg$Lu9%00000GaTv!xXHy1EQb%N{ zm1Gg2`L+u&N+d09X)kmk(H{^9(T$cMAyK3_tqi&nBj_S85`^AXVK>>0O1ednW-U#( zT)DZ)e3_f4-#PB&ETSIHbNKQ6p6~a0Io~76vWz52C|1>mF)Y&=iBKJpL0q9+=_MBR zdRm{>a*3!ZIK?E5pt6ngp)fad(sy$r?-W~2+m$pWg|FUmdWO4kOpdsoUnK1hf@9aE zasjqg@Tp{U%H+N5{)2Ed5Lx(W^LO+@!nkw zO*i582C#pE7kad~~uQOF|bzTuLbsXL5K*U!R=Hp!I!m|{hcL+v? zxi-*4_1o9f_P&8{3js!hU6dB&A$C-!?IJG961ef8d*h1eN+*^!^O5@g4m!nEP`II} zhGfSk8jAP%(Hp-g%QdVccvMHRc8=O-;lAj3VI_nuI8TGLA}TF9NieP@Y9PB7IATQ> zT}(f&Ws4R|%phljQZpo;$Si{Fm+4}vQrd)UJ#&|o#LN^eR?))Q%OF_?4FuHjT2SgewK&Qe1l ze4p6`A4M6LMU{x6A%Y<{A3PnZBHxM4IL7#Ht0!CFJnK5}E{`K6gwctr{oY1&`qeKY zi6Q-Bd5-rmitQ00000NkvXXu0mjf`lnDe literal 0 HcmV?d00001 diff --git a/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_select.png b/sdk/jme3-scenecomposer/src/com/jme3/gde/scenecomposer/icon_select.png new file mode 100644 index 0000000000000000000000000000000000000000..23cb917925348b454a10e2cd98c2ef53f82239b0 GIT binary patch literal 3052 zcmVKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0003ONklS>`y7lXaQ2_FyuZY-N``&s$A84fYd;;dzrTgHtBG z4fainqHu=8;S#vtubFK|0ISuCBuP+8QP=fmFc@3`8h8L6Pd?#ij9P0+(^M9Vg#a_) z8n6MY&mwJrSrkQ|Wm!rP1YdyDYms)VJO)roEk#7;^SPL&`P3J1^V=ZP98afHX_`iC u+kWl~IEdEz#rOSJ!!TxT0Cnki{vH78K26t6#KF7(0000