aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Gouesse <[email protected]>2018-01-27 11:31:54 +0100
committerJulien Gouesse <[email protected]>2018-01-27 11:31:54 +0100
commit3b2aee44d8587327c26d106ddfc16c78c8fa8396 (patch)
treee1679845809e59c6a291d91f0923567f97ccdfb3
parent32e0d417017c81b2c1ab3aba278a113e67547559 (diff)
parentcbc61566689660d39f469efe4c429f8adf5b239e (diff)
Merge commit 'cbc61566689660d39f469efe4c429f8adf5b239e'
-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 7bc8732..e924ede 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 = new ArrayList<>();
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 a800fa7..aa822a4 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 c8c2f77..47c5b67 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>.
*/
@@ -59,7 +59,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
@@ -70,8 +70,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.
@@ -165,7 +165,7 @@ public class UIHud extends Node {
/**
* Add the given component to this hud.
- *
+ *
* @param component
* the component to add
*/
@@ -179,7 +179,7 @@ public class UIHud extends Node {
/**
* Remove the given component from the hud
- *
+ *
* @param component
* the component to remove
*/
@@ -225,7 +225,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
*/
@@ -237,7 +237,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
@@ -371,7 +371,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
*/
@@ -388,7 +388,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.
@@ -409,7 +409,7 @@ public class UIHud extends Node {
/**
* Add the given hud listener to this hud.
- *
+ *
* @param listener
* the listener to add
*/
@@ -419,7 +419,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.
@@ -472,7 +472,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
@@ -497,7 +497,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(),
@@ -529,7 +529,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>() {
@Override
public boolean apply(final TwoInputStates arg0) {
@@ -545,7 +545,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();
@@ -588,12 +588,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();
@@ -640,7 +640,7 @@ public class UIHud extends Node {
/**
* Handle mouse presses.
- *
+ *
* @param button
* the button that was pressed.
* @param currentIS
@@ -690,7 +690,7 @@ public class UIHud extends Node {
/**
* Handle mouse releases.
- *
+ *
* @param button
* the button that was release.
* @param currentIS
@@ -725,7 +725,7 @@ public class UIHud extends Node {
/**
* Handle movement events.
- *
+ *
* @param mouseX
* the new x position of the mouse
* @param mouseY
@@ -772,7 +772,7 @@ public class UIHud extends Node {
/**
* Handle wheel events.
- *
+ *
* @param wheelDx
* the change in wheel position.
* @param currentIS
@@ -791,7 +791,7 @@ public class UIHud extends Node {
/**
* Handle key presses.
- *
+ *
* @param key
* the pressed key
* @param currentIS
@@ -808,7 +808,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
@@ -825,7 +825,7 @@ public class UIHud extends Node {
/**
* Handle key releases.
- *
+ *
* @param key
* the released key
* @param currentIS