diff options
author | Sven Gothel <[email protected]> | 2001-06-18 23:34:31 +0000 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2001-06-18 23:34:31 +0000 |
commit | 255908bf19515af5c3770cd304eece10f95b6ba8 (patch) | |
tree | 1e9cb3a5efb5380e811fd7f0f7d900fbcc32c5ba /demos/MiscDemos | |
parent | cc7376ee5616743cdd7b7a5c711f054b32ae8e4e (diff) |
2.8.0.0 pre-release cvs only
Diffstat (limited to 'demos/MiscDemos')
-rw-r--r-- | demos/MiscDemos/GearsVS.html | 13 | ||||
-rw-r--r-- | demos/MiscDemos/GearsVS.java | 501 | ||||
-rw-r--r-- | demos/MiscDemos/GearsVS_plugin13.html | 45 | ||||
-rw-r--r-- | demos/MiscDemos/jahuwaldt/gl/GLTools.java | 494 | ||||
-rw-r--r-- | demos/MiscDemos/jahuwaldt/gl/Matrix.java | 499 | ||||
-rw-r--r-- | demos/MiscDemos/jahuwaldt/gl/VirtualSphere.java | 255 |
6 files changed, 1807 insertions, 0 deletions
diff --git a/demos/MiscDemos/GearsVS.html b/demos/MiscDemos/GearsVS.html new file mode 100644 index 0000000..2f80c74 --- /dev/null +++ b/demos/MiscDemos/GearsVS.html @@ -0,0 +1,13 @@ +<HTML> +<HEAD> +<TITLE>Göthel Hard- und Software Entwicklungen</TITLE> +</HEAD> +<BODY LINK="#0000ff" VLINK="#800080" BGCOLOR="#e6e6ff"> +<hr> +<applet code="GearsVS.class" width=550 height=400> +<param name=frames value="55"> +</applet> +<hr> +</BODY> +</HTML> + diff --git a/demos/MiscDemos/GearsVS.java b/demos/MiscDemos/GearsVS.java new file mode 100644 index 0000000..c4a76f2 --- /dev/null +++ b/demos/MiscDemos/GearsVS.java @@ -0,0 +1,501 @@ +/**
+ * @(#) gears.java
+ * @(#) author: Brian Paul (converted to Java by Ron Cemer)
+ *
+ * This is a modification of the standard gears demo so that it
+ * uses the Virutal Sphere for converting mouse input to 3D
+ * rotation. --- Joe Huwaldt, Feburary 20, 2001
+ *
+ */
+
+import java.applet.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.lang.*;
+import java.util.*;
+import java.io.*;
+import java.util.*;
+import gl4java.*;
+import gl4java.drawable.*;
+import gl4java.awt.GLAnimCanvas;
+import gl4java.applet.SimpleGLAnimApplet1;
+import jahuwaldt.gl.*;
+
+
+/**
+* A version of the standard "gears" OpenGL demo
+* modified to use the Virtual Sphere algorithm for
+* converting 2D mouse movement into 3D model rotation.
+**/
+public class GearsVS extends SimpleGLAnimApplet1 {
+
+ /* Initialize the applet */
+
+
+ public void init() {
+ super.init();
+ Dimension d = getSize();
+
+ GLCapabilities caps = new GLCapabilities();
+ //caps.setDoubleBuffered(false);
+
+ canvas =
+ GLDrawableFactory.getFactory().createGLAnimCanvas(caps, d.width, d.height);
+
+ GearsVSRenderer gear = new GearsVSRenderer(true);
+ canvas.addGLEventListener(gear);
+
+ add("Center", canvas);
+ }
+
+ public static void main( String args[] ) {
+ GLContext.gljNativeDebug = true;
+ GLContext.gljClassDebug = true;
+
+ Frame mainFrame = new Frame("Gears with Virtual Sphere");
+
+ mainFrame.addWindowListener( new WindowAdapter() {
+ public void windowClosed(WindowEvent e) {
+ System.exit(0);
+ }
+ public void windowClosing(WindowEvent e) {
+ System.exit(0);
+ }
+ } );
+
+ Applet applet = new GearsVS();
+ mainFrame.add(applet);
+ applet.setSize(400, 500);
+ applet.init();
+ applet.start();
+
+ Dimension ps = applet.getPreferredSize();
+ mainFrame.setBounds(-100,-100,99,99);
+ mainFrame.setVisible(true);
+ mainFrame.setVisible(false);
+ mainFrame.setVisible(true);
+ Insets is = mainFrame.getInsets();
+ mainFrame.setBounds(0,0,
+ ps.width+is.left+is.right,
+ ps.height+is.top+is.bottom);
+ mainFrame.setVisible(true);
+ }
+
+ private class GearsVSRenderer implements GLEventListener, MouseListener, MouseMotionListener {
+ private static final float M_PI = 3.14159265359f;
+ private int gear1, gear2, gear3;
+ private float angle = 0.0f;
+
+ private boolean showGL = false;
+
+ private Point prevMouse;
+ private boolean mouseRButtonDown = false;
+ private float rot_matrix[] = Matrix.identity();
+
+ // Class variables required to implement the virtual sphere.
+ private VirtualSphere vs = new VirtualSphere();
+ private Point cueCenter = new Point();
+ private int cueRadius;
+ private boolean mouseDown = false;
+
+ private GLFunc gl;
+ private GLUFunc glu;
+ private GLContext glj;
+
+ Graphics gc = null;
+
+ public GearsVSRenderer(boolean showGL)
+ {
+ this.showGL=showGL;
+ }
+
+ public void init(GLDrawable drawable) {
+ gl = drawable.getGL();
+ glu = drawable.getGLU();
+ glj = drawable.getGLContext();
+
+ GLAnimCanvas cvs = (GLAnimCanvas)drawable;
+
+ Dimension size = cvs.getSize();
+ setupVS(size.width, size.height);
+
+ setInitialRotation();
+
+ float pos[] = { 5.0f, 5.0f, 10.0f, 0.0f };
+ float red[] = { 0.8f, 0.1f, 0.0f, 1.0f };
+ float green[] = { 0.0f, 0.8f, 0.2f, 1.0f };
+ float blue[] = { 0.2f, 0.2f, 1.0f, 1.0f };
+
+ gl.glClearColor(0f, 0f, 0f, 0f);
+
+ gl.glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ gl.glEnable(GL_CULL_FACE);
+ gl.glEnable(GL_LIGHTING);
+ gl.glEnable(GL_LIGHT0);
+ gl.glEnable(GL_DEPTH_TEST);
+
+ /* make the gears */
+ gear1 = gl.glGenLists(1);
+ gl.glNewList(gear1, GL_COMPILE);
+ gl.glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
+ gear(1.0f, 4.0f, 1.0f, 20, 0.7f);
+ gl.glEndList();
+
+ gear2 = gl.glGenLists(1);
+ gl.glNewList(gear2, GL_COMPILE);
+ gl.glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
+ gear(0.5f, 2.0f, 2.0f, 10, 0.7f);
+ gl.glEndList();
+
+ gear3 = gl.glGenLists(1);
+ gl.glNewList(gear3, GL_COMPILE);
+ gl.glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
+ gear(1.3f, 2.0f, 0.5f, 10, 0.7f);
+ gl.glEndList();
+
+ gl.glEnable(GL_NORMALIZE);
+
+ glj.gljCheckGL();
+
+ drawable.addMouseListener(this);
+ drawable.addMouseMotionListener(this);
+
+ System.out.println("init ..");
+ }
+
+ public void cleanup(GLDrawable drawable)
+ {
+ System.out.println("destroy(): " + this);
+ drawable.removeMouseListener(this);
+ drawable.removeMouseMotionListener(this);
+ }
+
+ public void reshape(gl4java.drawable.GLDrawable gld, int width, int height) {
+ float h = (float)height / (float)width;
+
+ gl.glViewport(0,0,width,height);
+ gl.glMatrixMode(GL_PROJECTION);
+ gl.glLoadIdentity();
+ gl.glFrustum(-1.0f, 1.0f, -h, h, 5.0f, 60.0f);
+ gl.glMatrixMode(GL_MODELVIEW);
+ gl.glLoadIdentity();
+ gl.glTranslatef(0.0f, 0.0f, -40.0f);
+
+ // Resize the virtual sphere too!
+ setupVS(width, height);
+ }
+
+ public void preDisplay(GLDrawable drawable)
+ {
+ }
+
+ public void display(GLDrawable drawable)
+ {
+
+ if(showGL)
+ {
+ showGL=false;
+ System.out.println("GL VERSION : "+gl.glGetString(GL_VERSION));
+ System.out.println("GL RENDERER: "+gl.glGetString(GL_RENDERER));
+ System.out.println("GL VENDOR : "+gl.glGetString(GL_VENDOR));
+ }
+
+ angle += 0.5f;
+
+ gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ gl.glPushMatrix();
+ gl.glMultMatrixf(rot_matrix);
+
+ gl.glPushMatrix();
+ gl.glTranslatef(-3.0f, -2.0f, 0.0f);
+ gl.glRotatef(angle, 0.0f, 0.0f, 1.0f);
+ gl.glCallList(gear1);
+ gl.glPopMatrix();
+
+ gl.glPushMatrix();
+ gl.glTranslatef(3.1f, -2.0f, 0.0f);
+ gl.glRotatef(-2.0f * angle - 9.0f, 0.0f, 0.0f, 1.0f);
+ gl.glCallList(gear2);
+ gl.glPopMatrix();
+
+ gl.glPushMatrix();
+ gl.glTranslatef(-3.1f, 4.2f, 0.0f);
+ gl.glRotatef(-2.0f * angle - 25.0f, 0.0f, 0.0f, 1.0f);
+ gl.glCallList(gear3);
+ gl.glPopMatrix();
+
+ gl.glPopMatrix();
+
+ }
+
+ public void postDisplay(GLDrawable drawable)
+ {
+ // If the mouse is down, draw the virtual sphere 2D representation.
+ if (mouseDown)
+ drawVS(drawable);
+ }
+ /**
+ * Set up the virtual sphere cue center and radius.
+ **/
+ private void setupVS(int w, int h) {
+ cueCenter.x = w/2;
+ cueCenter.y = h/2;
+
+ cueRadius = Math.min(w-20, h-20)/2;
+ }
+
+ /**
+ * Render a 2D representation of the virtual sphere
+ * to give the user some visual feedback.
+ **/
+ private void drawVS(GLDrawable drawable) {
+ GLAnimCanvas cvs = (GLAnimCanvas)drawable;
+
+ if(gc==null)
+ gc = cvs.getGraphics();
+ Color saveColor = gc.getColor();
+ gc.setColor(Color.gray);
+
+ vs.draw(gc, prevMouse, cueCenter, cueRadius);
+
+ gc.setColor(saveColor);
+ }
+
+ private void gear
+ (float inner_radius,
+ float outer_radius,
+ float width,
+ int teeth,
+ float tooth_depth)
+ {
+ int i;
+ float r0, r1, r2;
+ float angle, da;
+ float u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0f;
+ r2 = outer_radius + tooth_depth / 2.0f;
+
+ da = 2.0f * M_PI / teeth / 4.0f;
+
+ gl.glShadeModel(GL_FLAT);
+
+ gl.glNormal3f(0.0f, 0.0f, 1.0f);
+
+ /* draw front face */
+ gl.glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++)
+ {
+ angle = i * 2.0f * M_PI / teeth;
+ gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
+ gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
+ gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
+ gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
+ }
+ gl.glEnd();
+
+ /* draw front sides of teeth */
+ gl.glBegin(GL_QUADS);
+ da = 2.0f * M_PI / teeth / 4.0f;
+ for (i = 0; i < teeth; i++)
+ {
+ angle = i * 2.0f * M_PI / teeth;
+ gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
+ gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
+ gl.glVertex3f(r2 * (float)Math.cos(angle + 2.0f * da), r2 * (float)Math.sin(angle + 2.0f * da), width * 0.5f);
+ gl.glVertex3f(r1 * (float)Math.cos(angle + 3.0f * da), r1 * (float)Math.sin(angle + 3.0f * da), width * 0.5f);
+ }
+ gl.glEnd();
+
+ gl.glNormal3f(0.0f, 0.0f, -1.0f);
+
+ /* draw back face */
+ gl.glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++)
+ {
+ angle = i * 2.0f * M_PI / teeth;
+ gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
+ gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
+ gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
+ gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
+ }
+ gl.glEnd();
+
+ /* draw back sides of teeth */
+ gl.glBegin(GL_QUADS);
+ da = 2.0f * M_PI / teeth / 4.0f;
+ for (i = 0; i < teeth; i++)
+ {
+ angle = i * 2.0f * M_PI / teeth;
+ gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
+ gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
+ gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
+ gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
+ }
+ gl.glEnd();
+
+ /* draw outward faces of teeth */
+ gl.glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < teeth; i++)
+ {
+ angle = i * 2.0f * M_PI / teeth;
+ gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), width * 0.5f);
+ gl.glVertex3f(r1 * (float)Math.cos(angle), r1 * (float)Math.sin(angle), -width * 0.5f);
+ u = r2 * (float)Math.cos(angle + da) - r1 * (float)Math.cos(angle);
+ v = r2 * (float)Math.sin(angle + da) - r1 * (float)Math.sin(angle);
+ len = (float)Math.sqrt(u * u + v * v);
+ u /= len;
+ v /= len;
+ gl.glNormal3f(v, -u, 0.0f);
+ gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), width * 0.5f);
+ gl.glVertex3f(r2 * (float)Math.cos(angle + da), r2 * (float)Math.sin(angle + da), -width * 0.5f);
+ gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
+ gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), width * 0.5f);
+ gl.glVertex3f(r2 * (float)Math.cos(angle + 2 * da), r2 * (float)Math.sin(angle + 2 * da), -width * 0.5f);
+ u = r1 * (float)Math.cos(angle + 3 * da) - r2 * (float)Math.cos(angle + 2 * da);
+ v = r1 * (float)Math.sin(angle + 3 * da) - r2 * (float)Math.sin(angle + 2 * da);
+ gl.glNormal3f(v, -u, 0.0f);
+ gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), width * 0.5f);
+ gl.glVertex3f(r1 * (float)Math.cos(angle + 3 * da), r1 * (float)Math.sin(angle + 3 * da), -width * 0.5f);
+ gl.glNormal3f((float)Math.cos(angle), (float)Math.sin(angle), 0.0f);
+ }
+ gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), width * 0.5f);
+ gl.glVertex3f(r1 * (float)Math.cos(0), r1 * (float)Math.sin(0), -width * 0.5f);
+ gl.glEnd();
+
+ gl.glShadeModel(GL_SMOOTH);
+
+ /* draw inside radius cylinder */
+ gl.glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++)
+ {
+ angle = i * 2.0f * M_PI / teeth;
+ gl.glNormal3f(-(float)Math.cos(angle), -(float)Math.sin(angle), 0.0f);
+ gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), -width * 0.5f);
+ gl.glVertex3f(r0 * (float)Math.cos(angle), r0 * (float)Math.sin(angle), width * 0.5f);
+ }
+ gl.glEnd();
+ }
+
+ // Reset the rotation matrix to the default view.
+ private void setInitialRotation() {
+
+ Matrix.rotateY(Matrix.deg2Rad(30), rot_matrix);
+ Matrix.rotateX(Matrix.deg2Rad(20), rot_matrix);
+ fixRotationMatrix();
+ }
+
+ private void fixRotationMatrix()
+ {
+ // Fix any problems with the rotation matrix.
+ rot_matrix[3] =
+ rot_matrix[7] =
+ rot_matrix[11] =
+ rot_matrix[12] =
+ rot_matrix[13] =
+ rot_matrix[14] = 0.0f;
+ rot_matrix[15] = 1.0f;
+ float fac;
+ if ((fac = (float)Math.sqrt
+ ((rot_matrix[0]*rot_matrix[0]) +
+ (rot_matrix[4]*rot_matrix[4]) +
+ (rot_matrix[8]*rot_matrix[8]))) != 1.0f)
+ {
+ if (fac != 0.0f)
+ {
+ fac = 1.0f/fac;
+ rot_matrix[0] *= fac;
+ rot_matrix[4] *= fac;
+ rot_matrix[8] *= fac;
+ }
+ }
+ if ((fac = (float)Math.sqrt
+ ((rot_matrix[1]*rot_matrix[1]) +
+ (rot_matrix[5]*rot_matrix[5]) +
+ (rot_matrix[9]*rot_matrix[9]))) != 1.0f)
+ {
+ if (fac != 0.0f)
+ {
+ fac = 1.0f/fac;
+ rot_matrix[1] *= fac;
+ rot_matrix[5] *= fac;
+ rot_matrix[9] *= fac;
+ }
+ }
+ if ((fac = (float)Math.sqrt
+ ((rot_matrix[2]*rot_matrix[2]) +
+ (rot_matrix[6]*rot_matrix[6]) +
+ (rot_matrix[10]*rot_matrix[10]))) != 1.0f)
+ {
+ if (fac != 0.0f)
+ {
+ fac = 1.0f/fac;
+ rot_matrix[2] *= fac;
+ rot_matrix[6] *= fac;
+ rot_matrix[10] *= fac;
+ }
+ }
+ }
+
+ // Methods required for the implementation of MouseListener
+ public void mouseEntered( MouseEvent evt )
+ {
+ }
+
+ public void mouseExited( MouseEvent evt )
+ {
+ }
+
+ public void mousePressed( MouseEvent evt ) {
+
+ mouseDown = true;
+ prevMouse = evt.getPoint();
+ if ((evt.getModifiers() & evt.BUTTON3_MASK) != 0) {
+ mouseRButtonDown = true;
+ evt.consume();
+ }
+ }
+
+ public void mouseReleased( MouseEvent evt ) {
+
+ mouseDown = false;
+ if ((evt.getModifiers() & evt.BUTTON3_MASK) != 0) {
+ mouseRButtonDown = false;
+ evt.consume();
+ }
+ }
+
+ public void mouseClicked( MouseEvent evt )
+ {
+ }
+
+ // Methods required for the implementation of MouseMotionListener
+ float[] mouseMtx = new float[16]; // The rot-matrix calculated by the virtual sphere.
+ public void mouseDragged( MouseEvent evt )
+ {
+ Point newMouse = evt.getPoint();
+
+ if (newMouse.x != prevMouse.x || newMouse.y != prevMouse.y) {
+
+ // Use virtual sphere to determine an incremental rotation matrix.
+ vs.makeRotationMtx(prevMouse, newMouse, cueCenter, cueRadius, mouseMtx);
+
+ // Multiply overall rotation matrix by incremental rot-matrix to get new rotation.
+ rot_matrix = Matrix.multiply(rot_matrix, mouseMtx);
+ fixRotationMatrix();
+
+ prevMouse = newMouse;
+ }
+
+ evt.consume();
+
+ }
+
+ public void mouseMoved( MouseEvent evt )
+ {
+ }
+ }
+}
+
diff --git a/demos/MiscDemos/GearsVS_plugin13.html b/demos/MiscDemos/GearsVS_plugin13.html new file mode 100644 index 0000000..7cbc068 --- /dev/null +++ b/demos/MiscDemos/GearsVS_plugin13.html @@ -0,0 +1,45 @@ +<HTML> +<HEAD> +<TITLE>Göthel Hard- und Software Entwicklungen</TITLE> +</HEAD> +<BODY LINK="#0000ff" VLINK="#800080" BGCOLOR="#e6e6ff"> +<hr> +<!--"CONVERTED_APPLET"--> +<!-- CONVERTER VERSION 1.3 --> +<SCRIPT LANGUAGE="JavaScript"><!-- + var _info = navigator.userAgent; var _ns = false; + var _ie = (_info.indexOf("MSIE") > 0 && _info.indexOf("Win") > 0 && _info.indexOf("Windows 3.1") < 0); +//--></SCRIPT> +<COMMENT><SCRIPT LANGUAGE="JavaScript1.1"><!-- + var _ns = (navigator.appName.indexOf("Netscape") >= 0 && ((_info.indexOf("Win") > 0 && _info.indexOf("Win16") < 0 && java.lang.System.getProperty("os.version").indexOf("3.5") < 0) || (_info.indexOf("Sun") > 0) || (_info.indexOf("Linux") > 0))); +//--></SCRIPT></COMMENT> + +<SCRIPT LANGUAGE="JavaScript"><!-- + if (_ie == true) document.writeln('<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" WIDTH = 550 HEIGHT = 400 codebase="http://java.sun.com/products/plugin/1.3/jinstall-13-win32.cab#Version=1,3,0,0"><NOEMBED><XMP>'); + else if (_ns == true) document.writeln('<EMBED type="application/x-java-applet;version=1.3" CODE = "GearsVS.class" WIDTH = 550 HEIGHT = 400 frames = "55" scriptable=false pluginspage="http://java.sun.com/products/plugin/1.3/plugin-install.html"><NOEMBED><XMP>'); +//--></SCRIPT> +<APPLET CODE = "GearsVS.class" WIDTH = 550 HEIGHT = 400></XMP> +<PARAM NAME = CODE VALUE = "GearsVS.class" > + +<PARAM NAME="type" VALUE="application/x-java-applet;version=1.3"> +<PARAM NAME="scriptable" VALUE="false"> +<PARAM NAME = frames VALUE ="55"> + +</APPLET> + +</NOEMBED></EMBED></OBJECT> + + +<!-- +<APPLET CODE = "GearsVS.class" WIDTH = 550 HEIGHT = 400> +<PARAM NAME = frames VALUE ="55"> + + +</APPLET> +--> +<!--"END_CONVERTED_APPLET"--> + +<hr> +</BODY> +</HTML> + diff --git a/demos/MiscDemos/jahuwaldt/gl/GLTools.java b/demos/MiscDemos/jahuwaldt/gl/GLTools.java new file mode 100644 index 0000000..1c28540 --- /dev/null +++ b/demos/MiscDemos/jahuwaldt/gl/GLTools.java @@ -0,0 +1,494 @@ +/*
+* GLTools -- A collection of static methods for working with 3D graphics.
+*
+* Copyright (C) 2001 by Joseph A. Huwaldt <[email protected]>.
+* All rights reserved.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+**/
+
+package jahuwaldt.gl;
+
+
+/**
+* A set of static utility methods for working with 3D graphics.
+* In particular, these methods are geared for working efficiently
+* with GL4Java and OpenGL.
+*
+* <p> Modified by: Joseph A. Huwaldt </p>
+*
+* @author Joseph A. Huwaldt Date: January 13, 2001
+* @version February 19, 2001
+**/
+public class GLTools {
+
+ // Some constants for convenience.
+ private static final int X = 0;
+ private static final int Y = 1;
+ private static final int Z = 2;
+
+ // Some error messages.
+ private static final String kVector3DMsg = "Vectors must be 3D (3 elements).";
+ private static final String kPoint3DMsg = "Points must be 3D (3 elements).";
+ private static final String kNormal3DMsg = "Normal vector must be 3D (3 elements).";
+
+
+ /**
+ * This method will normalize a 3D vector to have
+ * a length of 1.0. The unit vector is placed in the
+ * specified output vector (which may safely be a reference
+ * to the input vector).
+ *
+ * @param vector The 3D (3 element) vector to be normalized.
+ * @param output The 3D (3 element) vector that will contain
+ * the normalized version of the input vector.
+ * @return A reference to the output normalized vector.
+ **/
+ public static final float[] normalize(float vector[], float[] output) {
+ if (vector.length != 3 || output.length != 3)
+ throw new IllegalArgumentException(kVector3DMsg);
+
+ float v0 = vector[X], v1 = vector[Y], v2 = vector[Z];
+ float length = (float)Math.sqrt( v0*v0 + v1*v1 + v2*v2 );
+
+ // Do not allow a divide by zero.
+ if (length == 0)
+ length = 1;
+
+ // Divide each element by the length to get a unit vector.
+ output[X] = v0/length;
+ output[Y] = v1/length;
+ output[Z] = v2/length;
+
+ return output;
+ }
+
+ /**
+ * This method will normalize a 3D vector to have
+ * a length of 1.0. A new vector is created that is the normalized
+ * version of the input vector.
+ *
+ * @param vector The 3D (3 element) vector to be normalized.
+ * @return A reference to the new output normalized vector.
+ **/
+ public static final float[] normalize(float vector[]) {
+ if (vector.length != 3)
+ throw new IllegalArgumentException(kVector3DMsg);
+
+ float v0 = vector[X], v1 = vector[Y], v2 = vector[Z];
+ float length = (float)Math.sqrt( v0*v0 + v1*v1 + v2*v2 );
+
+ // Do not allow a divide by zero.
+ if (length == 0)
+ length = 1;
+
+ // Divide each element by the length to get a unit vector.
+ float[] output = new float[3];
+ output[X] = v0/length;
+ output[Y] = v1/length;
+ output[Z] = v2/length;
+
+ return output;
+ }
+
+ /**
+ * Calculate the normal vector for a plane (triangle) defined
+ * by 3 points in space. The points must be specified in
+ * counterclockwise order. The normal vector is placed in the
+ * specified output vector.
+ *
+ * @param pnt1 The 1st 3D point in the plane.
+ * @param pnt2 The 2nd 3D point in the plane.
+ * @param pnt3 The 3rd 3D point in the plane.
+ * @param output The 3D vector (3 element array) that will be filled in
+ * with the normal vector for this plane.
+ * @return A reference to the output normal vector.
+ **/
+ public static final float[] calcNormal(float[] pnt1, float[] pnt2, float[] pnt3,
+ float[] output) {
+ if (pnt1.length != 3 || pnt2.length != 3 || pnt3.length != 3)
+ throw new IllegalArgumentException(kPoint3DMsg);
+ if (output.length != 3)
+ throw new IllegalArgumentException(kNormal3DMsg);
+
+ // Calculate two vectors from e three points.
+ float v10 = pnt1[X] - pnt2[X];
+ float v11 = pnt1[Y] - pnt2[Y];
+ float v12 = pnt1[Z] - pnt2[Z];
+
+ float v20 = pnt2[X] - pnt3[X];
+ float v21 = pnt2[Y] - pnt3[Y];
+ float v22 = pnt2[Z] - pnt3[Z];
+
+ // Take the cross product of the two vectors and store in output.
+ output[X] = v11*v22 - v12*v21;
+ output[Y] = v12*v20 - v10*v22;
+ output[Z] = v10*v21 - v11*v20;
+
+ // Normalize the resulting vector and return it.
+ return normalize(output, output);
+ }
+
+ /**
+ * Calculate the normal vector for a plane (triangle) defined
+ * by 3 points in space. The points must be specified in
+ * counterclockwise order. A new normal vector is created and
+ * returned by this method.
+ *
+ * @param pnt1 The 1st 3D point in the plane.
+ * @param pnt2 The 2nd 3D point in the plane.
+ * @param pnt3 The 3rd 3D point in the plane.
+ * @return A reference to the new 3D output normal vector.
+ **/
+ public static final float[] calcNormal(float[] pnt1, float[] pnt2, float[] pnt3) {
+ if (pnt1.length != 3 || pnt2.length != 3 || pnt3.length != 3)
+ throw new IllegalArgumentException(kPoint3DMsg);
+
+ // Calculate two vectors from e three points.
+ float v10 = pnt1[X] - pnt2[X];
+ float v11 = pnt1[Y] - pnt2[Y];
+ float v12 = pnt1[Z] - pnt2[Z];
+
+ float v20 = pnt2[X] - pnt3[X];
+ float v21 = pnt2[Y] - pnt3[Y];
+ float v22 = pnt2[Z] - pnt3[Z];
+
+ // Take the cross product of the two vectors and store in output.
+ float[] output = new float[3];
+ output[X] = v11*v22 - v12*v21;
+ output[Y] = v12*v20 - v10*v22;
+ output[Z] = v10*v21 - v11*v20;
+
+ // Normalize the resulting vector and return it.
+ return normalize(output, output);
+ }
+
+ /**
+ * Returns the length of a 3D vector.
+ *
+ * @param vector A 3D (3 element) vector.
+ * @return The length of the input vector.
+ **/
+ public static final float length3D(float[] vector) {
+ if (vector.length != 3)
+ throw new IllegalArgumentException(kVector3DMsg);
+ double dx = vector[X];
+ double dy = vector[Y];
+ double dz = vector[Z];
+ return (float)Math.sqrt(dx*dx + dy*dy + dz*dz);
+ }
+
+ /**
+ * Returns the dot product of two 3D vectors.
+ *
+ * @param a The 1st 3D (3 element) vector.
+ * @param b The 2nd 3D (3 element) vector.
+ * @return The dot product of the two vectors.
+ **/
+ public static final float dotProduct3D(float[] a, float[] b) {
+ if (a.length != 3 || b.length != 3)
+ throw new IllegalArgumentException(kVector3DMsg);
+ return (a[X]*b[X] + a[Y]*b[Y] + a[Z]*b[Z]);
+ }
+
+ /**
+ * Returns the right-handed cross product of 3D vectors A and B in AcrossB.
+ *
+ * @param A The 1st 3D (3 element) vector.
+ * @param B The 2nd 3D (3 element) vector.
+ * @param AcrossB A 3D (3 element) vector to be filled in with the cross
+ * product of A and B. This vector will be overwritten
+ * by this method.
+ * @return A reference to the input vector AcrossB.
+ **/
+ public static final float[] crossProduct3D(float[] A, float[] B, float[] AcrossB) {
+ if (A.length != 3 || B.length != 3 || AcrossB.length != 3)
+ throw new IllegalArgumentException(kVector3DMsg);
+ AcrossB[X] = A[Y] * B[Z] - A[Z] * B[Y];
+ AcrossB[Y] = A[Z] * B[X] - A[X] * B[Z];
+ AcrossB[Z] = A[X] * B[Y] - A[Y] * B[X];
+ return AcrossB;
+ }
+
+ /**
+ * A method for calculating 3D Euclidian distance or length.
+ *
+ * @param dx The difference between X coordinates (X2 - X1).
+ * @param dy The difference between Y coordinates (Y2 - Y1).
+ * @param dz The difference between Z coordinates (Z2 - Z1).
+ * @return The distance between the two points.
+ **/
+ public static final float distance(double dx, double dy, double dz) {
+ return (float)Math.sqrt(dx*dx + dy*dy + dz*dz);
+ }
+
+ /**
+ * A method for calculating the distance between two
+ * points specified as arrays with 3 elements.
+ *
+ * @param pnt1 An array with 3 elements (X,Y,Z) representing the 1st point.
+ * @param pnt2 An array with 3 elements (X,Y,Z) representing the 2nd point.
+ * @return The distance between the two points.
+ **/
+ public static final float distance(float[] pnt1, float[] pnt2) {
+ if (pnt1.length != 3 || pnt2.length != 3)
+ throw new IllegalArgumentException(kPoint3DMsg);
+ double dx = pnt2[X] - pnt1[X];
+ double dy = pnt2[Y] - pnt1[Y];
+ double dz = pnt2[Z] - pnt1[Z];
+ return (float)Math.sqrt(dx*dx + dy*dy + dz*dz);
+ }
+
+ /**
+ * A method for calculating the distance between two
+ * points specified as arrays with 3 elements.
+ *
+ * @param pnt1 An array with 3 elements (X,Y,Z) representing the 1st point.
+ * @param pnt2 An array with 3 elements (X,Y,Z) representing the 2nd point.
+ * @return The distance between the two points.
+ **/
+ public static final float distance(int[] pnt1, int[] pnt2) {
+ if (pnt1.length != 3 || pnt2.length != 3)
+ throw new IllegalArgumentException(kPoint3DMsg);
+ double dx = pnt2[X] - pnt1[X];
+ double dy = pnt2[Y] - pnt1[Y];
+ double dz = pnt2[Z] - pnt1[Z];
+ return (float)Math.sqrt(dx*dx + dy*dy + dz*dz);
+ }
+
+ /**
+ * A fast approximation to 3D Euclidian distance or length!
+ * Accurate to within 13%. Also knowns as the "Manhattan" distance.
+ * This method approximates 3D distance as follows:
+ * <code>
+ * dist = sqrt(dx*dx + dy*dy + dz*dz)
+ * approx. dist = max + (med + min)/4
+ * </code>
+ * Uses shifting and adding. No multiplication, division or sqrt calculations.
+ *
+ * @param dx The difference between X coordinates (X2 - X1).
+ * @param dy The difference between Y coordinates (Y2 - Y1).
+ * @param dz The difference between Z coordinates (Z2 - Z1).
+ * @return The approximate distance between two points.
+ **/
+ public static final int distanceApprox(int dx, int dy, int dz) {
+ int maxc = dx > 0 ? dx:-dx; // Math.abs(dx);
+ int medc = dy > 0 ? dy:-dy; // Math.abs(dy);
+ int minc = dz > 0 ? dz:-dz; // Math.abs(dz);
+
+ if (maxc < medc) {
+ int temp = maxc;
+ maxc = medc;
+ medc = temp;
+ }
+ if (maxc < minc) {
+ int temp = maxc;
+ maxc = minc;
+ minc = temp;
+ }
+
+ medc += minc;
+ medc >>= 2;
+ maxc += medc;
+
+ return maxc;
+ }
+
+ /**
+ * A fast approximation to 2D Euclidian distance or length!
+ * Also knowns as the "Manhattan" distance.
+ * This method approximates 2D distance as follows:
+ * <code>
+ * dist = sqrt(dx*dx + dy*dy)
+ * approx. dist = max + min/4
+ * </code>
+ * Uses shifting and adding. No multiplication, division or sqrt calculations.
+ *
+ * @param dx The difference between X coordinates (X2 - X1).
+ * @param dy The difference between Y coordinates (Y2 - Y1).
+ * @return The approximate distance between two points.
+ **/
+ public static final int distanceApprox(int dx, int dy) {
+ int maxc = dx > 0 ? dx:-dx; // Math.abs(dx);
+ int minc = dy > 0 ? dy:-dy; // Math.abs(dy);
+
+ if (maxc < minc) {
+ int temp = maxc;
+ maxc = minc;
+ minc = temp;
+ }
+
+ minc >>= 2;
+ maxc += minc;
+
+ return maxc;
+ }
+
+ // **** The following are used by the CORDIC fixed point trigonometry routines ****
+
+ private static final int COSCALE=0x11616E8E; // 291597966 = 0.2715717684432241*2^30, valid for j>13
+ private static final int QUARTER = 90<<16;
+ private static final int MAXITER=22;
+ // Table of Cordic values for arctangent in degrees.
+ private static final int arctantab[] = {
+ 4157273, 2949120, 1740967, 919879, 466945, 234379, 117304, 58666,
+ 29335, 14668, 7334, 3667, 1833, 917, 458, 229,
+ 115, 57, 29, 14, 7, 4, 2, 1
+ };
+ private static int xtemp, ytemp; // Temporary storage space used by CORDIC methods.
+
+
+ /**
+ * Converts fixed point coordinates (b,a) to polar coordinates (r, theta) and
+ * returns the angle theta in degrees as a fixed point integer number.
+ * This method is about 40% faster than Math.atan2() using 22 iterations,
+ * but a small amount of accuracy is lost. It is 50% faster than Math.atan2()
+ * using 11 iterations and is still good to +/- 1 degree.
+ * This code is based on that found in "Cordic.c" by Ken Turkowski.
+ *
+ * <p> WARNING!! This method is not thread safe! It stores intermediate results in
+ * a static class variable. Sorry, needed to do that for speed. </p>
+ *
+ * @param iter The number of CORDIC iterations to compute. Will be clamped to (1 <= iter <= 22).
+ * More iterations gives more accurate results, but takes longer.
+ * @param a The first fixed point coordinate value (a = (int)(y)<<16).
+ * @param b The 2nd fixed point coordinate value (b = (int)(x)<<16).
+ * @return The fixed point polar coordinate angle theta is returned (double theta = value/65536.).
+ * The angle returned is in degrees and is (0 <= theta < 360).
+ **/
+ public static final int fixedAtan2D(int iter, int a, int b) {
+ if ((a == 0) && (b == 0))
+ return 0;
+
+ fxPreNorm(a, b); /* Prenormalize vector for maximum precision */
+
+ b = pseudoPolarize(xtemp, ytemp, iter); /* Convert to polar coordinates */
+
+ // Get into a 0 to 360 degree range.
+ b = 90*(1<<16) - b;
+ if (b < 0)
+ b += 360<<16;
+ return b;
+ }
+
+ /**
+ * This method converts the fixed point input cartesian values
+ * to fixed point polar notation. On completion of this routine
+ * xtemp contains the radius and ytemp contains the angle. The
+ * angle is also returned by this method.
+ * This code is based on that found in "Cordic.c" by Ken Turkowski.
+ **/
+ private static int pseudoPolarize(int x, int y, int iter) {
+
+ /* Get the vector into the right half plane */
+ int theta = 0;
+ if (x < 0) {
+ x = -x;
+ y = -y;
+ theta = 2*QUARTER;
+ }
+
+ if (y > 0)
+ theta = -theta;
+
+ int[] arctanptr = arctantab;
+ int yi = 0, pos = 0;
+ if (y < 0) { /* Rotate positive */
+ yi = y + (x << 1);
+ x = x - (y << 1);
+ y = yi;
+ theta -= arctanptr[pos++]; /* Subtract angle */
+ }
+ else { /* Rotate negative */
+ yi = y - (x << 1);
+ x = x + (y << 1);
+ y = yi;
+ theta += arctanptr[pos++]; /* Add angle */
+ }
+
+ if (iter > MAXITER)
+ iter = MAXITER;
+ else if (iter < 1)
+ iter = 1;
+
+ for (int i = 0; i <= iter; i++) {
+ if (y < 0) { /* Rotate positive */
+ yi = y + (x >> i);
+ x = x - (y >> i);
+ y = yi;
+ theta -= arctanptr[pos++];
+ }
+ else { /* Rotate negative */
+ yi = y - (x >> i);
+ x = x + (y >> i);
+ y = yi;
+ theta += arctanptr[pos++];
+ }
+ }
+
+ xtemp = x;
+ ytemp = theta;
+ return theta;
+ }
+
+ /**
+ * FxPreNorm() block normalizes the arguments to a magnitude suitable for
+ * CORDIC pseudorotations. The returned value is the block exponent.
+ * This code is based on that found in "Cordic.c" by Ken Turkowski.
+ **/
+ private static int fxPreNorm(int x, int y) {
+ int signx=1, signy=1;
+
+ if (x < 0) {
+ x = -x;
+ signx = -signx;
+ }
+ if (y < 0) {
+ y = -y;
+ signy = -signy;
+ }
+
+ int shiftexp = 0; /* Block normalization exponent */
+
+ /* Prenormalize vector for maximum precision */
+ if (x < y) { /* |y| > |x| */
+ while (y < (1 << 27)) {
+ x <<= 1;
+ y <<= 1;
+ shiftexp--;
+ }
+ while (y > (1 << 28)) {
+ x >>= 1;
+ y >>= 1;
+ shiftexp++;
+ }
+ }
+ else { /* |x| > |y| */
+ while (x < (1 << 27)) {
+ x <<= 1;
+ y <<= 1;
+ shiftexp--;
+ }
+ while (x > (1 << 28)) {
+ x >>= 1;
+ y >>= 1;
+ shiftexp++;
+ }
+ }
+
+ xtemp = (signx < 0) ? -x : x;
+ ytemp = (signy < 0) ? -y : y;
+ return shiftexp;
+ }
+
+
+}
+
diff --git a/demos/MiscDemos/jahuwaldt/gl/Matrix.java b/demos/MiscDemos/jahuwaldt/gl/Matrix.java new file mode 100644 index 0000000..e043197 --- /dev/null +++ b/demos/MiscDemos/jahuwaldt/gl/Matrix.java @@ -0,0 +1,499 @@ +/*
+* Matrix -- Collection of methods for working with 3D transformation matricies.
+*
+* Copyright (C) 2001 by Joseph A. Huwaldt <[email protected]>.
+* All rights reserved.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+**/
+
+package jahuwaldt.gl;
+
+
+/**
+* A set of static utility methods for working with matricies.
+* In particular, these methods are geared for working efficiently
+* with OpenGL transformation matrices.
+*
+* <p> Modified by: Joseph A. Huwaldt </p>
+*
+* @author Joseph A. Huwaldt Date: January 13, 2001
+* @version January 30, 2001
+**/
+public class Matrix {
+
+ /**
+ * The value for Math.PI as a float instead of a double.
+ **/
+ public static final float PI = (float)Math.PI;
+
+ /**
+ * Convert's an angle in radians to one in degrees.
+ *
+ * @param rad The angle in radians to be converted.
+ * @return The angle in degrees.
+ **/
+ public static final float rad2Deg(float rad) {
+ return rad*180/PI;
+ }
+
+ /**
+ * Convert's an angle in degrees to one in radians.
+ *
+ * @param deg The angle in degrees to be converted.
+ * @return The angle in radians.
+ **/
+ public static final float deg2Rad(float deg) {
+ return deg*PI/180;
+ }
+
+ /**
+ * Set a 4x4 transformation matrix to the identity matrix.
+ * Equiv. to: T = I
+ *
+ * I = 1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * @param mtx The 4x4 matrix to be set.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] setIdentity(float mtx[]) {
+ mtx[0] = mtx[5] = mtx[10] = mtx[15] = 1;
+ mtx[1] = mtx[2] = mtx[3] = mtx[4] = 0;
+ mtx[6] = mtx[7] = mtx[8] = mtx[9] = 0;
+ mtx[11] = mtx[12] = mtx[13] = mtx[14] = 0;
+
+ return mtx;
+ }
+
+ /**
+ * Create a new 4x4 transformation matrix set to the identity matrix.
+ * Equiv. to: T = I
+ *
+ * I = 1 0 0 0
+ * 0 1 0 0
+ * 0 0 1 0
+ * 0 0 0 1
+ *
+ * @return A reference to a 4x4 identity matrix is returned.
+ **/
+ public static final float[] identity() {
+ float[] mtx = new float[16];
+ mtx[0] = mtx[5] = mtx[10] = mtx[15] = 1;
+ return mtx;
+ }
+
+ /**
+ * Set a 4x4 transformation matrix which rotates about the X-axis.
+ * Equiv. to: T = Rx
+ *
+ * Rx = 1 0 0 0
+ * 0 cos(a) sin(a) 0
+ * 0 -sin(a) cos(a) 0
+ * 0 0 0 1
+ *
+ * @param angle The rotation angle about the X-axis in radians.
+ * @param mtx The 4x4 matrix to be set.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] setRotateX(float angle, float mtx[]) {
+ float rsin = (float)Math.sin(angle);
+ float rcos = (float)Math.cos(angle);
+ mtx[0] = 1.0f;
+ mtx[1] = 0.0f;
+ mtx[2] = 0.0f;
+ mtx[3] = 0.0f;
+ mtx[4] = 0.0f;
+ mtx[5] = rcos;
+ mtx[6] = rsin;
+ mtx[7] = 0.0f;
+ mtx[8] = 0.0f;
+ mtx[9] = -rsin;
+ mtx[10] = rcos;
+ mtx[11] = 0.0f;
+ mtx[12] = 0.0f;
+ mtx[13] = 0.0f;
+ mtx[14] = 0.0f;
+ mtx[15] = 1.0f;
+
+ return mtx;
+ }
+
+ /**
+ * Set a 4x4 transformation matrix which rotates about the Y-axis.
+ * Equiv. to: T = Ry
+ *
+ * Ry = 1 0 0 0
+ * 0 cos(a) sin(a) 0
+ * 0 -sin(a) cos(a) 0
+ * 0 0 0 1
+ *
+ * @param angle The rotation angle about the Y-axis in radians.
+ * @param mtx The 4x4 matrix to be set.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] setRotateY(float angle, float mtx[]) {
+ float rsin = (float)Math.sin(angle);
+ float rcos = (float)Math.cos(angle);
+ mtx[0] = rcos;
+ mtx[1] = 0.0f;
+ mtx[2] = -rsin;
+ mtx[3] = 0.0f;
+ mtx[4] = 0.0f;
+ mtx[5] = 1.0f;
+ mtx[6] = 0.0f;
+ mtx[7] = 0.0f;
+ mtx[8] = rsin;
+ mtx[9] = 0.0f;
+ mtx[10] = rcos;
+ mtx[11] = 0.0f;
+ mtx[12] = 0.0f;
+ mtx[13] = 0.0f;
+ mtx[14] = 0.0f;
+ mtx[15] = 1.0f;
+
+ return mtx;
+ }
+
+ /**
+ * Set a 4x4 transformation matrix which rotates about the Z-axis.
+ * Equiv. to: T = Rz
+ *
+ * Rz = 1 0 0 0
+ * 0 cos(a) sin(a) 0
+ * 0 -sin(a) cos(a) 0
+ * 0 0 0 1
+ *
+ * @param angle The rotation angle about the Z-axis in radians.
+ * @param mtx The 4x4 matrix to be set.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] setRotateZ(float angle, float mtx[]) {
+ float rsin = (float)Math.sin(angle);
+ float rcos = (float)Math.cos(angle);
+ mtx[0] = rcos;
+ mtx[1] = rsin;
+ mtx[2] = 0.0f;
+ mtx[3] = 0.0f;
+ mtx[4] = -rsin;
+ mtx[5] = rcos;
+ mtx[6] = 0.0f;
+ mtx[7] = 0.0f;
+ mtx[8] = 0.0f;
+ mtx[9] = 0.0f;
+ mtx[10] = 1.0f;
+ mtx[11] = 0.0f;
+ mtx[12] = 0.0f;
+ mtx[13] = 0.0f;
+ mtx[14] = 0.0f;
+ mtx[15] = 1.0f;
+
+ return mtx;
+ }
+
+ /**
+ * Set a 4x4 transformation matrix which scales in each
+ * axis direction by the specified scale factors.
+ * Equiv. to: T = S
+ *
+ * S = sx 0 0 0
+ * 0 sy 0 0
+ * 0 0 sz 0
+ * 0 0 0 1
+ *
+ * @param sx The scale factor in the X-axis direction.
+ * @param sy The scale factor in the Y-axis direction.
+ * @param sz The scale factor in the Z-axis direction.
+ * @param mtx The 4x4 matrix to be set.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] setScale(float sx, float sy, float sz, float mtx[]) {
+ mtx[0] = sx;
+ mtx[5] = sy;
+ mtx[10] = sz;
+ mtx[15] = 1;
+ mtx[1] = mtx[2] = mtx[3] = mtx[4] = 0;
+ mtx[6] = mtx[7] = mtx[8] = mtx[9] = 0;
+ mtx[11] = mtx[12] = mtx[13] = mtx[14] = 0;
+
+ return mtx;
+ }
+
+ /**
+ * Set a 4x4 transformation matrix which translates in each
+ * axis direction by the specified amounts.
+ * Equiv. to: T = Tr
+ *
+ * Tr = 1 0 0 tx
+ * 0 1 0 ty
+ * 0 0 1 tz
+ * 0 0 0 1
+ *
+ * @param tx The translation amount in the X-axis direction.
+ * @param ty The translation amount in the Y-axis direction.
+ * @param tz The translation amount in the Z-axis direction.
+ * @param mtx The 4x4 matrix to be set.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] setTranslate(float tx, float ty, float tz, float mtx[]) {
+ mtx[0] = 1;
+ mtx[1] = mtx[2] = 0;
+ mtx[3] = tx;
+ mtx[4] = 0;
+ mtx[5] = 1;
+ mtx[6] = 0;
+ mtx[7] = ty;
+ mtx[8] = mtx[9] = 0;
+ mtx[10] = 1;
+ mtx[11] = tz;
+ mtx[12] = mtx[13] = mtx[14] = 0;
+ mtx[15] = 1;
+
+ return mtx;
+ }
+
+ /**
+ * Multiplies two 4x4 matricies together, and returns the
+ * result in a new output matrix. The multiplication is done
+ * fast, at the expense of code.
+ *
+ * @param mtx1 The 1st matrix being multiplied.
+ * @param mtx2 The 2nd matrix being multiplied.
+ * @return The output matrix containing the input matrices multiplied.
+ **/
+ public static final float[] multiply(float mtx1[], float mtx2[]) {
+ float nmtx[] = new float[16];
+
+ float m0 = mtx1[0], m1 = mtx1[1], m2 = mtx1[2], m3 = mtx1[3];
+ nmtx[0] = m0*mtx2[0] + m1*mtx2[4] + m2*mtx2[8] + m3*mtx2[12];
+ nmtx[1] = m0*mtx2[1] + m1*mtx2[5] + m2*mtx2[9] + m3*mtx2[13];
+ nmtx[2] = m0*mtx2[2] + m1*mtx2[6] + m2*mtx2[10] + m3*mtx2[14];
+ nmtx[3] = m0*mtx2[3] + m1*mtx2[7] + m2*mtx2[11] + m3*mtx2[15];
+
+ m0 = mtx1[4]; m1 = mtx1[5]; m2 = mtx1[6]; m3 = mtx1[7];
+ nmtx[4] = m0*mtx2[0] + m1*mtx2[4] + m2*mtx2[8] + m3*mtx2[12];
+ nmtx[5] = m0*mtx2[1] + m1*mtx2[5] + m2*mtx2[9] + m3*mtx2[13];
+ nmtx[6] = m0*mtx2[2] + m1*mtx2[6] + m2*mtx2[10] + m3*mtx2[14];
+ nmtx[7] = m0*mtx2[3] + m1*mtx2[7] + m2*mtx2[11] + m3*mtx2[15];
+
+ m0 = mtx1[8]; m1 = mtx1[9]; m2 = mtx1[10]; m3 = mtx1[11];
+ nmtx[8] = m0*mtx2[0] + m1*mtx2[4] + m2*mtx2[8] + m3*mtx2[12];
+ nmtx[9] = m0*mtx2[1] + m1*mtx2[5] + m2*mtx2[9] + m3*mtx2[13];
+ nmtx[10] = m0*mtx2[2] + m1*mtx2[6] + m2*mtx2[10] + m3*mtx2[14];
+ nmtx[11] = m0*mtx2[3] + m1*mtx2[7] + m2*mtx2[11] + m3*mtx2[15];
+
+ m0 = mtx1[12]; m1 = mtx1[13]; m2 = mtx1[14]; m3 = mtx1[15];
+ nmtx[12] = m0*mtx2[0] + m1*mtx2[4] + m2*mtx2[8] + m3*mtx2[12];
+ nmtx[13] = m0*mtx2[1] + m1*mtx2[5] + m2*mtx2[9] + m3*mtx2[13];
+ nmtx[14] = m0*mtx2[2] + m1*mtx2[6] + m2*mtx2[10] + m3*mtx2[14];
+ nmtx[15] = m0*mtx2[3] + m1*mtx2[7] + m2*mtx2[11] + m3*mtx2[15];
+
+ return nmtx;
+ }
+
+
+ /**
+ * Multiplies two 4x4 matricies together, and places them
+ * in the specified output matrix. The multiplication is done
+ * fast, at the expense of code. The output matrix may not
+ * be the same as one of the input matrices or the results
+ * are undefined.
+ *
+ * @param mtx1 The 1st matrix being multiplied.
+ * @param mtx2 The 2nd matrix being multiplied.
+ * @param dest The output matrix (results go here). Must not be
+ * one of the input matrices.
+ * @return A reference to the output matrix "dest" is returned.
+ **/
+ public static final float[] multiply(float mtx1[], float mtx2[], float dest[]) {
+
+ float m0 = mtx1[0], m1 = mtx1[1], m2 = mtx1[2], m3 = mtx1[3];
+ dest[0] = m0*mtx2[0] + m1*mtx2[4] + m2*mtx2[8] + m3*mtx2[12];
+ dest[1] = m0*mtx2[1] + m1*mtx2[5] + m2*mtx2[9] + m3*mtx2[13];
+ dest[2] = m0*mtx2[2] + m1*mtx2[6] + m2*mtx2[10] + m3*mtx2[14];
+ dest[3] = m0*mtx2[3] + m1*mtx2[7] + m2*mtx2[11] + m3*mtx2[15];
+
+ m0 = mtx1[4]; m1 = mtx1[5]; m2 = mtx1[6]; m3 = mtx1[7];
+ dest[4] = m0*mtx2[0] + m1*mtx2[4] + m2*mtx2[8] + m3*mtx2[12];
+ dest[5] = m0*mtx2[1] + m1*mtx2[5] + m2*mtx2[9] + m3*mtx2[13];
+ dest[6] = m0*mtx2[2] + m1*mtx2[6] + m2*mtx2[10] + m3*mtx2[14];
+ dest[7] = m0*mtx2[3] + m1*mtx2[7] + m2*mtx2[11] + m3*mtx2[15];
+
+ m0 = mtx1[8]; m1 = mtx1[9]; m2 = mtx1[10]; m3 = mtx1[11];
+ dest[8] = m0*mtx2[0] + m1*mtx2[4] + m2*mtx2[8] + m3*mtx2[12];
+ dest[9] = m0*mtx2[1] + m1*mtx2[5] + m2*mtx2[9] + m3*mtx2[13];
+ dest[10] = m0*mtx2[2] + m1*mtx2[6] + m2*mtx2[10] + m3*mtx2[14];
+ dest[11] = m0*mtx2[3] + m1*mtx2[7] + m2*mtx2[11] + m3*mtx2[15];
+
+ m0 = mtx1[12]; m1 = mtx1[13]; m2 = mtx1[14]; m3 = mtx1[15];
+ dest[12] = m0*mtx2[0] + m1*mtx2[4] + m2*mtx2[8] + m3*mtx2[12];
+ dest[13] = m0*mtx2[1] + m1*mtx2[5] + m2*mtx2[9] + m3*mtx2[13];
+ dest[14] = m0*mtx2[2] + m1*mtx2[6] + m2*mtx2[10] + m3*mtx2[14];
+ dest[15] = m0*mtx2[3] + m1*mtx2[7] + m2*mtx2[11] + m3*mtx2[15];
+
+ return dest;
+ }
+
+ /****************************************************************
+ * The following are matrix post concatenation routines that *
+ * can be used as speedy replacements for the more standard *
+ * matrix mult. routine to generate combined rotations. *
+ ****************************************************************/
+ /**
+ * Multiply an existing 4x4 transformation matrix by an X-axis
+ * rotation matrix quickly. This is much faster than calling
+ * setRotateX() followed by multiply().
+ * Equiv. to: T = T*Rx
+ *
+ * Rx = 1 0 0 0
+ * 0 cos(a) sin(a) 0
+ * 0 -sin(a) cos(a) 0
+ * 0 0 0 1
+ *
+ * @param angle The rotation angle about the X-axis in radians.
+ * @param mtx The 4x4 matrix to be multiplied by the rotation matrix.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] rotateX(float angle, float mtx[]) {
+ float rsin = (float)Math.sin(angle);
+ float rcos = (float)Math.cos(angle);
+
+ for (int i = 0 ; i < 4 ; i++) {
+ int i1 = i*4 + 1;
+ int i2 = i1 + 1;
+ float t = mtx[i1];
+ mtx[i1] = t*rcos - mtx[i2]*rsin;
+ mtx[i2] = t*rsin + mtx[i2]*rcos;
+ }
+
+ return mtx;
+ }
+
+ /**
+ * Multiply an existing 4x4 transformation matrix by a Y-axis
+ * rotation matrix quickly. This is much faster than calling
+ * setRotateY() followed by multiply().
+ * Equiv. to: T = T*Ry
+ *
+ * Ry = 1 0 0 0
+ * 0 cos(a) sin(a) 0
+ * 0 -sin(a) cos(a) 0
+ * 0 0 0 1
+ *
+ * @param angle The rotation angle about the Y-axis in radians.
+ * @param mtx The 4x4 matrix to be multiplied by the rotation matrix.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] rotateY(float angle, float mtx[]) {
+ float rsin = (float)Math.sin(angle);
+ float rcos = (float)Math.cos(angle);
+
+ for (int i = 0 ; i < 4 ; i++) {
+ int i0 = i*4;
+ int i2 = i0 + 2;
+ float t = mtx[i0];
+ mtx[i0] = t*rcos + mtx[i2]*rsin;
+ mtx[i2] = mtx[i2]*rcos - t*rsin;
+ }
+
+ return mtx;
+ }
+
+ /**
+ * Multiply an existing 4x4 transformation matrix by a Z-axis
+ * rotation matrix quickly. This is much faster than calling
+ * setRotateZ() followed by multiply().
+ * Equiv. to: T = T*Rz
+ *
+ * Rz = 1 0 0 0
+ * 0 cos(a) sin(a) 0
+ * 0 -sin(a) cos(a) 0
+ * 0 0 0 1
+ *
+ * @param angle The rotation angle about the Y-axis in radians.
+ * @param mtx The 4x4 matrix to be multiplied by the rotation matrix.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] rotateZ(float angle, float mtx[]) {
+ float rsin = (float)Math.sin(angle);
+ float rcos = (float)Math.cos(angle);
+
+ for (int i = 0 ; i < 4 ; i++) {
+ int i0 = i*4;
+ int i1 = i0 + 1;
+ float t = mtx[i0];
+ mtx[i0] = t*rcos - mtx[i1]*rsin;
+ mtx[i1] = t*rsin + mtx[i1]*rcos;
+ }
+
+ return mtx;
+ }
+
+ /**
+ * Multiply an existing 4x4 transformation matrix by a set of
+ * scale factors quickly. This is much faster than calling
+ * setScale() followed by multiply().
+ * Equiv. to: T = T*S
+ *
+ * S = sx 0 0 0
+ * 0 sy 0 0
+ * 0 0 sz 0
+ * 0 0 0 1
+ *
+ * @param sx The scale factor in the X-axis direction.
+ * @param sy The scale factor in the Y-axis direction.
+ * @param sz The scale factor in the Z-axis direction.
+ * @param mtx The 4x4 matrix to be multiplied by the scale factor matrix.
+ * @param A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] scale(float sx, float sy, float sz, float mtx[]) {
+ for (int i = 0 ; i < 4 ; i++) {
+ int i0 = i*4;
+ mtx[i0] *= sx;
+ mtx[i0 + 1] *= sy;
+ mtx[i0 + 2] *= sz;
+ }
+
+ return mtx;
+ }
+
+ /**
+ * Multiply an existing 4x4 transformation matrix by a
+ * translation matrix quickly. This is much faster than calling
+ * setTranslate() followed by multiply().
+ * Equiv. to: T = T*Tr
+ *
+ * Tr = 1 0 0 Tx
+ * 0 1 0 Ty
+ * 0 0 1 Tz
+ * 0 0 0 1
+ *
+ * @param tx The translation amount in the X-axis direction.
+ * @param ty The translation amount in the Y-axis direction.
+ * @param tz The translation amount in the Z-axis direction.
+ * @param mtx The 4x4 matrix to be multiplied by the translation matrix.
+ * @return A reference to the output matrix "mtx" is returned.
+ **/
+ public static final float[] translate(float tx, float ty, float tz, float mtx[]) {
+ for (int i=0 ; i < 4 ; i++) {
+ int i0 = i*4;
+ int i3 = i0 + 3;
+ mtx[i0] += mtx[i3]*tx;
+ mtx[i0 + 1] += mtx[i3]*ty;
+ mtx[i0 + 2] += mtx[i3]*tz;
+ }
+
+ return mtx;
+ }
+
+}
diff --git a/demos/MiscDemos/jahuwaldt/gl/VirtualSphere.java b/demos/MiscDemos/jahuwaldt/gl/VirtualSphere.java new file mode 100644 index 0000000..2ec7917 --- /dev/null +++ b/demos/MiscDemos/jahuwaldt/gl/VirtualSphere.java @@ -0,0 +1,255 @@ +/*
+* VirtualSphere -- A class that implements the Virtual Sphere algorithm for 3D rotation.
+*
+* Copyright (C) 2001 by Joseph A. Huwaldt <[email protected]>.
+* All rights reserved.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+**/
+
+package jahuwaldt.gl;
+
+
+import java.awt.*;
+
+
+/**
+* Implements the Virtual Sphere algorithm for 3D rotation using a 2D input device.
+* See paper "A Study in Interactive 3-D Rotation Using 2-D Control Devices" by
+* Michael Chen, S. Joy Mountford and Abigail Sellen published in the ACM Siggraph '88
+* proceedings (Volume 22, Number 4, August 1988) for more detail. The code here
+* provides a much simpler implementation than that described in the paper.
+* This is also known by as the "virtual track ball" or "cue ball" interface.
+*
+* <p> Ported from C to Java by Joseph A. Huwaldt, February 19, 2001 </p>
+* <p> Original C version had the following comments:
+* Author: Michael Chen, Human Interface Group / ATG,
+* Copyright � 1991-1993 Apple Computer, Inc. All rights reserved.
+* Part of Virtual Sphere Sample Code Release v1.1.
+* </p>
+*
+* <p> Modified by: Joseph A.Huwaldt </p>
+*
+* @author: Joseph A. Huwaldt Date: Feburary 19, 2001
+* @version February 20, 2001
+**/
+public class VirtualSphere {
+
+ // Some constants for convenience.
+ private static final int X = 0;
+ private static final int Y = 1;
+ private static final int Z = 2;
+
+ /**
+ * Storage for 3D point information passed between methods.
+ **/
+ private final float[] op = new float[3], oq = new float[3], a = new float[3];
+
+ /**
+ * Calculate a rotation matrix based on the axis and angle of rotation
+ * from the last 2 locations of the mouse relative to the Virtual
+ * Sphere cue circle.
+ *
+ * @param pnt1 The 1st mouse location in the window.
+ * @param pnt2 The 2nd mouse location in the window.
+ * @param cueCenter The center of the virtual sphere in the window.
+ * @param cueRadius The radius of the virtual sphere.
+ * @param rotMatrix Preallocated rotation matrix to be filled in
+ * by this method. Must have 16 floating point
+ * elements. This matrix will be overwritten by
+ * this method.
+ * @return A reference to the input rotMatrix is returned with the elements filled in.
+ **/
+ public float[] makeRotationMtx(Point pnt1, Point pnt2, Point cueCenter, int cueRadius,
+ float[] rotMatrix) {
+
+ // Vectors op and oq are defined as class variables to avoid wastefull memory allocations.
+
+ // Project mouse points to 3-D points on the +z hemisphere of a unit sphere.
+ pointOnUnitSphere (pnt1, cueCenter, cueRadius, op);
+ pointOnUnitSphere (pnt2, cueCenter, cueRadius, oq);
+
+ /* Consider the two projected points as vectors from the center of the
+ * unit sphere. Compute the rotation matrix that will transform vector
+ * op to oq. */
+ setRotationMatrix(rotMatrix, op, oq);
+
+ return rotMatrix;
+ }
+
+
+ /**
+ * Draw a 2D representation of the virtual sphere to the specified graphics context.
+ * The representation includes a circle for the perimiter of the virtual sphere
+ * and a cross-hair indicating where the mouse pointer is over the virtual sphere.
+ *
+ * @param gc The graphics context to be drawn into.
+ * @param mousePnt The location in window of the mouse.
+ * @param cueCenter The location in the window of the center of the virtual sphere.
+ * @param cueRadius The radius (in pixels) of the virtual sphere in the window.
+ **/
+ public void draw(Graphics gc, Point mousePnt, Point cueCenter, int cueRadius) {
+
+ // Draw the outline of the virtual sphere.
+ int x = cueCenter.x - cueRadius;
+ int y = cueCenter.y - cueRadius;
+ int diameter = 2*cueRadius;
+ gc.drawOval(x, y, diameter, diameter);
+
+ int mouseX = mousePnt.x - cueCenter.x;
+ int mouseY = cueCenter.y - mousePnt.y;
+ int mouseX2 = mouseX*mouseX;
+ int mouseY2 = mouseY*mouseY;
+ int cueRadius2 = cueRadius*cueRadius;
+
+ // Draw the mouse cue if we are over the sphere.
+ if (mouseX2 + mouseY2 < cueRadius2) {
+
+ // Draw the vertical cue line.
+ if (Math.abs(mouseX) > 4) {
+ // Draw a vertical elliptical arc through the mouse point.
+ double a = Math.sqrt(mouseX2/(1 - mouseY2/(float)cueRadius2));
+ double newMouseX = mouseX*cueRadius/a;
+ int angle = (int)(Math.atan2(mouseY, newMouseX)*180/Math.PI);
+ int width = (int)(2*a);
+ int nx = cueCenter.x - (int)a;
+ gc.drawArc(nx, y, width, diameter, angle - 10, 20);
+
+ } else {
+ // Mouse X near zero is a special case, just draw a vertical line.
+ float vy = mouseY/(float)cueRadius;
+ float vy2 = vy*vy;
+ double vz = Math.sqrt(1 - vy2);
+ double angle = Math.atan2(vy, vz) - 10*Math.PI/180;
+ double length = Math.sqrt(vy2 + vz*vz)*cueRadius;
+ int yl = cueCenter.y - (int)(length*Math.sin(angle));
+ int yh = cueCenter.y - (int)(length*Math.sin(angle + 20*Math.PI/180));
+ gc.drawLine(mousePnt.x, yl, mousePnt.x, yh);
+ }
+
+ // Draw the horizontal cue line.
+ if (Math.abs(mouseY) > 4) {
+ // Draw a horizontal elliptical arc through the mouse point.
+ double a = Math.sqrt(mouseY2/(1 - mouseX2/(float)cueRadius2));
+ double newMouseY = mouseY*cueRadius/a;
+ int angle = (int)(Math.atan2(newMouseY, mouseX)*180/Math.PI);
+ int width = (int)(2*a);
+ y = cueCenter.y - (int)a;
+ gc.drawArc(x, y, diameter, width, angle - 10, 20);
+
+ } else {
+ // Mouse Y near zero is a special case, just draw a horizontal line.
+ float vx = mouseX/(float)cueRadius;
+ float vx2 = vx*vx;
+ double vz = Math.sqrt(1 - vx2);
+ double angle = Math.atan2(vx, vz) - 10*Math.PI/180;
+ double length = Math.sqrt(vx2 + vz*vz)*cueRadius;
+ int xl = cueCenter.x + (int)(length*Math.sin(angle));
+ int xh = cueCenter.x + (int)(length*Math.sin(angle + 20*Math.PI/180));
+ gc.drawLine(xl, mousePnt.y, xh, mousePnt.y);
+ }
+ }
+ }
+
+ /**
+ * Project a 2D point on a circle to a 3D point on the +z hemisphere of a unit sphere.
+ * If the 2D point is outside the circle, it is first mapped to the nearest point on
+ * the circle before projection.
+ * Orthographic projection is used, though technically the field of view of the camera
+ * should be taken into account. However, the discrepancy is neglegible.
+ *
+ * @param p Window point to be projected onto the sphere.
+ * @param cueCenter Location of center of virtual sphere in window.
+ * @param cueRadius The radius of the virtual sphere.
+ * @param v Storage for the 3D projected point created by this method.
+ **/
+ private static void pointOnUnitSphere(Point p, Point cueCenter, int cueRadius, float[] v) {
+
+ /* Turn the mouse points into vectors relative to the center of the circle
+ * and normalize them. Note we need to flip the y value since the 3D coordinate
+ * has positive y going up. */
+ float vx = (p.x - cueCenter.x)/(float)cueRadius;
+ float vy = (cueCenter.y - p.y)/(float)cueRadius;
+ float lengthSqared = vx*vx + vy*vy;
+
+ /* Project the point onto the sphere, assuming orthographic projection.
+ * Points beyond the virtual sphere are normalized onto
+ * edge of the sphere (where z = 0). */
+ float vz = 0;
+ if (lengthSqared < 1)
+ vz = (float)Math.sqrt(1.0 - lengthSqared);
+
+ else {
+ float length = (float)Math.sqrt(lengthSqared);
+ vx /= length;
+ vy /= length;
+ }
+
+ v[X] = vx;
+ v[Y] = vy;
+ v[Z] = vz;
+ }
+
+ /**
+ * Computes a rotation matrix that would map (rotate) vectors op onto oq.
+ * The rotation is about an axis perpendicular to op and oq.
+ * Note this routine won't work if op or oq are zero vectors, or if they
+ * are parallel or antiparallel to each other.
+ *
+ * <p> Modification of Michael Pique's formula in
+ * Graphics Gems Vol. 1. Andrew Glassner, Ed. Addison-Wesley. </p>
+ *
+ * @param rotationMatrix The 16 element rotation matrix to be filled in.
+ * @param op The 1st 3D vector.
+ * @param oq The 2nd 3D vector.
+ **/
+ private void setRotationMatrix(float[] rotationMatrix, float[] op, float[] oq) {
+
+ // Vector a is defined as a class variable to avoid wastefull memory allocations.
+
+ GLTools.crossProduct3D(op, oq, a);
+ float s = GLTools.length3D(a);
+ float c = GLTools.dotProduct3D(op, oq);
+ float t = 1 - c;
+
+ float ax = a[X];
+ float ay = a[Y];
+ float az = a[Z];
+ if (s > 0) {
+ ax /= s;
+ ay /= s;
+ az /= s;
+ }
+
+ float tax = t*ax;
+ float taxay = tax*ay, taxaz = tax*az;
+ float saz = s*az, say = s*ay;
+ rotationMatrix[0] = tax*ax + c;
+ rotationMatrix[1] = taxay + saz;
+ rotationMatrix[2] = taxaz - say;
+
+ float tay = t*ay;
+ float tayaz = tay*az;
+ float sax = s*ax;
+ rotationMatrix[4] = taxay - saz;
+ rotationMatrix[5] = tay*ay + c;
+ rotationMatrix[6] = tayaz + sax;
+
+ rotationMatrix[8] = taxaz + say;
+ rotationMatrix[9] = tayaz - sax;
+ rotationMatrix[10] = t*az*az + c;
+
+ rotationMatrix[3] = rotationMatrix[7] = rotationMatrix[11] =
+ rotationMatrix[12] = rotationMatrix[13] = rotationMatrix[14] = 0;
+ rotationMatrix[15] = 1;
+ }
+}
+
|