Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * trackball.cpp - Smooth mouse movements for OpenGL window 00004 * 00005 * Created: Fri Apr 01 19:56:31 2011 00006 * Copyright 2011 Tim Niemueller [www.niemueller.de] 00007 * 00008 * The code has is based on the OpenGL example "smooth" by Nate Robins 00009 * It states: 00010 * "Simple trackball-like motion adapted (ripped off) from projtex.c 00011 * (written by David Yu and David Blythe). See the SIGGRAPH '96 00012 * Advanced OpenGL course notes." 00013 * 00014 ****************************************************************************/ 00015 00016 /* This program is free software; you can redistribute it and/or modify 00017 * it under the terms of the GNU General Public License as published by 00018 * the Free Software Foundation; either version 2 of the License, or 00019 * (at your option) any later version. 00020 * 00021 * This program is distributed in the hope that it will be useful, 00022 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00024 * GNU Library General Public License for more details. 00025 * 00026 * Read the full text in the LICENSE.GPL file in the doc directory. 00027 */ 00028 00029 #include "trackball.h" 00030 00031 #include <GL/glut.h> 00032 #include <cmath> 00033 00034 00035 // globals 00036 static GLuint tb_lasttime; 00037 static GLfloat tb_lastposition[3]; 00038 00039 static GLfloat tb_angle = 0.0; 00040 static GLfloat tb_axis[3]; 00041 static GLfloat tb_transform[4][4]; 00042 00043 static GLuint tb_width; 00044 static GLuint tb_height; 00045 00046 static GLint tb_button = -1; 00047 static GLboolean tb_tracking = GL_FALSE; 00048 static GLboolean tb_animate = GL_TRUE; 00049 00050 static void (* tb_original_idle_func)(); 00051 00052 // functions 00053 static void 00054 _tbPointToVector(int x, int y, int width, int height, float v[3]) 00055 { 00056 float d, a; 00057 00058 // project x, y onto a hemi-sphere centered within width, height. 00059 v[0] = (2.0 * x - width) / width; 00060 v[1] = (height - 2.0 * y) / height; 00061 d = sqrt(v[0] * v[0] + v[1] * v[1]); 00062 v[2] = cos((3.14159265 / 2.0) * ((d < 1.0) ? d : 1.0)); 00063 a = 1.0 / sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 00064 v[0] *= a; 00065 v[1] *= a; 00066 v[2] *= a; 00067 } 00068 00069 static void 00070 _tbAnimate(void) 00071 { 00072 tb_original_idle_func(); 00073 glutPostRedisplay(); 00074 } 00075 00076 void 00077 _tbStartMotion(int x, int y, int button, int time) 00078 { 00079 if (tb_button == -1) return; 00080 00081 tb_tracking = GL_TRUE; 00082 tb_lasttime = time; 00083 _tbPointToVector(x, y, tb_width, tb_height, tb_lastposition); 00084 } 00085 00086 void 00087 _tbStopMotion(int button, unsigned time) 00088 { 00089 if (tb_button == -1) return; 00090 00091 tb_tracking = GL_FALSE; 00092 00093 if (time == tb_lasttime && tb_animate) { 00094 glutIdleFunc(_tbAnimate); 00095 } else { 00096 tb_angle = 0.0; 00097 if (tb_animate) 00098 glutIdleFunc(tb_original_idle_func); 00099 } 00100 } 00101 00102 void 00103 tbAnimate(GLboolean animate, void (* idle_func)()) 00104 { 00105 tb_animate = animate; 00106 tb_original_idle_func = idle_func; 00107 } 00108 00109 void 00110 tbInit(GLuint button) 00111 { 00112 tb_button = button; 00113 tb_angle = 0.0; 00114 00115 // put the identity in the trackball transform 00116 glPushMatrix(); 00117 glLoadIdentity(); 00118 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)tb_transform); 00119 glPopMatrix(); 00120 } 00121 00122 void 00123 tbMatrix() 00124 { 00125 if (tb_button == -1) return; 00126 00127 glPushMatrix(); 00128 glLoadIdentity(); 00129 glRotatef(tb_angle, tb_axis[0], tb_axis[1], tb_axis[2]); 00130 glMultMatrixf((GLfloat *)tb_transform); 00131 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)tb_transform); 00132 glPopMatrix(); 00133 00134 glMultMatrixf((GLfloat *)tb_transform); 00135 } 00136 00137 void 00138 tbReshape(int width, int height) 00139 { 00140 if (tb_button == -1) return; 00141 00142 tb_width = width; 00143 tb_height = height; 00144 } 00145 00146 void 00147 tbMouse(int button, int state, int x, int y) 00148 { 00149 if (tb_button == -1) return; 00150 00151 if (state == GLUT_DOWN && button == tb_button) 00152 _tbStartMotion(x, y, button, glutGet(GLUT_ELAPSED_TIME)); 00153 else if (state == GLUT_UP && button == tb_button) 00154 _tbStopMotion(button, glutGet(GLUT_ELAPSED_TIME)); 00155 } 00156 00157 void 00158 tbMotion(int x, int y) 00159 { 00160 GLfloat current_position[3], dx, dy, dz; 00161 00162 if (tb_button == -1) return; 00163 00164 if (tb_tracking == GL_FALSE) 00165 return; 00166 00167 _tbPointToVector(x, y, tb_width, tb_height, current_position); 00168 00169 /* calculate the angle to rotate by (directly proportional to the 00170 length of the mouse movement */ 00171 dx = current_position[0] - tb_lastposition[0]; 00172 dy = current_position[1] - tb_lastposition[1]; 00173 dz = current_position[2] - tb_lastposition[2]; 00174 tb_angle = 90.0 * sqrt(dx * dx + dy * dy + dz * dz); 00175 00176 // calculate the axis of rotation (cross product) 00177 tb_axis[0] = tb_lastposition[1] * current_position[2] - 00178 tb_lastposition[2] * current_position[1]; 00179 tb_axis[1] = tb_lastposition[2] * current_position[0] - 00180 tb_lastposition[0] * current_position[2]; 00181 tb_axis[2] = tb_lastposition[0] * current_position[1] - 00182 tb_lastposition[1] * current_position[0]; 00183 00184 // reset for next time 00185 tb_lasttime = glutGet(GLUT_ELAPSED_TIME); 00186 tb_lastposition[0] = current_position[0]; 00187 tb_lastposition[1] = current_position[1]; 00188 tb_lastposition[2] = current_position[2]; 00189 00190 // remember to draw new position 00191 glutPostRedisplay(); 00192 }