/* ** Copyright 1992, Silicon Graphics, Inc. ** All Rights Reserved. ** ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.; ** the contents of this file may not be disclosed to third parties, copied or ** duplicated in any form, in whole or in part, without the prior written ** permission of Silicon Graphics, Inc. ** ** RESTRICTED RIGHTS LEGEND: ** Use, duplication or disclosure by the Government is subject to restrictions ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished - ** rights reserved under the Copyright Laws of the United States. ** ** $Revision: 1.4 $ ** $Date: 1996/03/29 01:55:31 $ */ #ifdef NT #include #endif #include #include "gluint.h" #include #include #ifdef NT #include "winmem.h" #else #include #endif #include #include typedef union { unsigned char ub[4]; unsigned short us[2]; unsigned long ui; char b[4]; short s[2]; long i; float f; } Type_Widget; /* Pixel storage modes */ typedef struct { GLint pack_alignment; GLint pack_row_length; GLint pack_skip_rows; GLint pack_skip_pixels; GLint pack_lsb_first; GLint pack_swap_bytes; GLint unpack_alignment; GLint unpack_row_length; GLint unpack_skip_rows; GLint unpack_skip_pixels; GLint unpack_lsb_first; GLint unpack_swap_bytes; } PixelStorageModes; /* * internal function declarations */ static GLfloat bytes_per_element(GLenum type); static GLint elements_per_group(GLenum format); #ifdef NT static GLboolean is_index(GLenum format); #else static GLint is_index(GLenum format); #endif static GLint image_size(GLint width, GLint height, GLenum format, GLenum type); static void fill_image(const PixelStorageModes *, GLint width, GLint height, GLenum format, GLenum type, GLboolean index_format, const void *userdata, GLushort *newimage); static void empty_image(const PixelStorageModes *, GLint width, GLint height, GLenum format, GLenum type, GLboolean index_format, const GLushort *oldimage, void *userdata); static void scale_internal(GLint components, GLint widthin, GLint heightin, const GLushort *datain, GLint widthout, GLint heightout, GLushort *dataout); static GLint retrieveStoreModes(PixelStorageModes *psm) { glGetError(); glGetIntegerv(GL_UNPACK_ALIGNMENT, &psm->unpack_alignment); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_UNPACK_ROW_LENGTH, &psm->unpack_row_length); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_UNPACK_SKIP_ROWS, &psm->unpack_skip_rows); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &psm->unpack_skip_pixels); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_UNPACK_LSB_FIRST, &psm->unpack_lsb_first); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_UNPACK_SWAP_BYTES, &psm->unpack_swap_bytes); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_PACK_ALIGNMENT, &psm->pack_alignment); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_PACK_ROW_LENGTH, &psm->pack_row_length); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_PACK_SKIP_ROWS, &psm->pack_skip_rows); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_PACK_SKIP_PIXELS, &psm->pack_skip_pixels); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_PACK_LSB_FIRST, &psm->pack_lsb_first); if (glGetError() != GL_NO_ERROR) { return 1; } glGetIntegerv(GL_PACK_SWAP_BYTES, &psm->pack_swap_bytes); if (glGetError() != GL_NO_ERROR) { return 1; } return 0; } static int computeLog(GLuint value) { int i; i = 0; /* Error! */ if (value == 0) return -1; for (;;) { if (value & 1) { /* Error ! */ if (value != 1) return -1; return i; } value = value >> 1; i++; } } /* ** Compute the nearest power of 2 number. This algorithm is a little ** strange, but it works quite well. */ static int nearestPower(GLuint value) { int i; i = 1; /* Error! */ if (value == 0) return -1; for (;;) { if (value == 1) { return i; } else if (value == 3) { return i*4; } value = value >> 1; i *= 2; } } static void halveImage(GLint components, GLuint width, GLuint height, const GLushort *datain, GLushort *dataout) { int i, j, k; int newwidth, newheight; int delta; GLushort *s; const GLushort *t; newwidth = width / 2; newheight = height / 2; delta = width * components; s = dataout; t = datain; /* Piece o' cake! */ for (i = 0; i < newheight; i++) { for (j = 0; j < newwidth; j++) { for (k = 0; k < components; k++) { s[0] = (t[0] + t[components] + t[delta] + t[delta+components] + 2) / 4; s++; t++; } t += components; } t += delta; } } static void scale_internal(GLint components, GLint widthin, GLint heightin, const GLushort *datain, GLint widthout, GLint heightout, GLushort *dataout) { float x, lowx, highx, convx, halfconvx; float y, lowy, highy, convy, halfconvy; float xpercent,ypercent; float percent; /* Max components in a format is 4, so... */ float totals[4]; float area; int i,j,k,yint,xint,xindex,yindex; int temp; if (widthin == widthout*2 && heightin == heightout*2) { halveImage(components, widthin, heightin, datain, dataout); return; } convy = (float) heightin/heightout; convx = (float) widthin/widthout; halfconvx = convx/2; halfconvy = convy/2; for (i = 0; i < heightout; i++) { y = convy * (i+0.5); if (heightin > heightout) { highy = y + halfconvy; lowy = y - halfconvy; } else { highy = y + 0.5; lowy = y - 0.5; } for (j = 0; j < widthout; j++) { x = convx * (j+0.5); if (widthin > widthout) { highx = x + halfconvx; lowx = x - halfconvx; } else { highx = x + 0.5; lowx = x - 0.5; } /* ** Ok, now apply box filter to box that goes from (lowx, lowy) ** to (highx, highy) on input data into this pixel on output ** data. */ totals[0] = totals[1] = totals[2] = totals[3] = 0.0; area = 0.0; y = lowy; yint = floor(y); while (y < highy) { yindex = (yint + heightin) % heightin; if (highy < yint+1) { ypercent = highy - y; } else { ypercent = yint+1 - y; } x = lowx; xint = floor(x); while (x < highx) { xindex = (xint + widthin) % widthin; if (highx < xint+1) { xpercent = highx - x; } else { xpercent = xint+1 - x; } percent = xpercent * ypercent; area += percent; temp = (xindex + (yindex * widthin)) * components; for (k = 0; k < components; k++) { totals[k] += datain[temp + k] * percent; } xint++; x = xint; } yint++; y = yint; } temp = (j + (i * widthout)) * components; for (k = 0; k < components; k++) { dataout[temp + k] = totals[k]/area; } } } } static GLboolean legalFormat(GLenum format) { switch(format) { case GL_COLOR_INDEX: case GL_STENCIL_INDEX: case GL_DEPTH_COMPONENT: case GL_RED: case GL_GREEN: case GL_BLUE: case GL_ALPHA: case GL_RGB: case GL_RGBA: #ifdef GL_EXT_bgra case GL_BGR_EXT: case GL_BGRA_EXT: #endif case GL_LUMINANCE: case GL_LUMINANCE_ALPHA: return GL_TRUE; default: return GL_FALSE; } } static GLboolean legalType(GLenum type) { switch(type) { case GL_BITMAP: case GL_BYTE: case GL_UNSIGNED_BYTE: case GL_SHORT: case GL_UNSIGNED_SHORT: case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: return GL_TRUE; default: return GL_FALSE; } } GLint gluScaleImage(GLenum format, GLint widthin, GLint heightin, GLenum typein, const void *datain, GLint widthout, GLint heightout, GLenum typeout, void *dataout) { int components; GLushort *beforeImage; GLushort *afterImage; PixelStorageModes psm; if (widthin == 0 || heightin == 0 || widthout == 0 || heightout == 0) { return 0; } if (widthin < 0 || heightin < 0 || widthout < 0 || heightout < 0) { return GLU_INVALID_VALUE; } if (!legalFormat(format) || !legalType(typein) || !legalType(typeout)) { return GLU_INVALID_ENUM; } if (retrieveStoreModes(&psm)) { return GL_OUT_OF_MEMORY; } beforeImage = malloc(image_size(widthin, heightin, format, GL_UNSIGNED_SHORT)); afterImage = malloc(image_size(widthout, heightout, format, GL_UNSIGNED_SHORT)); if (beforeImage == NULL || afterImage == NULL) { return GLU_OUT_OF_MEMORY; } fill_image(&psm,widthin, heightin, format, typein, is_index(format), datain, beforeImage); components = elements_per_group(format); scale_internal(components, widthin, heightin, beforeImage, widthout, heightout, afterImage); empty_image(&psm,widthout, heightout, format, typeout, is_index(format), afterImage, dataout); free((GLbyte *) beforeImage); free((GLbyte *) afterImage); return 0; } GLint gluBuild1DMipmaps(GLenum target, GLint components, GLint width, GLenum format, GLenum type, const void *data) { GLint newwidth; GLint level, levels; GLushort *newImage; GLint newImage_width; GLushort *otherImage; GLushort *imageTemp; GLint memreq; GLint maxsize; GLint cmpts; PixelStorageModes psm; GLboolean error = GL_FALSE; if (width < 1) { return GLU_INVALID_VALUE; } if (!legalFormat(format) || !legalType(type)) { return GLU_INVALID_ENUM; } if (format == GL_STENCIL_INDEX) { return GLU_INVALID_ENUM; } if (format == GL_DEPTH_COMPONENT) { return GLU_INVALID_ENUM; } if (retrieveStoreModes(&psm)) { return GL_OUT_OF_MEMORY; } glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); if (glGetError() != GL_NO_ERROR) { return GL_OUT_OF_MEMORY; } newwidth = nearestPower(width); if (newwidth > maxsize) newwidth = maxsize; levels = computeLog(newwidth); otherImage = NULL; newImage = (GLushort *) malloc(image_size(width, 1, format, GL_UNSIGNED_SHORT)); newImage_width = width; if (newImage == NULL) { return GLU_OUT_OF_MEMORY; } fill_image(&psm,width, 1, format, type, is_index(format), data, newImage); cmpts = elements_per_group(format); glGetError(); glPixelStorei(GL_UNPACK_ALIGNMENT, 2); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild1DMipmaps_cleanup; } glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild1DMipmaps_cleanup; } glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild1DMipmaps_cleanup; } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild1DMipmaps_cleanup; } /* ** If swap_bytes was set, swapping occurred in fill_image. */ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild1DMipmaps_cleanup; } for (level = 0; level <= levels; level++) { if (newImage_width == newwidth) { /* Use newImage for this level */ glTexImage1D(target, level, components, newImage_width, 0, format, GL_UNSIGNED_SHORT, (void *) newImage); } else { if (otherImage == NULL) { memreq = image_size(newwidth, 1, format, GL_UNSIGNED_SHORT); otherImage = (GLushort *) malloc(memreq); if (otherImage == NULL) { glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); glPixelStorei(GL_UNPACK_SKIP_PIXELS,psm.unpack_skip_pixels); glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); return GLU_OUT_OF_MEMORY; } } scale_internal(cmpts, newImage_width, 1, newImage, newwidth, 1, otherImage); /* Swap newImage and otherImage */ imageTemp = otherImage; otherImage = newImage; newImage = imageTemp; newImage_width = newwidth; glTexImage1D(target, level, components, newImage_width, 0, format, GL_UNSIGNED_SHORT, (void *) newImage); } if (newwidth > 1) newwidth /= 2; } gluBuild1DMipmaps_cleanup: glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); free((GLbyte *) newImage); if (otherImage) { free((GLbyte *) otherImage); } if (error == GL_TRUE) return GL_OUT_OF_MEMORY; else return 0; } GLint gluBuild2DMipmaps(GLenum target, GLint components, GLint width, GLint height, GLenum format, GLenum type, const void *data) { GLint newwidth, newheight; GLint level, levels; GLushort *newImage; GLint newImage_width; GLint newImage_height; GLushort *otherImage; GLushort *imageTemp; GLint memreq; GLint maxsize; GLint cmpts; GLboolean error = GL_FALSE; PixelStorageModes psm; if (width < 1 || height < 1) { return GLU_INVALID_VALUE; } if (!legalFormat(format) || !legalType(type)) { return GLU_INVALID_ENUM; } if (format == GL_STENCIL_INDEX) { return GLU_INVALID_ENUM; } if (format == GL_DEPTH_COMPONENT) { return GLU_INVALID_ENUM; } if (retrieveStoreModes(&psm)) { return GL_OUT_OF_MEMORY; } glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize); if (glGetError() != GL_NO_ERROR) { return GL_OUT_OF_MEMORY; } newwidth = nearestPower(width); if (newwidth > maxsize) newwidth = maxsize; newheight = nearestPower(height); if (newheight > maxsize) newheight = maxsize; levels = computeLog(newwidth); level = computeLog(newheight); if (level > levels) levels=level; otherImage = NULL; newImage = (GLushort *) malloc(image_size(width, height, format, GL_UNSIGNED_SHORT)); newImage_width = width; newImage_height = height; if (newImage == NULL) { return GLU_OUT_OF_MEMORY; } fill_image(&psm,width, height, format, type, is_index(format), data, newImage); cmpts = elements_per_group(format); glGetError(); glPixelStorei(GL_UNPACK_ALIGNMENT, 2); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild2DMipmaps_cleanup; } glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild2DMipmaps_cleanup; } glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild2DMipmaps_cleanup; } glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild2DMipmaps_cleanup; } /* ** If swap_bytes was set, swapping occurred in fill_image. */ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); if (glGetError() != GL_NO_ERROR) { error = GL_TRUE; goto gluBuild2DMipmaps_cleanup; } for (level = 0; level <= levels; level++) { if (newImage_width == newwidth && newImage_height == newheight) { /* Use newImage for this level */ glTexImage2D(target, level, components, newImage_width, newImage_height, 0, format, GL_UNSIGNED_SHORT, (void *) newImage); } else { if (otherImage == NULL) { memreq = image_size(newwidth, newheight, format, GL_UNSIGNED_SHORT); otherImage = (GLushort *) malloc(memreq); if (otherImage == NULL) { glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); return GLU_OUT_OF_MEMORY; } } scale_internal(cmpts, newImage_width, newImage_height, newImage, newwidth, newheight, otherImage); /* Swap newImage and otherImage */ imageTemp = otherImage; otherImage = newImage; newImage = imageTemp; newImage_width = newwidth; newImage_height = newheight; glTexImage2D(target, level, components, newImage_width, newImage_height, 0, format, GL_UNSIGNED_SHORT, (void *) newImage); } if (newwidth > 1) newwidth /= 2; if (newheight > 1) newheight /= 2; } gluBuild2DMipmaps_cleanup: glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment); glPixelStorei(GL_UNPACK_SKIP_ROWS, psm.unpack_skip_rows); glPixelStorei(GL_UNPACK_SKIP_PIXELS, psm.unpack_skip_pixels); glPixelStorei(GL_UNPACK_ROW_LENGTH, psm.unpack_row_length); glPixelStorei(GL_UNPACK_SWAP_BYTES, psm.unpack_swap_bytes); free((GLbyte *) newImage); if (otherImage) { free((GLbyte *) otherImage); } if (error == GL_TRUE) return GL_OUT_OF_MEMORY; else return 0; } /* * Utility Routines */ static GLint elements_per_group(GLenum format) { /* * Return the number of elements per group of a specified format */ switch(format) { case GL_RGB: #ifdef GL_EXT_bgra case GL_BGR_EXT: #endif return 3; case GL_LUMINANCE_ALPHA: return 2; case GL_RGBA: #ifdef GL_EXT_bgra case GL_BGRA_EXT: #endif return 4; default: return 1; } } static GLfloat bytes_per_element(GLenum type) { /* * Return the number of bytes per element, based on the element type */ switch(type) { case GL_BITMAP: return 1.0 / 8.0; case GL_UNSIGNED_SHORT: case GL_SHORT: return 2; case GL_UNSIGNED_BYTE: case GL_BYTE: return 1; case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: default: return 4; } } #ifdef NT static GLboolean is_index(GLenum format) #else static GLint is_index(GLenum format) #endif { return format == GL_COLOR_INDEX || format == GL_STENCIL_INDEX; } /* ** Compute memory required for internal packed array of data of given type ** and format. */ static GLint image_size(GLint width, GLint height, GLenum format, GLenum type) { int bytes_per_row; int components; assert(width > 0); assert(height > 0); components = elements_per_group(format); if (type == GL_BITMAP) { bytes_per_row = (width + 7) / 8; } else { bytes_per_row = bytes_per_element(type) * width; } return bytes_per_row * height * components; } /* ** Extract array from user's data applying all pixel store modes. ** The internal format used is an array of unsigned shorts. */ static void fill_image(const PixelStorageModes *psm, GLint width, GLint height, GLenum format, GLenum type, GLboolean index_format, const void *userdata, GLushort *newimage) { GLint components; GLint element_size; GLint rowsize; GLint padding; GLint groups_per_line; GLint group_size; GLint elements_per_line; const GLubyte *start; const GLubyte *iter; GLushort *iter2; GLint i, j, k; GLint myswap_bytes; myswap_bytes = psm->unpack_swap_bytes; components = elements_per_group(format); if (psm->unpack_row_length > 0) { groups_per_line = psm->unpack_row_length; } else { groups_per_line = width; } /* All formats except GL_BITMAP fall out trivially */ if (type == GL_BITMAP) { GLint bit_offset; GLint current_bit; rowsize = (groups_per_line * components + 7) / 8; padding = (rowsize % psm->unpack_alignment); if (padding) { rowsize += psm->unpack_alignment - padding; } start = (GLubyte *) userdata + psm->unpack_skip_rows * rowsize + (psm->unpack_skip_pixels * components / 8); elements_per_line = width * components; iter2 = newimage; for (i = 0; i < height; i++) { iter = start; bit_offset = (psm->unpack_skip_pixels * components) % 8; for (j = 0; j < elements_per_line; j++) { /* Retrieve bit */ if (psm->unpack_lsb_first) { current_bit = iter[0] & (1 << bit_offset); } else { current_bit = iter[0] & (1 << (7 - bit_offset)); } if (current_bit) { if (index_format) { *iter2 = 1; } else { *iter2 = 65535; } } else { *iter2 = 0; } bit_offset++; if (bit_offset == 8) { bit_offset = 0; iter++; } iter2++; } start += rowsize; } } else { element_size = bytes_per_element(type); group_size = element_size * components; if (element_size == 1) myswap_bytes = 0; rowsize = groups_per_line * group_size; padding = (rowsize % psm->unpack_alignment); if (padding) { rowsize += psm->unpack_alignment - padding; } start = (GLubyte *) userdata + psm->unpack_skip_rows * rowsize + psm->unpack_skip_pixels * group_size; elements_per_line = width * components; iter2 = newimage; for (i = 0; i < height; i++) { iter = start; for (j = 0; j < elements_per_line; j++) { Type_Widget widget; switch(type) { case GL_UNSIGNED_BYTE: if (index_format) { *iter2 = *iter; } else { *iter2 = (*iter) * 257; } break; case GL_BYTE: if (index_format) { *iter2 = *((GLbyte *) iter); } else { /* rough approx */ *iter2 = (*((GLbyte *) iter)) * 516; } break; case GL_UNSIGNED_SHORT: case GL_SHORT: if (myswap_bytes) { widget.ub[0] = iter[1]; widget.ub[1] = iter[0]; } else { widget.ub[0] = iter[0]; widget.ub[1] = iter[1]; } if (type == GL_SHORT) { if (index_format) { *iter2 = widget.s[0]; } else { /* rough approx */ *iter2 = widget.s[0]*2; } } else { *iter2 = widget.us[0]; } break; case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: if (myswap_bytes) { widget.ub[0] = iter[3]; widget.ub[1] = iter[2]; widget.ub[2] = iter[1]; widget.ub[3] = iter[0]; } else { widget.ub[0] = iter[0]; widget.ub[1] = iter[1]; widget.ub[2] = iter[2]; widget.ub[3] = iter[3]; } if (type == GL_FLOAT) { if (index_format) { *iter2 = widget.f; } else { *iter2 = 65535 * widget.f; } } else if (type == GL_UNSIGNED_INT) { if (index_format) { *iter2 = (GLushort)widget.ui; } else { *iter2 = widget.ui >> 16; } } else { if (index_format) { *iter2 = (GLushort)widget.i; } else { *iter2 = widget.i >> 15; } } break; } iter += element_size; iter2++; } start += rowsize; } } } /* ** Insert array into user's data applying all pixel store modes. ** The internal format is an array of unsigned shorts. ** empty_image() because it is the opposite of fill_image(). */ static void empty_image(const PixelStorageModes *psm, GLint width, GLint height, GLenum format, GLenum type, GLboolean index_format, const GLushort *oldimage, void *userdata) { GLint components; GLint element_size; GLint rowsize; GLint padding; GLint groups_per_line; GLint group_size; GLint elements_per_line; GLubyte *start; GLubyte *iter; const GLushort *iter2; GLint i, j, k; GLint myswap_bytes; myswap_bytes = psm->pack_swap_bytes; components = elements_per_group(format); if (psm->pack_row_length > 0) { groups_per_line = psm->pack_row_length; } else { groups_per_line = width; } /* All formats except GL_BITMAP fall out trivially */ if (type == GL_BITMAP) { GLint bit_offset; GLint current_bit; rowsize = (groups_per_line * components + 7) / 8; padding = (rowsize % psm->pack_alignment); if (padding) { rowsize += psm->pack_alignment - padding; } start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize + (psm->pack_skip_pixels * components / 8); elements_per_line = width * components; iter2 = oldimage; for (i = 0; i < height; i++) { iter = start; bit_offset = (psm->pack_skip_pixels * components) % 8; for (j = 0; j < elements_per_line; j++) { if (index_format) { current_bit = iter2[0] & 1; } else { if (iter2[0] > 32767) { current_bit = 1; } else { current_bit = 0; } } if (current_bit) { if (psm->pack_lsb_first) { *iter |= (1 << bit_offset); } else { *iter |= (1 << (7 - bit_offset)); } } else { if (psm->pack_lsb_first) { *iter &= ~(1 << bit_offset); } else { *iter &= ~(1 << (7 - bit_offset)); } } bit_offset++; if (bit_offset == 8) { bit_offset = 0; iter++; } iter2++; } start += rowsize; } } else { element_size = bytes_per_element(type); group_size = element_size * components; if (element_size == 1) myswap_bytes = 0; rowsize = groups_per_line * group_size; padding = (rowsize % psm->pack_alignment); if (padding) { rowsize += psm->pack_alignment - padding; } start = (GLubyte *) userdata + psm->pack_skip_rows * rowsize + psm->pack_skip_pixels * group_size; elements_per_line = width * components; iter2 = oldimage; for (i = 0; i < height; i++) { iter = start; for (j = 0; j < elements_per_line; j++) { Type_Widget widget; switch(type) { case GL_UNSIGNED_BYTE: if (index_format) { *iter = (GLubyte)*iter2; } else { *iter = *iter2 >> 8; } break; case GL_BYTE: if (index_format) { *((GLbyte *) iter) = (GLbyte)*iter2; } else { *((GLbyte *) iter) = *iter2 >> 9; } break; case GL_UNSIGNED_SHORT: case GL_SHORT: if (type == GL_SHORT) { if (index_format) { widget.s[0] = *iter2; } else { widget.s[0] = *iter2 >> 1; } } else { widget.us[0] = *iter2; } if (myswap_bytes) { iter[0] = widget.ub[1]; iter[1] = widget.ub[0]; } else { iter[0] = widget.ub[0]; iter[1] = widget.ub[1]; } break; case GL_INT: case GL_UNSIGNED_INT: case GL_FLOAT: if (type == GL_FLOAT) { if (index_format) { widget.f = *iter2; } else { widget.f = *iter2 / (float) 65535.0; } } else if (type == GL_UNSIGNED_INT) { if (index_format) { widget.ui = *iter2; } else { widget.ui = (unsigned int) *iter2 * 65537; } } else { if (index_format) { widget.i = *iter2; } else { widget.i = ((unsigned int) *iter2 * 65537)/2; } } if (myswap_bytes) { iter[3] = widget.ub[0]; iter[2] = widget.ub[1]; iter[1] = widget.ub[2]; iter[0] = widget.ub[3]; } else { iter[0] = widget.ub[0]; iter[1] = widget.ub[1]; iter[2] = widget.ub[2]; iter[3] = widget.ub[3]; } break; } iter += element_size; iter2++; } start += rowsize; } } }