// tflorez interface Selectable { //Vector2f getScreenPosition(); Vector3f getPositionVec(); Vector3f getDisplayPositionVec(); } interface Label { void setName(String name); String getName(); void setLabel(String label); String getLabel(); } class DistanceMeasurement { ISelectableLabel start, end; Vector3f difference = new Vector3f(); Vector3f differenceInTargetCoords = new Vector3f(); Vector3f midpoint = new Vector3f(); Vector3f midpointDisplayPos = new Vector3f(); Vector3f labelDisplayPos = new Vector3f(); int textColor = 0xFFFFFFFF; DistanceMeasurement(ISelectableLabel start, ISelectableLabel end) { this.start = start; this.end = end; update(); } void update() { difference.sub(end.getPositionVec(), start.getPositionVec()); lorentzMatrix.transform(difference, differenceInTargetCoords); midpoint.scaleAdd(0.5, difference, start.getPositionVec()); Relativity.displayTransform(lorentzMatrix, midpoint, midpointDisplayPos); } void drawGL(GL gl) { update(); String theLabel = this.buildLabel(); float theScale = 0.5; float labelX = screenX(midpointDisplayPos); float labelY = screenY(midpointDisplayPos) + height / 5f; labelDisplayPos = kamera.screenToModel(labelX, labelY); Vector3f startDispVec = start.getDisplayPositionVec(); Vector3f endDispVec = end.getDisplayPositionVec(); gl.glBegin(GL.GL_TRIANGLES); gl.glColor4f(1, 1, 1, 0); glVertexGL(gl, startDispVec); glVertexGL(gl, endDispVec); gl.glColor4f(1, 1, 1, 0.5); glVertexGL(gl, labelDisplayPos); gl.glEnd(); myLabelor.setTextColor(this.textColor); myLabelor.drawLabelGL(gl, theLabel, labelDisplayPos, theScale); } String buildLabel() { String theLabel = new String( "Distance Measurement: \n" + start.getName() + " to " + end.getName() + "\nworld coord distance: " + nfVec(this.difference, 1) + "\ntarget coord distance: " + nfVec(this.differenceInTargetCoords, 1) ); return theLabel; } } class FanSelection extends SelectableLabel { Selectable parentSelectable; ArrayList selectableLabels; //float radius; AxisAngle4f lookAxisAngle = new AxisAngle4f(kamera.look, 0); Matrix4f rotLook = new Matrix4f(); FanSelection(Selectable parentSelectable, List selectableLabels) { this.parentSelectable = parentSelectable; this.selectableLabels = new ArrayList(selectableLabels); if (parentSelectable instanceof Label) { this.setLabel( ((Label) parentSelectable).getName() ); this.setDisplayPosition(parentSelectable.getDisplayPositionVec()); } update(); } void update() { Vector3f parentDisplayPos = parentSelectable.getDisplayPositionVec(); Vector3f labelPos = new Vector3f(); Vector3f radialVec = new Vector3f(kamera.up); float distToLabel = getDistance(parentDisplayPos, kamera.pos); this.setDisplayPosition(parentDisplayPos); radialVec.scale(distToLabel / 12 * selectableLabels.size()); float theta = TWO_PI / (float)(selectableLabels.size()); lookAxisAngle.set(kamera.look, theta); rotLook.set(lookAxisAngle); for (int i=0; i 10) { updateHoverAndPick(this.selection, theKamera.pos, getPickDirection(theKamera, mouseX, mouseY)); } } void updateHoverAndPick (Collection theSelectables, Vector3f cameraPos, Vector3f pickingRayDirection) { millisLastUpdateHover = millis(); hover.clear(); hoverAngles.clear(); bestPick = null; angleToBestPick = PI; float distToBestPick = Float.MAX_VALUE; Vector3f cameraToSelectable = new Vector3f(); for (Iterator iter=theSelectables.iterator(); iter.hasNext();) { Selectable p = (Selectable) iter.next(); if (p == null || p.getDisplayPositionVec() == null) { continue; } cameraToSelectable.sub(p.getDisplayPositionVec(), cameraPos); float distToSelectable = cameraToSelectable.length(); float angleRayToSelectable = cameraToSelectable.angle(pickingRayDirection); if ( (angleRayToSelectable < angleToBestPick) || ( (angleRayToSelectable < minAngleToPreferClosest) && (distToSelectable < distToBestPick) ) ) { distToBestPick = distToSelectable; angleToBestPick = angleRayToSelectable; bestPick = p; } if ( angleRayToSelectable < minHoverAngle) { hover.add(p); hoverAngles.put(p, Float.valueOf(angleRayToSelectable)); } } } //Selectable pickPoint(Vector3f cameraPos, Vector3f pickingRayDirection) { Selectable pickPoint(Kamera theKamera, int theMouseX, int theMouseY) { updateHoverAndPick(this.selectables, theKamera.pos, getPickDirection(theKamera, theMouseX, theMouseY)); println(this + "pickPoint(): bestPick: " + bestPick + " , angle: " + angleToBestPick); println("minSelectionAngle: " + minSelectionAngle); if (angleToBestPick < minSelectionAngle) { return (Selectable) bestPick; } else { return null; } } } class Labelor { VTextRenderer vtext; float lineHeight; boolean backgroundVisible = false; float[] backgroundColor = new float[] {0.1f, 0.1f, 0.1f, 0.9f}; Labelor() { vtext = myVTextRenderer; // Use the highest lineHeight expected, rather than the sporadic bounds textRender gives for each string lineHeight = (float) vtext._textRender.getBounds("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ|()123456789!@#$%^&*").getHeight(); } void setTextColor(int theColorARGB) { this.vtext.setColor(getColor4fv(theColorARGB)); } void setBackgroundColor(int theColorARGB) { this.backgroundColor = getColor4fv(theColorARGB); } void drawLabelGL(GL gl, SelectableLabel sl, float scale) { drawLabelGL(gl, sl.getLabel(), sl.getDisplayPositionVec(), scale, 0f); } void drawLabelGL(GL gl, String msg, Vector3f position, float scale) { drawLabelGL(gl, msg, position, scale, -2.0f); } /* * @param verticalOffset vertical offset from the label's position on screen * (as a multiple of text lineheight) */ void drawLabelGL(GL gl, String msg, Vector3f position, float scale, float verticalOffset) { beginCylindricalBillboardGL(position.x, position.y, position.z); //SCALE float unclampedScale = 0.1; float nearClampRatio = 0.001; float farClampRatio = 0.00085*scale * 1280f / width; beginDistanceScaleGL(position, kamera.pos, unclampedScale, nearClampRatio, farClampRatio); // LABEL TEXT String[] msgLines = msg.split("\n"); for (int i=0; i>16) & 0xFF), (byte)((c>>8) & 0xFF), (byte)(c & 0xFF), (byte)((c>>24) & 0xFF)); } float[] getColor4fv(color c) { colorMode(RGB, 1.0f); return new float[] { red(c), green(c), blue(c), alpha(c) }; } // GL CONVENIENCE UTILS - TEXTURE void beginTextureGL(Texture tex) { tex.bind(); tex.enable(); } void endTextureGL(Texture tex) { tex.disable(); } // GL CONVENIENCE UTILS - SCALING void beginDistanceScaleGL(Vector3f objectPos, Vector3f kameraPos, float scale) { float s = scale * getDistance(objectPos, kameraPos); gl.glPushMatrix(); gl.glScalef(s, s, s); } void beginDistanceScaleGL(Vector3f objectPos, Vector3f kameraPos, float scale, float nearClampRatio, float farClampRatio) { float distToKamera = getDistance(objectPos, kameraPos); float s = min(distToKamera * nearClampRatio, scale); s = max(s, distToKamera * farClampRatio); gl.glPushMatrix(); gl.glScalef(s, s, s); } void endDistanceScaleGL() { gl.glPopMatrix(); } //Vector3f Utils float getDistance(Vector3f va, Vector3f vb) { float x = va.x - vb.x; float y = va.y - vb.y; float z = va.z - vb.z; return sqrt(x*x + y*y + z*z); } Vector3f getOffset(Vector3f from, Vector3f to) { return new Vector3f(to.x - from.x, to.y - from.y, to.z - from.z); } void scaleVectors(Vector3f[] v, float scale) { for (int i=0; i offset) : offset + (m - offset) % n * (m <= offset) : offset + (m - offset) % n + n */ double modulus(double m, double n, double offset) { if (m > offset) { return offset + (m - offset) % n; } else { return offset + n + (m - offset) % n; } } float logBase10(float value) { return (log(value) / log(10)); } float nearestPowerOf10Below(float value) { return pow(10, (int)logBase10(value)); } // STRING FORMATTING String nfVecArray(Vector3f[] vecArray, int digits) { StringBuilder sb = new StringBuilder(); for (int i=0; i 1) { fpsRecent = (frameCount - prevFrameCount) / deltaSeconds; secondsLastFpsAvg = seconds; prevFrameCount = frameCount; } } float getSecondsPerFrame() { return (float)secondsPerFrameStats.getMean(); } float getFramesPerSecond() { return 1.0f / getSecondsPerFrame(); } } void intervalSay(int frameInterval, String msg) { if (frameCount % frameInterval == 0) { println(msg); } } static class Dbg { static void say(String msg) { println(msg); } static void warn(String msg) { println("WARNING: " + msg); } static void dumphex(String name, int i) { println("hex(" + name + "): " + hex(i)); } static void dumpStreamBytes(InputStream inputStream, int numBytes) { try { byte[] b = new byte[numBytes]; inputStream.read(b, 0, numBytes); println("inputStream.toString(): " + inputStream.toString()); println("inputStream Bytes[0.."+numBytes+"]:"); dumpBytes(b, numBytes); } catch (Exception e){ println("Error reading inputStream: "); } } static void dumpBytes(byte[] b, int numBytes){ for (int i=0; i