/* * gltools.c * Block * * Created by Richard Wright on 10/16/06. * OpenGL SuperBible, 4th Edition * */ #include "gltools.h" #include "math3d.h" #include /////////////////////////////////////////////////////////////////////////////// // Get the OpenGL version number bool gltGetOpenGLVersion(int &nMajor, int &nMinor) { const char *szVersionString = (const char *)glGetString(GL_VERSION); if (szVersionString == NULL) { nMajor = 0; nMinor = 0; return false; } // Get major version number. This stops at the first non numeric character nMajor = atoi(szVersionString); // Get minor version number. Start past the first ".", atoi terminates on first non numeric char. nMinor = atoi(strstr(szVersionString, ".")+1); return true; } /////////////////////////////////////////////////////////////////////////////// // This function determines if the named OpenGL Extension is supported // Returns 1 or 0 int gltIsExtSupported(const char *extension) { GLubyte *extensions = NULL; const GLubyte *start; GLubyte *where, *terminator; where = (GLubyte *) strchr(extension, ' '); if (where || *extension == '\0') return 0; extensions = (GLubyte *)glGetString(GL_EXTENSIONS); start = extensions; for (;;) { where = (GLubyte *) strstr((const char *) start, extension); if (!where) break; terminator = where + strlen(extension); if (where == start || *(where - 1) == ' ') { if (*terminator == ' ' || *terminator == '\0') return 1; } start = terminator; } return 0; } #ifdef _WIN32 /////////////////////////////////////////////////////////////////////////////// // Win32 Only, check for WGL extension #include "wglext.h" int gltIsWGLExtSupported(HDC hDC, const char *szExtension) { GLubyte *extensions = NULL; const GLubyte *start; GLubyte *where, *terminator; PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB; // Just look or the entry point wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); if (wglGetExtensionsStringARB == NULL) return 0; where = (GLubyte *) strchr(szExtension, ' '); if (where || *szExtension == '\0') return 0; extensions = (GLubyte *)wglGetExtensionsStringARB(hDC); start = extensions; for (;;) { where = (GLubyte *) strstr((const char *) start, szExtension); if (!where) break; terminator = where + strlen(szExtension); if (where == start || *(where - 1) == ' ') { if (*terminator == ' ' || *terminator == '\0') return 1; } start = terminator; } return 0; } #endif ///////////////////////////////////////////////////////////// // Get a pointer to an OpenGL extension // Note on the Mac, this does a lot of work that could be saved // if you call this function repeatedly. Write your own function that // gets the bundle once, gets all the function pointers, then releases // the bundle. void *gltGetExtensionPointer(const char *szExtensionName) { #ifdef WIN32 // Well, this one is simple. An OpenGL context must be // current first. Returns NULL if extension not supported return (void *)wglGetProcAddress(szExtensionName); #endif #ifdef linux // Pretty much ditto above return (void *)glXGetProcAddress((GLubyte *)szExtensionName); #endif #ifdef __APPLE__ // Mac is a bit more tricky. // First we need the bundle CFBundleRef openGL = 0; SInt16 fwVersion = 0; SInt32 fwDir = 0; if (FindFolder(kSystemDomain, kFrameworksFolderType, kDontCreateFolder, &fwVersion, &fwDir) != noErr) return NULL; FSSpec fSpec; FSRef fRef; if (FSMakeFSSpec(fwVersion, fwDir, "\pOpenGL.framework", &fSpec) != noErr) return NULL; FSpMakeFSRef(&fSpec, &fRef); CFURLRef url = CFURLCreateFromFSRef(kCFAllocatorDefault, &fRef); if (!url) return NULL; openGL = CFBundleCreate(kCFAllocatorDefault, url); CFRelease(url); // Then load the function pointer from the bundle CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, szExtensionName, kCFStringEncodingMacRoman); void *pFunc = CFBundleGetFunctionPointerForName(openGL, string); // Release the bundle and string CFRelease(string); CFRelease(openGL); // Return the function ponter return pFunc; #endif } /////////////////////////////////////////////////////////////////// // Draw the unit axis. A small white sphere represents the origin // and the three axes are colored Red, Green, and Blue, which // corresponds to positive X, Y, and Z respectively. Each axis has // an arrow on the end, and normals are provided should the axes // be lit. These are all built using the quadric shapes. For best // results, put this in a display list. void gltDrawUnitAxes(void) { GLUquadricObj *pObj; // Temporary, used for quadrics // Measurements float fAxisRadius = 0.025f; float fAxisHeight = 1.0f; float fArrowRadius = 0.06f; float fArrowHeight = 0.1f; // Setup the quadric object pObj = gluNewQuadric(); gluQuadricDrawStyle(pObj, GLU_FILL); gluQuadricNormals(pObj, GLU_SMOOTH); gluQuadricOrientation(pObj, GLU_OUTSIDE); gluQuadricTexture(pObj, GLU_FALSE); /////////////////////////////////////////////////////// // Draw the blue Z axis first, with arrowed head glColor3f(0.0f, 0.0f, 1.0f); gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1); glPushMatrix(); glTranslatef(0.0f, 0.0f, 1.0f); gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1); glRotatef(180.0f, 1.0f, 0.0f, 0.0f); gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1); glPopMatrix(); /////////////////////////////////////////////////////// // Draw the Red X axis 2nd, with arrowed head glColor3f(1.0f, 0.0f, 0.0f); glPushMatrix(); glRotatef(90.0f, 0.0f, 1.0f, 0.0f); gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1); glPushMatrix(); glTranslatef(0.0f, 0.0f, 1.0f); gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1); glRotatef(180.0f, 0.0f, 1.0f, 0.0f); gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1); glPopMatrix(); glPopMatrix(); /////////////////////////////////////////////////////// // Draw the Green Y axis 3rd, with arrowed head glColor3f(0.0f, 1.0f, 0.0f); glPushMatrix(); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1); glPushMatrix(); glTranslatef(0.0f, 0.0f, 1.0f); gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1); glRotatef(180.0f, 1.0f, 0.0f, 0.0f); gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1); glPopMatrix(); glPopMatrix(); //////////////////////////////////////////////////////// // White Sphere at origin glColor3f(1.0f, 1.0f, 1.0f); gluSphere(pObj, 0.05f, 15, 15); // Delete the quadric gluDeleteQuadric(pObj); } // For best results, put this in a display list // Draw a torus (doughnut) at z = fZVal... torus is in xy plane void gltDrawTorus(GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor) { M3DVector3f vNormal; double majorStep = 2.0f*M3D_PI / numMajor; double minorStep = 2.0f*M3D_PI / numMinor; int i, j; for (i=0; i This is defined in gltools.h static GLubyte shaderText[MAX_SHADER_LENGTH]; //////////////////////////////////////////////////////////////// // Load the shader from the specified file. Returns false if the // shader could not be loaded bool bLoadShaderFile(const char *szFile, GLhandleARB shader) { GLint shaderLength = 0; FILE *fp; GLcharARB *fsStringPtr[1]; // Open the shader file fp = fopen(szFile, "r"); if (fp != NULL) { // See how long the file s while (fgetc(fp) != EOF) shaderLength++; // Allocate a block of memory to send in the shader assert(shaderLength < MAX_SHADER_LENGTH); // make me bigger! if (shaderLength > MAX_SHADER_LENGTH) { fclose(fp); return false; } // Go back to beginning of file rewind(fp); // Read the whole file in if (shaderText != NULL) fread(shaderText, 1, shaderLength, fp); // Make sure it is null terminated and close the file shaderText[shaderLength] = '\0'; fclose(fp); } else return false; // Load the string fsStringPtr[0] = (GLcharARB *)shaderText; glShaderSourceARB(shader, 1, (const GLcharARB **)fsStringPtr, NULL); return true; } ///////////////////////////////////////////////////////////////// // Load a pair of shaders, compile, and link together. Specify the complete // path and file name of each ASCII shader file. Note, there is no support for // just loading say a vertex program... you have to do both. GLhandleARB gltLoadShaderPair(const char *szVertexProg, const char *szFragmentProg) { // Temporary Shader objects GLhandleARB hVertexShader; GLhandleARB hFragmentShader; GLhandleARB hReturn = 0; GLint testVal; // Create shader objects hVertexShader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); hFragmentShader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); // Load them. If fail clean up and return null if (bLoadShaderFile(szVertexProg, hVertexShader) == false) { glDeleteObjectARB(hVertexShader); glDeleteObjectARB(hFragmentShader); return 0; } if (bLoadShaderFile(szFragmentProg, hFragmentShader) == false) { glDeleteObjectARB(hVertexShader); glDeleteObjectARB(hFragmentShader); return 0; } // Compile them glCompileShaderARB(hVertexShader); glCompileShaderARB(hFragmentShader); // Check for errors glGetObjectParameterivARB(hVertexShader, GL_OBJECT_COMPILE_STATUS_ARB, &testVal); if (testVal == GL_FALSE) { glDeleteObjectARB(hVertexShader); glDeleteObjectARB(hFragmentShader); return 0; } glGetObjectParameterivARB(hFragmentShader, GL_OBJECT_COMPILE_STATUS_ARB, &testVal); if (testVal == GL_FALSE) { glDeleteObjectARB(hVertexShader); glDeleteObjectARB(hFragmentShader); return 0; } // Link them - assuming it works... hReturn = glCreateProgramObjectARB(); glAttachObjectARB(hReturn, hVertexShader); glAttachObjectARB(hReturn, hFragmentShader); glLinkProgramARB(hReturn); // These are no longer needed glDeleteObjectARB(hVertexShader); glDeleteObjectARB(hFragmentShader); return hReturn; }