#include "mouse.h"
#include "math.h"
#include <QtOpenGL/glut.h>
//单位矩阵
GLfloat ab_quat[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
GLfloat ab_last[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
GLfloat ab_next[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
//到远点的距离
GLfloat ab_zoom = 1.0;
GLfloat ab_zoom2 = 1.0;
//球的半径
GLfloat ab_sphere = 1.0;
GLfloat ab_sphere2 = 1.0;
//距离原点的平面交叉
//边缘的可见范围
GLfloat ab_edge = 1.0;
//我们是否在使用球体
bool ab_planar = false;
GLfloat ab_planedist = 0.5;
Mouse ab_start = Mouse(0,0,1);//开始
Mouse ab_curr = Mouse(0,0,1);
Mouse ab_eye = Mouse(0,0,1);
Mouse ab_eyedir = Mouse(0,0,1);
Mouse ab_up = Mouse(0,1,0);
Mouse ab_out = Mouse(1,0,0);
GLdouble ab_glp[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
GLdouble ab_glm[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};
int ab_glv[4] = {0,0,640,480};
Mouse::Mouse()
{
}
Mouse::Mouse(GLfloat xx, GLfloat yy, GLfloat zz)
{
x = xx; y = yy; z = zz;
}
Mouse::~Mouse()
{
}
//设置缩放
void arcball_setzoom(GLfloat radius, Mouse eye, Mouse up)
{
ab_eye = eye;
ab_zoom2 = ab_eye * ab_eye;
ab_zoom = sqrt(ab_zoom2);
ab_sphere = radius; // sphere radius
ab_sphere2 = ab_sphere * ab_sphere;
ab_eyedir = ab_eye * (1.0 / ab_zoom); // distance to eye
ab_edge = ab_sphere2 / ab_zoom; // plane of visible edge
if(ab_sphere <= 0.0) // 轨迹球模式
{
ab_planar = true;
ab_up = up;
ab_out = ( ab_eyedir ^ ab_up );
ab_planedist = (0.0 - ab_sphere) * ab_zoom;
} else
ab_planar = false;
glGetDoublev(GL_PROJECTION_MATRIX,ab_glp); //在这里获得的矩阵的各元素值
glGetIntegerv(GL_VIEWPORT,ab_glv);//查询特定画面可用的缓冲区的存储信息
}
//影响arcball对openGL的取向
void arcball_rotate()
{
glMultMatrixf(ab_quat);
}
//四元数
static void quaternion(GLfloat* q, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GLfloat x2 = x*x;
GLfloat y2 = y*y;
GLfloat z2 = z*z;
GLfloat xy = x*y;
GLfloat xz = x*z;
GLfloat yz = y*z;
GLfloat wx = w*x;
GLfloat wy = w*y;
GLfloat wz = w*z;
q[0] = 1 - 2*y2 - 2*z2;
q[1] = 2*xy + 2*wz;
q[2] = 2*xz - 2*wy;
q[4] = 2*xy - 2*wz;
q[5] = 1 - 2*x2 - 2*z2;
q[6] = 2*yz + 2*wx;
q[8] = 2*xz + 2*wy;
q[9] = 2*yz - 2*wx;
q[10]= 1 - 2*x2 - 2*y2;
}
//重置旋转矩阵
static void quatidentity(GLfloat* q)
{ q[0]=1; q[1]=0; q[2]=0; q[3]=0;
q[4]=0; q[5]=1; q[6]=0; q[7]=0;
q[8]=0; q[9]=0; q[10]=1; q[11]=0;
q[12]=0; q[13]=0; q[14]=0; q[15]=1;
}
//复制旋转矩阵
static void quatcopy(GLfloat* dst, GLfloat* src)
{ dst[0]=src[0]; dst[1]=src[1]; dst[2]=src[2];
dst[4]=src[4]; dst[5]=src[5]; dst[6]=src[6];
dst[8]=src[8]; dst[9]=src[9]; dst[10]=src[10];
}
//增加两个旋转矩阵
static void quatnext(GLfloat* dest, GLfloat* left, GLfloat* right)
{
dest[0] = left[0]*right[0] + left[1]*right[4] + left[2] *right[8];
dest[1] = left[0]*right[1] + left[1]*right[5] + left[2] *right[9];
dest[2] = left[0]*right[2] + left[1]*right[6] + left[2] *right[10];
dest[4] = left[4]*right[0] + left[5]*right[4] + left[6] *right[8];
dest[5] = left[4]*right[1] + left[5]*right[5] + left[6] *right[9];
dest[6] = left[4]*right[2] + left[5]*right[6] + left[6] *right[10];
dest[8] = left[8]*right[0] + left[9]*right[4] + left[10]*right[8];
dest[9] = left[8]*right[1] + left[9]*right[5] + left[10]*right[9];
dest[10]= left[8]*right[2] + left[9]*right[6] + left[10]*right[10];
}
// 通过可见的边缘找到飞机的十字路口
static Mouse edge_coords(Mouse m)
{
// 找到边缘平面的交集
float t = (ab_edge - ab_zoom) / (ab_eyedir * m);
Mouse a = ab_eye + (m*t);
// 从这一点上找到eye-axis的方向
// 沿着边刨
Mouse c = (ab_eyedir * ab_edge) - a;
// 找到的十字路口与射线从球体
// 物体向eye-axis以外的领域。
float ac = (a*c);
float c2 = (c*c);
float q = ( 0.0 - ac - sqrt( ac*ac - c2*((a*a)-ab_sphere2) ) ) / c2;
return (a+(c*q)).unit();
}
// 找到与球面相交的十字路口
static Mouse sphere_coords(GLdouble mx, GLdouble my)
{
GLdouble ax,ay,az;
gluUnProject(mx,my,0,ab_glm,ab_glp,ab_glv,&ax,&ay,&az);
Mouse m = Mouse((float)ax,(float)ay,(float)az) - ab_eye;
// 鼠标位置显示: eye + t*m
// 交叉领域集中在原点
GLfloat a = m*m;
GLfloat b = (ab_eye*m);
GLfloat root = (b*b) - a*(ab_zoom2 - ab_sphere2);
if(root <= 0) return edge_coords(m);
GLfloat t = (0.0 - b - sqrt(root)) / a;
return (ab_eye+(m*t)).unit();
}
// 得到与平面交叉旋转“轨迹球”
static Mouse planar_coords(GLdouble mx, GLdouble my)
{
GLdouble ax,ay,az;
gluUnProject(mx,my,0,ab_glm,ab_glp,ab_glv,&ax,&ay,&az);
Mouse m = Mouse((GLfloat)ax,(GLfloat)ay,(GLfloat)az) - ab_eye;
// 相交点的轨迹球
GLfloat t = (ab_planedist - ab_zoom) / (ab_eyedir * m);
Mouse d = ab_eye + m*t;
return Mouse(d*ab_up,d*ab_out,0.0);
}
// 重置arcball
void arcball_reset()
{
quatidentity(ab_quat);
quatidentity(ab_last);
}
// 开始旋转
void arcball_start(int mx, int my)
{
// 保存一份当前旋转进行比较
quatcopy(ab_last,ab_quat);
if(ab_planar) ab_start = planar_coords((GLdouble)mx,(GLdouble)my);
else ab_start = sphere_coords((GLdouble)mx,(GLdouble)my);
}
// 更新当前arcball旋转
void arcball_move(int mx, int my,float times)
{
if(ab_planar)
{
ab_curr = planar_coords((GLdouble)mx,(GLdouble)my);
if(ab_curr.equals(ab_start)) return;
// d is motion since the last position
Mouse d = ab_curr - ab_start;
GLfloat angle = d.length() * 0.5;
GLfloat cosa = cos( angle );
GLfloat sina = sin( angle );
// p is perpendicular to d
Mouse p = ((ab_out*d.x)-(ab_up*d.y)).unit() * sina;
quaternion(ab_next,p.x,p.y,p.z,cosa);
quatnext(ab_quat,ab_last,ab_next);
// planar style only ever relates to the last point
quatcopy(ab_last,ab_quat);
ab_start = ab_curr;
} else {
ab_curr = sphere_coords((GLdouble)mx,(GLdouble)my);
if(ab_curr.equals(ab_start))
{ // avoid potential rare divide by tiny
quatcopy(ab_quat,ab_last);
return;
}
// use a dot product to get the angle between them
// use a cross product to get the vector to rotate around
GLfloat cos2a = ab_start*ab_curr;
GLfloat sina = sqrt((1.0 - cos2a)*0.5);
GLfloat cosa = sqrt((1.0 + cos2a)*0.5);
Mouse cross = (ab_start^ab_curr).unit() * sina ;
quaternion(ab_next,cross.x,cross.y,cross.z,cosa);
// update the rotation matrix
quatnext(ab_quat,ab_last,ab_next);
}
}
Mouse inline Mouse::rotate_x( Mouse v, float sin_ang, float cos_ang )
{
return Mouse(
v.x,
(v.y * cos_ang) + (v.z * sin_ang),
(v.z * cos_ang) - (v.y * sin_ang)
);
}
Mouse inline Mouse::rotate_y( Mouse v, float sin_ang, float cos_ang )
{
return Mouse(
(v.x * cos_ang) + (v.z * sin_ang),
v.y,
(v.z * cos_ang) - (v.x * sin_ang)
);
}
float Mouse::randf()
{
return ((1.0f / 127.f) * (((float)(rand() & 255)) - 128.0f)) ;
}