}
public void doActionPerformed(final AbstractSceneExplorerNode rootNode, final DataObject dataObject) {
+ doActionPerformed(rootNode, dataObject, true);
+ }
+
+ public void doActionPerformed(final AbstractSceneExplorerNode rootNode, final DataObject dataObject, boolean recordUndo) {
final Object object = doApplyTool(rootNode);
- if (object!=null) {
+
+ if (object!=null && recordUndo) {
+
Lookup lookup = Lookup.getDefault() ;
SceneUndoRedoManager manager = lookup.lookup(SceneUndoRedoManager.class);
TerrainEditorTopComponent.textureTable.columnModel.title4=Normal
TerrainEditorTopComponent.eraseButton.toolTipText=Erase a texture from the terrain
TerrainEditorTopComponent.eraseButton.text=
-TerrainEditorTopComponent.paintButton.toolTipText=Paint a texture onto the terrain
-TerrainEditorTopComponent.paintButton.text=
TerrainEditorTopComponent.paintingPanel.border.title=Painting
TerrainEditorTopComponent.triPlanarCheckBox.toolTipText=Enable if you have a lot of vertical surfaces. It will look nice but lower performance
TerrainEditorTopComponent.triPlanarCheckBox.text=Tri-planar
@Override
protected void checkClick(int button, boolean pressed) {
+ checkMouseButtonState(button, pressed);
+ }
+
+ @Override
+ protected void checkDragged(int button, boolean pressed) {
+ checkMouseButtonState(button, pressed);
+ }
+
+ private void checkMouseButtonState(int button, boolean pressed) {
+ if (isTerrainEditButtonEnabled() && !forceCameraControls) {
+ if (terrainEditToolActivated != pressed)
+ toolController.doTerrainEditToolActionEnded(); // button state change, trigger undo action
+ terrainEditToolActivated = pressed;
+ }
- /*if (button == 0) {
+
+ if (button == 0) {
if (isTerrainEditButtonEnabled() && !forceCameraControls) {
- terrainEditToolActivated = true;
+ toolController.setPrimary(pressed);
+ System.out.println("primary "+pressed);
}
}
-
- if (button == 1) {
- if (isTerrainEditButtonEnabled() && !forceCameraControls) {
- toolController.doTerrainEditToolAlternateActivated();
- }
- }*/
-
+
if (button == 1) {
if (isTerrainEditButtonEnabled() && !forceCameraControls) {
- toolController.doTerrainEditToolAlternateActivated();
+ toolController.setAlternate(pressed);
+ System.out.println("alternate "+pressed);
}
}
}
- @Override
+ /*@Override
protected void checkDragged(int button, boolean pressed) {
- if (button == 0 && !forceCameraControls) {
+ if ( (button == 0 || button == 1) && !forceCameraControls) {
terrainEditToolActivated = true;
}
- }
+ }*/
@Override
protected void checkMoved() {
lastModifyTime = 0;
if (terrainEditToolActivated) {
toolController.doTerrainEditToolActivated();
+ toolController.doTerrainEditToolAlternateActivated();
}
- terrainEditToolActivated = false;
+ //terrainEditToolActivated = false;
lastModifyTime = app.getContext().getTimer().getTime();
}
}
-<?xml version="1.1" encoding="UTF-8" ?>
+<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.6" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<NonVisualComponents>
<Component id="hintPanel" max="32767" attributes="1"/>
<Component id="paintingPanel" alignment="0" max="32767" attributes="1"/>
<Component id="toolSettingsPanel" alignment="0" pref="132" max="32767" attributes="1"/>
- <Component id="jPanel2" pref="132" max="32767" attributes="1"/>
+ <Component id="jPanel2" max="32767" attributes="1"/>
</Group>
</Group>
</Group>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="removeTextureButtonActionPerformed"/>
</Events>
</Component>
- <Component class="javax.swing.JToggleButton" name="paintButton">
- <Properties>
- <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
- <ComponentRef name="terrainModButtonGroup"/>
- </Property>
- <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
- <Image iconType="3" name="/com/jme3/gde/terraineditor/icon_terrain-paint-circle.png"/>
- </Property>
- <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
- <ResourceString bundle="com/jme3/gde/terraineditor/Bundle.properties" key="TerrainEditorTopComponent.paintButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
- </Property>
- <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
- <ResourceString bundle="com/jme3/gde/terraineditor/Bundle.properties" key="TerrainEditorTopComponent.paintButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
- </Property>
- <Property name="focusable" type="boolean" value="false"/>
- <Property name="horizontalTextPosition" type="int" value="0"/>
- <Property name="verticalTextPosition" type="int" value="3"/>
- </Properties>
- <Events>
- <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="paintButtonActionPerformed"/>
- </Events>
- </Component>
<Component class="javax.swing.JToggleButton" name="eraseButton">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/jme3/gde/terraineditor/Bundle.properties" key="TerrainEditorTopComponent.eraseButton.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
</Property>
+ <Property name="enabled" type="boolean" value="false"/>
<Property name="focusable" type="boolean" value="false"/>
<Property name="horizontalTextPosition" type="int" value="0"/>
<Property name="verticalTextPosition" type="int" value="3"/>
<Property name="majorTickSpacing" type="int" value="10"/>
<Property name="minorTickSpacing" type="int" value="5"/>
<Property name="paintTicks" type="boolean" value="true"/>
- <Property name="snapToTicks" type="boolean" value="true"/>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="com/jme3/gde/terraineditor/Bundle.properties" key="TerrainEditorTopComponent.radiusSlider.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
</Property>
jSeparator2 = new javax.swing.JToolBar.Separator();
addTextureButton = new javax.swing.JButton();
removeTextureButton = new javax.swing.JButton();
- paintButton = new javax.swing.JToggleButton();
eraseButton = new javax.swing.JToggleButton();
jSeparator3 = new javax.swing.JToolBar.Separator();
radiusLabel = new javax.swing.JLabel();
});
jToolBar1.add(removeTextureButton);
- terrainModButtonGroup.add(paintButton);
- paintButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/terraineditor/icon_terrain-paint-circle.png"))); // NOI18N
- org.openide.awt.Mnemonics.setLocalizedText(paintButton, org.openide.util.NbBundle.getMessage(TerrainEditorTopComponent.class, "TerrainEditorTopComponent.paintButton.text")); // NOI18N
- paintButton.setToolTipText(org.openide.util.NbBundle.getMessage(TerrainEditorTopComponent.class, "TerrainEditorTopComponent.paintButton.toolTipText")); // NOI18N
- paintButton.setFocusable(false);
- paintButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
- paintButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
- paintButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- paintButtonActionPerformed(evt);
- }
- });
- jToolBar1.add(paintButton);
-
terrainModButtonGroup.add(eraseButton);
eraseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/com/jme3/gde/terraineditor/icon_terrain-erase-circle.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(eraseButton, org.openide.util.NbBundle.getMessage(TerrainEditorTopComponent.class, "TerrainEditorTopComponent.eraseButton.text")); // NOI18N
eraseButton.setToolTipText(org.openide.util.NbBundle.getMessage(TerrainEditorTopComponent.class, "TerrainEditorTopComponent.eraseButton.toolTipText")); // NOI18N
+ eraseButton.setEnabled(false);
eraseButton.setFocusable(false);
eraseButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
eraseButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
radiusSlider.setMajorTickSpacing(10);
radiusSlider.setMinorTickSpacing(5);
radiusSlider.setPaintTicks(true);
- radiusSlider.setSnapToTicks(true);
radiusSlider.setToolTipText(org.openide.util.NbBundle.getMessage(TerrainEditorTopComponent.class, "TerrainEditorTopComponent.radiusSlider.toolTipText")); // NOI18N
radiusSlider.setValue(5);
radiusSlider.setOpaque(false);
.addComponent(hintPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(paintingPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(toolSettingsPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 132, Short.MAX_VALUE)
- .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, 132, Short.MAX_VALUE)))
+ .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
);
}// </editor-fold>//GEN-END:initComponents
}
}//GEN-LAST:event_lowerTerrainButtonActionPerformed
- private void paintButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_paintButtonActionPerformed
- if (paintButton.isSelected()) {
- PaintTerrainTool tool = new PaintTerrainTool();
- toolController.setTerrainEditButtonState(tool);
- setHintText(tool);
- } else {
- toolController.setTerrainEditButtonState(null);
- setHintText((TerrainTool) null);
- }
- }//GEN-LAST:event_paintButtonActionPerformed
-
private void addTextureButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addTextureButtonActionPerformed
if (editorController == null || editorController.getTerrain(null) == null) {
return;
private void eraseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eraseButtonActionPerformed
if (eraseButton.isSelected()) {
- EraseTerrainTool tool = new EraseTerrainTool();
+ PaintTerrainTool tool = new PaintTerrainTool();
toolController.setTerrainEditButtonState(tool);
setHintText(tool);
} else {
private javax.swing.JToggleButton levelTerrainButton;
private javax.swing.JToggleButton lowerTerrainButton;
private javax.swing.JTextField octavesField;
- private javax.swing.JToggleButton paintButton;
private javax.swing.JPanel paintingPanel;
private javax.swing.JLabel radiusLabel;
private javax.swing.JSlider radiusSlider;
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.AbstractSceneExplorerNode;
import com.jme3.gde.core.sceneexplorer.nodes.JmeNode;
import com.jme3.gde.core.sceneexplorer.nodes.JmeSpatial;
import com.jme3.gde.terraineditor.tools.TerrainTool;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
import java.util.concurrent.Callable;
+import org.openide.loaders.DataObject;
/**
* The controller for the terrain modification tools. It will in turn interact
private float toolWeight;
private int selectedTextureIndex = -1;
private boolean mesh = false;
+ private boolean primary = false;
+ private boolean alternate = false;
public TerrainToolController(Node toolsNode, AssetManager manager, JmeNode rootNode) {
*/
public void doTerrainEditToolActivated() {
- if (terrainTool != null) {
+ if (terrainTool != null && primary && !alternate) {
Vector3f point = getMarkerLocation();
if (point != null) {
topComponent.getExtraToolParams();
*/
public void doTerrainEditToolAlternateActivated() {
- if (terrainTool != null) {
- Vector3f point = cameraController.getTerrainCollisionPoint();
+ if (terrainTool != null && alternate && !primary) {
+ //Vector3f point = cameraController.getTerrainCollisionPoint();
+ Vector3f point = getMarkerLocation();
if (point != null) {
+ topComponent.getExtraToolParams();
terrainTool.actionSecondary(point, selectedTextureIndex, jmeRootNode, editorController.getCurrentDataObject());
}
}
+ public void setPrimary(boolean primary) {
+ this.primary = primary;
+ }
+
+ public void setAlternate(boolean alternate) {
+ this.alternate = alternate;
+ }
+
void setExtraToolParams(ExtraToolParams params) {
if (terrainTool != null) {
terrainTool.setExtraParams(params);
terrainTool.keyPressed(kie);
}
}
+
+ /**
+ * The action on the tool has ended (mouse button up), record the Undo (for painting only now)
+ */
+ void doTerrainEditToolActionEnded() {
+ if (terrainTool != null) {
+ System.out.println("undo tagged");
+ terrainTool.actionEnded(jmeRootNode, editorController.getCurrentDataObject());
+ }
+ }
}
*/
public abstract class AbstractTerrainToolAction extends AbstractStatefulGLToolAction {
+ private Terrain terrain;
+
protected Terrain getTerrain(Spatial root) {
+ if (terrain != null)
+ return terrain;
+
// is this the terrain?
if (root instanceof Terrain && root instanceof Node) {
- return (Terrain)root;
+ terrain = (Terrain)root;
+ return terrain;
}
if (root instanceof Node) {
package com.jme3.gde.terraineditor.tools;
import com.jme3.gde.core.sceneexplorer.nodes.AbstractSceneExplorerNode;
+import com.jme3.gde.core.sceneexplorer.nodes.actions.AbstractStatefulGLToolAction;
+import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit;
+import com.jme3.gde.core.undoredo.SceneUndoRedoManager;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Node;
+import com.jme3.terrain.Terrain;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.undo.CannotRedoException;
+import javax.swing.undo.CannotUndoException;
import org.openide.loaders.DataObject;
+import org.openide.util.Lookup;
/**
- *
+ * Paint or erase the textures on the terrain.
+ *
* @author Brent Owens
*/
public class PaintTerrainTool extends TerrainTool {
+ private boolean painting = false; // to check when undo actions need to be set
+ List<PaintTerrainToolAction> actions = new ArrayList<PaintTerrainToolAction>();
+
+
@Override
public void actionPrimary(Vector3f point, int textureIndex, AbstractSceneExplorerNode rootNode, DataObject dataObject) {
- if (radius == 0 || weight == 0)
- return;
- PaintTerrainToolAction action = new PaintTerrainToolAction(point, radius, weight, textureIndex);
- action.doActionPerformed(rootNode, dataObject);
+ setPrimary(true);
+ action(point, textureIndex, rootNode, dataObject);
}
@Override
public void actionSecondary(Vector3f point, int textureIndex, AbstractSceneExplorerNode rootNode, DataObject dataObject) {
- // do nothing
+ setPrimary(false);
+ action(point, textureIndex, rootNode, dataObject);
+ }
+
+ private void action(Vector3f point, int textureIndex, AbstractSceneExplorerNode rootNode, DataObject dataObject) {
+ if (radius == 0 || weight == 0)
+ return;
+
+ if (!painting)
+ painting = true;
+
+ PaintTerrainToolAction action;
+ if (isPrimary())
+ action = new PaintTerrainToolAction(point, radius, weight, textureIndex);
+ else
+ action = new PaintTerrainToolAction(point, radius, -weight, textureIndex);
+ action.doActionPerformed(rootNode, dataObject, false);
+ actions.add(action);
+ }
+
+ @Override
+ public void actionEnded(AbstractSceneExplorerNode rootNode, DataObject dataObject) {
+ if (painting) {
+ painting = false;
+
+ if (actions.isEmpty())
+ return;
+
+ // record undo action
+ List<PaintTerrainToolAction> cloned = new ArrayList<PaintTerrainToolAction>();
+ cloned.addAll(actions);
+ recordUndo(cloned, rootNode, dataObject);
+ actions.clear();
+ }
+ }
+
+ /**
+ * Is it already painting?
+ * If the user releases the mouse outside the window, this can be used to check
+ * if they were painting, and if so, call actionEnded()
+ */
+ public boolean isPainting() {
+ return painting;
}
@Override
super.addMarkerPrimary(parent);
markerPrimary.getMaterial().setColor("Color", ColorRGBA.Cyan);
}
+
+ private void recordUndo(final List<PaintTerrainToolAction> actions, final AbstractSceneExplorerNode rootNode, final DataObject dataObject) {
+ Lookup lookup = Lookup.getDefault() ;
+ SceneUndoRedoManager manager = lookup.lookup(SceneUndoRedoManager.class);
+
+ AbstractUndoableSceneEdit undoer = new AbstractUndoableSceneEdit() {
+
+ @Override
+ public void sceneUndo() throws CannotUndoException {
+ Terrain terrain = null;
+ for (int i=actions.size()-1; i>=0; i--) {
+ PaintTerrainToolAction a = actions.get(i);
+ if (terrain == null)
+ terrain = a.getTerrain(rootNode.getLookup().lookup(Node.class));
+ a.doUndoTool(rootNode, terrain);
+ }
+ setModified(rootNode, dataObject);
+ }
+
+ @Override
+ public void sceneRedo() throws CannotRedoException {
+ for (int i=0; i<actions.size(); i++) {
+ PaintTerrainToolAction a = actions.get(i);
+ a.applyTool(rootNode);
+ }
+ setModified(rootNode, dataObject);
+ }
+
+ };
+ if (manager != null) // this is a temporary check, it should never be null but occasionally is
+ manager.addEdit(this, undoer);
+ }
+
+ protected void setModified(final AbstractSceneExplorerNode rootNode, final DataObject dataObject) {
+ if (dataObject.isModified())
+ return;
+ java.awt.EventQueue.invokeLater(new Runnable() {
+
+ public void run() {
+ dataObject.setModified(true);
+ rootNode.refresh(true);
+ }
+ });
+ }
}
import java.nio.ByteBuffer;
/**
- * Paint the texture at the specified location.
+ * Paint or erase the texture at the specified location.
*
* @author Brent Owens
*/
name = "Paint terrain";
}
+ public Object applyTool(AbstractSceneExplorerNode rootNode) {
+ return doApplyTool(rootNode);
+ }
+
@Override
protected Object doApplyTool(AbstractSceneExplorerNode rootNode) {
Terrain terrain = getTerrain(rootNode.getLookup().lookup(Node.class));
private Vector3f axis;
private Meshes mesh;
private final Map<Vector3f, Float> cachedMap = new HashMap<Vector3f, Float>(); // caching only
+ private boolean primary = true;
public static enum Meshes {
Box, Sphere
this.manager = manager;
addMarkerPrimary(parent);
}
+
+ public boolean isPrimary() {
+ return primary;
+ }
+
+ public void setPrimary(boolean primary) {
+ this.primary = primary;
+ }
/**
* The primary action for the tool gets activated
public abstract void actionSecondary(Vector3f point, int textureIndex, AbstractSceneExplorerNode rootNode, DataObject dataObject);
/**
+ * The action has ended, record undo actions.
+ * Currently just implemented for Paint tool
+ */
+ public void actionEnded(AbstractSceneExplorerNode rootNode, DataObject dataObject) {}
+
+ /**
* Signals that this tool will or will not snap to fixed axis angles
*/
protected boolean useStraightLine() {