/* ** License Applicability. Except to the extent portions of this file are ** made subject to an alternative license as permitted in the SGI Free ** Software License B, Version 1.1 (the "License"), the contents of this ** file are subject only to the provisions of the License. You may not use ** this file except in compliance with the License. You may obtain a copy ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** ** http://oss.sgi.com/projects/FreeB ** ** Note that, as provided in the License, the Software is distributed on an ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** ** Original Code. The Original Code is: OpenGL Sample Implementation, ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. ** Copyright in any portions created by third parties is as indicated ** elsewhere herein. All Rights Reserved. ** ** Additional Notice Provisions: The application programming interfaces ** established by SGI in conjunction with the Original Code are The ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X ** Window System(R) (Version 1.3), released October 19, 1998. This software ** was created using the OpenGL(R) version 1.2.1 Sample Implementation ** published by SGI, but has not been independently verified as being ** compliant with the OpenGL(R) version 1.2.1 Specification. ** ** $Date: 2006/05/01 16:01:17 $ $Revision: 1.6 $ ** $Header: /home/krh/git/sync/mesa-cvs-repo/Mesa/src/glu/sgi/libutil/project.c,v 1.6 2006/05/01 16:01:17 brianp Exp $ */ #include "gluos.h" #include #include #include #include "gluint.h" void cgl_GLTranslatef(struct GLContextIFace *Self, GLfloat x, GLfloat y, GLfloat z); void cgl_GLOrtho(struct GLContextIFace *Self, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); void cgl_GLMultMatrixd(struct GLContextIFace *Self, const GLdouble *mat); void cgl_GLMultMatrixf(struct GLContextIFace *Self, const GLfloat *mat); void cgl_GLScalef(struct GLContextIFace *Self, GLfloat x, GLfloat y, GLfloat z); /* ** Make m an identity matrix */ static void __gluMakeIdentityd(GLdouble m[16]) { m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0; m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0; m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0; m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1; } static void __gluMakeIdentityf(GLfloat m[16]) { m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0; m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0; m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0; m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1; } void GLAPIENTRY cgl_GLUOrtho2D(struct GLContextIFace *Self, GLdouble left, GLdouble right, GLdouble bottom, GLdouble top) { cgl_GLOrtho(Self,left, right, bottom, top, -1, 1); } #define __glPi 3.14159265358979323846 void GLAPIENTRY cgl_GLUPerspective(struct GLContextIFace *Self, GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar) { GLdouble m[4][4]; double sine, cotangent, deltaZ; double radians = fovy / 2 * __glPi / 180; deltaZ = zFar - zNear; sine = sin(radians); if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) { return; } cotangent = COS(radians) / sine; __gluMakeIdentityd(&m[0][0]); m[0][0] = cotangent / aspect; m[1][1] = cotangent; m[2][2] = -(zFar + zNear) / deltaZ; m[2][3] = -1; m[3][2] = -2 * zNear * zFar / deltaZ; m[3][3] = 0; cgl_GLMultMatrixd(Self,&m[0][0]); } static void normalize(float v[3]) { float r; r = sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] ); if (r == 0.0) return; v[0] /= r; v[1] /= r; v[2] /= r; } static void cross(float v1[3], float v2[3], float result[3]) { result[0] = v1[1]*v2[2] - v1[2]*v2[1]; result[1] = v1[2]*v2[0] - v1[0]*v2[2]; result[2] = v1[0]*v2[1] - v1[1]*v2[0]; } void GLAPIENTRY cgl_GLULookAt(struct GLContextIFace *Self, GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx, GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy, GLdouble upz) { float forward[3], side[3], up[3]; GLfloat m[4][4]; forward[0] = centerx - eyex; forward[1] = centery - eyey; forward[2] = centerz - eyez; up[0] = upx; up[1] = upy; up[2] = upz; normalize(forward); /* Side = forward x up */ cross(forward, up, side); normalize(side); /* Recompute up as: up = side x forward */ cross(side, forward, up); __gluMakeIdentityf(&m[0][0]); m[0][0] = side[0]; m[1][0] = side[1]; m[2][0] = side[2]; m[0][1] = up[0]; m[1][1] = up[1]; m[2][1] = up[2]; m[0][2] = -forward[0]; m[1][2] = -forward[1]; m[2][2] = -forward[2]; cgl_GLMultMatrixf(Self,&m[0][0]); cgl_GLTranslatef(Self,(GLfloat)-eyex, (GLfloat)-eyey, (GLfloat)-eyez); } static void __gluMultMatrixVecd(const GLdouble matrix[16], const GLdouble in[4], GLdouble out[4]) { int i; for (i=0; i<4; i++) { out[i] = in[0] * matrix[0*4+i] + in[1] * matrix[1*4+i] + in[2] * matrix[2*4+i] + in[3] * matrix[3*4+i]; } } /* ** inverse = invert(src) ** New, faster implementation by Shan Hao Bo, April 2006. */ static int __gluInvertMatrixd(const GLdouble src[16], GLdouble inverse[16]) { int i, j, k; double t; GLdouble temp[4][4]; for (i=0; i<4; i++) { for (j=0; j<4; j++) { temp[i][j] = src[i*4+j]; } } __gluMakeIdentityd(inverse); for (i = 0; i < 4; i++) { if (temp[i][i] == 0.0f) { /* ** Look for non-zero element in column */ for (j = i + 1; j < 4; j++) { if (temp[j][i] != 0.0f) { break; } } if (j != 4) { /* ** Swap rows. */ for (k = 0; k < 4; k++) { t = temp[i][k]; temp[i][k] = temp[j][k]; temp[j][k] = t; t = inverse[i*4+k]; inverse[i*4+k] = inverse[j*4+k]; inverse[j*4+k] = t; } } else { /* ** No non-zero pivot. The matrix is singular, which shouldn't ** happen. This means the user gave us a bad matrix. */ return GL_FALSE; } } t = 1.0f / temp[i][i]; for (k = 0; k < 4; k++) { temp[i][k] *= t; inverse[i*4+k] *= t; } for (j = 0; j < 4; j++) { if (j != i) { t = temp[j][i]; for (k = 0; k < 4; k++) { temp[j][k] -= temp[i][k]*t; inverse[j*4+k] -= inverse[i*4+k]*t; } } } } return GL_TRUE; } static void __gluMultMatricesd(const GLdouble a[16], const GLdouble b[16], GLdouble r[16]) { int i, j; for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { r[i*4+j] = a[i*4+0]*b[0*4+j] + a[i*4+1]*b[1*4+j] + a[i*4+2]*b[2*4+j] + a[i*4+3]*b[3*4+j]; } } } GLint GLAPIENTRY cgl_GLUProject(struct GLContextIFace *Self, GLdouble objx, GLdouble objy, GLdouble objz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *winx, GLdouble *winy, GLdouble *winz) { double in[4]; double out[4]; in[0]=objx; in[1]=objy; in[2]=objz; in[3]=1.0; __gluMultMatrixVecd(modelMatrix, in, out); __gluMultMatrixVecd(projMatrix, out, in); if (in[3] == 0.0) return(GL_FALSE); in[0] /= in[3]; in[1] /= in[3]; in[2] /= in[3]; /* Map x, y and z to range 0-1 */ in[0] = in[0] * 0.5 + 0.5; in[1] = in[1] * 0.5 + 0.5; in[2] = in[2] * 0.5 + 0.5; /* Map x,y to viewport */ in[0] = in[0] * viewport[2] + viewport[0]; in[1] = in[1] * viewport[3] + viewport[1]; *winx=in[0]; *winy=in[1]; *winz=in[2]; return(GL_TRUE); } GLint GLAPIENTRY cgl_GLUUnProject(struct GLContextIFace *Self, GLdouble winx, GLdouble winy, GLdouble winz, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLdouble *objx, GLdouble *objy, GLdouble *objz) { double finalMatrix[16]; double in[4]; double out[4]; __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix); if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE); in[0]=winx; in[1]=winy; in[2]=winz; in[3]=1.0; /* Map x and y from window coordinates */ in[0] = (in[0] - viewport[0]) / viewport[2]; in[1] = (in[1] - viewport[1]) / viewport[3]; /* Map to range -1 to 1 */ in[0] = in[0] * 2 - 1; in[1] = in[1] * 2 - 1; in[2] = in[2] * 2 - 1; __gluMultMatrixVecd(finalMatrix, in, out); if (out[3] == 0.0) return(GL_FALSE); out[0] /= out[3]; out[1] /= out[3]; out[2] /= out[3]; *objx = out[0]; *objy = out[1]; *objz = out[2]; return(GL_TRUE); } GLint GLAPIENTRY cgl_GLUUnProject4(struct GLContextIFace *Self, GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw, const GLdouble modelMatrix[16], const GLdouble projMatrix[16], const GLint viewport[4], GLclampd nearVal, GLclampd farVal, GLdouble *objx, GLdouble *objy, GLdouble *objz, GLdouble *objw) { double finalMatrix[16]; double in[4]; double out[4]; __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix); if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE); in[0]=winx; in[1]=winy; in[2]=winz; in[3]=clipw; /* Map x and y from window coordinates */ in[0] = (in[0] - viewport[0]) / viewport[2]; in[1] = (in[1] - viewport[1]) / viewport[3]; in[2] = (in[2] - nearVal) / (farVal - nearVal); /* Map to range -1 to 1 */ in[0] = in[0] * 2 - 1; in[1] = in[1] * 2 - 1; in[2] = in[2] * 2 - 1; __gluMultMatrixVecd(finalMatrix, in, out); if (out[3] == 0.0) return(GL_FALSE); *objx = out[0]; *objy = out[1]; *objz = out[2]; *objw = out[3]; return(GL_TRUE); } void GLAPIENTRY cgl_GLUPickMatrix(struct GLContextIFace *Self, GLdouble x, GLdouble y, GLdouble deltax, GLdouble deltay, GLint viewport[4]) { if (deltax <= 0 || deltay <= 0) { return; } /* Translate and scale the picked region to the entire window */ cgl_GLTranslatef(Self,(viewport[2] - 2 * (x - viewport[0])) / deltax, (viewport[3] - 2 * (y - viewport[1])) / deltay, 0); cgl_GLScalef(Self,viewport[2] / deltax, viewport[3] / deltay, 1.0); }