aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Slack <[email protected]>2017-06-02 19:02:23 -0500
committerJoshua Slack <[email protected]>2017-06-02 19:02:23 -0500
commitcbc61566689660d39f469efe4c429f8adf5b239e (patch)
tree7f4811bc04e605f25643d645337f553960b35ba0
parent67d620baf5eaf5b0ce66800e468719a9ef79ef25 (diff)
Updates to allow overriding SpatialState in InteractManager.
Updates to allow easier overriding of input flow in UIHud. Added new example tying together UI and Interact
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/ui/InteractUIExample.java693
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java8
-rw-r--r--ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java12
-rw-r--r--ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java50
4 files changed, 725 insertions, 38 deletions
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/ui/InteractUIExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/ui/InteractUIExample.java
new file mode 100644
index 0000000..1dfa5b2
--- /dev/null
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/ui/InteractUIExample.java
@@ -0,0 +1,693 @@
+/**
+ * Copyright (c) 2008-2017 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.example.ui;
+
+import java.lang.reflect.Field;
+import java.util.LinkedList;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.ardor3d.bounding.BoundingBox;
+import com.ardor3d.example.ExampleBase;
+import com.ardor3d.example.Purpose;
+import com.ardor3d.extension.interact.InteractManager;
+import com.ardor3d.extension.interact.data.SpatialState;
+import com.ardor3d.extension.interact.filter.PlaneBoundaryFilter;
+import com.ardor3d.extension.interact.widget.AbstractInteractWidget;
+import com.ardor3d.extension.interact.widget.BasicFilterList;
+import com.ardor3d.extension.interact.widget.IFilterList;
+import com.ardor3d.extension.interact.widget.MovePlanarWidget;
+import com.ardor3d.extension.interact.widget.MovePlanarWidget.MovePlane;
+import com.ardor3d.extension.ui.FloatingUIContainer;
+import com.ardor3d.extension.ui.Orientation;
+import com.ardor3d.extension.ui.UIButton;
+import com.ardor3d.extension.ui.UIComboBox;
+import com.ardor3d.extension.ui.UIContainer;
+import com.ardor3d.extension.ui.UIFrame;
+import com.ardor3d.extension.ui.UIHud;
+import com.ardor3d.extension.ui.UIPanel;
+import com.ardor3d.extension.ui.UISlider;
+import com.ardor3d.extension.ui.backdrop.EmptyBackdrop;
+import com.ardor3d.extension.ui.border.EmptyBorder;
+import com.ardor3d.extension.ui.event.ActionEvent;
+import com.ardor3d.extension.ui.event.ActionListener;
+import com.ardor3d.extension.ui.event.SelectionListener;
+import com.ardor3d.extension.ui.layout.BorderLayoutData;
+import com.ardor3d.extension.ui.layout.RowLayout;
+import com.ardor3d.extension.ui.model.DefaultComboBoxModel;
+import com.ardor3d.extension.ui.util.Insets;
+import com.ardor3d.framework.Canvas;
+import com.ardor3d.image.Texture;
+import com.ardor3d.input.Key;
+import com.ardor3d.input.logical.InputTrigger;
+import com.ardor3d.input.logical.KeyReleasedCondition;
+import com.ardor3d.input.logical.TriggerAction;
+import com.ardor3d.input.logical.TwoInputStates;
+import com.ardor3d.intersection.PickData;
+import com.ardor3d.intersection.Pickable;
+import com.ardor3d.intersection.PrimitivePickResults;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.MathUtils;
+import com.ardor3d.math.Plane;
+import com.ardor3d.math.Quaternion;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.state.MaterialState;
+import com.ardor3d.renderer.state.MaterialState.ColorMaterial;
+import com.ardor3d.renderer.state.TextureState;
+import com.ardor3d.scenegraph.Mesh;
+import com.ardor3d.scenegraph.Spatial;
+import com.ardor3d.scenegraph.controller.SpatialController;
+import com.ardor3d.scenegraph.hint.PickingHint;
+import com.ardor3d.scenegraph.shape.Box;
+import com.ardor3d.scenegraph.shape.Tube;
+import com.ardor3d.scenegraph.visitor.Visitor;
+import com.ardor3d.util.ReadOnlyTimer;
+import com.ardor3d.util.TextureManager;
+import com.google.common.collect.Lists;
+
+/**
+ * An example illustrating the use of the interact framework.
+ */
+@Purpose(htmlDescriptionKey = "com.ardor3d.example.interact.InteractUIExample", //
+thumbnailPath = "com/ardor3d/example/media/thumbnails/interact_InteractUIExample.jpg", //
+maxHeapMemory = 64)
+public class InteractUIExample extends ExampleBase {
+
+ final UIHud hud = new UIHud();
+ private InteractManager manager;
+ private MovePlanarWidget moveWidget;
+ private InsertMarkerUIWidget insertWidget;
+ private ColorSelectUIWidget colorWidget;
+ private PulseControlUIWidget pulseWidget;
+
+ final Vector3 tempVec = new Vector3();
+
+ public static void main(final String[] args) {
+ start(InteractUIExample.class);
+ }
+
+ @Override
+ protected void updateExample(final ReadOnlyTimer timer) {
+ manager.update(timer);
+ }
+
+ @Override
+ protected void renderExample(final Renderer renderer) {
+ super.renderExample(renderer);
+ manager.render(renderer);
+ renderer.renderBuckets();
+ hud.draw(renderer);
+ }
+
+ @Override
+ protected void updateLogicalLayer(final ReadOnlyTimer timer) {
+ hud.getLogicalLayer().checkTriggers(timer.getTimePerFrame());
+ }
+
+ @Override
+ protected void initExample() {
+ _canvas.setTitle("Interact Example");
+
+ final Camera camera = _canvas.getCanvasRenderer().getCamera();
+ camera.setLocation(15, 11, -9);
+ camera.lookAt(0, 0, 0, Vector3.UNIT_Y);
+
+ // setup our interact controls
+ addControls();
+
+ // create a floor to act as a reference.
+ addFloor();
+
+ // create a few way-markers to start things off
+ initPath();
+
+ }
+
+ private void addFloor() {
+ final Box floor = new Box("floor", Vector3.ZERO, 100, 5, 100);
+ floor.setTranslation(0, -5, 0);
+ final TextureState ts = new TextureState();
+ ts.setTexture(TextureManager.load("models/obj/pitcher.jpg", Texture.MinificationFilter.Trilinear, true));
+ floor.setRenderState(ts);
+ floor.getSceneHints().setPickingHint(PickingHint.Pickable, false);
+ floor.setModelBound(new BoundingBox());
+ _root.attachChild(floor);
+ _root.updateGeometricState(0);
+ }
+
+ LinkedList<Spatial> path = Lists.newLinkedList();
+
+ private void initPath() {
+ final Spatial marker1 = createMarker();
+ marker1.setName("marker1");
+ final Spatial marker2 = createMarkerAfter(marker1);
+ marker2.setName("marker2");
+ createMarkerBefore(marker2).setName("marker3");
+
+ // auto select the joint
+ _root.updateGeometricState(0);
+ manager.setSpatialTarget(marker1);
+ }
+
+ private void removeMarker(final Spatial ref) {
+ final int index = path.indexOf(ref);
+ if (path.remove(ref)) {
+ ref.removeFromParent();
+ manager.setSpatialTarget(null);
+ if (path.size() == 0) {
+ manager.setSpatialTarget(null);
+ } else if (path.size() <= index) {
+ manager.setSpatialTarget(path.get(index - 1));
+ } else {
+ manager.setSpatialTarget(path.get(index));
+ }
+ }
+ }
+
+ private Spatial createMarker() {
+ final Tube t = new Tube("marker", 1, 0.25, .25);
+ t.setModelBound(new BoundingBox());
+ t.updateGeometricState(0);
+ t.addTranslation(0, .25, 0);
+ t.getSceneHints().setPickingHint(PickingHint.Pickable, true);
+ final MaterialState ms = new MaterialState();
+ ms.setColorMaterial(ColorMaterial.AmbientAndDiffuse);
+ t.setRenderState(ms);
+ final MarkerData data = new MarkerData();
+ t.setUserData(data);
+ t.addController(new SpatialController<Spatial>() {
+ private double _scaleTime = 0;
+
+ public void update(final double time, final Spatial caller) {
+ // update our rotation
+ final double pulseSpeed = ((MarkerData) t.getUserData()).pulseSpeed;
+ if (pulseSpeed != 0.0) {
+ _scaleTime = _scaleTime + (_timer.getTimePerFrame() * pulseSpeed);
+ final double scale = MathUtils.sin(_scaleTime) * .99 + 1.0;
+ t.setScale(scale);
+ } else {
+ t.setScale(1.0);
+ }
+ }
+ });
+ _root.attachChild(t);
+ path.add(t);
+ return t;
+ }
+
+ private Spatial createMarkerAfter(final Spatial ref) {
+ final Spatial marker = createMarker();
+
+ // copy transform (orientation and position) of ref
+ marker.setTranslation(ref.getTranslation());
+ marker.setRotation(ref.getRotation());
+
+ // check if we're moving into place between two points, or just after last point
+ final int indexOfRef = path.indexOf(ref);
+ if (indexOfRef == path.size() - 2) {
+ // we're adding after last point, so no need to move in list
+ // just translate us in the forward z direction of the last node
+ final Vector3 fwd = marker.getRotation().applyPost(Vector3.UNIT_Z, null);
+ marker.addTranslation(fwd.multiplyLocal(8.0));
+ } else {
+ // we're adding a point between two others - get our other ref
+ final Spatial postRef = path.get(indexOfRef + 1);
+
+ // move new marker into list between the other two points
+ path.remove(marker);
+ path.add(indexOfRef + 1, marker);
+
+ // translate and orient between points
+ marker.setTranslation(ref.getTranslation().add(postRef.getTranslation(), null).divideLocal(2.0));
+
+ final Quaternion rotHelper1 = new Quaternion();
+ rotHelper1.fromRotationMatrix(ref.getRotation());
+ final Quaternion rotHelper2 = new Quaternion();
+ rotHelper2.fromRotationMatrix(postRef.getRotation());
+ marker.setRotation(rotHelper1.slerp(rotHelper2, .5, null));
+ }
+
+ manager.setSpatialTarget(marker);
+
+ return marker;
+ }
+
+ private Spatial createMarkerBefore(final Spatial ref) {
+ final int indexOfRef = path.indexOf(ref);
+ if (indexOfRef <= 0) {
+ return null;
+ }
+
+ return createMarkerAfter(path.get(indexOfRef - 1));
+ }
+
+ private void addControls() {
+ // create our manager
+ manager = new InteractManager(new MarkerState());
+ manager.setupInput(_canvas, _physicalLayer, _logicalLayer);
+
+ hud.setupInput(_canvas, _physicalLayer, manager.getLogicalLayer());
+ hud.setMouseManager(_mouseManager);
+
+ final BasicFilterList filterList = new BasicFilterList();
+
+ // add some widgets.
+ insertWidget = new InsertMarkerUIWidget(filterList);
+ manager.addWidget(insertWidget);
+
+ colorWidget = new ColorSelectUIWidget(filterList);
+ manager.addWidget(colorWidget);
+
+ pulseWidget = new PulseControlUIWidget(filterList);
+ manager.addWidget(pulseWidget);
+
+ moveWidget = new MovePlanarWidget(filterList).withPlane(MovePlane.XZ).withDefaultHandle(.33, .33,
+ ColorRGBA.YELLOW);
+ manager.addWidget(moveWidget);
+
+ // set the default as current
+ manager.setActiveWidget(moveWidget);
+
+ // add triggers to change which widget is active
+ manager.getLogicalLayer().registerTrigger(
+ new InputTrigger(new KeyReleasedCondition(Key.ONE), new TriggerAction() {
+ @Override
+ public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
+ manager.setActiveWidget(moveWidget);
+ }
+ }));
+ manager.getLogicalLayer().registerTrigger(
+ new InputTrigger(new KeyReleasedCondition(Key.TWO), new TriggerAction() {
+ @Override
+ public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
+ manager.setActiveWidget(insertWidget);
+ }
+ }));
+ manager.getLogicalLayer().registerTrigger(
+ new InputTrigger(new KeyReleasedCondition(Key.THREE), new TriggerAction() {
+ @Override
+ public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
+ manager.setActiveWidget(colorWidget);
+ }
+ }));
+ manager.getLogicalLayer().registerTrigger(
+ new InputTrigger(new KeyReleasedCondition(Key.FOUR), new TriggerAction() {
+ @Override
+ public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
+ manager.setActiveWidget(pulseWidget);
+ }
+ }));
+
+ // add some filters
+ manager.addFilter(new PlaneBoundaryFilter(new Plane(Vector3.UNIT_Y, 0)));
+ }
+
+ @Override
+ protected void processPicks(final PrimitivePickResults pickResults) {
+ final PickData pick = pickResults.findFirstIntersectingPickData();
+ if (pick != null) {
+ final Pickable target = pick.getTarget();
+ if (target instanceof Spatial) {
+ manager.setSpatialTarget((Spatial) target);
+ System.out.println("Setting target to: " + ((Spatial) target).getName());
+ return;
+ }
+ }
+ manager.setSpatialTarget(null);
+ }
+
+ class InsertMarkerUIWidget extends AbstractInteractWidget {
+
+ UIFrame popupFrame;
+
+ public InsertMarkerUIWidget(final IFilterList filterList) {
+ super(filterList);
+
+ createFrame();
+ }
+
+ private void createFrame() {
+
+ final RowLayout rowLay = new RowLayout(true);
+ final UIPanel centerPanel = new UIPanel(rowLay);
+ centerPanel.setBackdrop(new EmptyBackdrop());
+ centerPanel.setLayoutData(BorderLayoutData.CENTER);
+
+ AddButton(centerPanel, "+", new ActionListener() {
+ @Override
+ public void actionPerformed(final ActionEvent event) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ return;
+ }
+ createMarkerBefore(spat);
+ }
+ });
+
+ AddButton(centerPanel, "-", new ActionListener() {
+ @Override
+ public void actionPerformed(final ActionEvent event) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ return;
+ }
+ removeMarker(spat);
+ }
+ });
+
+ AddButton(centerPanel, "+", new ActionListener() {
+ @Override
+ public void actionPerformed(final ActionEvent event) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ return;
+ }
+ createMarkerAfter(spat);
+ }
+ });
+
+ popupFrame = new FloatingUIContainer();
+ popupFrame.getContentPanel().add(centerPanel);
+ popupFrame.getBasePanel().setBackdrop(new EmptyBackdrop());
+ popupFrame.getBasePanel().setBorder(new EmptyBorder());
+
+ popupFrame.updateMinimumSizeFromContents();
+ popupFrame.layout();
+ popupFrame.pack();
+
+ _handle = popupFrame;
+ }
+
+ private void AddButton(final UIContainer parent, final String label, final ActionListener actionListener) {
+ final UIButton button = new UIButton(label);
+ button.setPadding(Insets.EMPTY);
+ button.setMargin(Insets.EMPTY);
+ button.setMaximumContentSize(22, 22);
+ button.setMinimumContentSize(22, 22);
+ button.addActionListener(actionListener);
+ parent.add(button);
+ }
+
+ @Override
+ public void render(final Renderer renderer, final InteractManager manager) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ return;
+ }
+
+ tempVec.zero();
+ tempVec.set(Camera.getCurrentCamera().getScreenCoordinates(spat.getWorldTransform().applyForward(tempVec)));
+ tempVec.setZ(0);
+ tempVec.subtractLocal(popupFrame.getContentWidth() / 2, -10, 0);
+ _handle.setTranslation(tempVec);
+ _handle.updateWorldTransform(true);
+ }
+
+ @Override
+ public void receivedControl(final InteractManager manager) {
+ super.receivedControl(manager);
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat != null) {
+ hud.add(popupFrame);
+ }
+ }
+
+ @Override
+ public void lostControl(final InteractManager manager) {
+ super.lostControl(manager);
+ hud.remove(popupFrame);
+ }
+
+ @Override
+ public void targetChanged(final InteractManager manager) {
+ super.targetChanged(manager);
+ if (manager.getActiveWidget() == this) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ hud.remove(popupFrame);
+ } else {
+ hud.add(popupFrame);
+ }
+ }
+ }
+ }
+
+ class ColorSelectUIWidget extends AbstractInteractWidget {
+
+ UIFrame popupFrame;
+ ColorRGBA unconsumedColor;
+
+ public ColorSelectUIWidget(final IFilterList filterList) {
+ super(filterList);
+
+ createFrame();
+ }
+
+ private void createFrame() {
+
+ final UIPanel centerPanel = new UIPanel(null);
+ centerPanel.setBackdrop(new EmptyBackdrop());
+ centerPanel.setLayoutData(BorderLayoutData.CENTER);
+
+ final UIComboBox combo = new UIComboBox(new DefaultComboBoxModel("White", "Black", "Red", "Green", "Blue",
+ "Yellow", "Magenta", "Cyan"));
+ combo.setLocalComponentWidth(100);
+ combo.addSelectionListener(new SelectionListener<UIComboBox>() {
+ @Override
+ public void selectionChanged(final UIComboBox component, final Object newValue) {
+ try {
+ final Field field = ColorRGBA.class.getField(newValue.toString().toUpperCase());
+ final ColorRGBA color = (ColorRGBA) field.get(null);
+ if (manager.getSpatialState() instanceof MarkerState) {
+ unconsumedColor = color;
+ }
+
+ } catch (final Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+ centerPanel.add(combo);
+
+ popupFrame = new FloatingUIContainer();
+ popupFrame.getContentPanel().add(centerPanel);
+ popupFrame.getBasePanel().setBackdrop(new EmptyBackdrop());
+ popupFrame.getBasePanel().setBorder(null);
+
+ popupFrame.updateMinimumSizeFromContents();
+ popupFrame.layout();
+ popupFrame.pack();
+
+ _handle = popupFrame;
+ }
+
+ @Override
+ public void render(final Renderer renderer, final InteractManager manager) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ return;
+ }
+
+ tempVec.zero();
+ tempVec.set(Camera.getCurrentCamera().getScreenCoordinates(spat.getWorldTransform().applyForward(tempVec)));
+ tempVec.setZ(0);
+ tempVec.subtractLocal(popupFrame.getContentWidth() / 2, -20, 0);
+ _handle.setTranslation(tempVec);
+ _handle.updateWorldTransform(true);
+ }
+
+ @Override
+ public void receivedControl(final InteractManager manager) {
+ super.receivedControl(manager);
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat != null) {
+ hud.add(popupFrame);
+ }
+ }
+
+ @Override
+ public void lostControl(final InteractManager manager) {
+ super.lostControl(manager);
+ hud.remove(popupFrame);
+ }
+
+ @Override
+ public void processInput(final Canvas source, final TwoInputStates inputStates,
+ final AtomicBoolean inputConsumed, final InteractManager manager) {
+ super.processInput(source, inputStates, inputConsumed, manager);
+ if (unconsumedColor != null) {
+ ((MarkerState) manager.getSpatialState()).data.color.set(unconsumedColor);
+ inputConsumed.set(true);
+ unconsumedColor = null;
+ }
+ }
+
+ @Override
+ public void targetChanged(final InteractManager manager) {
+ super.targetChanged(manager);
+ if (manager.getActiveWidget() == this) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ hud.remove(popupFrame);
+ } else {
+ hud.add(popupFrame);
+ }
+ }
+ }
+ }
+
+ class PulseControlUIWidget extends AbstractInteractWidget {
+
+ UIFrame popupFrame;
+ Double unconsumedPulse;
+
+ public PulseControlUIWidget(final IFilterList filterList) {
+ super(filterList);
+
+ createFrame();
+ }
+
+ private void createFrame() {
+
+ final UIPanel centerPanel = new UIPanel(null);
+ centerPanel.setBackdrop(new EmptyBackdrop());
+ centerPanel.setLayoutData(BorderLayoutData.CENTER);
+
+ final UISlider slider = new UISlider(Orientation.Horizontal, 0, 100, 0);
+ slider.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(final ActionEvent event) {
+ if (manager.getSpatialTarget() == null) {
+ return;
+ }
+ if (manager.getSpatialState() instanceof MarkerState) {
+ unconsumedPulse = slider.getValue() * 0.05;
+ }
+ }
+ });
+ slider.setLocalComponentWidth(100);
+ centerPanel.add(slider);
+
+ popupFrame = new FloatingUIContainer();
+ popupFrame.getContentPanel().add(centerPanel);
+ popupFrame.getBasePanel().setBackdrop(new EmptyBackdrop());
+ popupFrame.getBasePanel().setBorder(null);
+
+ popupFrame.updateMinimumSizeFromContents();
+ popupFrame.layout();
+ popupFrame.pack();
+
+ _handle = popupFrame;
+ }
+
+ @Override
+ public void render(final Renderer renderer, final InteractManager manager) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ return;
+ }
+
+ tempVec.zero();
+ tempVec.set(Camera.getCurrentCamera().getScreenCoordinates(spat.getWorldTransform().applyForward(tempVec)));
+ tempVec.setZ(0);
+ tempVec.subtractLocal(popupFrame.getContentWidth() / 2, -20, 0);
+ _handle.setTranslation(tempVec);
+ _handle.updateWorldTransform(true);
+ }
+
+ @Override
+ public void receivedControl(final InteractManager manager) {
+ super.receivedControl(manager);
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat != null) {
+ hud.add(popupFrame);
+ }
+ }
+
+ @Override
+ public void lostControl(final InteractManager manager) {
+ super.lostControl(manager);
+ hud.remove(popupFrame);
+ }
+
+ @Override
+ public void processInput(final Canvas source, final TwoInputStates inputStates,
+ final AtomicBoolean inputConsumed, final InteractManager manager) {
+ super.processInput(source, inputStates, inputConsumed, manager);
+ if (unconsumedPulse != null) {
+ ((MarkerState) manager.getSpatialState()).data.pulseSpeed = unconsumedPulse;
+ inputConsumed.set(true);
+ unconsumedPulse = null;
+ }
+ }
+
+ @Override
+ public void targetChanged(final InteractManager manager) {
+ super.targetChanged(manager);
+ if (manager.getActiveWidget() == this) {
+ final Spatial spat = manager.getSpatialTarget();
+ if (spat == null) {
+ hud.remove(popupFrame);
+ } else {
+ hud.add(popupFrame);
+ }
+ }
+ }
+ }
+
+ class MarkerData {
+ public ColorRGBA color = new ColorRGBA(ColorRGBA.WHITE);
+ public double pulseSpeed;
+
+ public void copy(final MarkerData source) {
+ color.set(source.color);
+ pulseSpeed = source.pulseSpeed;
+ }
+ }
+
+ class MarkerState extends SpatialState {
+ public final MarkerData data = new MarkerData();
+
+ @Override
+ public void applyState(final Spatial target) {
+ super.applyState(target);
+ if (target.getUserData() instanceof MarkerData) {
+ final MarkerData tData = (MarkerData) target.getUserData();
+ if (tData.pulseSpeed != data.pulseSpeed) {
+ tData.pulseSpeed = data.pulseSpeed;
+ }
+
+ if (!tData.color.equals(data.color)) {
+ tData.color.set(data.color);
+ target.acceptVisitor(new Visitor() {
+ @Override
+ public void visit(final Spatial spatial) {
+ if (spatial instanceof Mesh) {
+ final Mesh mesh = (Mesh) spatial;
+ mesh.setDefaultColor(tData.color);
+ mesh.setSolidColor(tData.color);
+ }
+ }
+ }, true);
+ }
+ }
+ }
+
+ @Override
+ public void copyState(final Spatial source) {
+ super.copyState(source);
+ if (source.getUserData() instanceof MarkerData) {
+ data.copy((MarkerData) source.getUserData());
+ }
+ }
+ }
+}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java
index f855cb3..447a226 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/InteractManager.java
@@ -61,7 +61,7 @@ public class InteractManager {
/**
* Spatial state tracking.
*/
- protected SpatialState _state = new SpatialState();
+ protected final SpatialState _state;
/**
* List of filters to modify state prior to applying to a Spatial target.
@@ -69,6 +69,12 @@ public class InteractManager {
protected List<UpdateFilter> _filters = Lists.newArrayList();
public InteractManager() {
+ _state = new SpatialState();
+ setupLogicalLayer();
+ }
+
+ public InteractManager(final SpatialState stateTracking) {
+ _state = stateTracking;
setupLogicalLayer();
}
diff --git a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java
index 2364e25..e3918d1 100644
--- a/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java
+++ b/ardor3d-extras/src/main/java/com/ardor3d/extension/interact/data/SpatialState.java
@@ -16,36 +16,24 @@ import com.ardor3d.scenegraph.Spatial;
public class SpatialState {
protected Transform _transform = new Transform();
- protected Object _userData = null;
public SpatialState() {}
/** copy constructor */
public SpatialState(final SpatialState toCopy) {
_transform.set(toCopy._transform);
- _userData = toCopy._userData;
}
public Transform getTransform() {
return _transform;
}
- public Object getUserData() {
- return _userData;
- }
-
- public void setUserData(final Object userData) {
- _userData = userData;
- }
-
public void copyState(final Spatial source) {
_transform.set(source.getTransform());
- _userData = source.getUserData();
}
public void applyState(final Spatial target) {
target.setTransform(_transform);
- target.setUserData(_userData);
}
}
diff --git a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java
index 1eae2d2..0ece8fa 100644
--- a/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java
+++ b/ardor3d-ui/src/main/java/com/ardor3d/extension/ui/UIHud.java
@@ -3,7 +3,7 @@
*
* This file is part of Ardor3D.
*
- * Ardor3D is free software: you can redistribute it and/or modify it
+ * Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/
@@ -60,7 +60,7 @@ public class UIHud extends Node {
/**
* The logical layer used by this UI to receive input events.
*/
- private final LogicalLayer _logicalLayer = new LogicalLayer();
+ protected final LogicalLayer _logicalLayer = new LogicalLayer();
/**
* The single tooltip used by this hud - lazy inited
@@ -71,8 +71,8 @@ public class UIHud extends Node {
* Internal flag indicating whether the last input event was consumed by the UI. This is used to decide if we will
* forward the event to the next LogicalLayer.
*/
- private boolean _mouseInputConsumed;
- private boolean _keyInputConsumed;
+ protected boolean _mouseInputConsumed;
+ protected boolean _keyInputConsumed;
/**
* Flag used to determine if we should use mouse input when mouse is grabbed. Defaults to true.
@@ -166,7 +166,7 @@ public class UIHud extends Node {
/**
* Add the given component to this hud.
- *
+ *
* @param component
* the component to add
*/
@@ -180,7 +180,7 @@ public class UIHud extends Node {
/**
* Remove the given component from the hud
- *
+ *
* @param component
* the component to remove
*/
@@ -226,7 +226,7 @@ public class UIHud extends Node {
/**
* Reorder the components so that the given component is drawn last and is therefore "on top" of any others.
- *
+ *
* @param component
* the component to bring to front
*/
@@ -238,7 +238,7 @@ public class UIHud extends Node {
/**
* Look for a UIComponent at the given screen coordinates. If no pickable component is at that location, null is
* returned.
- *
+ *
* @param x
* the x screen coordinate
* @param y
@@ -372,7 +372,7 @@ public class UIHud extends Node {
/**
* Add the given drag listener to this hud. Expired WeakReferences are also cleaned.
- *
+ *
* @param listener
* the listener to add
*/
@@ -389,7 +389,7 @@ public class UIHud extends Node {
/**
* Remove any matching drag listener from this hud. Expired WeakReferences are also cleaned.
- *
+ *
* @param listener
* the listener to remove
* @return true if at least one "equal" DragListener was found in the pool of listeners and removed.
@@ -410,7 +410,7 @@ public class UIHud extends Node {
/**
* Add the given hud listener to this hud.
- *
+ *
* @param listener
* the listener to add
*/
@@ -420,7 +420,7 @@ public class UIHud extends Node {
/**
* Remove any matching hud listener from this hud.
- *
+ *
* @param listener
* the listener to remove
* @return true if at least one "equal" HudListener was found in the pool of listeners and removed.
@@ -473,7 +473,7 @@ public class UIHud extends Node {
/**
* Convenience method for setting up the UI's connection to the Ardor3D input system, along with a forwarding
* address for input events that the UI does not care about.
- *
+ *
* @param canvas
* the canvas to register with
* @param physicalLayer
@@ -498,7 +498,7 @@ public class UIHud extends Node {
if (!_keyInputConsumed) {
// nothing consumed
forwardTo.getApplier()
- .checkAndPerformTriggers(forwardTo.getTriggers(), source, states, tpf);
+ .checkAndPerformTriggers(forwardTo.getTriggers(), source, states, tpf);
} else {
// only key state consumed
final TwoInputStates forwardingState = new TwoInputStates(states.getPrevious(),
@@ -530,7 +530,7 @@ public class UIHud extends Node {
/**
* Set up our logical layer with a trigger that hands input to the UI and saves whether it was "consumed".
*/
- private void setupLogicalLayer() {
+ protected void setupLogicalLayer() {
_logicalLayer.registerTrigger(new InputTrigger(new Predicate<TwoInputStates>() {
public boolean apply(final TwoInputStates arg0) {
// always trigger this.
@@ -544,7 +544,7 @@ public class UIHud extends Node {
}));
}
- private boolean offerKeyInputToUI(final TwoInputStates inputStates) {
+ protected boolean offerKeyInputToUI(final TwoInputStates inputStates) {
boolean consumed = false;
final InputState current = inputStates.getCurrent();
@@ -587,12 +587,12 @@ public class UIHud extends Node {
/**
* Parse a given set of input states for UI events and pass these events to the UI components contained in this hud.
- *
+ *
* @param inputStates
* our two InputState objects, detailing a before and after snapshot of the input system.
* @return true if a UI element consumed the event described by inputStates.
*/
- private boolean offerMouseInputToUI(final TwoInputStates inputStates) {
+ protected boolean offerMouseInputToUI(final TwoInputStates inputStates) {
boolean consumed = false;
final InputState current = inputStates.getCurrent();
@@ -639,7 +639,7 @@ public class UIHud extends Node {
/**
* Handle mouse presses.
- *
+ *
* @param button
* the button that was pressed.
* @param currentIS
@@ -689,7 +689,7 @@ public class UIHud extends Node {
/**
* Handle mouse releases.
- *
+ *
* @param button
* the button that was release.
* @param currentIS
@@ -724,7 +724,7 @@ public class UIHud extends Node {
/**
* Handle movement events.
- *
+ *
* @param mouseX
* the new x position of the mouse
* @param mouseY
@@ -771,7 +771,7 @@ public class UIHud extends Node {
/**
* Handle wheel events.
- *
+ *
* @param wheelDx
* the change in wheel position.
* @param currentIS
@@ -790,7 +790,7 @@ public class UIHud extends Node {
/**
* Handle key presses.
- *
+ *
* @param key
* the pressed key
* @param currentIS
@@ -807,7 +807,7 @@ public class UIHud extends Node {
/**
* Handle key held (pressed down over more than one input update cycle.)
- *
+ *
* @param key
* the held key
* @param currentIS
@@ -824,7 +824,7 @@ public class UIHud extends Node {
/**
* Handle key releases.
- *
+ *
* @param key
* the released key
* @param currentIS