/* ** cc -o textile textile.c -lGLU -lGL -lglut -lXmu -lX11 -lm */ #include #include #include #include #include #include "texture.h" int maxTextureSize; int maxTextureLevel; int imageWidth, imageHeight; GLubyte *imageData; int texWidthLevel0, texHeightLevel0; int texWidthTiles, texHeightTiles; GLubyte **texImageLevel; GLboolean useBorder = GL_TRUE; GLboolean useClamp = GL_TRUE; GLboolean useLinear = GL_TRUE; GLboolean useMipmap = GL_TRUE; GLboolean useTextureTiling = GL_TRUE; /* (int)floor(log2(a)) */ static int iflog2(unsigned int a) { int x = 0; while (a >>= 1) ++x; return x; } static void initialize(void) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-0.5, 0.5, -0.5, 0.5, 0.5, 1.5); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0, 0, -0.90); glRotatef( 45.0, 0, 1, 0); glTranslatef(-0.5, -0.5, 0.0); #if 0 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); #else maxTextureSize = 32; #endif maxTextureLevel = iflog2(maxTextureSize); texImageLevel = (GLubyte **) calloc(maxTextureLevel+1, sizeof(GLubyte *)); if (texImageLevel == NULL) { fprintf(stderr, "texture level image allocation failed\n"); exit(EXIT_FAILURE); } glClearColor(0.1, 0.1, 0.1, 0.1); } static void imgLoad(char *filename_in, int *w_out, int *h_out, GLubyte **img_out) { int comp; *img_out = (GLubyte *)read_texture(filename_in, w_out, h_out, &comp); if (img_out == NULL) { fprintf(stderr, "unable to read %s\n", filename_in); exit(EXIT_FAILURE); } if (comp != 3 && comp != 4) { fprintf(stderr, "%s: image is not RGB or RGBA\n", filename_in); exit(EXIT_FAILURE); } } static void buildMipmaps(void) { int level, levelWidth, levelHeight; if (useTextureTiling) { int width2 = iflog2(imageWidth); int height2 = iflog2(imageHeight); width2 = (width2 > maxTextureLevel) ? width2 : maxTextureLevel; height2 = (height2 > maxTextureLevel) ? height2 : maxTextureLevel; texWidthLevel0 = 1 << width2; texHeightLevel0 = 1 << height2; texWidthTiles = texWidthLevel0 >> maxTextureLevel; texHeightTiles = texHeightLevel0 >> maxTextureLevel; } else { texWidthLevel0 = maxTextureSize; texHeightLevel0 = maxTextureSize; texWidthTiles = 1; texHeightTiles = 1; } texImageLevel[0] = (GLubyte *) calloc(1, (texWidthLevel0+2)*(texHeightLevel0+2)*4*sizeof(GLubyte)); glPixelStorei(GL_PACK_ROW_LENGTH, texWidthLevel0+2); glPixelStorei(GL_PACK_SKIP_PIXELS, 1); glPixelStorei(GL_PACK_SKIP_ROWS, 1); gluScaleImage(GL_RGBA, imageWidth, imageHeight, GL_UNSIGNED_BYTE, imageData, texWidthLevel0, texHeightLevel0, GL_UNSIGNED_BYTE, texImageLevel[0]); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 1); glPixelStorei(GL_UNPACK_SKIP_ROWS, 1); levelWidth = texWidthLevel0; levelHeight = texHeightLevel0; for (level=0; level 1) ? levelWidth / 2 : 1; int newLevelHeight = (levelHeight > 1) ? levelHeight / 2 : 1; texImageLevel[level+1] = (GLubyte *) calloc(1, (newLevelWidth+2)*(newLevelHeight+2)*4*sizeof(GLubyte)); glPixelStorei(GL_PACK_ROW_LENGTH, newLevelWidth+2); glPixelStorei(GL_UNPACK_ROW_LENGTH, levelWidth+2); gluScaleImage(GL_RGBA, levelWidth, levelHeight, GL_UNSIGNED_BYTE, texImageLevel[level], newLevelWidth, newLevelHeight, GL_UNSIGNED_BYTE, texImageLevel[level+1]); levelWidth = newLevelWidth; levelHeight = newLevelHeight; } glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_SKIP_PIXELS, 0); glPixelStorei(GL_PACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); } static void freeMipmaps(void) { int i; for (i=0; i<=maxTextureLevel; ++i) { if (texImageLevel[i] != NULL) { free(texImageLevel[i]); texImageLevel[i] = NULL; } } } static void loadTile(int row, int col) { int border = useBorder ? 1 : 0; int level, levelWidth, levelHeight; levelWidth = texWidthLevel0; levelHeight = texHeightLevel0; for (level=0; level<=maxTextureLevel; ++level) { int tileWidth = levelWidth / texWidthTiles; int tileHeight = levelHeight / texHeightTiles; int skipPixels = col * tileWidth + (1 - border); int skipRows = row * tileHeight + (1 - border); glPixelStorei(GL_UNPACK_ROW_LENGTH, levelWidth+2); glPixelStorei(GL_UNPACK_SKIP_PIXELS, skipPixels); glPixelStorei(GL_UNPACK_SKIP_ROWS, skipRows); glTexImage2D(GL_TEXTURE_2D, level, 4, tileWidth + 2*border, tileHeight + 2*border, border, GL_RGBA, GL_UNSIGNED_BYTE, texImageLevel[level]); if (levelWidth > 1) levelWidth = levelWidth / 2; if (levelHeight > 1) levelHeight = levelHeight / 2; } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); } static void redraw(void) { GLenum minFilterMode, magFilterMode, wrapMode; char *minFilterName, *magFilterName, *wrapName; int i, j; if (useLinear) { if (useMipmap) { minFilterMode = GL_LINEAR_MIPMAP_LINEAR; minFilterName = "LINEAR_MIPMAP_LINEAR"; } else { minFilterMode = GL_LINEAR; minFilterName = "LINEAR"; } magFilterMode = GL_LINEAR; magFilterName = "LINEAR"; } else { if (useMipmap) { minFilterMode = GL_NEAREST_MIPMAP_LINEAR; minFilterName = "NEAREST_MIPMAP_LINEAR"; } else { minFilterMode = GL_NEAREST; minFilterName = "NEAREST"; } magFilterMode = GL_NEAREST; magFilterName = "NEAREST"; } if (useClamp) { wrapMode = GL_CLAMP; wrapName = "CLAMP"; } else { wrapMode = GL_REPEAT; wrapName = "REPEAT"; } fprintf(stderr, "tile(%s) ", useTextureTiling ? "yes" : "no"); fprintf(stderr, "border(%s) ", useBorder ? "yes" : "no"); fprintf(stderr, "filter(%s, %s) ", minFilterName, magFilterName); fprintf(stderr, "wrap(%s) ", wrapName); fprintf(stderr, "\n"); glClear(GL_COLOR_BUFFER_BIT); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilterMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilterMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode); buildMipmaps(); glEnable(GL_TEXTURE_2D); for (i=0; i