Rotating Sphere with mouse [solved]

Hello,

Im having an small problem i cant figure out (my math skills are not very good).
I want to rotate an sphere with the mouse.

The following code works with one axis:

float xdelta = (float)(Math.cos(Math.toRadians(rx)));
float zdelta = (float)(Math.sin(Math.toRadians(rx)));

glRotatef(rx,0f,1f,0f);
glRotatef(ry,xdelta,0f,zdelta);

where rx = x rotation (mouse input)
ry = y rotation (mouse input)

however this has odd results when both rx and ry != 0.

So my question is: how to rotate an 3d rotation matrix?

search for: arcball

Thank you, solved

I adapted some code i found on code.google.com


package window.Rendering;

import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;
import org.lwjgl.util.vector.Vector4f;


/**
 * Tutorial and code taken from Nehe Lesson 48
 *
 */
public class ArcBall {
    private static final float Epsilon = 1.0e-5f;

    Vector3f StVec;          //Saved click vector
    Vector3f EnVec;          //Saved drag vector
    float adjustWidth;       //Mouse bounds width
    float adjustHeight;      //Mouse bounds height

    public ArcBall(float NewWidth, float NewHeight) {
        StVec = new Vector3f();
        EnVec = new Vector3f();
        setBounds(NewWidth, NewHeight);
    }

    public void mapToSphere(Vector2f point, Vector3f vector) {
        // Copy paramter into temp point
        Vector2f tempPoint = new Vector2f(point.x, point.y);

        // Adjust point coords and scale down to range of [-1 ... 1]
        tempPoint.setX((tempPoint.getX() * this.adjustWidth) - 1.0f);
        tempPoint.setY(1.0f - (tempPoint.getY() * this.adjustHeight));

        // Compute the square of the length of the vector to the point from the center
        float length = (tempPoint.getX() * tempPoint.getX()) + (tempPoint.getY() * tempPoint.getY());

        // If the point is mapped outside of the sphere... (length > radius squared)
        if (length > 1.0f) {
            // Compute a normalizing factor (radius / sqrt(length))
            float norm = (float) (1.0 / Math.sqrt(length));

            // Return the "normalized" vector, a point on the sphere
            vector.x = tempPoint.getX() * norm;
            vector.y = tempPoint.getY() * norm;
            vector.z = 0.0f;
        } else    //Else it's on the inside
        {
            // Return a vector to a point mapped inside the sphere 
            // sqrt(radius squared - length)
            vector.x = tempPoint.getX();
            vector.y = tempPoint.getY();
            vector.z = (float) Math.sqrt(1.0f - length);
        }

    }

    public void setBounds(float NewWidth, float NewHeight) {
        assert((NewWidth > 1.0f) && (NewHeight > 1.0f));

        // Set adjustment factor for width/height
        adjustWidth = 1.0f / ((NewWidth - 1.0f) * 0.5f);
        adjustHeight = 1.0f / ((NewHeight - 1.0f) * 0.5f);
    }

    // Mouse down
    public void click(Vector2f NewPt) {
        mapToSphere(NewPt, this.StVec);
    }

    // Mouse drag, calculate rotation
    public void drag(Vector2f NewPt, Vector4f NewRot) {
        // Map the point to the sphere
        this.mapToSphere(NewPt, EnVec);

        // Return the quaternion equivalent to the rotation
        if (NewRot != null) {
            Vector3f Perp = new Vector3f();

            // Compute the vector perpendicular to the begin and end vectors
            Vector3f.cross(StVec, EnVec, Perp);

            // Compute the length of the perpendicular vector
            if (Perp.length() > Epsilon)    //if its non-zero
            {
                // We're ok, so return the perpendicular vector as the transform 
                // after all
                NewRot.setX(Perp.x);
                NewRot.setY(Perp.y);
                NewRot.setZ(Perp.z);
                // In the quaternion values, w is cosine (theta / 2), 
                // where theta is rotation angle
                NewRot.setW(0.3f*Vector3f.dot(StVec, EnVec)); //Faktor 0.3 beschleunigt die Bewegung etwas
            } else                                    //if its zero
            {
                // The begin and end vectors coincide, so return an identity transform
                NewRot.setX(0.0f);
                NewRot.setY(0.0f);
                NewRot.setZ(0.0f);
                NewRot.setW(0.0f);
            }
        }
    }

}