Files Classes Functions Hierarchy
00001 #include <cassert> 00002 #include <cstdlib> 00003 #include <cmath> 00004 #include <memory> 00005 #include <cstring> 00006 #include <iostream> 00007 using namespace std; 00008 00009 #include <GL/glut.h> 00010 00011 #include <zpr.h> 00012 00013 #include <graphmisc.h> 00014 00015 00017 GLdouble zprGLmatrix::zero = 1.0E-15; 00018 00020 zpr* zpr::global = 0; 00021 00022 #define SHOW(x) #x << '=' << (x) 00023 00024 00025 // 00026 // From Mesa-2.2\src\glu\project.c 00027 // 00028 00029 // 00030 // Compute the inverse of a 4x4 matrix. Contributed by scotter@lafn.org 00031 // 00032 00033 void zprGLmatrix::invertMatrix(GLdouble *out, GLdouble const *m ) 00034 { 00035 00036 /* NB. OpenGL Matrices are COLUMN major. */ 00037 #define MAT(m,r,c) (m)[(c)*4+(r)] 00038 00039 // <TODO> Renaming the indexes??? Do they have a problem counting from 0? Why? 00040 /* Here's some shorthand converting standard (row,column) to index. */ 00041 #define m11 MAT(m,0,0) 00042 #define m12 MAT(m,0,1) 00043 #define m13 MAT(m,0,2) 00044 #define m14 MAT(m,0,3) 00045 #define m21 MAT(m,1,0) 00046 #define m22 MAT(m,1,1) 00047 #define m23 MAT(m,1,2) 00048 #define m24 MAT(m,1,3) 00049 #define m31 MAT(m,2,0) 00050 #define m32 MAT(m,2,1) 00051 #define m33 MAT(m,2,2) 00052 #define m34 MAT(m,2,3) 00053 #define m41 MAT(m,3,0) 00054 #define m42 MAT(m,3,1) 00055 #define m43 MAT(m,3,2) 00056 #define m44 MAT(m,3,3) 00057 00058 static GLdouble temporary[16]; /* Allow out == in. */ 00059 GLdouble * tmp = out; 00060 00061 bool const outin(m==out); 00062 if (outin) 00063 tmp = & temporary[0]; 00064 00065 /* Inverse = adjoint / det. (See linear algebra texts.)*/ 00066 00067 /* pre-compute 2x2 dets for last two rows when computing */ 00068 /* cofactors of first two rows. */ 00069 GLdouble d12(m31*m42-m41*m32); 00070 GLdouble d13(m31*m43-m41*m33); 00071 GLdouble d23(m32*m43-m42*m33); 00072 GLdouble d24(m32*m44-m42*m34); 00073 GLdouble d34(m33*m44-m43*m34); 00074 GLdouble d41(m34*m41-m44*m31); 00075 00076 tmp[0] = (m22 * d34 - m23 * d24 + m24 * d23); 00077 tmp[1] = -(m21 * d34 + m23 * d41 + m24 * d13); 00078 tmp[2] = (m21 * d24 + m22 * d41 + m24 * d12); 00079 tmp[3] = -(m21 * d23 - m22 * d13 + m23 * d12); 00080 00081 /* Compute determinant as early as possible using these cofactors. */ 00082 GLdouble det(m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2] + m14 * tmp[3]); 00083 00084 /* Singularity test. */ 00085 if (abs(det)>zero) 00086 { 00087 GLdouble invDet(1.0 / det); 00088 /* Compute rest of inverse. */ 00089 tmp[0] *= invDet; 00090 tmp[1] *= invDet; 00091 tmp[2] *= invDet; 00092 tmp[3] *= invDet; 00093 00094 tmp[4] = -(m12 * d34 - m13 * d24 + m14 * d23) * invDet; 00095 tmp[5] = (m11 * d34 + m13 * d41 + m14 * d13) * invDet; 00096 tmp[6] = -(m11 * d24 + m12 * d41 + m14 * d12) * invDet; 00097 tmp[7] = (m11 * d23 - m12 * d13 + m13 * d12) * invDet; 00098 00099 /* Pre-compute 2x2 dets for first two rows when computing */ 00100 /* cofactors of last two rows. */ 00101 d12 = m11*m22-m21*m12; 00102 d13 = m11*m23-m21*m13; 00103 d23 = m12*m23-m22*m13; 00104 d24 = m12*m24-m22*m14; 00105 d34 = m13*m24-m23*m14; 00106 d41 = m14*m21-m24*m11; 00107 00108 tmp[8] = (m42 * d34 - m43 * d24 + m44 * d23) * invDet; 00109 tmp[9] = -(m41 * d34 + m43 * d41 + m44 * d13) * invDet; 00110 tmp[10] = (m41 * d24 + m42 * d41 + m44 * d12) * invDet; 00111 tmp[11] = -(m41 * d23 - m42 * d13 + m43 * d12) * invDet; 00112 tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23) * invDet; 00113 tmp[13] = (m31 * d34 + m33 * d41 + m34 * d13) * invDet; 00114 tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12) * invDet; 00115 tmp[15] = (m31 * d23 - m32 * d13 + m33 * d12) * invDet; 00116 00117 if (outin) 00118 memcpy(out, tmp, 16*sizeof(GLdouble)); 00119 } 00120 00121 #undef m11 00122 #undef m12 00123 #undef m13 00124 #undef m14 00125 #undef m21 00126 #undef m22 00127 #undef m23 00128 #undef m24 00129 #undef m31 00130 #undef m32 00131 #undef m33 00132 #undef m34 00133 #undef m41 00134 #undef m42 00135 #undef m43 00136 #undef m44 00137 #undef MAT 00138 } 00139 00140 00141 00142 void zpr::readModelView() 00143 { 00144 glGetDoublev(GL_MODELVIEW_MATRIX,matrix); 00145 zprGLmatrix::invertMatrix(matrixI,matrix); 00146 } 00147 00148 void zpr::reshape(int width_,int height_) 00149 { 00150 assert(zpr::global!=0); 00151 global->reshapezpr(width_,height_); 00152 } 00153 00154 void zpr::write() 00155 { 00156 glViewport(0,0,width,height); 00157 00158 glMatrixMode(GL_PROJECTION); 00159 glLoadIdentity(); 00160 assert(zNear>0.0); 00161 assert(zFar>zNear); 00162 glFrustum(left,right,bottom,top,zNear,zFar); 00163 glMatrixMode(GL_MODELVIEW); 00164 00165 glerrordisplay(); 00166 } 00167 00168 void zpr::reshapezpr(intc width_,intc height_) 00169 { 00170 width = width_; 00171 height = height_; 00172 00173 //cout << "width=" << width << endl; 00174 //cout << "height=" << height << endl; 00175 00176 //glViewport(0, 0, (GLsizei) width_, (GLsizei) height_); 00177 00178 writeDefault(); 00179 } 00180 00181 void zpr::writeDefault() 00182 { 00183 assert( height>0.0); 00184 assert( width>0.0); 00185 00186 left=-1.0; 00187 right=1.0; 00188 00189 double dy = (double) height / (double)width; 00190 bottom=-dy; 00191 top=dy; 00192 00193 zNear=1.0; 00194 zFar=6.0; 00195 write(); 00196 } 00197 00198 void zpr::mouse(int button, int state, int x, int y) 00199 { 00200 assert(global!=0); 00201 00202 global->mousezpr(button,state,x,y); 00203 } 00204 00205 void zpr::readMouse 00206 ( 00207 GLdouble *px, 00208 GLdouble *py, 00209 GLdouble *pz, 00210 intc x, 00211 intc y 00212 ) const 00213 { 00214 // Use the ortho projection and viewport information 00215 // to map from mouse co-ordinates back into world 00216 // co-ordinates 00217 00218 int viewport[4]; 00219 glGetIntegerv(GL_VIEWPORT,viewport); 00220 00221 *px = (GLdouble)(x-viewport[0])/(GLdouble)(viewport[2]); 00222 *py = (GLdouble)(y-viewport[1])/(GLdouble)(viewport[3]); 00223 00224 *px = left + (*px)*(right-left); 00225 *py = top + (*py)*(bottom-top); 00226 *pz = zNear; 00227 } 00228 00229 00230 00231 void zpr::mousezpr(intc button, intc state, intc x, intc y) 00232 { 00233 mouseX = x; 00234 mouseY = y; 00235 00236 if (state==GLUT_UP) 00237 switch (button) 00238 { 00239 case GLUT_LEFT_BUTTON: mouseLeft = false; break; 00240 case GLUT_MIDDLE_BUTTON: mouseMiddle = false; break; 00241 case GLUT_RIGHT_BUTTON: mouseRight = false; break; 00242 } 00243 else 00244 switch (button) 00245 { 00246 case GLUT_LEFT_BUTTON: mouseLeft = true; break; 00247 case GLUT_MIDDLE_BUTTON: mouseMiddle = true; break; 00248 case GLUT_RIGHT_BUTTON: mouseRight = true; break; 00249 } 00250 00251 readMouse(&mouseXworld,&mouseYworld,&mouseZworld,x,y); 00252 00253 //if (mousecallback) 00254 // (*mousecallback)(*this); 00255 if (mousecallback) 00256 (*mousecallback)(); 00257 } 00258 00259 void zpr::motion(int x, int y) 00260 { 00261 assert(global!=0); 00262 global->motionzpr(x,y); 00263 } 00264 00265 void zpr::motionzpr(intc x, intc y) 00266 { 00267 bool changed = false; 00268 00269 intc dx = x - mouseX; 00270 intc dy = y - mouseY; 00271 00272 if (dx==0 && dy==0) 00273 return; 00274 00275 if (mouseMiddle || (mouseLeft && mouseRight)) 00276 { 00277 GLdouble s = exp((GLdouble)dy*0.01); 00278 glScalef(s,s,s); 00279 changed = true; 00280 } 00281 else 00282 if (mouseLeft) 00283 { 00284 GLdouble ax,ay,az; 00285 GLdouble bx,by,bz; 00286 GLdouble angle; 00287 00288 ax = dy; 00289 ay = dx; 00290 az = 0.0; 00291 angle = vlen(ax,ay,az)/(GLdouble)(width+1)*180.0; 00292 00293 /* Use inverse matrix to determine local axis of rotation */ 00294 00295 bx = matrixI[0]*ax + matrixI[4]*ay + matrixI[8]*az; 00296 by = matrixI[1]*ax + matrixI[5]*ay + matrixI[9]*az; 00297 bz = matrixI[2]*ax + matrixI[6]*ay + matrixI[10]*az; 00298 00299 glRotatef(angle,bx,by,bz); 00300 00301 changed = true; 00302 } 00303 else 00304 if (mouseRight) 00305 { 00306 GLdouble px,py,pz; 00307 00308 readMouse(&px,&py,&pz,x,y); 00309 00310 glLoadIdentity(); 00311 glTranslatef(px-mouseXworld,py-mouseYworld,pz-mouseZworld); 00312 glMultMatrixd(matrix); 00313 00314 mouseXworld = px; 00315 mouseYworld = py; 00316 mouseZworld = pz; 00317 00318 changed = true; 00319 } 00320 00321 mouseX = x; 00322 mouseY = y; 00323 00324 if (changed) 00325 { 00326 readModelView(); 00327 glutPostRedisplay(); 00328 } 00329 } 00330 00331 zpr::zpr() 00332 { 00333 global = this; 00334 00335 mouseX = 0; 00336 mouseY = 0; 00337 00338 mouseLeft = false; 00339 mouseRight = false; 00340 mouseMiddle = false; 00341 00342 mouseXworld = 0.0; 00343 mouseYworld = 0.0; 00344 mouseZworld = 0.0; 00345 00346 mousecallback = 0; 00347 00348 //glMatrixMode(GL_MODELVIEW); 00349 //glLoadIdentity(); 00350 00351 readScreenDimensions(); 00352 00353 glMatrixMode(GL_PROJECTION); 00354 glLoadIdentity(); 00355 00356 zNear=1.0; 00357 zFar=10.0; 00358 gluPerspective(30, (GLfloat) width/(GLfloat) height, zNear, zFar); 00359 00360 glMatrixMode(GL_MODELVIEW); 00361 00362 glLoadIdentity(); 00363 gluLookAt 00364 ( 00365 0.0, 0.0, 2.0, // Eye - creates a x: [-2,2] y: [-2,2] screen. 00366 0.0, 0.0, 0.0, // Center 00367 0.0, 1.0, 0.0 // Up 00368 ); 00369 00370 00371 glerrordisplay(); 00372 update(); 00373 00374 glutReshapeFunc(reshape); 00375 glutMouseFunc(mouse); 00376 glutMotionFunc(motion); 00377 } 00378 00379 void zpr::printInfo() const 00380 { 00381 cout << SHOW(left) << endl; 00382 cout << SHOW(right) << endl; 00383 cout << SHOW(bottom) << endl; 00384 cout << SHOW(top) << endl; 00385 cout << SHOW(zNear) << endl; 00386 cout << SHOW(zFar) << endl; 00387 cout << SHOW(width) << endl; 00388 cout << SHOW(height) << endl; 00389 } 00390 00391 void zpr::writefromXaxis() 00392 { 00393 GLdouble const xlen = right - left; 00394 GLdouble const ylen = xlen * (GLdouble) height / (GLdouble) width; 00395 top = bottom + ylen; 00396 00397 write(); 00398 } 00399 00400 /* 00401 00402 void zpr::setViewVolumeFromXaxis 00403 ( 00404 int const width_, 00405 int const height_, 00406 GLdouble const left_, 00407 GLdouble const right_, 00408 GLdouble const bottom_, 00409 GLdouble const zNear_, 00410 GLdouble const zFar_ 00411 ) 00412 { 00413 width = width_; 00414 height = height_; 00415 00416 GLdouble const xlen = right_ - left_; 00417 GLdouble const ylen = xlen * (GLdouble) height / (GLdouble) width; 00418 GLdouble top_ = bottom_ + ylen; 00419 00420 00421 //cout << "left_=" << left_; 00422 //cout << " right_=" << right_; 00423 //cout << " bottom_=" << bottom_; 00424 //cout << " top_=" << top_; 00425 //cout << endl << endl; 00426 00427 //cout << "xlen=" << xlen << " " << "ylen=" << ylen << endl; 00428 //cout << "top_=" << top_ << endl; 00429 00430 00431 setViewVolume(left_,right_,bottom_,top_,zNear_,zFar_); 00432 } 00433 00434 */ 00435 00436 00437 00438 00439 void zprGLmatrix::print() const 00440 { 00441 uint i; 00442 uint k; 00443 uint i2=0; 00444 for ( i=0; i<4; ++i) 00445 { 00446 for (k=0; k<4; ++k) 00447 { 00448 cout << matrix[i2] << " "; 00449 ++i2; 00450 } 00451 cout << endl; 00452 } 00453 } 00454 00455 void zprGLmatrix::printTranspose() const 00456 { 00457 uint i; 00458 uint k; 00459 for ( i=0; i<4; ++i) 00460 { 00461 for (k=0; k<4; ++k) 00462 { 00463 cout << access(i,k) << " "; 00464 } 00465 cout << endl; 00466 } 00467 } 00468 00469 void zpr::readScreenDimensions() 00470 { 00471 GLint viewport[4]; 00472 glGetIntegerv( GL_VIEWPORT, viewport ); 00473 00474 glerrordisplay(); 00475 00476 width = viewport[2]; 00477 height = viewport[3]; 00478 } 00479 00480 void zpr::readProjection() 00481 { 00482 static GLdouble pmatrix[16]; 00483 00484 glerrordisplay(); 00485 00486 glGetDoublev(GL_PROJECTION_MATRIX,pmatrix); 00487 00488 glerrordisplay(); 00489 00490 zprGLmatrix mat(pmatrix); 00491 00492 GLdouble a[6]; 00493 a[0] = mat.access(0,0); 00494 a[1] = mat.access(1,1); 00495 a[2] = mat.access(0,2); 00496 a[3] = mat.access(1,2); 00497 a[4] = mat.access(2,2); 00498 a[5] = mat.access(2,3); 00499 00500 // This is essentially an inverse of a glFrustrum(...) call. 00501 // Here the input parameters to the glFrustrum call are 00502 // calculated from the projection matrix. 00503 GLdouble c0 = (1.0-a[4])/(1.0+a[4]); 00504 //GLdouble z0 = a[5]*(c0+1.0)*-0.5/c0; 00505 GLdouble z0 = a[5]*(1.0+1.0/c0)*-0.50; 00506 GLdouble z1 = -c0*z0; 00507 GLdouble x0 = z0*(a[2]-1.0)/a[0]; 00508 GLdouble x1 = (z0*2.0+a[0]*x0)/a[0]; 00509 GLdouble y0 = z0*(a[3]-1.0)/a[1]; 00510 GLdouble y1 = (z0*2.0+a[1]*y0)/a[1]; 00511 00512 left = x0; 00513 right = x1; 00514 bottom = y0; 00515 top = y1; 00516 zNear = z0; 00517 zFar = z1; 00518 00519 glerrordisplay(); 00520 } 00521 00522 00523
1.5.8