windows-nt/Source/XPSP1/NT/multimedia/opengl/glu/libutil/mipmap.c
2020-09-26 16:20:57 +08:00

1108 lines
27 KiB
C

/*
** 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 <glos.h>
#endif
#include <assert.h>
#include "gluint.h"
#include <GL/glu.h>
#include <stdio.h>
#ifdef NT
#include "winmem.h"
#else
#include <stdlib.h>
#endif
#include <string.h>
#include <math.h>
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;
}
}
}