/* * stereoTest.cpp * GLUTTest * * Created by GGS on Wed Nov 06 2002. * Copyright (c) 2002 Apple. All rights reserved. * Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in consideration of your agreement to the following terms, and your use, installation, modification or redistribution of this Apple software constitutes acceptance of these terms. If you do not agree with these terms, please do not use, install, modify or redistribute this Apple software. In consideration of your agreement to abide by the following terms, and subject to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs copyrights in this original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the Apple Software, with or without modifications, in source and/or binary forms; provided that if you redistribute the Apple Software in its entirety and without modifications, you must retain this notice and the following text and disclaimers in all such redistributions of the Apple Software. Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to endorse or promote products derived from the Apple Software without specific prior written permission from Apple. Except as expressly stated in this notice, no other rights or licenses, express or implied, are granted by Apple herein, including but not limited to any patent rights that may be infringed by your derivative works or by other works in which the Apple Software may be incorporated. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* Uses techniques described by Paul Bourke 1999 - 2002 */ /* including parallel axis asymmetric frustum perspective projection */ /* see: */ /* Tranguloid Trefoil example surface by Roger Bagula see */ #include using std::cout; using std::endl; #include #include #include #include "trackball.h" #define CROSSPROD(p1,p2,p3) \ p3.x = p1.y*p2.z - p1.z*p2.y; \ p3.y = p1.z*p2.x - p1.x*p2.z; \ p3.z = p1.x*p2.y - p1.y*p2.x #define EPS 0.00001 #define DTOR 0.0174532925 #define RTOD 57.2957795 #define TWOPI 6.283185307179586476925287 #define PI 3.141592653589793238462643 typedef struct { GLdouble x,y,z; } recVec; typedef struct { GLdouble r,g,b; } recColor; typedef struct { recVec viewPos; // View position recVec viewDir; // View direction vector recVec viewUp; // View up direction recVec rotPoint; // Point to rotate about GLdouble focalLength; // Focal Length along view direction GLdouble aperture; // gCamera aperture GLdouble eyeSep; // Eye separation GLint screenWidth,screenHeight; // current window/screen height and width } recCamera; GLuint gColorScheme = 1; GLuint gSubDivisions = 64; GLuint gIJRatio = 3; recVec *gVertexPos = NULL,*gVertexNormal = NULL; recColor *gVertexColor = NULL; GLuint gPolyList = 0; GLuint gLineList = 0; GLuint gPointList = 0; char gSurfName[256] = ""; char gSurfCredit[256] = ""; char gSurfX[256] = ""; char gSurfY[256] = ""; char gSurfZ[256] = ""; char gSurfRange[256] = ""; int main_window = NULL; GLint gDollyStartPoint[2] = {0, 0}; GLboolean gDolly = GL_FALSE; GLfloat gTrackBallRotation [4] = {0.0, 0.0, 0.0, 0.0}; GLboolean gTrackBall = GL_FALSE; GLfloat gWorldRotation [4] = {100.0, -0.7, 0.6, 0.5}; GLboolean gStereo = GL_TRUE; GLboolean gPoints = GL_FALSE; GLboolean gLines = GL_FALSE; GLboolean gPolygons = GL_TRUE; GLboolean gShowHelp = GL_TRUE; GLboolean gShowInfo = GL_TRUE; GLboolean gShowCredits = GL_TRUE; GLboolean gLighting = GL_TRUE; GLint gSurface = 0; GLdouble gShapeSize = 11.0; recCamera gCamera; recVec gOrigin = {0.0, 0.0, 0.0}; GLboolean gDragStart = false; int gLastKey = ' '; // - gCamera control ---------------- void gCameraReset(void) { gCamera.aperture = 50; gCamera.focalLength = 9; gCamera.eyeSep = gCamera.focalLength / 20; gCamera.rotPoint = gOrigin; gCamera.viewPos.x = 0.0; gCamera.viewPos.y = 0.0; gCamera.viewPos.z = -gCamera.focalLength; gCamera.viewDir.x = -gCamera.viewPos.x; gCamera.viewDir.y = -gCamera.viewPos.y; gCamera.viewDir.z = -gCamera.viewPos.z; gCamera.viewUp.x = 0; gCamera.viewUp.y = 1; gCamera.viewUp.z = 0; } // - Utilities --------------------- void DrawString(GLfloat x, GLfloat y, char *string) { int len, i; glRasterPos2f(x, y); len = (int) strlen(string); for (i = 0; i < len; i++) { glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, string[i]); } } void normalise(recVec *p) { double length; length = sqrt(p->x * p->x + p->y * p->y + p->z * p->z); if (length != 0) { p->x /= length; p->y /= length; p->z /= length; } else { p->x = 0; p->y = 0; p->z = 0; } } recVec CalcNormal(recVec p,recVec p1,recVec p2) { recVec n,pa,pb; pa.x = p1.x - p.x; pa.y = p1.y - p.y; pa.z = p1.z - p.z; pb.x = p2.x - p.x; pb.y = p2.y - p.y; pb.z = p2.z - p.z; normalise(&pa); normalise(&pb); n.x = pa.y * pb.z - pa.z * pb.y; n.y = pa.z * pb.x - pa.x * pb.z; n.z = pa.x * pb.y - pa.y * pb.x; normalise(&n); return(n); } /* Based on GetColour by Paul Bourke */ recColor GetColor(double v,double vmin,double vmax,int type) { double dv,vmid; recColor c = {1.0,1.0,1.0}; recColor c1,c2,c3; double ratio; if (v < vmin) v = vmin; if (v > vmax) v = vmax; dv = vmax - vmin; switch (type) { case 1: if (v < (vmin + 0.25 * dv)) { c.r = 0; c.g = 4 * (v - vmin) / dv; c.b = 1; } else if (v < (vmin + 0.5 * dv)) { c.r = 0; c.g = 1; c.b = 1 + 4 * (vmin + 0.25 * dv - v) / dv; } else if (v < (vmin + 0.75 * dv)) { c.r = 4 * (v - vmin - 0.5 * dv) / dv; c.g = 1; c.b = 0; } else { c.r = 1; c.g = 1 + 4 * (vmin + 0.75 * dv - v) / dv; c.b = 0; } break; case 2: c.r = (v - vmin) / dv; c.g = 0; c.b = (vmax - v) / dv; break; case 3: c.r = (v - vmin) / dv; c.b = c.r; c.g = c.r; break; case 4: if (v < (vmin + dv / 6.0)) { c.r = 1; c.g = 6 * (v - vmin) / dv; c.b = 0; } else if (v < (vmin + 2.0 * dv / 6.0)) { c.r = 1 + 6 * (vmin + dv / 6.0 - v) / dv; c.g = 1; c.b = 0; } else if (v < (vmin + 3.0 * dv / 6.0)) { c.r = 0; c.g = 1; c.b = 6 * (v - vmin - 2.0 * dv / 6.0) / dv; } else if (v < (vmin + 4.0 * dv / 6.0)) { c.r = 0; c.g = 1 + 6 * (vmin + 3.0 * dv / 6.0 - v) / dv; c.b = 1; } else if (v < (vmin + 5.0 * dv / 6.0)) { c.r = 6 * (v - vmin - 4.0 * dv / 6.0) / dv; c.g = 0; c.b = 1; } else { c.r = 1; c.g = 0; c.b = 1 + 6 * (vmin + 5.0 * dv / 6.0 - v) / dv; } break; case 5: c.r = (v - vmin) / (vmax - vmin); c.g = 1; c.b = 0; break; case 6: c.r = (v - vmin) / (vmax - vmin); c.g = (vmax - v) / (vmax - vmin); c.b = c.r; break; case 7: if (v < (vmin + 0.25 * dv)) { c.r = 0; c.g = 4 * (v - vmin) / dv; c.b = 1 - c.g; } else if (v < (vmin + 0.5 * dv)) { c.r = 4 * (v - vmin - 0.25 * dv) / dv; c.g = 1 - c.r; c.b = 0; } else if (v < (vmin + 0.75 * dv)) { c.g = 4 * (v - vmin - 0.5 * dv) / dv; c.r = 1 - c.g; c.b = 0; } else { c.r = 0; c.b = 4 * (v - vmin - 0.75 * dv) / dv; c.g = 1 - c.b; } break; case 8: if (v < (vmin + 0.5 * dv)) { c.r = 2 * (v - vmin) / dv; c.g = c.r; c.b = c.r; } else { c.r = 1 - 2 * (v - vmin - 0.5 * dv) / dv; c.g = c.r; c.b = c.r; } break; case 9: if (v < (vmin + dv / 3)) { c.b = 3 * (v - vmin) / dv; c.g = 0; c.r = 1 - c.b; } else if (v < (vmin + 2 * dv / 3)) { c.r = 0; c.g = 3 * (v - vmin - dv / 3) / dv; c.b = 1; } else { c.r = 3 * (v - vmin - 2 * dv / 3) / dv; c.g = 1 - c.r; c.b = 1; } break; case 10: if (v < (vmin + 0.2 * dv)) { c.r = 0; c.g = 5 * (v - vmin) / dv; c.b = 1; } else if (v < (vmin + 0.4 * dv)) { c.r = 0; c.g = 1; c.b = 1 + 5 * (vmin + 0.2 * dv - v) / dv; } else if (v < (vmin + 0.6 * dv)) { c.r = 5 * (v - vmin - 0.4 * dv) / dv; c.g = 1; c.b = 0; } else if (v < (vmin + 0.8 * dv)) { c.r = 1; c.g = 1 - 5 * (v - vmin - 0.6 * dv) / dv; c.b = 0; } else { c.r = 1; c.g = 5 * (v - vmin - 0.8 * dv) / dv; c.b = 5 * (v - vmin - 0.8 * dv) / dv; } break; case 11: c1.r = 200 / 255.0; c1.g = 60 / 255.0; c1.b = 0 / 255.0; c2.r = 250 / 255.0; c2.g = 160 / 255.0; c2.b = 110 / 255.0; c.r = (c2.r - c1.r) * (v - vmin) / dv + c1.r; c.g = (c2.g - c1.g) * (v - vmin) / dv + c1.g; c.b = (c2.b - c1.b) * (v - vmin) / dv + c1.b; break; case 12: c1.r = 55 / 255.0; c1.g = 55 / 255.0; c1.b = 45 / 255.0; // c2.r = 200 / 255.0; c2.g = 60 / 255.0; c2.b = 0 / 255.0; c2.r = 235 / 255.0; c2.g = 90 / 255.0; c2.b = 30 / 255.0; c3.r = 250 / 255.0; c3.g = 160 / 255.0; c3.b = 110 / 255.0; ratio = 0.4; vmid = vmin + ratio * dv; if (v < vmid) { c.r = (c2.r - c1.r) * (v - vmin) / (ratio*dv) + c1.r; c.g = (c2.g - c1.g) * (v - vmin) / (ratio*dv) + c1.g; c.b = (c2.b - c1.b) * (v - vmin) / (ratio*dv) + c1.b; } else { c.r = (c3.r - c2.r) * (v - vmid) / ((1-ratio)*dv) + c2.r; c.g = (c3.g - c2.g) * (v - vmid) / ((1-ratio)*dv) + c2.g; c.b = (c3.b - c2.b) * (v - vmid) / ((1-ratio)*dv) + c2.b; } break; case 13: c1.r = 0 / 255.0; c1.g = 255 / 255.0; c1.b = 0 / 255.0; c2.r = 255 / 255.0; c2.g = 150 / 255.0; c2.b = 0 / 255.0; c3.r = 255 / 255.0; c3.g = 250 / 255.0; c3.b = 240 / 255.0; ratio = 0.3; vmid = vmin + ratio * dv; if (v < vmid) { c.r = (c2.r - c1.r) * (v - vmin) / (ratio*dv) + c1.r; c.g = (c2.g - c1.g) * (v - vmin) / (ratio*dv) + c1.g; c.b = (c2.b - c1.b) * (v - vmin) / (ratio*dv) + c1.b; } else { c.r = (c3.r - c2.r) * (v - vmid) / ((1-ratio)*dv) + c2.r; c.g = (c3.g - c2.g) * (v - vmid) / ((1-ratio)*dv) + c2.g; c.b = (c3.b - c2.b) * (v - vmid) / ((1-ratio)*dv) + c2.b; } break; case 14: c.r = 1; c.g = 1 - (v - vmin) / dv; c.b = 0; break; case 15: if (v < (vmin + 0.25 * dv)) { c.r = 0; c.g = 4 * (v - vmin) / dv; c.b = 1; } else if (v < (vmin + 0.5 * dv)) { c.r = 0; c.g = 1; c.b = 1 - 4 * (v - vmin - 0.25 * dv) / dv; } else if (v < (vmin + 0.75 * dv)) { c.r = 4 * (v - vmin - 0.5 * dv) / dv; c.g = 1; c.b = 0; } else { c.r = 1; c.g = 1; c.b = 4 * (v - vmin - 0.75 * dv) / dv; } break; case 16: if (v < (vmin + 0.5 * dv)) { c.r = 0.0; c.g = 2 * (v - vmin) / dv; c.b = 1 - 2 * (v - vmin) / dv; } else { c.r = 2 * (v - vmin - 0.5 * dv) / dv; c.g = 1 - 2 * (v - vmin - 0.5 * dv) / dv; c.b = 0.0; } break; case 17: if (v < (vmin + 0.5 * dv)) { c.r = 1.0; c.g = 1 - 2 * (v - vmin) / dv; c.b = 2 * (v - vmin) / dv; } else { c.r = 1 - 2 * (v - vmin - 0.5 * dv) / dv; c.g = 2 * (v - vmin - 0.5 * dv) / dv; c.b = 1.0; } break; case 18: c.r = 0; c.g = (v - vmin) / (vmax - vmin); c.b = 1; break; case 19: c.r = (v - vmin) / (vmax - vmin); c.g = c.r; c.b = 1; break; case 20: c1.r = 0 / 255.0; c1.g = 160 / 255.0; c1.b = 0 / 255.0; c2.r = 180 / 255.0; c2.g = 220 / 255.0; c2.b = 0 / 255.0; c3.r = 250 / 255.0; c3.g = 220 / 255.0; c3.b = 170 / 255.0; ratio = 0.3; vmid = vmin + ratio * dv; if (v < vmid) { c.r = (c2.r - c1.r) * (v - vmin) / (ratio*dv) + c1.r; c.g = (c2.g - c1.g) * (v - vmin) / (ratio*dv) + c1.g; c.b = (c2.b - c1.b) * (v - vmin) / (ratio*dv) + c1.b; } else { c.r = (c3.r - c2.r) * (v - vmid) / ((1-ratio)*dv) + c2.r; c.g = (c3.g - c2.g) * (v - vmid) / ((1-ratio)*dv) + c2.g; c.b = (c3.b - c2.b) * (v - vmid) / ((1-ratio)*dv) + c2.b; } break; } return(c); } // - Drawing ------------ void SetLighting(void) { GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0}; GLfloat mat_shininess[] = {90.0}; GLfloat position[4] = {7.0,-7.0,12.0,0.0}; GLfloat ambient[4] = {0.2,0.2,0.2,1.0}; GLfloat diffuse[4] = {1.0,1.0,1.0,1.0}; GLfloat specular[4] = {1.0,1.0,1.0,1.0}; glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular); glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE); glLightfv(GL_LIGHT0,GL_POSITION,position); glLightfv(GL_LIGHT0,GL_AMBIENT,ambient); glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuse); glLightfv(GL_LIGHT0,GL_SPECULAR,specular); glEnable(GL_LIGHT0); } /* Code based on work by Paul Bourke */ #define kSurfaces 5 // expects u & v (-PI to PI) recVec Eval(double u, double v, int type) { recVec p; double temp; switch (type) { case 0: sprintf (gSurfName, "Tranguloid Trefoil"); sprintf (gSurfCredit, "by Roger Bagula"); sprintf (gSurfX, "x = 2 sin(3 u) / (2 + cos(v)) )"); sprintf (gSurfY, "y = 2 (sin(u) + 2 sin(2 u)) / (2 + cos(v + 2 pi / 3)) "); sprintf (gSurfZ, "z = (cos(u) - 2 cos(2 u)) (2 + cos(v)) (2 + cos(v + 2 pi / 3)) / 4"); sprintf (gSurfRange, "-pi <= u <= pi, -pi <= v <= pi "); p.x = sin(3*u) * 2 / (2 + cos(v)); p.y = (sin(u) + 2 * sin(2*u)) * 2 / (2 + cos(v + TWOPI / 3)); p.z = (cos(u) - 2 * cos(2*u)) * (2 + cos(v)) * (2 + cos(v + TWOPI/3))/4; break; case 1: sprintf (gSurfName, "Triaxial Tritorus"); sprintf (gSurfCredit, "by Roger Bagula"); sprintf (gSurfX, "x = sin(u) (1 + cos(v))"); sprintf (gSurfY, "y = sin(u + 2pi / 3) (1 + cos(v + 2pi / 3)) "); sprintf (gSurfZ, "z = sin(u + 4pi / 3) (1 + cos(v + 4pi / 3))"); sprintf (gSurfRange, "0 <= u <= 2 pi, 0 <= v <= 2 pi"); p.x = sin (u) * (1 + cos (v)); p.y = sin (u + 2 * PI / 3) * (1 + cos (v + 2 * PI / 3)); p.z = sin (u + 4 * PI / 3) * (1 + cos (v + 4 * PI / 3)); break; case 2: sprintf (gSurfName, "Stiletto Surface"); sprintf (gSurfCredit, "by Roger Bagula"); sprintf (gSurfX, "x = (2 + cos(u)) cos(v)^3 sin(v)"); sprintf (gSurfY, "y = (2 + cos(u + 2pi /3)) cos(v + 2pi / 3)^2 sin(v + 2pi / 3)^2"); sprintf (gSurfZ, "z = -(2 + cos(u - 2pi / 3)) cos(v + 2pi / 3)^2 sin(v + 2pi / 3)^2"); sprintf (gSurfRange, "0 <= u <= 2 pi, 0 <= v <= 2 pi"); // reverse u and v for better distribution or points temp = u; u = v + PI; v = temp + PI; // convert to: 0 <= u <= 2 pi, 0 <= v <= 2 pi p.x = (2 + cos(u)) * pow(cos(v), 3) * sin(v); p.y = (2 + cos(u+TWOPI/3)) * pow (cos(v+TWOPI/3), 2) * pow (sin(v+TWOPI/3), 2); p.z = -(2 + cos(u-TWOPI/3)) * pow (cos(v+TWOPI/3), 2) * pow (sin(v+TWOPI/3), 2); break; case 3: sprintf (gSurfName, "Slippers Surface"); sprintf (gSurfCredit, "by Roger Bagula"); sprintf (gSurfX, "x = (2 + cos(u)) cos(v)^3 sin(v)"); sprintf (gSurfY, "y = (2 + cos(u + 2pi / 3)) cos(2pi / 3 + v)^2 sin(2pi / 3 + v)^2"); sprintf (gSurfZ, "z = -(2 + cos(u - 2pi / 3)) cos(2pi / 3 - v)^2 sin(2pi / 3 - v)^3"); sprintf (gSurfRange, "0 <= u <= 2 pi, 0 <= v <= 2 pi"); temp = u; u = v + PI * 2; v = temp + PI; // convert to: 0 <= u <= 4 pi, 0 <= v <= 2 pi p.x = (2 + cos (u)) * pow (cos (v), 3) * sin(v); p.y = (2 + cos (u + TWOPI / 3)) * pow (cos (TWOPI / 3 + v), 2) * pow (sin (TWOPI / 3 + v), 2); p.z = -(2 + cos (u - TWOPI / 3)) * pow (cos (TWOPI / 3 - v), 2) * pow (sin (TWOPI / 3 - v), 3); break; case 4: sprintf (gSurfName, "Maeder's Owl"); sprintf (gSurfCredit, "by R. Maeder"); sprintf (gSurfX, "x = v cos(u) - 0.5 v^2 cos(2 u)"); sprintf (gSurfY, "y = - v sin(u) - 0.5 v^2 sin(2 u) "); sprintf (gSurfZ, "z = 4 v^1.5 cos(3 u / 2) / 3 "); sprintf (gSurfRange, "0 <= u <= 4 pi, 0 <= v <= 1"); u = (u + PI) * 2; v = (v + PI) / TWOPI; // convert to: 0 <= u <= 4 pi, 0 <= v <= 1 p.x = v * cos(u) - 0.5 * v * v * cos(2 * u); p.y = -v * sin(u) - 0.5 * v * v * sin(2 * u); p.z = 4 * pow(v,1.5) * cos(1.5 * u) / 3; break; p.x = v * cos(u) - 0.5 * v * v * cos(2 * u); p.y = - v * sin(u) - 0.5 * v * v * sin(2 * u); p.z = 4 * pow(v,1.5) * cos(1.5 * u) / 3; } return(p); } void BuildGeometry(void) { long i,j, index; long maxI = gSubDivisions * gIJRatio, maxJ = gSubDivisions; double u, v, delta=0.001; recVec p1,p2; if (gVertexPos) free (gVertexPos); gVertexPos = (recVec*) malloc ((maxI) * (maxJ) * sizeof (recVec)); if (gVertexNormal) free (gVertexNormal); gVertexNormal = (recVec*) malloc ((maxI) * (maxJ) * sizeof (recVec)); if (gVertexColor) free (gVertexColor); gVertexColor = (recColor*) malloc ((maxI) * (maxJ) * sizeof (recColor)); for (i = 0; i < maxI; i++) { for (j = 0; j < maxJ; j++) { index = i * maxJ + j; u = -PI + (i % maxI) * TWOPI / maxI; v = -PI + (j % maxJ) * TWOPI / maxJ; gVertexPos[index] = Eval(u,v, gSurface); p1 = Eval(u + delta, v, gSurface); p2 = Eval(u, v + delta, gSurface); gVertexNormal[index] = CalcNormal(gVertexPos[index],p1,p2); gVertexColor[index] = GetColor(u, -PI, PI, gColorScheme); } } if (gPolyList) glDeleteLists (gPolyList, 1); gPolyList = glGenLists (1); glNewList(gPolyList, GL_COMPILE); for (i=0; i< maxI; i++) { glBegin(GL_TRIANGLE_STRIP); for (j = 0; j <= maxJ; j++) { index = (i % maxI) * maxJ + (j % maxJ); glColor3f (gVertexColor[index].r, gVertexColor[index].g, gVertexColor[index].b); glNormal3f (gVertexNormal[index].x, gVertexNormal[index].y, gVertexNormal[index].z); glVertex3f (gVertexPos[index].x, gVertexPos[index].y, gVertexPos[index].z); index = ((i + 1) % maxI) * maxJ + (j % maxJ); glColor3f (gVertexColor[index].r, gVertexColor[index].g, gVertexColor[index].b); glNormal3f (gVertexNormal[index].x, gVertexNormal[index].y, gVertexNormal[index].z); glVertex3f (gVertexPos[index].x, gVertexPos[index].y, gVertexPos[index].z); } glEnd (); } glEndList (); if (gLineList) glDeleteLists (gLineList, 1); gLineList = glGenLists (1); glNewList(gLineList, GL_COMPILE); for (i=0; i< maxI; i++) { glBegin(GL_LINE_STRIP); for (j = 0; j < maxJ; j++) { index = i * maxJ + j; glColor3d (gVertexColor[index].r, gVertexColor[index].g, gVertexColor[index].b); glVertex3d (gVertexPos[index].x, gVertexPos[index].y, gVertexPos[index].z); } index = i * maxJ + 0; glColor3d (gVertexColor[index].r, gVertexColor[index].g, gVertexColor[index].b); glVertex3d (gVertexPos[index].x, gVertexPos[index].y, gVertexPos[index].z); glEnd (); } for (j=0; j< maxJ; j++) { glBegin(GL_LINE_STRIP); for (i = 0; i < maxI; i++) { index = i * maxJ + j; glColor3d (gVertexColor[index].r, gVertexColor[index].g, gVertexColor[index].b); glVertex3d (gVertexPos[index].x, gVertexPos[index].y, gVertexPos[index].z); } index = 0 + j; glColor3d (gVertexColor[index].r, gVertexColor[index].g, gVertexColor[index].b); glVertex3d (gVertexPos[index].x, gVertexPos[index].y, gVertexPos[index].z); glEnd (); } glEndList (); if (gPointList) glDeleteLists (gPointList, 1); gPointList = glGenLists (1); glNewList(gPointList, GL_COMPILE); glBegin(GL_POINTS); for (i=0; i< maxI; i++) { for (j = 0; j < maxJ; j++) { index = i * maxJ + j; glColor3d (gVertexColor[index].r, gVertexColor[index].g, gVertexColor[index].b); glVertex3d (gVertexPos[index].x, gVertexPos[index].y, gVertexPos[index].z); } } glEnd (); glEndList (); } void DrawText (GLint window_width, GLint window_height) { char outString [256] = ""; GLint matrixMode; GLint vp[4]; GLint lineSpacing = 13; GLint line = 0; GLint startOffest = 7; glGetIntegerv(GL_VIEWPORT, vp); glViewport(0, 0, window_width, window_height); glGetIntegerv(GL_MATRIX_MODE, &matrixMode); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glScalef(2.0f / window_width, -2.0f / window_height, 1.0f); glTranslatef(-window_width / 2.0f, -window_height / 2.0f, 0.0f); // draw glColor3f (1.0, 1.0, 0.0); if (gShowInfo) { sprintf (outString, "Camera Position: (%0.1f, %0.1f, %0.1f)", gCamera.viewPos.x, gCamera.viewPos.y, gCamera.viewPos.z); DrawString (10, window_height - (lineSpacing * line++) - startOffest, outString); sprintf (outString, "Trackball Rotation: (%0.1f, %0.2f, %0.2f, %0.2f)", gTrackBallRotation[0], gTrackBallRotation[1], gTrackBallRotation[2], gTrackBallRotation[3]); DrawString (10, window_height - (lineSpacing * line++) - startOffest, outString); sprintf (outString, "World Rotation: (%0.1f, %0.2f, %0.2f, %0.2f)", gWorldRotation[0], gWorldRotation[1], gWorldRotation[2], gWorldRotation[3]); DrawString (10, window_height - (lineSpacing * line++) - startOffest, outString); sprintf (outString, "Aperture: %0.1f", gCamera.aperture); DrawString (10, window_height - (lineSpacing * line++) - startOffest, outString); if (gStereo) sprintf (outString, "Eye Separation: %0.2f", gCamera.eyeSep); else sprintf (outString, "Eye Separation: 0.0"); DrawString (10, window_height - (lineSpacing * line++) - startOffest, outString); sprintf (outString, "Focus Distance: %0.1f", gCamera.focalLength); DrawString (10, window_height - (lineSpacing * line++) - startOffest, outString); sprintf (outString, "Vertices: %ld, Color Scheme: %ld", gSubDivisions * gIJRatio * gSubDivisions, gColorScheme); DrawString (10, window_height - (lineSpacing * line++) - startOffest, outString); } if (gShowHelp) { line = 1; sprintf (outString, "Controls:\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "left button drag: rotate camera\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "right (or crtl-left) button drag: dolly (zoom) camera\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "arrows: eye separation & focal length\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "-/+: aperture\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "[/]: cycle color scheme\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, ";/': decrease/increase subdivisions\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "\\: cycle surface type\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "P: toggle points\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "W: toggle wireframe\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "F: toggle fill\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "L: toggle lighting\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "S: toggle stereo\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "H: toggle help\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "I: toggle info\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); sprintf (outString, "C: toggle surface credits\n"); DrawString (10, (lineSpacing * line++) + startOffest, outString); } if (gShowCredits) { #define khStart 350 line = 1; glColor3f (1.0, 1.0, 1.0); DrawString (window_width - khStart, (lineSpacing * line++) + startOffest, gSurfName); DrawString (window_width - khStart, (lineSpacing * line++) + startOffest, gSurfCredit); glColor3f (0.7, 0.7, 0.7); DrawString (window_width - khStart, (lineSpacing * line++) + startOffest, gSurfX); DrawString (window_width - khStart, (lineSpacing * line++) + startOffest, gSurfY); DrawString (window_width - khStart, (lineSpacing * line++) + startOffest, gSurfZ); DrawString (window_width - khStart, (lineSpacing * line++) + startOffest, gSurfRange); } glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(matrixMode); glViewport(vp[0], vp[1], vp[2], vp[3]); } // - Blue line syncing code ------------- void DrawBlueLine(GLint window_width, GLint window_height) { GLint i; unsigned long buffer; glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_ALPHA_TEST); glDisable(GL_BLEND); for(i = 0; i < 6; i++) glDisable(GL_CLIP_PLANE0 + i); glDisable(GL_COLOR_LOGIC_OP); glDisable(GL_COLOR_MATERIAL); glDisable(GL_DEPTH_TEST); glDisable(GL_DITHER); glDisable(GL_FOG); glDisable(GL_LIGHTING); glDisable(GL_LINE_SMOOTH); glDisable(GL_LINE_STIPPLE); glDisable(GL_SCISSOR_TEST); glDisable(GL_SHARED_TEXTURE_PALETTE_EXT); glDisable(GL_STENCIL_TEST); glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_3D); glDisable(GL_TEXTURE_CUBE_MAP); glDisable(GL_TEXTURE_RECTANGLE_EXT); glDisable(GL_VERTEX_PROGRAM_ARB); for(buffer = GL_BACK_LEFT; buffer <= GL_BACK_RIGHT; buffer++) { GLint matrixMode; GLint vp[4]; glDrawBuffer(buffer); glGetIntegerv(GL_VIEWPORT, vp); glViewport(0, 0, window_width, window_height); glGetIntegerv(GL_MATRIX_MODE, &matrixMode); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glScalef(2.0f / window_width, -2.0f / window_height, 1.0f); glTranslatef(-window_width / 2.0f, -window_height / 2.0f, 0.0f); // draw sync lines glColor3d(0.0f, 0.0f, 0.0f); glBegin(GL_LINES); // Draw a background line glVertex3f(0.0f, window_height - 0.5f, 0.0f); glVertex3f(window_width, window_height - 0.5f, 0.0f); glEnd(); glColor3d(0.0f, 0.0f, 1.0f); glBegin(GL_LINES); // Draw a line of the correct length (the cross over is about 40% across the screen from the left glVertex3f(0.0f, window_height - 0.5f, 0.0f); if(buffer == GL_BACK_LEFT) glVertex3f(window_width * 0.30f, window_height - 0.5f, 0.0f); else glVertex3f(window_width * 0.80f, window_height - 0.5f, 0.0f); glEnd(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(matrixMode); glViewport(vp[0], vp[1], vp[2], vp[3]); } glPopAttrib(); } void DrawBlueLine_Simple(GLint window_width, GLint window_height) { unsigned long buffer; for(buffer = GL_BACK_LEFT; buffer <= GL_BACK_RIGHT; buffer++) { GLint matrixMode; GLint vp[4]; glDrawBuffer(buffer); glGetIntegerv(GL_VIEWPORT, vp); glViewport(0, 0, window_width, window_height); glGetIntegerv(GL_MATRIX_MODE, &matrixMode); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glScalef(2.0f / window_width, -2.0f / window_height, 1.0f); glTranslatef(-window_width / 2.0f, -window_height / 2.0f, 0.0f); // draw sync lines glColor3d(0.0f, 0.0f, 0.0f); glBegin(GL_LINES); // Draw a background line glVertex3f(0.0f, window_height - 0.5f, 0.0f); glVertex3f(window_width, window_height - 0.5f, 0.0f); glEnd(); glColor3d(0.0f, 0.0f, 1.0f); glBegin(GL_LINES); // Draw a line of the correct length (the cross over is about 40% across the screen from the left glVertex3f(0.0f, window_height - 0.5f, 0.0f); if(buffer == GL_BACK_LEFT) glVertex3f(window_width * 0.30f, window_height - 0.5f, 0.0f); else glVertex3f(window_width * 0.80f, window_height - 0.5f, 0.0f); glVertex3f(window_width, window_height - 0.5f, 0.0f); glEnd(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(matrixMode); glViewport(vp[0], vp[1], vp[2], vp[3]); } } // - GLUT callbacks ------------------ void init (void) { glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); glDisable(GL_DITHER); glDisable(GL_CULL_FACE); glLineWidth(1.0); glPointSize(1.0); glPolygonMode(GL_FRONT_AND_BACK,GL_FILL); glFrontFace(GL_CCW); glClearColor(0.0,0.0,0.0,0.0); /* Background recColor */ gCameraReset (); SetLighting (); BuildGeometry (); } void reshape (int w, int h) { glViewport(0,0,(GLsizei)w,(GLsizei)h); gCamera.screenWidth = w; gCamera.screenHeight = h; glutPostRedisplay(); } /* uses parallel axis asymmetric frustum perspective projection for correct stereo */ void display(void) { recVec r; GLdouble ratio, radians, wd2, ndfl; GLdouble left, right, top, bottom, near, far; near = -gCamera.viewPos.z - gShapeSize * 0.5; if (near < 0.1) near = 0.1; far = -gCamera.viewPos.z + gShapeSize * 0.5; // Misc stuff ratio = gCamera.screenWidth / (double)gCamera.screenHeight; radians = DTOR * gCamera.aperture / 2; wd2 = near * tan(radians); ndfl = near / gCamera.focalLength; // Derive the two eye positions CROSSPROD (gCamera.viewDir, gCamera.viewUp, r); normalise (&r); if (gStereo) { r.x *= gCamera.eyeSep / 3; r.y *= gCamera.eyeSep / 3; r.z *= gCamera.eyeSep / 3; } else { r.x = 0.0; r.y = 0.0; r.z = 0.0; } // Left: glDrawBuffer(GL_BACK_LEFT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode (GL_PROJECTION); glLoadIdentity (); if (gStereo) { left = - ratio * wd2 + 0.5 * gCamera.eyeSep * ndfl; right = ratio * wd2 + 0.5 * gCamera.eyeSep * ndfl; } else { left = - ratio * wd2; right = ratio * wd2; } top = wd2; bottom = - wd2; glFrustum (left, right, bottom, top, near, far); glMatrixMode (GL_MODELVIEW); glLoadIdentity (); gluLookAt (gCamera.viewPos.x - r.x, gCamera.viewPos.y - r.y, gCamera.viewPos.z - r.z, gCamera.viewPos.x - r.x + gCamera.viewDir.x, gCamera.viewPos.y - r.y + gCamera.viewDir.y, gCamera.viewPos.z - r.z + gCamera.viewDir.z, gCamera.viewUp.x, gCamera.viewUp.y ,gCamera.viewUp.z); // track ball rotation glRotatef (gTrackBallRotation[0], gTrackBallRotation[1], gTrackBallRotation[2], gTrackBallRotation[3]); glRotatef (gWorldRotation[0], gWorldRotation[1], gWorldRotation[2], gWorldRotation[3]); if (gPolygons) { if (gLighting) glEnable(GL_LIGHTING); else glDisable(GL_LIGHTING); glCallList (gPolyList); glDisable(GL_LIGHTING); } else if (gLines) { glDisable(GL_LIGHTING); glCallList (gLineList); } else if (gPoints) { glDisable(GL_LIGHTING); glCallList (gPointList); } DrawText (gCamera.screenWidth, gCamera.screenHeight); // Right: glDrawBuffer(GL_BACK_RIGHT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (gStereo) { left = - ratio * wd2 - 0.5 * gCamera.eyeSep * ndfl; right = ratio * wd2 - 0.5 * gCamera.eyeSep * ndfl; } else { left = - ratio * wd2; right = ratio * wd2; } top = wd2; bottom = - wd2; glFrustum (left, right, bottom, top, near, far); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(gCamera.viewPos.x + r.x, gCamera.viewPos.y + r.y, gCamera.viewPos.z + r.z, gCamera.viewPos.x + r.x + gCamera.viewDir.x, gCamera.viewPos.y + r.y + gCamera.viewDir.y, gCamera.viewPos.z + r.z + gCamera.viewDir.z, gCamera.viewUp.x, gCamera.viewUp.y, gCamera.viewUp.z); // track ball rotation glRotatef (gTrackBallRotation[0], gTrackBallRotation[1], gTrackBallRotation[2], gTrackBallRotation[3]); glRotatef (gWorldRotation[0], gWorldRotation[1], gWorldRotation[2], gWorldRotation[3]); if (gPolygons) { if (gLighting) glEnable(GL_LIGHTING); else glDisable(GL_LIGHTING); glCallList (gPolyList); glDisable(GL_LIGHTING); } else if (gLines) { glDisable(GL_LIGHTING); glCallList (gLineList); } else if (gPoints) { glDisable(GL_LIGHTING); glCallList (gPointList); } DrawText (gCamera.screenWidth, gCamera.screenHeight); // Draw blue synch line: DrawBlueLine (gCamera.screenWidth, gCamera.screenHeight); glutSwapBuffers(); } void animate(void) { // glutPostRedisplay(); } void special(int key, int px, int py) { gLastKey = key; switch (key) { case GLUT_KEY_UP: // arrow forward, close in on world gCamera.focalLength -= 0.5f; if (gCamera.focalLength < 0.0f) gCamera.focalLength = 0.0f; glutPostRedisplay(); break; case GLUT_KEY_DOWN: // arrow back, back away from world gCamera.focalLength += 0.5f; glutPostRedisplay(); break; case GLUT_KEY_LEFT: // arrow left, close eyes together gCamera.eyeSep -= 0.05f; if (gCamera.eyeSep < 0.0) gCamera.eyeSep = 0.0; glutPostRedisplay(); break; case GLUT_KEY_RIGHT: // arrow right, spread eyes apart gCamera.eyeSep += 0.05f; glutPostRedisplay(); break; } } void key(unsigned char key, int px, int py) { gLastKey = key; switch (key) { case 27: exit(0); break; case 'h': // point case 'H': gShowHelp = 1 - gShowHelp; glutPostRedisplay(); break; case 'i': // point case 'I': gShowInfo = 1 - gShowInfo; glutPostRedisplay(); break; case 'c': // point case 'C': gShowCredits = 1 - gShowCredits; glutPostRedisplay(); break; case 'f': // fill case 'F': gPolygons = 1; gLines = 0; gPoints = 0; glutPostRedisplay(); break; case 'w': // lines case 'W': gPolygons = 0; gLines = 1; gPoints = 0; glutPostRedisplay(); break; case 'p': // point case 'P': gPolygons = 0; gLines = 0; gPoints = 1; glutPostRedisplay(); break; case 's': // stereo case 'S': gStereo = 1 - gStereo; glutPostRedisplay(); break; case 'l': // stereo case 'L': gLighting = 1 - gLighting; glutPostRedisplay(); break; case '[': // next lower color scheme case '{': gColorScheme -= 1; if (gColorScheme < 1) gColorScheme = 20; BuildGeometry (); glutPostRedisplay(); break; case ']': // next higher color scheme case '}': gColorScheme += 1; if (gColorScheme > 20) gColorScheme = 1; BuildGeometry (); glutPostRedisplay(); break; case ';': // next lower subdivision setting case ':': gSubDivisions = (GLuint) (gSubDivisions / 1.2); if (gSubDivisions < 8) gSubDivisions = 8; BuildGeometry (); glutPostRedisplay(); break; case '\'': // next higher subdivision setting case '"': gSubDivisions = (GLuint) (gSubDivisions * 1.2); BuildGeometry (); glutPostRedisplay(); break; case '\\': // next higher subdivision setting gSurface += 1; gSurface %= kSurfaces; BuildGeometry (); glutPostRedisplay(); break; case '=': // increase camera aperture case '+': gCamera.aperture += 0.5f; glutPostRedisplay(); break; case '-': // decrease camera aperture case '_': gCamera.aperture -= 0.5f; if (gCamera.aperture < 0.0f) gCamera.aperture = 0.0f; glutPostRedisplay(); break; } } void mouseDolly (int x, int y) { if (gDolly) { GLfloat dolly = (gDollyStartPoint[1] - y) / 30.0f; GLfloat eyeRelative = gCamera.eyeSep / gCamera.focalLength; gCamera.focalLength += gCamera.focalLength / gCamera.viewPos.z * dolly; if (gCamera.focalLength < 1.0) gCamera.focalLength = 1.0; gCamera.eyeSep = gCamera.focalLength * eyeRelative; gCamera.viewPos.z += dolly; if (gCamera.viewPos.z > -1.0) gCamera.viewPos.z = -1.0; gDollyStartPoint[0] = x; gDollyStartPoint[1] = y; glutPostRedisplay(); } } void mouseTrackball (int x, int y) { if (gTrackBall) { rollToTrackball (x, y, gTrackBallRotation); glutPostRedisplay(); } } void mouse (int button, int state, int x, int y) { if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) { if (gDolly) { // if we are currently dollying, end dolly mouseDolly (x, y); gDolly = GL_FALSE; glutMotionFunc (NULL); gTrackBallRotation [0] = gTrackBallRotation [1] = gTrackBallRotation [2] = gTrackBallRotation [3] = 0.0f; glutMotionFunc (NULL); } startTrackball (x, y, 0, 0, gCamera.screenWidth, gCamera.screenHeight); glutMotionFunc (mouseTrackball); gTrackBall = GL_TRUE; } else if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_UP)) { gTrackBall = GL_FALSE; glutMotionFunc (NULL); rollToTrackball (x, y, gTrackBallRotation); addToRotationTrackball (gTrackBallRotation, gWorldRotation); gTrackBallRotation [0] = gTrackBallRotation [1] = gTrackBallRotation [2] = gTrackBallRotation [3] = 0.0f; } else if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_DOWN)) { if (gTrackBall) {// if we are currently trackballing, end trackball gTrackBall = GL_FALSE; glutMotionFunc (NULL); rollToTrackball (x, y, gTrackBallRotation); addToRotationTrackball (gTrackBallRotation, gWorldRotation); gTrackBallRotation [0] = gTrackBallRotation [1] = gTrackBallRotation [2] = gTrackBallRotation [3] = 0.0f; } gDollyStartPoint[0] = x; gDollyStartPoint[1] = y; glutMotionFunc (mouseDolly); gDolly = GL_TRUE; } else if ((button == GLUT_RIGHT_BUTTON) && (state == GLUT_UP)) { mouseDolly (x, y); gDolly = GL_FALSE; glutMotionFunc (NULL); gTrackBallRotation [0] = gTrackBallRotation [1] = gTrackBallRotation [2] = gTrackBallRotation [3] = 0.0f; glutMotionFunc (NULL); } } // - main ----------------------------------- int main (int argc, const char * argv[]) { glutInit(&argc, (char **)argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH | GLUT_STEREO); // stereo display mode for glut glutGameModeString("1024x768:32@120"); // must now use full screen game mode glutEnterGameMode(); // enter gamemode to get stereo context (may get invalid drawable warnings in console, this is normal and will be fixed in the future) init(); glutReshapeFunc (reshape); glutDisplayFunc (display); glutIdleFunc (animate); glutKeyboardFunc (key); glutSpecialFunc (special); glutMouseFunc (mouse); glutMainLoop(); return 0; }