diff --git a/lib/ArtClientLib-2.6.0/src/net/dhleong/acl/world/SystemManager.java b/lib/ArtClientLib-2.6.0/src/net/dhleong/acl/world/SystemManager.java index b6555ca..2d994b9 100644 --- a/lib/ArtClientLib-2.6.0/src/net/dhleong/acl/world/SystemManager.java +++ b/lib/ArtClientLib-2.6.0/src/net/dhleong/acl/world/SystemManager.java @@ -280,9 +280,9 @@ public ShipSystem getSystemTypeAt(int x, int y, int z) { } /** - * Get the overall health of the given system + * Get the overall healthPct of the given system * @param sys - * @return A float [0, 1] indicating percentage health + * @return A float [0, 1] indicating percentage healthPct * @throws IllegalStateException if the SystemManager doesn't * yet have a ShipSystemGrid */ diff --git a/src/com/brindyblitz/artemis/engconsole/ui/SystemSlider.java b/src/com/brindyblitz/artemis/engconsole/ui/SystemSlider.java index 6918b0c..69f5116 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/SystemSlider.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/SystemSlider.java @@ -45,7 +45,7 @@ public class SystemSlider extends JPanel implements MouseWheelListener { ENERGY_INCREMENT = 25, COOLANT_INCREMENT = 1, - // TODO: consider adding this to configuration options. It's not just a super-power-user option. Mice vary + // TODO: FILE ISSUE > consider adding this to configuration options. It's not just a super-power-user option. Mice vary // a lot on scroll rates and wheel dynamics, and smart trackpads (e.g. those on MacBooks) can act as scroll // devices as well. 50 feels too slow for my mouse wheel and too fast for my trackpad. // ~Jake diff --git a/src/com/brindyblitz/artemis/engconsole/ui/damcon/Damcon.java b/src/com/brindyblitz/artemis/engconsole/ui/damcon/Damcon.java index 43958ef..36d938f 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/damcon/Damcon.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/damcon/Damcon.java @@ -1,8 +1,6 @@ package com.brindyblitz.artemis.engconsole.ui.damcon; -import java.awt.Color; -import java.awt.GraphicsConfiguration; -import java.awt.Point; +import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; @@ -10,27 +8,9 @@ import java.awt.event.MouseWheelListener; import java.io.File; import java.io.FileNotFoundException; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.TimerTask; - -import javax.media.j3d.Appearance; -import javax.media.j3d.BranchGroup; -import javax.media.j3d.Canvas3D; -import javax.media.j3d.ColoringAttributes; -import javax.media.j3d.LineAttributes; -import javax.media.j3d.Node; -import javax.media.j3d.PickInfo; -import javax.media.j3d.PolygonAttributes; -import javax.media.j3d.RestrictedAccessException; -import javax.media.j3d.Shape3D; -import javax.media.j3d.Transform3D; -import javax.media.j3d.TransformGroup; -import javax.media.j3d.TransparencyAttributes; +import java.util.*; + +import javax.media.j3d.*; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.vecmath.AxisAngle4d; @@ -40,13 +20,13 @@ import javax.vecmath.Vector3d; import com.brindyblitz.artemis.engconsole.EngineeringConsoleManager; -import com.brindyblitz.artemis.engconsole.EngineeringConsoleManager.EnhancedDamconStatus; // See: http://download.java.net/media/java3d/javadoc/1.5.1/ import com.sun.j3d.loaders.IncorrectFormatException; import com.sun.j3d.loaders.ParsingErrorException; import com.sun.j3d.loaders.Scene; import com.sun.j3d.loaders.objectfile.ObjectFile; import com.sun.j3d.utils.pickfast.PickCanvas; +import com.sun.j3d.utils.picking.PickTool; import com.sun.j3d.utils.universe.SimpleUniverse; import com.sun.j3d.utils.universe.Viewer; import com.sun.j3d.utils.universe.ViewingPlatform; @@ -78,7 +58,7 @@ public class Damcon implements MouseListener, MouseMotionListener, MouseWheelLis ZOOM_FACTOR = 0.25d, ROTATION_FACTOR = 0.01d, MIN_PITCH_Y = 0.1d, - MIN_ZOOM_RADIUS = 3.7d, + MIN_ZOOM_RADIUS = 2d, // 3.7d keeps us out of the inside of the Artemis model MAX_ZOOM_RADIUS = 15d; private static final Vector2d MAX_ROTATION_AMOUNT = new Vector2d(0.125, 0.125); @@ -92,6 +72,8 @@ public class Damcon implements MouseListener, MouseMotionListener, MouseWheelLis private Map<GridCoord, InternalNode> internalNodes = new HashMap<>(); private Set<InternalHallway> internalHallways = new HashSet<>(); private Map<Integer, InternalTeam> internalTeams = new HashMap<>(); + private Map<Node, Internal> nodesToInternals = new HashMap<>(); + private static final float PICK_TOLERANCE = 0.1f; public Damcon(EngineeringConsoleManager engineeringConsoleManager) { this.engineeringConsoleManager = engineeringConsoleManager; @@ -100,7 +82,7 @@ public Damcon(EngineeringConsoleManager engineeringConsoleManager) { if (WINDOW_HACK) { createUniverseAndScene_HACK(); - // TODO: This is a hack to get rid of the extra window. The reason this creates a new window is explained here: + // TODO: FILE ISSUE > This is a hack to get rid of the extra window. The reason this creates a new window is explained here: // http://download.java.net/media/java3d/javadoc/1.3.2/com/sun/j3d/utils/universe/Viewer.html // This might help: https://community.oracle.com/thread/1274674?start=0&tstart=0 JFrame unused_frame = universe.getViewer().getJFrame(0); @@ -132,7 +114,7 @@ private void loadAndWireframeifyModel() { String OBJ_PATH = new File(System.getProperty("user.dir"), "art/models/obj-from-blender/artemis2.obj").getPath(); try { this.scene = new ObjectFile(ObjectFile.RESIZE).load(OBJ_PATH); - wireframeifyScene(scene, LineAttributes.PATTERN_SOLID); + wireframeifyNonPickableScene(scene, LineAttributes.PATTERN_SOLID); } catch (FileNotFoundException | IncorrectFormatException | ParsingErrorException e) { e.printStackTrace(System.err); @@ -140,23 +122,19 @@ private void loadAndWireframeifyModel() { } private void loadInternalNodes() { - BranchGroup node_branchgroup = new BranchGroup(); + BranchGroup node_branchgroup = new BranchGroup(), damcon_branchgroup = new BranchGroup(); node_branchgroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND); node_branchgroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE); for (VesselNode vn : this.engineeringConsoleManager.getGrid()) { InternalNode in = new InternalNode(vn); internalNodes.put(vn.getGridCoord(), in); + nodesToInternals.put(in.getShape(), in); node_branchgroup.addChild(in.getBranchGroup()); } this.universe.addBranchGraph(node_branchgroup); - pickCanvas = new PickCanvas(this.canvas, node_branchgroup); - pickCanvas.setMode(PickInfo.PICK_GEOMETRY); - pickCanvas.setFlags(PickInfo.NODE | PickInfo.CLOSEST_INTERSECTION_POINT); - pickCanvas.setTolerance(0.5f); - this.engineeringConsoleManager.addChangeListener(new EngineeringConsoleManager.EngineeringConsoleChangeListener() { @Override public void onChange() { @@ -164,18 +142,20 @@ public void onChange() { InternalNode node = internalNodes.get(entry.getKey()); node.updateHealth(entry.getValue()); } - - for (EnhancedDamconStatus damconStatus : engineeringConsoleManager.getDamconTeams()) { + + for (EngineeringConsoleManager.EnhancedDamconStatus damconStatus : engineeringConsoleManager.getDamconTeams()) { InternalTeam it = internalTeams.get(damconStatus.getTeamNumber()); if (it == null) { it = new InternalTeam(damconStatus.getX(), damconStatus.getY(), damconStatus.getZ()); internalTeams.put(damconStatus.getTeamNumber(), it); - node_branchgroup.addChild(it.getBranchGroup()); + damcon_branchgroup.addChild(it.getBranchGroup()); } it.updatePos(damconStatus.getX(), damconStatus.getY(), damconStatus.getZ()); } } }); + + this.universe.addBranchGraph(damcon_branchgroup); } private void loadCorridors() { @@ -184,7 +164,9 @@ private void loadCorridors() { for (VesselNodeConnection vnc : this.engineeringConsoleManager.getGridConnections()) { InternalHallway ih = new InternalHallway(vnc); internalHallways.add(ih); - corridor_bg.addChild(ih.getShape()); + Node node = ih.getShape(); + nodesToInternals.put(node, ih); + corridor_bg.addChild(node); } this.universe.addBranchGraph(corridor_bg); @@ -206,6 +188,12 @@ private void createUniverseAndScene_HACK() { private void addMouseListeners() { this.canvas = universe.getCanvas(); + + pickCanvas = new PickCanvas(this.canvas, this.universe.getLocale()); + pickCanvas.setMode(PickInfo.PICK_GEOMETRY); // TODO: > needs to be PICK_GEOMETRY_INTERSECT_INFO? see https://community.oracle.com/thread/1276552?start=0&tstart=0 + pickCanvas.setFlags(PickInfo.NODE | PickInfo.CLOSEST_INTERSECTION_POINT); + pickCanvas.setTolerance(PICK_TOLERANCE); + this.canvas.addMouseListener(this); this.canvas.addMouseMotionListener(this); this.canvas.addMouseWheelListener(this); @@ -230,7 +218,7 @@ private TransformGroup getCamera() { /////////////// // Wireframe // /////////////// - private static void wireframeifyScene(Scene scene, int line_attribute_pattern) { + private static void wireframeifyNonPickableScene(Scene scene, int line_attribute_pattern) { Appearance wireframe = getWireframeAppearance(line_attribute_pattern); // TODO: This works for the Artemis OBJ model. If the scene graph has multiple Shape3D nodes, this would need to be set on all of them. Is that necessary or can we guarantee it won't be needed? @@ -240,14 +228,7 @@ private static void wireframeifyScene(Scene scene, int line_attribute_pattern) { if (node.getClass().equals(Shape3D.class)) { Shape3D s3d = (Shape3D) node; s3d.setAppearance(wireframe); - try { - s3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); - // TODO: try scene.setCapability above with BranchGroup.ALLOW_CHILDREN_WRITE etc. and see if this exception is no longer thrown - // See http://www.java-tips.org/other-api-tips-100035/119-java3d/1527-how-to-use-the-capability.html - // I got it working for the internal node spheres so I probably just need to figure out which node(s) to set it on, or set it on creation - } catch(RestrictedAccessException e) { - // e=Exception in thread "AWT-EventQueue-0" javax.media.j3d.RestrictedAccessException: Cannot modify capability bits on a live or compiled object - } + s3d.setPickable(false); } } } @@ -284,17 +265,28 @@ private static Appearance getWireframeAppearance(int line_attributes_pattern) { /////////// // Mouse // /////////// + @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == 1) { - // TODO: damcon selection and orders issuing - // pickCanvas.setShapeLocation(e); - // PickInfo[] pickInfos = pickCanvas.pickAll(); - - System.out.println("Left click:\n"); - /*for (PickInfo pi : pickInfos) { - System.out.println(pi); - }*/ + pickCanvas.setShapeLocation(e); + PickInfo pi = pickCanvas.pickClosest(); + + // TODO: DAMCON > Use pickAll(). Prioritize as follows: + // DAMCON teams, system nodes, non-system nodes, hallways + + for (Internal i : nodesToInternals.values()) { + i.setSelected(false); + } + + if (pi == null) { + return; + } + + Node scene_node = pi.getNode(); + Internal internal = nodesToInternals.get(scene_node); + internal.setSelected(true); + System.out.println("Selecting " + internal); } } @@ -457,7 +449,7 @@ public void setDamageShake (boolean enabled) { } public void setLineType(int line_attributes_pattern) { - wireframeifyScene(this.scene, line_attributes_pattern); + wireframeifyNonPickableScene(this.scene, line_attributes_pattern); } public void startDamageShake(long duration_ms, double intensity) { diff --git a/src/com/brindyblitz/artemis/engconsole/ui/damcon/Internal.java b/src/com/brindyblitz/artemis/engconsole/ui/damcon/Internal.java index 4a024f8..aa314c0 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/damcon/Internal.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/damcon/Internal.java @@ -1,12 +1,10 @@ package com.brindyblitz.artemis.engconsole.ui.damcon; -import com.brindyblitz.artemis.engconsole.ui.SystemStatusRenderer; import com.brindyblitz.artemis.engconsole.ui.SystemStatusSlider; import net.dhleong.acl.vesseldata.VesselNode; import javax.media.j3d.Appearance; -import javax.media.j3d.Node; import javax.vecmath.Color3f; import javax.vecmath.Point3f; import java.awt.*; @@ -15,7 +13,8 @@ public abstract class Internal { protected static final float SCALE = 0.0034f; protected static final float SHININESS = 0f; protected float alpha; - + protected boolean selected = false; + protected float healthPct = 1f; protected static Point3f vesselNodePosition(VesselNode vn) { Point3f p = new Point3f(-vn.getX(), vn.getY(), vn.getZ()); @@ -24,7 +23,14 @@ protected static Point3f vesselNodePosition(VesselNode vn) { } protected abstract Appearance appearanceFromHealthPercentage(float pct); - public abstract void updateHealth(float pct); + + public void updateHealth(float pct) { + this.healthPct = pct; + } + + protected void updateSelection() { + + } protected Color3f getColorFromHealth(float pct) { Color color = Color.getHSBColor( @@ -32,4 +38,8 @@ protected Color3f getColorFromHealth(float pct) { return new Color3f(color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f); } + public void setSelected(boolean selected) { + this.selected = selected; + updateSelection(); + } } diff --git a/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalHallway.java b/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalHallway.java index 113a68e..4aeeb50 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalHallway.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalHallway.java @@ -1,5 +1,6 @@ package com.brindyblitz.artemis.engconsole.ui.damcon; +import com.sun.j3d.utils.picking.PickTool; import net.dhleong.acl.vesseldata.VesselNodeConnection; import javax.media.j3d.*; @@ -23,11 +24,18 @@ public InternalHallway(VesselNodeConnection vessel_node_connection) { lineArray.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); this.shape = new Shape3D(lineArray, appearanceFromHealthPercentage(1f)); + this.shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + + this.shape.setCapability(Shape3D.ENABLE_PICK_REPORTING); this.shape.setPickable(true); + + // TODO: > make fully transparent sphere here for picking similar to picking from InternalNode? + // can you even pick a hallway in the real client? } @Override public void updateHealth(float pct) { + super.updateHealth(pct); shape.setAppearance(appearanceFromHealthPercentage(pct)); } diff --git a/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalNode.java b/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalNode.java index d2c1159..4774686 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalNode.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalNode.java @@ -23,39 +23,63 @@ public InternalNode(VesselNode vessel_node) { this.branchGroup = new BranchGroup(); - if (this.vesselNode.getSystem() != null) { - Vector3f pos = new Vector3f(-vessel_node.getX(), vessel_node.getY(), vessel_node.getZ()); - pos.scale(SCALE); + Vector3f pos = new Vector3f(-vessel_node.getX(), vessel_node.getY(), vessel_node.getZ()); + pos.scale(SCALE); - sphere = new Sphere(RADIUS, appearanceFromHealthPercentage(1f)); - sphere.getShape(Sphere.BODY).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + sphere = new Sphere(RADIUS, appearanceFromHealthPercentage(1f)); + sphere.getShape(Sphere.BODY).setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); - sphere.setCapability(Shape3D.ENABLE_PICK_REPORTING); - sphere.setPickable(true); + Transform3D transform = new Transform3D(); + transform.setTranslation(new Vector3f(Internal.vesselNodePosition(vessel_node))); - Transform3D transform = new Transform3D(); - transform.setTranslation(new Vector3f(Internal.vesselNodePosition(vessel_node))); + TransformGroup tg = new TransformGroup(); + tg.setTransform(transform); + tg.addChild(this.sphere); - TransformGroup tg = new TransformGroup(); - tg.setTransform(transform); - tg.addChild(sphere); + this.branchGroup.addChild(tg); - this.branchGroup.addChild(tg); - } + // TODO: this one works, remove unneeded calls to appearance caps elsewhere (except for internalhallway) + // be careful not to break anything! + Shape3D shape = this.sphere.getShape(Sphere.BODY); + shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); + + shape.setCapability(Shape3D.ENABLE_PICK_REPORTING); + shape.setPickable(true); } @Override public void updateHealth(float pct) { + super.updateHealth(pct); sphere.setAppearance(appearanceFromHealthPercentage(pct)); } + @Override + protected void updateSelection() { + if (!isSystemNode()) { + return; + } + + // TODO: > bug here. Transparency of something is jumping on first node selection after launch. Investigate. + if (selected) { + Appearance app = appearanceFromHealthPercentage(healthPct); + TransparencyAttributes ta = new TransparencyAttributes(TransparencyAttributes.NICEST, 0f); + app.setTransparencyAttributes(ta); + sphere.setAppearance(app); + } else { + updateHealth(healthPct); + } + + // TODO: can I pull this up to Internal? Node vs. shape vs. group issue, same as elsewhere, worth cleaning up + } + @Override protected Appearance appearanceFromHealthPercentage(float pct) { Appearance app = new Appearance(); app.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ); app.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE); app.setMaterial(new Material(BLACK, getColorFromHealth(pct), BLACK, BLACK, SHININESS)); - TransparencyAttributes transparency = new TransparencyAttributes(TransparencyAttributes.NICEST, alpha); // TODO: when hovering, make opaque + TransparencyAttributes transparency = new TransparencyAttributes(TransparencyAttributes.NICEST, + isSystemNode() ? alpha : 1f); // TODO: FILE ISSUE > when hovering, make opaque or circle or something app.setTransparencyAttributes(transparency); return app; } @@ -65,6 +89,10 @@ private InternalNode(Vector3d position, int IDONTWORKYET) { throw new NotImplementedException(); } + // Billboards... + // http://www.java2s.com/Code/Java/3D/Thisapplicationdemonstratestheuseofabillboardnode.htm + // http://www.java2s.com/Code/Java/3D/Createsasimplerotatingscenethatincludestwotextbillboards.htm + ///// ColorCube color_cube = new ColorCube(0.05d); @@ -104,4 +132,17 @@ private InternalNode(Vector3d position, int IDONTWORKYET) { public BranchGroup getBranchGroup() { return branchGroup; } + + public Shape3D getShape() { + return this.sphere.getShape(Sphere.BODY); + } + + private boolean isSystemNode() { + return this.vesselNode.getSystem() != null; + } + + @Override + public String toString() { + return "Node: " + this.vesselNode; + } } \ No newline at end of file diff --git a/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalTeam.java b/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalTeam.java index 10de15c..18a643e 100644 --- a/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalTeam.java +++ b/src/com/brindyblitz/artemis/engconsole/ui/damcon/InternalTeam.java @@ -24,18 +24,11 @@ public InternalTeam(float x, float y, float z) { this.branchGroup = new BranchGroup(); - sphere = new Sphere(RADIUS, appearance()); - // sphere = new Sphere(RADIUS, Shape3D.ALLOW_APPEARANCE_WRITE | Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE, appearanceFromHealthPercentage(1f)); - /*sphere.setCapability(Shape3D.ALLOW_APPEARANCE_READ); - sphere.setCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_READ); - sphere.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); - sphere.setCapability(Shape3D.ALLOW_APPEARANCE_OVERRIDE_WRITE);*/ - sphere.setCapability(Shape3D.ENABLE_PICK_REPORTING); - sphere.setPickable(true); - - + Shape3D shape = sphere.getShape(Sphere.BODY); + shape.setCapability(Shape3D.ENABLE_PICK_REPORTING); + shape.setPickable(true); tg = new TransformGroup(); updatePos(x, y, z); @@ -43,7 +36,6 @@ public InternalTeam(float x, float y, float z) { tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); this.branchGroup.addChild(tg); - } public void updatePos(float x, float y, float z) { @@ -67,7 +59,7 @@ private static Appearance appearance() { app.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_READ); app.setCapability(Appearance.ALLOW_COLORING_ATTRIBUTES_WRITE); app.setMaterial(new Material(ambientColour, emissiveColour, diffuseColour, specularColour, shininess)); - TransparencyAttributes transparency = new TransparencyAttributes(TransparencyAttributes.NICEST, .5f); // TODO: when hovering, make opaque + TransparencyAttributes transparency = new TransparencyAttributes(TransparencyAttributes.NICEST, .5f); // TODO: FILE ISSUE > when hovering, make opaque app.setTransparencyAttributes(transparency); return app; } @@ -75,4 +67,6 @@ private static Appearance appearance() { public BranchGroup getBranchGroup() { return branchGroup; } + + // TODO: > clean this up to bring in line with other Internal classes } \ No newline at end of file