Files
igl/examples/beach-balls/BeachBall.cpp
T

237 lines
5.3 KiB
C++

#include "BeachBall.h"
#include <igl/draw_beach_ball.h>
#include <igl/quat_to_mat.h>
#include <igl/unproject_to_zero_plane.h>
#include <igl/unproject.h>
#include <igl/project.h>
#include <igl/quat_mult.h>
#include <igl/quat_conjugate.h>
#include <igl/trackball.h>
#include <igl/mat_to_quat.h>
#include <OpenGL/GL.h>
#include <iostream>
#include <cmath>
BeachBall::BeachBall():
radius(1),
is_hover(false),
is_down(false),
trackball_on(false),
down_x(-1),
down_y(-1)
{
r[0]=r[1]=r[2]=0;r[3]=1;
t[0]=t[1]=t[2]=0;t[3]=0;
}
void BeachBall::pushmv() const
{
glPushMatrix();
glLoadIdentity();
glMultMatrixd(mv);
}
void BeachBall::popmv() const
{
glPopMatrix();
}
void BeachBall::push() const
{
using namespace igl;
glPushMatrix();
// Translate to relative origin
glTranslated(t[0],t[1],t[2]);
// Rotate to relative orientation
double mat[4*4]; quat_to_mat(r,mat); glMultMatrixd(mat);
}
void BeachBall::pop() const
{
glPopMatrix();
}
void BeachBall::draw()
{
using namespace std;
using namespace igl;
// Keep track of relative identity (modelview) matrix at draw call
glGetDoublev(GL_MODELVIEW_MATRIX,mv);
push();
// Dim if hovered over
float ld[4];
glGetLightfv(GL_LIGHT0,GL_DIFFUSE,ld);
if(is_hover)
{
float ld_hover[4];
ld_hover[0] = 0.5*ld[0];
ld_hover[1] = 0.5*ld[1];
ld_hover[2] = 0.5*ld[2];
ld_hover[3] = 0.5*ld[3];
glLightfv(GL_LIGHT0,GL_DIFFUSE,ld_hover);
}
// Adjust scale only after setting origin
glPushMatrix();
glScaled(radius,radius,radius);
// draw oriented glyph
draw_beach_ball();
// Pop scale
glPopMatrix();
// Reset lighting
glLightfv(GL_LIGHT0,GL_DIFFUSE,ld);
// Reset relative identity
pop();
}
bool BeachBall::in(const int x,const int y) const
{
using namespace igl;
using namespace std;
pushmv();
push();
// Now origin is center of object
double obj[3];
// Check if unprojected screen point is nearby
unproject_to_zero_plane(x,y, &obj[0], &obj[1], &obj[2]);
bool near = (obj[0]*obj[0] + obj[1]*obj[1] + obj[2]*obj[2])<radius*radius;
pop();
popmv();
return near;
}
bool BeachBall::hover(const int x,const int y)
{
return is_hover = in(x,y);
}
bool BeachBall::down(const int x,const int y)
{
using namespace std;
using namespace igl;
is_down = in(x,y);
if(is_down)
{
copy(r,r+4,down_r);
copy(t,t+4,down_t);
down_x = x;
down_y = y;
trackball_on = true;
}
return is_down;
}
bool BeachBall::drag(const int x,const int y)
{
using namespace igl;
using namespace std;
if(!is_down)
{
return false;
}
if(trackball_on)
{
// Pick up origin location
pushmv();
push();
double origin[3];
project(0,0,0,&origin[0],&origin[1],&origin[2]);
pop();
popmv();
double rot[4];
int VP[4];
glGetIntegerv(GL_VIEWPORT,VP);
trackball<double>(
VP[2],
VP[3],
2,
(down_x-origin[0]+VP[2]/2),
VP[3]-(down_y-origin[1]+VP[3]/2),
( x-origin[0]+VP[2]/2),
VP[3]-( y-origin[1]+VP[3]/2),
rot);
{
// We've computed change in rotation according to this view:
// R = mv * r, R' = rot * (mv * r)
// But we only want new value for r:
// R' = mv * r'
// mv * r' = rot * (mv * r)
// r' = mv* * rot * sr * r
// Convert modelview matrix to quaternion
double sr_conj[4],scene_rot[4],t1[4],t2[4];
mat4_to_quat(mv,scene_rot);
//cout<<"::sr: "<<
// BeachBall::scene_rot[0]<<" "<<
// BeachBall::scene_rot[1]<<" "<<
// BeachBall::scene_rot[2]<<" "<<
// BeachBall::scene_rot[3]<<" "<<
// endl;
//cout<<" sr: "<<
// scene_rot[0]<<" "<<
// scene_rot[1]<<" "<<
// scene_rot[2]<<" "<<
// scene_rot[3]<<" "<<
// endl;
// Normalize to unit quaternion (rotation only)
double len =
sqrt(scene_rot[0]*scene_rot[0]+
scene_rot[1]*scene_rot[1]+
scene_rot[2]*scene_rot[2]+
scene_rot[3]*scene_rot[3]);
for(int j = 0;j<4;j++)
{
scene_rot[j] /= len;
}
// TODO: Just use Eigen::Quaterniond
quat_conjugate(scene_rot,sr_conj);
quat_mult<double>(sr_conj,rot,t1);
quat_mult<double>(t1,scene_rot,t2);
quat_mult<double>(t2,down_r,r);
}
}else
{
// We want that origin follows mouse move. First define plane we
// projecteing screen mouse movement to as perpendicular plan passing
// through this origin.
pushmv();
// down_t projected to screen to get depth value
double p[3];
project(down_t[0],down_t[1],down_t[2],&p[0],&p[1],&p[2]);
// unprojected down_x,down_y with down_t depth
double du[3];
unproject(down_x,down_y,p[2],&du[0],&du[1],&du[2]);
// unprojected x,y with down_t depth
double u[3];
unproject(x,y,p[2],&u[0], &u[1], &u[2]);
popmv();
// Then move this origin according to project mouse displacment
t[0] = down_t[0] + (u[0]-du[0]);
t[1] = down_t[1] + (u[1]-du[1]);
t[2] = down_t[2] + (u[2]-du[2]);
}
return is_down;
}
bool BeachBall::right_down(const int x,const int y)
{
using namespace std;
using namespace igl;
is_down = in(x,y);
if(is_down)
{
copy(r,r+4,down_r);
copy(t,t+4,down_t);
down_x = x;
down_y = y;
}
return is_down;
}
bool BeachBall::up(const int /*x*/,const int /*y*/)
{
trackball_on = false;
return is_down = false;
}