package LDraw.Support; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.ArrayList; import java.util.HashMap; import javax.media.opengl.GL2; import Command.LDrawColor; import Command.LDrawDrawableElement; import Common.Box2; import Common.Matrix4; import Common.Ray3; import Common.Vector2f; import Common.Vector3f; import Renderer.ILDrawRenderer; public class LDrawDragHandle extends LDrawDrawableElement { // Shared tag to draw the standard drag handle sphere private static IntBuffer vaoTag; private static IntBuffer vboTag; private static IntBuffer vboVertexCount; private static final float HandleDiameter = 7.0f; int tag; Vector3f position; Vector3f initialPosition; ILDrawDragHandler target; SelT action; public LDrawDragHandle(){ vaoTag = IntBuffer.allocate(1); vboTag = IntBuffer.allocate(1); vboVertexCount = IntBuffer.allocate(1); position = Vector3f.getZeroVector3f(); initialPosition = Vector3f.getZeroVector3f(); } // ========== initWithTag:position: // ============================================= // // Purpose: Initialize the object with a tag to identify what vertex it is // connected to. // // ============================================================================== public LDrawDragHandle initWithTag(int tagIn, Vector3f positionIn) { super.init(); tag = tagIn; position = positionIn; initialPosition = positionIn; //makeSphereWithLongitudinalCount(gl2, 8, 8); return this; }// end initWithTag:position: // ========== initialPosition // =================================================== // // Purpose: Returns the coordinate this handle what at when initialized. // // ============================================================================== public Vector3f initialPosition() { return initialPosition; } // ========== isSelected // ======================================================== // // Purpose: Drag handles only show up when their associated primitive is // selected, so we always report being selected. This will make us // more transparent to the view selection code. // // ============================================================================== public boolean isSelected() { return true; } // ========== position // ========================================================== // // Purpose: Returns the world-coordinate location of the handle. // // ============================================================================== public Vector3f position() { return position; } // ========== tag // =============================================================== // // Purpose: Returns the identifier for this handle. Used to associate the // handle with a vertex. // // ============================================================================== public int tag() { return tag; } // ========== target // ============================================================ // // Purpose: Returns the object which owns the drag handle. // // ============================================================================== public ILDrawDragHandler target() { return target; } // ========== setAction: // ======================================================== // // Purpose: Sets the method to invoke when the handle is repositioned. // // ============================================================================== public void setAction(SelT actionIn) { action = actionIn; } // ========== setPosition:updateTarget: // ========================================= // // Purpose: Updates the current handle position, and triggers the action if // update flag is true. // // ============================================================================== public void setPosition(Vector3f positionIn, boolean update) { position = positionIn; if (update) { if (action == SelT.DragHandleChanged) target.dragHandleChanged(this); } }// end setPosition:updateTarget: // ========== setTarget: // ======================================================== // // Purpose: Sets the object to invoke the action on. // // ============================================================================== public void setTarget(ILDrawDragHandler sender) { target = sender; } // ========== draw:viewScale:parentColor: // ======================================= // // Purpose: Draw the drag handle. // // ============================================================================== public void draw(GL2 gl2, HashMap<Integer, Boolean> optionsMask, float scaleFactor, LDrawColor parentColor) { float handleScale = 0.0f; float drawRadius = 0.0f; handleScale = 1.0f / scaleFactor; drawRadius = HandleDiameter / 2 * handleScale; gl2.glDisable(GL2.GL_TEXTURE_2D); gl2.glPushMatrix(); { gl2.glTranslatef(position.getX(), position.getY(), position.getZ()); gl2.glScalef(drawRadius, drawRadius, drawRadius); gl2.glBindVertexArray(vaoTag.get(0)); gl2.glDrawArrays(GL2.GL_TRIANGLE_STRIP, 0, vboVertexCount.get(0)); gl2.glBindVertexArray(0); // Failing to unbind can cause bizarre // crashes if other VAOs are in display // lists } gl2.glPopMatrix(); gl2.glEnable(GL2.GL_TEXTURE_2D); }// end draw:viewScale:parentColor: // ========== drawSelf: // =========================================================== // // Purpose: Draw this directive and its subdirectives by calling APIs on // the passed in renderer, then calling drawSelf on children. // // Notes: Drag handles don't use DLs - they simply push their pos // to the renderer immediately. // // ================================================================================ public void drawSelf(ILDrawRenderer renderer) { float xyz[] = { position.getX(), position.getY(), position.getZ() }; renderer.drawDragHandle(xyz, HandleDiameter / 2); }// end drawSelf: // ========== hitTest:transform:viewScale:boundsOnly:creditObject:hits: // ======= // // Purpose: Tests the directive for an intersection between the pickRay and // spherical drag handle. // // ============================================================================== public void hitTest(Ray3 pickRay, Matrix4 transform, float scaleFactor, boolean boundsOnly, LDrawDirective creditObject, HashMap<LDrawDirective, Float> hits) { float handleScale = 0.0f; float drawRadius = 0.0f; FloatBuffer intersectDepth = FloatBuffer.allocate(1); boolean intersects = false; handleScale = 1.0f / scaleFactor; drawRadius = HandleDiameter / 2 * handleScale; drawRadius *= 1.5; // allow a little fudge intersects = MatrixMath.V3RayIntersectsSphere(pickRay, position, drawRadius, intersectDepth); if (intersects) { LDrawUtilities.registerHitForObject(this, intersectDepth, creditObject, hits); } }// end hitTest:transform:viewScale:boundsOnly:creditObject:hits: // ========== // depthTest:inBox:transform:creditObject:bestObject:bestDepth:======= // // Purpose: depthTest finds the closest primitive (in screen space) // overlapping a given point, as well as its device coordinate // depth. // // ============================================================================== public void depthTest(Vector2f pt, Box2 bounds, Matrix4 transform, LDrawDirective creditObject, ArrayList<LDrawDirective> bestObject, FloatBuffer bestDepth) { Vector3f v1 = MatrixMath.V3MulPointByProjMatrix(position, transform); if (MatrixMath.V2BoxContains(bounds, MatrixMath.V2Make(v1.getX(), v1.getY()))) { if (v1.getZ() <= bestDepth.get(0)) { bestDepth.put(v1.getZ()); if (creditObject != null) bestObject.add(creditObject); else bestObject.add(this); } } }// end depthTest:inBox:transform:creditObject:bestObject:bestDepth: // ========== moveBy: // =========================================================== // // Purpose: Displace the receiver by the given amounts in each direction. // The amounts in moveVector or relative to the element's current // location. // // Subclasses are required to move by exactly this amount. Any // adjustments they wish to make need to be returned in // -displacementForNudge:. // // ============================================================================== public void moveBy(Vector3f moveVector) { Vector3f newPosition = MatrixMath.V3Add(position, moveVector); setPosition(newPosition, true); }// end moveBy: }