/* gltools.c * * OpenGL Tools * * */ #include #include #include #include #include "gltools.h" /* mipmapping enabled by default */ GLuint gltLoadTGATexture(const char *fname) { GLuint handle; /* variables used for texture loading */ GLbyte *pBytes; GLint iWidth, iHeight, iComponents; GLenum eFormat; glGenTextures(1, &handle); glBindTexture(GL_TEXTURE_2D, handle); /* load texture */ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); pBytes = gltLoadTGA(fname, &iWidth, &iHeight, &iComponents, &eFormat); if (!pBytes) fprintf(stderr, "gltLoadTGA: failed to load texture!\n"); glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes); free(pBytes); /* seems like mipmapping only applies to MIN_FILTER since mipmapping divides * current texture into smaller and smaller pieces */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); /* GL_LINEAR to disable mipmapping */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); return handle; } void gltListExtensions(void) { const GLubyte *ext_str; char *ext_str_copy; ext_str = glGetString(GL_EXTENSIONS); if (!ext_str) return; ext_str_copy = (char *) malloc(strlen((char *) ext_str) + 1); if (!ext_str_copy) { fprintf(stderr, "gltListExtensions failed, %s:%d\n", __FILE__, __LINE__); perror("malloc"); exit(-1); } strcpy(ext_str_copy, (char *) ext_str); char *tok; while ((tok = strsep(&ext_str_copy, " "))) printf("%s\n", tok); if (ext_str_copy) free(ext_str_copy); } void gltOpenGLInfo(void) { const GLubyte *str; str = glGetString(GL_VENDOR); fprintf(stdout, "OpenGL vendor: %s\n", str ? (char *) str : "unknown"); str = glGetString(GL_RENDERER); fprintf(stdout, "OpenGL renderer: %s\n", str ? (char *) str : "unknown"); str = glGetString(GL_VERSION); fprintf(stdout, "OpenGL version: %s\n", str ? (char *) str : "unknown"); str = glGetString(GL_SHADING_LANGUAGE_VERSION); fprintf(stdout, "GLSL version: %s\n", str ? (char *) str : "unknown"); } GLboolean gltQueryExtension(const char *extName) { char *p = (char *) glGetString(GL_EXTENSIONS); char *end = p + strlen(p); while (p < end) { int n = strcspn(p, " "); if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0)) return GL_TRUE; p += (n + 1); } return GL_FALSE; } GLint gltWriteTGA(const char *szFileName) { FILE *pFile; /* file pointer */ TGAHEADER tgaHeader; /* tga file header */ unsigned long lImageSize; /* size in bytes of image */ GLbyte *pBits = NULL; /* pointer to bits */ GLint iViewport[4]; /* viewport in pixels */ GLenum lastBuffer; /* storage for the current read buffer setting */ /* get the viewport dimensions */ glGetIntegerv(GL_VIEWPORT, iViewport); /* how big is the image going to be (targas are tightly packed) */ lImageSize = iViewport[2] * 3 * iViewport[3]; /* allocate block, if this doesn't work, go home */ pBits = (GLbyte *) malloc(lImageSize); if (pBits == NULL) { perror("malloc"); return 0; } /* change how bits are stored */ glPixelStorei(GL_PACK_ALIGNMENT, 1); glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); /* get the current read buffer setting and save it, switch to * the front buffer and do the read operation, finally, restore * the read buffer state */ glGetIntegerv(GL_READ_BUFFER, (GLint *) &lastBuffer); glReadBuffer(GL_FRONT); glReadPixels(0, 0, iViewport[2], iViewport[3], GL_BGR_EXT, GL_UNSIGNED_BYTE, pBits); glReadBuffer(lastBuffer); /* initialize the targa header */ tgaHeader.identsize = 0; tgaHeader.colorMapType = 0; tgaHeader.imageType = 2; tgaHeader.colorMapStart = 0; tgaHeader.colorMapLength = 0; tgaHeader.colorMapBits = 0; tgaHeader.xstart = 0; tgaHeader.ystart = 0; tgaHeader.width = iViewport[2]; tgaHeader.height = iViewport[3]; tgaHeader.bits = 24; tgaHeader.descriptor = 0; /* attempt to open the file */ pFile = fopen(szFileName, "wb"); if (pFile == NULL) { perror("fopen"); free(pBits); /* free buffer and return error */ return 0; } /* write the header */ fwrite(&tgaHeader, sizeof(TGAHEADER), 1, pFile); /* write the image data */ fwrite(pBits, lImageSize, 1, pFile); /* free temporary buffer and close the file */ free(pBits); fclose(pFile); return 1; } GLbyte *gltLoadTGA(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat) { FILE *pFile; /* file pointer */ TGAHEADER tgaHeader; /* TGA file header */ unsigned long lImageSize; /* size in bytes of image */ short sDepth; /* pixel depth; */ GLbyte *pBits = NULL; /* pointer to bits */ /* default/failed values */ *iWidth = 0; *iHeight = 0; *eFormat = GL_BGR_EXT; *iComponents = GL_RGB8; /* attempt to open the file */ pFile = fopen(szFileName, "rb"); if (pFile == NULL) { perror("fopen"); return 0; } /* read in header (binary) */ fread(&tgaHeader, 18 /* sizeof(TGAHEADER) */, 1, pFile); /* get width, height, and depth of texture */ *iWidth = tgaHeader.width; *iHeight = tgaHeader.height; sDepth = tgaHeader.bits / 8; /* put some validity checks here, very simply, i only understand * or care about 8, 24, or 32 bit targas */ if (tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32) return NULL; /* calculate size of image buffer */ lImageSize = tgaHeader.width * tgaHeader.height * sDepth; /* allocate memory and check for success */ pBits = (GLbyte *) malloc(lImageSize * sizeof(GLbyte)); if (pBits == NULL) { perror("malloc"); return NULL; } /* read in the bits */ /* check for read error, this should catch rle or other */ /* weird formats that i don't want to recognize */ if (fread(pBits, lImageSize, 1, pFile) != 1) { perror("fread"); free(pBits); return NULL; } /* set opengl format expected */ switch (sDepth) { case 3: /* most likely case */ *eFormat = GL_BGR_EXT; *iComponents = GL_RGB8; break; case 4: *eFormat = GL_BGRA_EXT; *iComponents = GL_RGBA8; break; case 1: *eFormat = GL_LUMINANCE; *iComponents = GL_LUMINANCE8; break; } /* done with file */ fclose(pFile); /* return pointer to image data */ return pBits; } #ifdef _WIN32 /* this function is insane in a good way */ char *strsep(char **stringp, const char *delim) { char *result; if ((stringp == NULL) || (*stringp == NULL)) return NULL; result = *stringp; while (**stringp && !strchr(delim, **stringp)) ++*stringp; if (**stringp) *(*stringp)++ = '\0'; else *stringp = NULL; return result; } #endif