#include #include #include #include #if defined(__linux__) #include #elif defined(__APPLE__) #include #else #warning "Not sure where to find glut.h" #endif #include "paulslib.h" #include "bitmaplib.h" #include "opengllib.h" /* Clear the left and/or right buffer Call as ClearBuffer(1) for mono ClearBuffer(2) for stereo ClearBuffer(1) if in stereo and the card will clear both, eg: 4D51T */ void ClearBuffers(int which) { if (which == 2) { glDrawBuffer(GL_BACK_LEFT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDrawBuffer(GL_BACK_RIGHT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } else { glDrawBuffer(GL_BACK); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } } void ClearAllBuffers(void) { glDrawBuffer(GL_FRONT_AND_BACK); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT); } /* Write the current view to an image file Do the right thing for stereo, ie: two images The format corresponds to the Write_Bitmap() formats. Use a negative format to get the image flipped vertically Honour the name if supplied, else do automatic naming Don't overwrite existing files if automatic naming is in effect. */ int WindowDump(char *name,int width,int height,int stereo,int format) { FILE *fptr; static int counter = 0; char fname[32],ext[8]; BITMAP4 *image = NULL; /* Allocate our buffer for the image */ if ((image = Create_Bitmap(width,height)) == NULL) { fprintf(stderr,"WindowDump - Failed to allocate memory for image\n"); return(FALSE); } glFinish(); glPixelStorei(GL_PACK_ALIGNMENT,1); /* Open the file */ switch (ABS(format)) { case 1: strcpy(ext,"tga"); break; case 11: strcpy(ext,"tga"); break; case 12: strcpy(ext,"tga"); break; case 13: strcpy(ext,"tga"); break; case 2: strcpy(ext,"ppm"); break; case 3: strcpy(ext,"rgb"); break; case 4: strcpy(ext,"raw"); break; case 5: strcpy(ext,"tif"); break; case 6: strcpy(ext,"eps"); break; case 7: strcpy(ext,"eps"); break; case 8: strcpy(ext,"raw"); break; case 9: strcpy(ext,"bmp"); break; } if (strlen(name) <= 0) { if (stereo) sprintf(fname,"L_%04d.%s",counter,ext); else sprintf(fname,"%04d.%s",counter,ext); } else { if (stereo) sprintf(fname,"L_%s.%s",name,ext); else sprintf(fname,"%s.%s",name,ext); } while (strlen(name) <= 0 && (fptr = fopen(fname,"rb")) != NULL) { counter++; fclose(fptr); if (stereo) sprintf(fname,"L_%04d.%s",counter,ext); else sprintf(fname,"%04d.%s",counter,ext); } if ((fptr = fopen(fname,"wb")) == NULL) { fprintf(stderr,"WindowDump - Failed to open file for window dump\n"); return(FALSE); } /* Copy the image into our buffer */ glReadBuffer(GL_BACK_LEFT); glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,image); /* Write the file */ Write_Bitmap(fptr,image,width,height,format); fclose(fptr); if (stereo) { /* Open the file */ if (strlen(name) <= 0) { sprintf(fname,"R_%04d.%s",counter,ext); } else { sprintf(fname,"R_%s.%s",name,ext); } while (strlen(name) <= 0 && (fptr = fopen(fname,"rb")) != NULL) { counter++; fclose(fptr); sprintf(fname,"R_%04d.%s",counter,ext); } if ((fptr = fopen(fname,"wb")) == NULL) { fprintf(stderr,"WindowDump - Failed to open file for window dump\n"); return(FALSE); } /* Copy the image into our buffer */ glReadBuffer(GL_BACK_RIGHT); glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,image); /* Write the file */ Write_Bitmap(fptr,image,width,height,format); fclose(fptr); } Destroy_Bitmap(image); counter++; return(TRUE); } /* Create a wireframe or solid box betwwen two diagonal vertices Assume it is all one colour and that has already been set up If type == 0 then draw a wireframe box 1 solid 2 wireframe with inset The faces are ordered CCW +-----+ /| /| y / | / | ^ / | / | | p/min+-----+ | / / / / | +-----+pma/x | | / | / +-------> x | / | / / |/ |/ / +-----+ / z */ void CreateBox(XYZ pmin,XYZ pmax,int type) { XYZ dp; switch (type) { case 0: glBegin(GL_LINE_STRIP); glVertex3f(pmin.x,pmin.y,pmin.z); glVertex3f(pmax.x,pmin.y,pmin.z); glVertex3f(pmax.x,pmin.y,pmax.z); glVertex3f(pmin.x,pmin.y,pmax.z); glVertex3f(pmin.x,pmin.y,pmin.z); glVertex3f(pmin.x,pmax.y,pmin.z); glVertex3f(pmax.x,pmax.y,pmin.z); glVertex3f(pmax.x,pmax.y,pmax.z); glVertex3f(pmin.x,pmax.y,pmax.z); glVertex3f(pmin.x,pmax.y,pmin.z); glEnd(); glBegin(GL_LINES); glVertex3f(pmax.x,pmin.y,pmin.z); glVertex3f(pmax.x,pmax.y,pmin.z); glVertex3f(pmax.x,pmin.y,pmax.z); glVertex3f(pmax.x,pmax.y,pmax.z); glVertex3f(pmin.x,pmin.y,pmax.z); glVertex3f(pmin.x,pmax.y,pmax.z); glEnd(); break; case 2: dp.x = (pmax.x - pmin.x) / 20; dp.y = (pmax.y - pmin.y) / 20; dp.z = (pmax.z - pmin.z) / 20; glBegin(GL_LINE_STRIP); glVertex3f(pmin.x-dp.x,pmin.y-dp.y,pmin.z-dp.z); glVertex3f(pmax.x+dp.x,pmin.y-dp.y,pmin.z-dp.z); glVertex3f(pmax.x+dp.x,pmin.y-dp.y,pmax.z+dp.z); glVertex3f(pmin.x-dp.x,pmin.y-dp.y,pmax.z+dp.z); glVertex3f(pmin.x-dp.x,pmin.y-dp.y,pmin.z-dp.z); glVertex3f(pmin.x-dp.x,pmax.y+dp.y,pmin.z-dp.z); glVertex3f(pmax.x+dp.x,pmax.y+dp.y,pmin.z-dp.z); glVertex3f(pmax.x+dp.x,pmax.y+dp.y,pmax.z+dp.z); glVertex3f(pmin.x-dp.x,pmax.y+dp.y,pmax.z+dp.z); glVertex3f(pmin.x-dp.x,pmax.y+dp.y,pmin.z-dp.z); glEnd(); glBegin(GL_LINES); glVertex3f(pmax.x+dp.x,pmin.y-dp.y,pmin.z-dp.z); glVertex3f(pmax.x+dp.x,pmax.y+dp.y,pmin.z-dp.z); glVertex3f(pmax.x+dp.x,pmin.y-dp.y,pmax.z+dp.z); glVertex3f(pmax.x+dp.x,pmax.y+dp.y,pmax.z+dp.z); glVertex3f(pmin.x-dp.x,pmin.y-dp.y,pmax.z+dp.z); glVertex3f(pmin.x-dp.x,pmax.y+dp.y,pmax.z+dp.z); glEnd(); glBegin(GL_LINE_STRIP); /* Right */ glVertex3f(pmin.x-dp.x,pmin.y,pmin.z); glVertex3f(pmin.x-dp.x,pmin.y,pmax.z); glVertex3f(pmin.x-dp.x,pmax.y,pmax.z); glVertex3f(pmin.x-dp.x,pmax.y,pmin.z); glVertex3f(pmin.x-dp.x,pmin.y,pmin.z); glEnd(); glBegin(GL_LINE_STRIP); /* Left */ glVertex3f(pmax.x+dp.x,pmin.y,pmin.z); glVertex3f(pmax.x+dp.x,pmin.y,pmax.z); glVertex3f(pmax.x+dp.x,pmax.y,pmax.z); glVertex3f(pmax.x+dp.x,pmax.y,pmin.z); glVertex3f(pmax.x+dp.x,pmin.y,pmin.z); glEnd(); glBegin(GL_LINE_STRIP); /* Top */ glVertex3f(pmin.x,pmax.y+dp.y,pmin.z); glVertex3f(pmin.x,pmax.y+dp.y,pmax.z); glVertex3f(pmax.x,pmax.y+dp.y,pmax.z); glVertex3f(pmax.x,pmax.y+dp.y,pmin.z); glVertex3f(pmin.x,pmax.y+dp.y,pmin.z); glEnd(); glBegin(GL_LINE_STRIP); /* Bottom */ glVertex3f(pmin.x,pmin.y-dp.y,pmin.z); glVertex3f(pmin.x,pmin.y-dp.y,pmax.z); glVertex3f(pmax.x,pmin.y-dp.y,pmax.z); glVertex3f(pmax.x,pmin.y-dp.y,pmin.z); glVertex3f(pmin.x,pmin.y-dp.y,pmin.z); glEnd(); glBegin(GL_LINE_STRIP); /* Front */ glVertex3f(pmin.x,pmin.y,pmin.z-dp.z); glVertex3f(pmin.x,pmax.y,pmin.z-dp.z); glVertex3f(pmax.x,pmax.y,pmin.z-dp.z); glVertex3f(pmax.x,pmin.y,pmin.z-dp.z); glVertex3f(pmin.x,pmin.y,pmin.z-dp.z); glEnd(); glBegin(GL_LINE_STRIP); /* Back */ glVertex3f(pmin.x,pmin.y,pmax.z+dp.z); glVertex3f(pmin.x,pmax.y,pmax.z+dp.z); glVertex3f(pmax.x,pmax.y,pmax.z+dp.z); glVertex3f(pmax.x,pmin.y,pmax.z+dp.z); glVertex3f(pmin.x,pmin.y,pmax.z+dp.z); glEnd(); break; case 1: glBegin(GL_QUADS); glNormal3f(0.0,0.0,-1.0); glTexCoord2f(0.0,0.0); glVertex3f(pmin.x,pmin.y,pmin.z); glTexCoord2f(1.0,0.0); glVertex3f(pmin.x,pmax.y,pmin.z); glTexCoord2f(1.0,1.0); glVertex3f(pmax.x,pmax.y,pmin.z); glTexCoord2f(0.0,1.0); glVertex3f(pmax.x,pmin.y,pmin.z); glNormal3f(0.0,0.0,1.0); glTexCoord2f(0.0,0.0); glVertex3f(pmin.x,pmin.y,pmax.z); glTexCoord2f(1.0,0.0); glVertex3f(pmax.x,pmin.y,pmax.z); glTexCoord2f(1.0,1.0); glVertex3f(pmax.x,pmax.y,pmax.z); glTexCoord2f(0.0,1.0); glVertex3f(pmin.x,pmax.y,pmax.z); glNormal3f(-1.0,0.0,0.0); glTexCoord2f(0.0,0.0); glVertex3f(pmin.x,pmin.y,pmax.z); glTexCoord2f(1.0,0.0); glVertex3f(pmin.x,pmax.y,pmax.z); glTexCoord2f(1.0,1.0); glVertex3f(pmin.x,pmax.y,pmin.z); glTexCoord2f(0.0,1.0); glVertex3f(pmin.x,pmin.y,pmin.z); glNormal3f(1.0,0.0,0.0); glTexCoord2f(0.0,0.0); glVertex3f(pmax.x,pmin.y,pmax.z); glTexCoord2f(1.0,0.0); glVertex3f(pmax.x,pmin.y,pmin.z); glTexCoord2f(1.0,1.0); glVertex3f(pmax.x,pmax.y,pmin.z); glTexCoord2f(0.0,1.0); glVertex3f(pmax.x,pmax.y,pmax.z); glNormal3f(0.0,-1.0,0.0); glTexCoord2f(0.0,0.0); glVertex3f(pmin.x,pmin.y,pmax.z); glTexCoord2f(1.0,0.0); glVertex3f(pmin.x,pmin.y,pmin.z); glTexCoord2f(1.0,1.0); glVertex3f(pmax.x,pmin.y,pmin.z); glTexCoord2f(0.0,1.0); glVertex3f(pmax.x,pmin.y,pmax.z); glNormal3f(0.0,1.0,0.0); glTexCoord2f(0.0,0.0); glVertex3f(pmin.x,pmax.y,pmax.z); glTexCoord2f(1.0,0.0); glVertex3f(pmax.x,pmax.y,pmax.z); glTexCoord2f(1.0,1.0); glVertex3f(pmax.x,pmax.y,pmin.z); glTexCoord2f(0.0,1.0); glVertex3f(pmin.x,pmax.y,pmin.z); glEnd(); break; } } /* Create a regular wireframe grid Split the x,y,z range into "resol" steps. */ void CreateRegularGrid(XYZ pmin,XYZ pmax,int resol) { int i,j,k; double x,y,z,dx,dy,dz; dx = (pmax.x - pmin.x) / resol; dy = (pmax.y - pmin.y) / resol; dz = (pmax.z - pmin.z) / resol; glBegin(GL_LINES); for (k=0;k<=resol;k++) { z = pmin.z + dz * k; for (i=0;i<=resol;i++) { x = pmin.x + dx * i; glVertex3f(x,pmin.y,z); glVertex3f(x,pmax.y,z); } } for (k=0;k<=resol;k++) { z = pmin.z + dz * k; for (j=0;j<=resol;j++) { y = pmin.y + dy * j; glVertex3f(pmin.x,y,z); glVertex3f(pmax.x,y,z); } } for (i=0;i<=resol;i++) { x = pmin.x + dx * i; for (j=0;j<=resol;j++) { y = pmin.y + dy * j; glVertex3f(x,y,pmin.z); glVertex3f(x,y,pmax.z); } } glEnd(); } /* Create a polygon from the vertices Handle degenerate case Calculate normals if not provided Include colours if provided per vertex */ void CreatePolygon(XYZ *p,XYZ *n,COLOUR *c,int np) { int i; XYZ normal = {1,0,0}; if (np < 1) { ; } else if (np == 1) { glVertex3f(p[0].x,p[0].y,p[0].z); } else if (np == 2) { glVertex3f(p[0].x,p[0].y,p[0].z); glVertex3f(p[1].x,p[1].y,p[1].z); } else if (np == 3 || np == 4) { if (n == NULL) normal = CalcNormal(p[0],p[1],p[2]); for (i=0;i 1) at the origin, glTranslate() and glScale() as required. */ void CreateSuperEllipse(double power1,double power2,int n,int method) { int i,j; double theta1,theta2,theta3; XYZ p,p1,p2,en; double delta; /* Shall we just draw a point? */ if (n < 4) { glBegin(GL_POINTS); glVertex3f(0.0,0.0,0.0); glEnd(); return; } /* Shall we just draw a plus */ if (power1 > 10 && power2 > 10) { glBegin(GL_LINES); glVertex3f(-1.0, 0.0, 0.0); glVertex3f( 1.0, 0.0, 0.0); glVertex3f( 0.0,-1.0, 0.0); glVertex3f( 0.0, 1.0, 0.0); glVertex3f( 0.0, 0.0,-1.0); glVertex3f( 0.0, 0.0, 1.0); glEnd(); return; } delta = 0.01 * TWOPI / n; for (j=0;jx = tmp * SIGN(ct2) * pow(fabs(ct2),p2); p->y = SIGN(st1) * pow(fabs(st1),p1); p->z = tmp * SIGN(st2) * pow(fabs(st2),p2); } /* Create a sphere centered at c, with radius r, and precision n Draw a point for zero radius spheres Use CCW facet ordering "method" is 0 for quads, 1 for triangles (quads look nicer in wireframe mode) Partial spheres can be created using theta1->theta2, phi1->phi2 in radians 0 30000 || height > 30000) { fprintf(stderr,"Failed to read TGA header\n"); fclose(fptr); return(ptr); } /* Allocate memory for the texture */ if ((ptr = realloc(ptr,width*height*sizeof(BITMAP4))) == NULL) { fprintf(stderr,"Failed to allocate memory for texture \"%s\"\n",fname); fclose(fptr); return(ptr); } *w = width; *h = height; /* Start off with a random texture, totally opaque */ for (i=0;i<(*w)*(*h);i++) { ptr[i].r = rand() % 255; ptr[i].g = rand() % 255; ptr[i].b = rand() % 255; ptr[i].a = 255; } /* Actually read the texture */ if (TGA_Read(fptr,ptr,&width,&height) != 0) { fprintf(stderr,"TGA file read error\n"); } fclose(fptr); return(ptr); } /* Draw some text on the screen in a particular colour Coordinates are 0 to screen width and 0 to screenheight This particular implementation uses a 8 by 13 nonproprotional font Other bitmap fonts should be GLUT_BITMAP_9_BY_15 GLUT_BITMAP_8_BY_13 GLUT_BITMAP_TIMES_ROMAN_10 GLUT_BITMAP_TIMES_ROMAN_24 GLUT_BITMAP_HELVETICA_10 GLUT_BITMAP_HELVETICA_12 GLUT_BITMAP_HELVETICA_18 */ void DrawGLText(int x,int y,char *s) { int lines; char *p; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0,glutGet(GLUT_WINDOW_WIDTH),0,glutGet(GLUT_WINDOW_HEIGHT),-1,1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRasterPos2i(x,y); for (p=s,lines=0;*p;p++) { if (*p == '\n' || *p == '\r') { lines++; glRasterPos2i(x,y-(lines*13)); } else { glutBitmapCharacter(GLUT_BITMAP_8_BY_13,*p); } } glPopMatrix(); glPopMatrix(); } /* Draw text in the x-y plane The x,y,z coordinate is the bottom left corner (looking down -ve z axis) */ void DrawTextXY(double x,double y,double z,double scale,char *s) { unsigned int i; glPushMatrix(); glTranslatef(x,y,z); glScalef(scale,scale,scale); for (i=0;i 126) continue; c -= 32; for (j=1;j= width-2 || y >= height-2) return; CROSSPROD(vd,vu,right); Normalise(&right); dx = 2 * (x - width/2) / (double)width; dy = 2 * (height/2 - y) / (double)height; thetav = aperture * DTOR; tanthetav = tan(thetav / 2); thetah = 2 * atan(width * tanthetav / height); tanthetah = tan(thetah / 2); /* A ray goes from vp to p2 */ p2.x = vp.x + vd.x + dx * tanthetah * right.x + dy * tanthetav * vu.x; p2.y = vp.y + vd.y + dx * tanthetah * right.y + dy * tanthetav * vu.y; p2.z = vp.z + vd.z + dx * tanthetah * right.z + dy * tanthetav * vu.z; /* Find where this ray hits the plane at "depth" */ D = -(vd.x * (vp.x + depth * vd.x) + vd.y * (vp.y + depth * vd.y) + vd.z * (vp.z + depth * vd.z)); mu = vd.x * vp.x + vd.y * vp.y + vd.z * vp.z + D; denom = vd.x * (vp.x - p2.x) + vd.y * (vp.y - p2.y) + vd.z * (vp.z - p2.z); mu /= denom; center.x = vp.x + mu * (p2.x - vp.x); center.y = vp.y + mu * (p2.y - vp.y); center.z = vp.z + mu * (p2.z - vp.z); dd = depth / 10; glBegin(GL_LINES); glVertex3f(center.x-dd,center.y,center.z); glVertex3f(center.x+dd,center.y,center.z); glVertex3f(center.x,center.y-dd,center.z); glVertex3f(center.x,center.y+dd,center.z); glVertex3f(center.x,center.y,center.z-dd); glVertex3f(center.x,center.y,center.z+dd); glEnd(); } /* Draw a blue line on the last pixel row for poor mans stereo syncing -1 for left eye, 1 for right eye Assume glDrawBuffer() is already pointing at the right place */ void DrawBlueLine(int width,int height,int eye) { GLint i; 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_STENCIL_TEST); glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_3D); //glDisable(GL_TEXTURE_CUBE_MAP); /* Set the viewport to the entire window */ glViewport(0,0,width,height); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0,glutGet(GLUT_WINDOW_WIDTH),0,glutGet(GLUT_WINDOW_HEIGHT),-1,1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); /* Erase the last pixel row to black */ glColor3d(0.0,0.0,0.0); glBegin(GL_LINES); glVertex2i(0,0); glVertex2i(width,0); glEnd(); /* Draw a line of the correct length the cross over is about 40% across the screen from the left */ glColor3d(0.0,0.0,1.0); glBegin(GL_LINES); glVertex2i(0,0); if (eye < 0) glVertex2i(width/4,0); else glVertex2i(3*width/4,0); glEnd(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPopAttrib(); }