From 255908bf19515af5c3770cd304eece10f95b6ba8 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Mon, 18 Jun 2001 23:34:31 +0000 Subject: 2.8.0.0 pre-release cvs only --- demos/GLFDemos/glf3dtext.html | 16 + demos/GLFDemos/glf3dtext.java | 366 +++++++++++++++++ demos/GLFDemos/glf3dtext2.html | 16 + demos/GLFDemos/glf3dtext2.java | 378 ++++++++++++++++++ demos/GLFDemos/glf3dtext2_plugin13.html | 48 +++ demos/GLFDemos/glf3dtext_plugin13.html | 48 +++ demos/GLFDemos/index.html | 24 ++ demos/GLFDemos/index_plugin13.html | 26 ++ demos/MiscDemos/GearsVS.html | 13 + demos/MiscDemos/GearsVS.java | 501 ++++++++++++++++++++++++ demos/MiscDemos/GearsVS_plugin13.html | 45 +++ demos/MiscDemos/jahuwaldt/gl/GLTools.java | 494 +++++++++++++++++++++++ demos/MiscDemos/jahuwaldt/gl/Matrix.java | 499 +++++++++++++++++++++++ demos/MiscDemos/jahuwaldt/gl/VirtualSphere.java | 255 ++++++++++++ 14 files changed, 2729 insertions(+) create mode 100644 demos/GLFDemos/glf3dtext.html create mode 100755 demos/GLFDemos/glf3dtext.java create mode 100644 demos/GLFDemos/glf3dtext2.html create mode 100644 demos/GLFDemos/glf3dtext2.java create mode 100644 demos/GLFDemos/glf3dtext2_plugin13.html create mode 100644 demos/GLFDemos/glf3dtext_plugin13.html create mode 100644 demos/GLFDemos/index.html create mode 100644 demos/GLFDemos/index_plugin13.html create mode 100644 demos/MiscDemos/GearsVS.html create mode 100644 demos/MiscDemos/GearsVS.java create mode 100644 demos/MiscDemos/GearsVS_plugin13.html create mode 100644 demos/MiscDemos/jahuwaldt/gl/GLTools.java create mode 100644 demos/MiscDemos/jahuwaldt/gl/Matrix.java create mode 100644 demos/MiscDemos/jahuwaldt/gl/VirtualSphere.java (limited to 'demos') diff --git a/demos/GLFDemos/glf3dtext.html b/demos/GLFDemos/glf3dtext.html new file mode 100644 index 0000000..522300a --- /dev/null +++ b/demos/GLFDemos/glf3dtext.html @@ -0,0 +1,16 @@ + + +Göthel Hard- und Software Entwicklungen + + +Try to drag the mouse (press-button and move) with/without the SHIFT key! +
+
+ + + +
+ + + + diff --git a/demos/GLFDemos/glf3dtext.java b/demos/GLFDemos/glf3dtext.java new file mode 100755 index 0000000..5c606c7 --- /dev/null +++ b/demos/GLFDemos/glf3dtext.java @@ -0,0 +1,366 @@ + +import gl4java.*; +import gl4java.drawable.*; +import gl4java.awt.GLAnimCanvas; +import gl4java.applet.SimpleGLAnimApplet1; +import gl4java.utils.textures.*; +import gl4java.utils.glf.*; + +import java.awt.*; +import java.awt.event.*; +import java.applet.*; +import java.net.*; + +public class glf3dtext extends SimpleGLAnimApplet1 +{ + public void init() + { + super.init(); + GLContext.gljNativeDebug = false; + GLContext.gljClassDebug = false; + + Dimension d = getSize(); + + GLCapabilities caps = new GLCapabilities(); + + canvas = + GLDrawableFactory.getFactory().createGLAnimCanvas(caps, d.width, d.height); + + glf3dtextRenderer renderer = new glf3dtextRenderer(); + canvas.addGLEventListener(renderer); + + add("Center", canvas); + addMouseListener(this); + } + + public static void main( String args[] ) + { + Frame mainFrame = new Frame("font test 2"); + + glf3dtext applet = new glf3dtext(); + + applet.setSize(400, 400); + applet.init(); + applet.start(); + + mainFrame.add(applet); + + mainFrame.pack(); + mainFrame.setVisible(true); + } + + class glf3dtextRenderer + implements GLEventListener, MouseListener,MouseMotionListener + { + float []mPosObjTrans; + float []mPosObjRot; + + Point mousePoint; + Point oldMousePoint; + boolean mouseMoveFlag; + + private GLFunc gl; + private GLUFunc glu; + private GLContext glj; + + protected GLF glf = null; + + int fArial1 = 0; + int fArialBMF = 0; + + int fTechno1 = 0; + int fTechnoBMF = 0; + + int fTimesNew1 = 0; + int fTimesNewBMF = 0; + + public glf3dtextRenderer () + { + super(); + } + + public void init(GLDrawable drawable) + { + gl = drawable.getGL(); + glu = drawable.getGLU(); + glj = drawable.getGLContext(); + + glf = new GLF(); + + fArial1 = glf.glfLoadFont("arial1.glf"); + fArialBMF = glf.glfLoadBFont("arial.bmf"); + + fTechno1 = glf.glfLoadFont("techno1.glf"); + fTechnoBMF = glf.glfLoadBFont("techno.bmf"); + + fTimesNew1 = glf.glfLoadFont("times_new1.glf"); + fTimesNewBMF = glf.glfLoadBFont("times_new.bmf"); + + // cameraMatrix init + mPosObjTrans=new float[16]; + for(int i=0;i<16;i++) + mPosObjTrans[i]=0f; + mPosObjTrans[0]=mPosObjTrans[5]=mPosObjTrans[10]=mPosObjTrans[15]=1f; + + mPosObjRot=new float[16]; + for(int i=0;i<16;i++) + mPosObjRot[i]=0f; + mPosObjRot[0]=mPosObjRot[5]=mPosObjRot[10]=mPosObjRot[15]=1f; + + TranlateObj(0f,0f,-10f); + + gl.glShadeModel (GL_SMOOTH); + gl.glEnable(GL_DEPTH_TEST); + + gl.glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + gl.glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glj.gljCheckGL(); + + canvas.addMouseListener(this); + canvas.addMouseMotionListener(this); + mouseMoveFlag=false; + } + + public void cleanup(GLDrawable drawable) + { + System.out.println("destroy(): " + this); + removeMouseListener(this); + removeMouseMotionListener(this); + } + + public void display(GLDrawable drawable) + { + int i; + + // just render it + gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + SetCamera(); + + DrawScene(); + + glj.gljCheckGL(); + } + + public void preDisplay(GLDrawable drawable) + { + } + + public void postDisplay(GLDrawable drawable) + { + } + + public void reshape(gl4java.drawable.GLDrawable gld,int width,int height) + { + gl.glMatrixMode (GL_MODELVIEW); + gl.glViewport (0, 0, width, height); + gl.glLoadIdentity(); + SetCamera(); + } + + + public void drawGrid(float x0, float y0, + float width, float height, float step) + { + float i,j; + + /* draw grid */ + gl.glBegin(GL_LINES); + for(i=x0;i + +Göthel Hard- und Software Entwicklungen + + +Try to drag the mouse (press-button and move) with/without the SHIFT key! +
+
+ + + +
+ + + + diff --git a/demos/GLFDemos/glf3dtext2.java b/demos/GLFDemos/glf3dtext2.java new file mode 100644 index 0000000..9efb0bf --- /dev/null +++ b/demos/GLFDemos/glf3dtext2.java @@ -0,0 +1,378 @@ + +import gl4java.*; +import gl4java.drawable.*; +import gl4java.awt.GLAnimCanvas; +import gl4java.applet.SimpleGLAnimApplet1; +import gl4java.utils.textures.*; +import gl4java.utils.glf.*; + +import java.awt.*; +import java.awt.event.*; +import java.applet.*; +import java.net.*; + +public class glf3dtext2 extends SimpleGLAnimApplet1 +{ + public void init() + { + super.init(); + GLContext.gljNativeDebug = false; + GLContext.gljClassDebug = false; + + Dimension d = getSize(); + + GLCapabilities caps = new GLCapabilities(); + + canvas = + GLDrawableFactory.getFactory().createGLAnimCanvas(caps, d.width, d.height); + + glf3dtextRenderer renderer = new glf3dtextRenderer(); + canvas.addGLEventListener(renderer); + + add("Center", canvas); + addMouseListener(this); + } + + public static void main( String args[] ) + { + Frame mainFrame = new Frame("font test 2"); + + glf3dtext2 applet = new glf3dtext2(); + + applet.setSize(400, 400); + applet.init(); + applet.start(); + + mainFrame.add(applet); + + mainFrame.pack(); + mainFrame.setVisible(true); + } + + class glf3dtextRenderer + implements GLEventListener, MouseListener,MouseMotionListener + { + float []mPosObjTrans; + float []mPosObjRot; + + Point mousePoint; + Point oldMousePoint; + boolean mouseMoveFlag; + + private GLFunc gl; + private GLUFunc glu; + private GLContext glj; + + protected GLF glf = null; + + int fArial1 = 0; + int fArialBMF = 0; + + int fTechno1 = 0; + int fTechnoBMF = 0; + + int fTimesNew1 = 0; + int fTimesNewBMF = 0; + + float angle=0f; + + public glf3dtextRenderer () + { + super(); + } + + public void init(GLDrawable drawable) + { + gl = drawable.getGL(); + glu = drawable.getGLU(); + glj = drawable.getGLContext(); + + glf = new GLF(); + + glf.glfInit(); + + fArial1 = glf.glfLoadFont("arial1.glf"); + fArialBMF = glf.glfLoadBMFFont("arial.bmf"); + + fTechno1 = glf.glfLoadFont("techno1.glf"); + fTechnoBMF = glf.glfLoadBMFFont("techno.bmf"); + + fTimesNew1 = glf.glfLoadFont("times_new1.glf"); + fTimesNewBMF = glf.glfLoadBMFFont("times_new.bmf"); + + // cameraMatrix init + mPosObjTrans=new float[16]; + for(int i=0;i<16;i++) + mPosObjTrans[i]=0f; + mPosObjTrans[0]=mPosObjTrans[5]=mPosObjTrans[10]=mPosObjTrans[15]=1f; + + mPosObjRot=new float[16]; + for(int i=0;i<16;i++) + mPosObjRot[i]=0f; + mPosObjRot[0]=mPosObjRot[5]=mPosObjRot[10]=mPosObjRot[15]=1f; + + TranlateObj(0f,0f,-10f); + + gl.glShadeModel (GL_SMOOTH); + gl.glEnable(GL_DEPTH_TEST); + + gl.glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + gl.glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glj.gljCheckGL(); + + canvas.addMouseListener(this); + canvas.addMouseMotionListener(this); + mouseMoveFlag=false; + } + + public void cleanup(GLDrawable drawable) + { + System.out.println("destroy(): " + this); + removeMouseListener(this); + removeMouseMotionListener(this); + glf.glfClose(); + } + + public void display(GLDrawable drawable) + { + int i; + + // just render it + gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + SetCamera(); + + DrawScene(); + + glj.gljCheckGL(); + } + + public void preDisplay(GLDrawable drawable) + { + } + + public void postDisplay(GLDrawable drawable) + { + } + + public void reshape(gl4java.drawable.GLDrawable gld,int width,int height) + { + gl.glMatrixMode (GL_MODELVIEW); + gl.glViewport (0, 0, width, height); + gl.glLoadIdentity(); + SetCamera(); + } + + + public void drawGrid(float x0, float y0, + float width, float height, float step) + { + float i,j; + + /* draw grid */ + gl.glBegin(GL_LINES); + for(i=x0;i 359f) angle = angle - 360f; + + gl.glScalef(0.5f, 0.5f, 0.5f); + gl.glTranslatef(-2.2f,-4f,0.5f); + + gl.glTranslatef(0f,2f,0f); + glf.glfDraw3DWiredStringF(fArial1, "Arial - GLF 3D Text"); + + gl.glTranslatef(0f,2f,0f); + glf.glfDraw3DSolidStringF(fArial1, "Arial - GLF 3D Text"); + + gl.glTranslatef(0f,2f,0f); + glf.glfDraw3DWiredStringF(fTechno1, "Techno - GLF 3D Text"); + + gl.glTranslatef(0f,2f,0f); + glf.glfDraw3DSolidStringF(fTechno1, "Techno - GLF 3D Text"); + + gl.glTranslatef(0f,2f,0f); + glf.glfDraw3DWiredStringF(fTimesNew1, "TimesNew - GLF 3D Text"); + + gl.glTranslatef(0f,2f,0f); + glf.glfDraw3DSolidStringF(fTimesNew1, "TimesNew - GLF 3D Text"); + + gl.glTranslatef(0f,2f,0f); + glf.glfSetCurrentBMFFont(fArialBMF); + glf.glfStartBitmapDrawing(); + glf.glfDrawBString("Arial BMF - GLF 3D Text"); + glf.glfStopBitmapDrawing(); + + gl.glTranslatef(0f, 2f, 0f); + glf.glfSetCurrentBMFFont(fTechnoBMF); + glf.glfStartBitmapDrawing(); + glf.glfDrawBString("Techno BMF - GLF 3D Text"); + glf.glfStopBitmapDrawing(); + + gl.glTranslatef(0f, 2f, 0f); + glf.glfSetCurrentBMFFont(fTimesNewBMF); + glf.glfStartBitmapDrawing(); + glf.glfDrawBString("TimesNew BMF - GLF 3D Text"); + glf.glfStopBitmapDrawing(); + + gl.glPopMatrix(); + } + + void SetCamera() + { + Dimension dim=getSize(); + float aspect=(float)dim.width/(float)dim.height; + + gl.glMatrixMode (GL_PROJECTION); + gl.glLoadIdentity (); + glu.gluPerspective(60f,aspect,.01,100); + } + + void RotateObj(float degree, + float axisX, + float axisY, + float axisZ) + { + gl.glMatrixMode (GL_MODELVIEW); + gl.glLoadIdentity (); + + // kamera setzen + gl.glRotatef(degree,axisX,axisY,axisZ); + gl.glMultMatrixf(mPosObjRot); + gl.glGetFloatv(GL_MODELVIEW_MATRIX,mPosObjRot); + } + + void TranlateObj(float x,float y,float z) + { + gl.glMatrixMode (GL_MODELVIEW); + gl.glLoadIdentity (); + + // kamera setzen + gl.glLoadMatrixf(mPosObjTrans); + gl.glTranslatef(x,y,z); + gl.glGetFloatv(GL_MODELVIEW_MATRIX,mPosObjTrans); + } + + // entfernt rotationen aus aktueller matrix + double Billboard() + { + float[] mat=new float[16]; + + gl.glGetFloatv(GL_MODELVIEW_MATRIX,mat); + mat[0] = mat[5] = mat[10] = 1; + mat[1] = mat[2] = mat[4] = mat[6] = mat[8] = mat[9] = 0; + gl.glLoadMatrixf(mat); + + return mat[14]; + } + + // Methods required for the implementation of MouseListener + public void mouseEntered( MouseEvent evt ) + { + } + + public void mouseExited( MouseEvent evt ) + { + } + + public void mousePressed( MouseEvent evt ) + { + if(mouseMoveFlag==false) + { // start drag + mouseMoveFlag=true; + mousePoint=evt.getPoint(); + } + } + + public void mouseReleased( MouseEvent evt ) + { + mouseMoveFlag=false; + } + + public void mouseClicked( MouseEvent evt ) + { + Component comp = evt.getComponent(); + } + + public void mouseDragged(MouseEvent e) + { + if(mouseMoveFlag==true) + { + oldMousePoint=new Point(mousePoint); + mousePoint=e.getPoint(); + + Point dif=new Point(mousePoint.x-oldMousePoint.x, + mousePoint.y-oldMousePoint.y); + + if( glj.gljMakeCurrent() == false ) + { + System.out.println("problem in use() method"); + return; + } + + if(e.isShiftDown()==true) + TranlateObj((float)dif.x/6.0f,(float)dif.y/-6.0f,0f); + else if(e.isAltDown()==true) + { + TranlateObj(0f,0f,(float)dif.y/6.0f); + RotateObj(dif.x,0f,0f,1f); + } + else + { + RotateObj(dif.x,0f,1f,0f); + RotateObj(dif.y,1f,0f,0f); + } + + glj.gljFree(); + + repaint(); + + } + } + public void mouseMoved(MouseEvent e) + { + } + + + } +} diff --git a/demos/GLFDemos/glf3dtext2_plugin13.html b/demos/GLFDemos/glf3dtext2_plugin13.html new file mode 100644 index 0000000..fd19db1 --- /dev/null +++ b/demos/GLFDemos/glf3dtext2_plugin13.html @@ -0,0 +1,48 @@ + + +Göthel Hard- und Software Entwicklungen + + +Try to drag the mouse (press-button and move) with/without the SHIFT key! +
+
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + diff --git a/demos/GLFDemos/glf3dtext_plugin13.html b/demos/GLFDemos/glf3dtext_plugin13.html new file mode 100644 index 0000000..67d233c --- /dev/null +++ b/demos/GLFDemos/glf3dtext_plugin13.html @@ -0,0 +1,48 @@ + + +Göthel Hard- und Software Entwicklungen + + +Try to drag the mouse (press-button and move) with/without the SHIFT key! +
+
+ + + + + + + + + + + + + + + + + + + + + +
+ + + + diff --git a/demos/GLFDemos/index.html b/demos/GLFDemos/index.html new file mode 100644 index 0000000..3b014e2 --- /dev/null +++ b/demos/GLFDemos/index.html @@ -0,0 +1,24 @@ + + + + + + + Misc Demos + + +

Here are the GLF-Demos for GL4Java >= 2.7.2.0:
+
+

To use the Java2 Plug-In (Java2, JRE, Plug-In 1.3), click here !
+
+Try to use the right-mouse-button for a pop-up menu within the demos ! +
+

 GLF Font Demo 1 +: GLF Font Demo 1 (GLF DEMO) +

 GLF Font Demo 2 +: GLF Font Demo 2 with rotation (GLF DEMO) +
  +
+
+ + diff --git a/demos/GLFDemos/index_plugin13.html b/demos/GLFDemos/index_plugin13.html new file mode 100644 index 0000000..deb60a6 --- /dev/null +++ b/demos/GLFDemos/index_plugin13.html @@ -0,0 +1,26 @@ + + + + + + + Misc Demos + + +

Here are the GLF Demos for GL4Java >= 2.7.2.0: & Java2 Plug-In 1.3 +


  +The Java2 (sdk, jre, plugin 1.3) policy file example to give GL4Java the necessary permissions (Click here) ! +
  +
+Try to use the right-mouse-button for a pop-up menu within the demos ! +
+

 GLF Font Demo 1 +: GLF Font Demo 1 (GLF DEMO) +

 GLF Font Demo 2 +: GLF Font Demo 2 with rotation (GLF DEMO) +
  +
+
+ + 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 @@ + + +Göthel Hard- und Software Entwicklungen + + +


+ + + +
+ + + 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 @@ + + +Göthel Hard- und Software Entwicklungen + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ + + 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 . +* 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. +* +*

Modified by: Joseph A. Huwaldt

+* +* @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: + * + * dist = sqrt(dx*dx + dy*dy + dz*dz) + * approx. dist = max + (med + min)/4 + * + * 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: + * + * dist = sqrt(dx*dx + dy*dy) + * approx. dist = max + min/4 + * + * 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. + * + *

WARNING!! This method is not thread safe! It stores intermediate results in + * a static class variable. Sorry, needed to do that for speed.

+ * + * @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 . +* 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. +* +*

Modified by: Joseph A. Huwaldt

+* +* @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 . +* 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. +* +*

Ported from C to Java by Joseph A. Huwaldt, February 19, 2001

+*

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. +*

+* +*

Modified by: Joseph A.Huwaldt

+* +* @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. + * + *

Modification of Michael Pique's formula in + * Graphics Gems Vol. 1. Andrew Glassner, Ed. Addison-Wesley.

+ * + * @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; + } +} + -- cgit v1.2.3