* 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-0572b91ccdca3.0
parent
6c80e0a558
commit
dda8ee2c38
@ -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<Object>() { |
||||||
|
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<Object>() { |
||||||
|
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()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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<Object>() { |
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
After Width: | Height: | Size: 570 B |
After Width: | Height: | Size: 632 B |
After Width: | Height: | Size: 741 B |
After Width: | Height: | Size: 3.0 KiB |
@ -0,0 +1,160 @@ |
|||||||
|
/* |
||||||
|
* To change this template, choose Tools | Templates |
||||||
|
* and open the template in the editor. |
||||||
|
*/ |
||||||
|
package com.jme3.gde.scenecomposer.tools; |
||||||
|
|
||||||
|
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; |
||||||
|
import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit; |
||||||
|
import com.jme3.gde.scenecomposer.SceneEditTool; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import com.jme3.math.FastMath; |
||||||
|
import com.jme3.math.Quaternion; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.scene.Geometry; |
||||||
|
import com.jme3.scene.Node; |
||||||
|
import com.jme3.scene.Spatial; |
||||||
|
import com.jme3.scene.shape.Quad; |
||||||
|
import org.openide.loaders.DataObject; |
||||||
|
|
||||||
|
/** |
||||||
|
* Move an object. |
||||||
|
* When created, it generates a quad that will lie along a plane |
||||||
|
* that the user selects for moving on. When the mouse is over |
||||||
|
* the axisMarker, it will highlight the plane that it is over: XY,XZ,YZ. |
||||||
|
* When clicked and then dragged, the selected object will move along that |
||||||
|
* plane. |
||||||
|
* @author Brent Owens |
||||||
|
*/ |
||||||
|
public class MoveTool extends SceneEditTool { |
||||||
|
|
||||||
|
private Vector3f pickedPlane; |
||||||
|
private Vector3f startLoc; |
||||||
|
private Vector3f lastLoc; |
||||||
|
private boolean wasDragging = false; |
||||||
|
private Vector3f offset; |
||||||
|
private Node plane; |
||||||
|
Material pinkMat; |
||||||
|
private final Quaternion XY = new Quaternion().fromAngleAxis(0, new Vector3f(1,0,0)); |
||||||
|
private final Quaternion YZ = new Quaternion().fromAngleAxis(-FastMath.PI/2, new Vector3f(0,1,0)); |
||||||
|
private final Quaternion XZ = new Quaternion().fromAngleAxis(FastMath.PI/2, new Vector3f(1,0,0)); |
||||||
|
|
||||||
|
|
||||||
|
public MoveTool() { |
||||||
|
axisPickType = AxisMarkerPickType.planeOnly; |
||||||
|
setOverrideCameraControl(true); |
||||||
|
|
||||||
|
float size = 1000; |
||||||
|
Geometry g = new Geometry("plane", new Quad(size, size)); |
||||||
|
g.setLocalTranslation(-size/2, -size/2, 0); |
||||||
|
plane = new Node(); |
||||||
|
plane.attachChild(g); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void actionPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||||
|
if (!pressed) { |
||||||
|
setDefaultAxisMarkerColors(); |
||||||
|
pickedPlane = null; // mouse released, reset selection
|
||||||
|
offset = null; |
||||||
|
if (wasDragging) { |
||||||
|
actionPerformed(new MoveUndo(selectedSpatial, startLoc, lastLoc)); |
||||||
|
wasDragging = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void actionSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject dataObject) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseMoved(Vector2f screenCoord) { |
||||||
|
if (pickedPlane == null) { |
||||||
|
highlightAxisMarker(camera, screenCoord, axisPickType); |
||||||
|
} |
||||||
|
else { |
||||||
|
pickedPlane = null; |
||||||
|
offset = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||||
|
if (!pressed) { |
||||||
|
setDefaultAxisMarkerColors(); |
||||||
|
pickedPlane = null; // mouse released, reset selection
|
||||||
|
offset = null; |
||||||
|
if (wasDragging) { |
||||||
|
actionPerformed(new MoveUndo(selectedSpatial, startLoc, lastLoc)); |
||||||
|
wasDragging = false; |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (selectedSpatial == null) |
||||||
|
return; |
||||||
|
if (pickedPlane == null) { |
||||||
|
pickedPlane = pickAxisMarker(camera, screenCoord, axisPickType); |
||||||
|
if (pickedPlane == null) |
||||||
|
return; |
||||||
|
startLoc = selectedSpatial.getLocalTranslation().clone(); |
||||||
|
|
||||||
|
if (pickedPlane.equals(new Vector3f(1,1,0))) |
||||||
|
plane.setLocalRotation(XY); |
||||||
|
else if (pickedPlane.equals(new Vector3f(1,0,1))) |
||||||
|
plane.setLocalRotation(XZ); |
||||||
|
else if (pickedPlane.equals(new Vector3f(0,1,1))) |
||||||
|
plane.setLocalRotation(YZ); |
||||||
|
plane.setLocalTranslation(startLoc); |
||||||
|
} |
||||||
|
|
||||||
|
Vector3f planeHit = pickWorldLocation(camera, screenCoord, plane); |
||||||
|
if (planeHit == null) |
||||||
|
return; |
||||||
|
|
||||||
|
if (offset == null) |
||||||
|
offset = planeHit.subtract(startLoc); // get the offset when we start so it doesn't jump
|
||||||
|
|
||||||
|
Vector3f newPos = planeHit.subtract(offset); |
||||||
|
lastLoc = newPos; |
||||||
|
selectedSpatial.setLocalTranslation(newPos); |
||||||
|
updateToolsTransformation(selectedSpatial); |
||||||
|
|
||||||
|
wasDragging = true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private class MoveUndo extends AbstractUndoableSceneEdit { |
||||||
|
|
||||||
|
private Spatial spatial; |
||||||
|
private Vector3f before,after; |
||||||
|
|
||||||
|
MoveUndo(Spatial spatial, Vector3f before, Vector3f after) { |
||||||
|
this.spatial = spatial; |
||||||
|
this.before = before; |
||||||
|
this.after = after; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void sceneUndo() { |
||||||
|
spatial.setLocalTranslation(before); |
||||||
|
toolController.selectedSpatialTransformed(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void sceneRedo() { |
||||||
|
spatial.setLocalTranslation(after); |
||||||
|
toolController.selectedSpatialTransformed(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
/* |
||||||
|
* To change this template, choose Tools | Templates |
||||||
|
* and open the template in the editor. |
||||||
|
*/ |
||||||
|
package com.jme3.gde.scenecomposer.tools; |
||||||
|
|
||||||
|
import com.jme3.gde.core.scene.SceneApplication; |
||||||
|
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode; |
||||||
|
import com.jme3.gde.scenecomposer.SceneEditTool; |
||||||
|
import com.jme3.math.Quaternion; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import com.jme3.math.Vector3f; |
||||||
|
import com.jme3.scene.Spatial; |
||||||
|
import java.util.concurrent.Callable; |
||||||
|
import org.openide.loaders.DataObject; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Brent Owens |
||||||
|
*/ |
||||||
|
public class SelectTool extends SceneEditTool { |
||||||
|
|
||||||
|
protected Spatial selected; |
||||||
|
private boolean wasDragging = false; |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void actionPrimary(Vector2f screenCoord, boolean pressed, final JmeNode rootNode, DataObject dataObject) { |
||||||
|
if (!pressed && !wasDragging) { |
||||||
|
// mouse released and wasn't dragging, select a new spatial
|
||||||
|
final Spatial result = pickWorldSpatial(getCamera(), screenCoord, rootNode); |
||||||
|
|
||||||
|
java.awt.EventQueue.invokeLater(new Runnable() { |
||||||
|
public void run() { |
||||||
|
if (result != null) { |
||||||
|
SceneApplication.getApplication().setCurrentFileNode(rootNode.getChild(result)); |
||||||
|
} else { |
||||||
|
SceneApplication.getApplication().setCurrentFileNode(rootNode); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
if (result != null) { |
||||||
|
replaceSelectionShape(result); |
||||||
|
updateToolsTransformation(selectedSpatial); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
if (!pressed) { |
||||||
|
wasDragging = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void actionSecondary(final Vector2f screenCoord, boolean pressed, final JmeNode rootNode, DataObject dataObject) { |
||||||
|
if (!pressed && !wasDragging) { |
||||||
|
final Vector3f result = pickWorldLocation(getCamera(), screenCoord, rootNode); |
||||||
|
toolController.doSetCursorLocation(result); |
||||||
|
} |
||||||
|
if (!pressed) { |
||||||
|
wasDragging = false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void mouseMoved(Vector2f screenCoord) { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void draggedPrimary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||||
|
wasDragging = pressed; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void draggedSecondary(Vector2f screenCoord, boolean pressed, JmeNode rootNode, DataObject currentDataObject) { |
||||||
|
wasDragging = pressed; |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue