3 * Mesa 3-D graphics library
5 * Copyright (C) 1995-2000 Brian Paul
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 * Compute ceiling of integer quotient of A divided by B:
37 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
47 /* To work around optimizer bug in MSVC4.1 */
48 #if defined(__WIN32__) && !defined(OPENSTEP)
49 void dummy(GLuint j, GLuint k);
50 void dummy(GLuint j, GLuint k)
58 static GLint GLAPIENTRY
59 mesa_gluScaleImage(GLenum format,
60 GLsizei widthin, GLsizei heightin,
61 GLenum typein, const void *datain,
62 GLsizei widthout, GLsizei heightout,
63 GLenum typeout, void *dataout)
65 GLint components, i, j, k;
66 GLfloat *tempin, *tempout;
68 GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
69 GLint packrowlength, packalignment, packskiprows, packskippixels;
70 GLint sizein, sizeout;
71 GLint rowstride, rowlen;
74 /* Determine number of components per pixel */
77 case GL_STENCIL_INDEX:
78 case GL_DEPTH_COMPONENT:
86 case GL_LUMINANCE_ALPHA:
101 return GLU_INVALID_ENUM;
104 /* Determine bytes per input datum */
106 case GL_UNSIGNED_BYTE:
107 sizein = sizeof(GLubyte);
110 sizein = sizeof(GLbyte);
112 case GL_UNSIGNED_SHORT:
113 sizein = sizeof(GLushort);
116 sizein = sizeof(GLshort);
118 case GL_UNSIGNED_INT:
119 sizein = sizeof(GLuint);
122 sizein = sizeof(GLint);
125 sizein = sizeof(GLfloat);
128 /* not implemented yet */
130 return GL_INVALID_ENUM;
133 /* Determine bytes per output datum */
135 case GL_UNSIGNED_BYTE:
136 sizeout = sizeof(GLubyte);
139 sizeout = sizeof(GLbyte);
141 case GL_UNSIGNED_SHORT:
142 sizeout = sizeof(GLushort);
145 sizeout = sizeof(GLshort);
147 case GL_UNSIGNED_INT:
148 sizeout = sizeof(GLuint);
151 sizeout = sizeof(GLint);
154 sizeout = sizeof(GLfloat);
157 /* not implemented yet */
159 return GL_INVALID_ENUM;
162 /* Get glPixelStore state */
163 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackrowlength);
164 glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackalignment);
165 glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpackskiprows);
166 glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpackskippixels);
167 glGetIntegerv(GL_PACK_ROW_LENGTH, &packrowlength);
168 glGetIntegerv(GL_PACK_ALIGNMENT, &packalignment);
169 glGetIntegerv(GL_PACK_SKIP_ROWS, &packskiprows);
170 glGetIntegerv(GL_PACK_SKIP_PIXELS, &packskippixels);
172 /* Allocate storage for intermediate images */
173 tempin = (GLfloat *) malloc(widthin * heightin
174 * components * sizeof(GLfloat));
176 return GLU_OUT_OF_MEMORY;
178 tempout = (GLfloat *) malloc(widthout * heightout
179 * components * sizeof(GLfloat));
182 return GLU_OUT_OF_MEMORY;
187 * Unpack the pixel data and convert to floating point
190 if (unpackrowlength > 0) {
191 rowlen = unpackrowlength;
196 if (sizein >= unpackalignment) {
197 rowstride = components * rowlen;
200 rowstride = unpackalignment / sizein
201 * CEILING(components * rowlen * sizein, unpackalignment);
205 case GL_UNSIGNED_BYTE:
207 for (i = 0; i < heightin; i++) {
208 GLubyte *ubptr = (GLubyte *) datain
210 + unpackskiprows * rowstride + unpackskippixels * components;
211 for (j = 0; j < widthin * components; j++) {
213 tempin[k++] = (GLfloat) * ubptr++;
219 for (i = 0; i < heightin; i++) {
220 GLbyte *bptr = (GLbyte *) datain
222 + unpackskiprows * rowstride + unpackskippixels * components;
223 for (j = 0; j < widthin * components; j++) {
225 tempin[k++] = (GLfloat) * bptr++;
229 case GL_UNSIGNED_SHORT:
231 for (i = 0; i < heightin; i++) {
232 GLushort *usptr = (GLushort *) datain
234 + unpackskiprows * rowstride + unpackskippixels * components;
235 for (j = 0; j < widthin * components; j++) {
237 tempin[k++] = (GLfloat) * usptr++;
243 for (i = 0; i < heightin; i++) {
244 GLshort *sptr = (GLshort *) datain
246 + unpackskiprows * rowstride + unpackskippixels * components;
247 for (j = 0; j < widthin * components; j++) {
249 tempin[k++] = (GLfloat) * sptr++;
253 case GL_UNSIGNED_INT:
255 for (i = 0; i < heightin; i++) {
256 GLuint *uiptr = (GLuint *) datain
258 + unpackskiprows * rowstride + unpackskippixels * components;
259 for (j = 0; j < widthin * components; j++) {
261 tempin[k++] = (GLfloat) * uiptr++;
267 for (i = 0; i < heightin; i++) {
268 GLint *iptr = (GLint *) datain
270 + unpackskiprows * rowstride + unpackskippixels * components;
271 for (j = 0; j < widthin * components; j++) {
273 tempin[k++] = (GLfloat) * iptr++;
279 for (i = 0; i < heightin; i++) {
280 GLfloat *fptr = (GLfloat *) datain
282 + unpackskiprows * rowstride + unpackskippixels * components;
283 for (j = 0; j < widthin * components; j++) {
285 tempin[k++] = *fptr++;
290 return GLU_INVALID_ENUM;
299 sx = (GLfloat) (widthin - 1) / (GLfloat) (widthout - 1);
301 sx = (GLfloat) (widthin - 1);
303 sy = (GLfloat) (heightin - 1) / (GLfloat) (heightout - 1);
305 sy = (GLfloat) (heightin - 1);
307 /*#define POINT_SAMPLE*/
309 for (i = 0; i < heightout; i++) {
311 for (j = 0; j < widthout; j++) {
314 GLfloat *src = tempin + (ii * widthin + jj) * components;
315 GLfloat *dst = tempout + (i * widthout + j) * components;
317 for (k = 0; k < components; k++) {
323 if (sx < 1.0 && sy < 1.0) {
324 /* magnify both width and height: use weighted sample of 4 pixels */
325 GLint i0, i1, j0, j1;
327 GLfloat *src00, *src01, *src10, *src11;
331 for (i = 0; i < heightout; i++) {
336 /* i1 = (i+1) * sy - EPSILON;*/
338 for (j = 0; j < widthout; j++) {
343 /* j1 = (j+1) * sx - EPSILON; */
346 /* compute weighted average of pixels in rect (i0,j0)-(i1,j1) */
347 src00 = tempin + (i0 * widthin + j0) * components;
348 src01 = tempin + (i0 * widthin + j1) * components;
349 src10 = tempin + (i1 * widthin + j0) * components;
350 src11 = tempin + (i1 * widthin + j1) * components;
352 dst = tempout + (i * widthout + j) * components;
354 for (k = 0; k < components; k++) {
355 s1 = *src00++ * (1.0 - beta) + *src01++ * beta;
356 s2 = *src10++ * (1.0 - beta) + *src11++ * beta;
357 *dst++ = s1 * (1.0 - alpha) + s2 * alpha;
363 /* shrink width and/or height: use an unweighted box filter */
369 for (i = 0; i < heightout; i++) {
374 /* i1 = (i+1) * sy - EPSILON; */
375 for (j = 0; j < widthout; j++) {
380 /* j1 = (j+1) * sx - EPSILON; */
382 dst = tempout + (i * widthout + j) * components;
384 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
385 for (k = 0; k < components; k++) {
387 for (ii = i0; ii <= i1; ii++) {
388 for (jj = j0; jj <= j1; jj++) {
389 sum += *(tempin + (ii * widthin + jj) * components + k);
392 sum /= (j1 - j0 + 1) * (i1 - i0 + 1);
402 * Return output image
405 if (packrowlength > 0) {
406 rowlen = packrowlength;
411 if (sizeout >= packalignment) {
412 rowstride = components * rowlen;
415 rowstride = packalignment / sizeout
416 * CEILING(components * rowlen * sizeout, packalignment);
420 case GL_UNSIGNED_BYTE:
422 for (i = 0; i < heightout; i++) {
423 GLubyte *ubptr = (GLubyte *) dataout
425 + packskiprows * rowstride + packskippixels * components;
426 for (j = 0; j < widthout * components; j++) {
428 *ubptr++ = (GLubyte) tempout[k++];
434 for (i = 0; i < heightout; i++) {
435 GLbyte *bptr = (GLbyte *) dataout
437 + packskiprows * rowstride + packskippixels * components;
438 for (j = 0; j < widthout * components; j++) {
440 *bptr++ = (GLbyte) tempout[k++];
444 case GL_UNSIGNED_SHORT:
446 for (i = 0; i < heightout; i++) {
447 GLushort *usptr = (GLushort *) dataout
449 + packskiprows * rowstride + packskippixels * components;
450 for (j = 0; j < widthout * components; j++) {
452 *usptr++ = (GLushort) tempout[k++];
458 for (i = 0; i < heightout; i++) {
459 GLshort *sptr = (GLshort *) dataout
461 + packskiprows * rowstride + packskippixels * components;
462 for (j = 0; j < widthout * components; j++) {
464 *sptr++ = (GLshort) tempout[k++];
468 case GL_UNSIGNED_INT:
470 for (i = 0; i < heightout; i++) {
471 GLuint *uiptr = (GLuint *) dataout
473 + packskiprows * rowstride + packskippixels * components;
474 for (j = 0; j < widthout * components; j++) {
476 *uiptr++ = (GLuint) tempout[k++];
482 for (i = 0; i < heightout; i++) {
483 GLint *iptr = (GLint *) dataout
485 + packskiprows * rowstride + packskippixels * components;
486 for (j = 0; j < widthout * components; j++) {
488 *iptr++ = (GLint) tempout[k++];
494 for (i = 0; i < heightout; i++) {
495 GLfloat *fptr = (GLfloat *) dataout
497 + packskiprows * rowstride + packskippixels * components;
498 for (j = 0; j < widthout * components; j++) {
500 *fptr++ = tempout[k++];
505 return GLU_INVALID_ENUM;
509 /* free temporary image storage */
520 * Return the largest k such that 2^k <= n.
529 for (k = 0; n >>= 1; k++);
537 * Find the value nearest to n which is also a power of two.
544 for (m = 1; m < n; m *= 2);
547 if (m - n <= n - m / 2) {
557 * Given an pixel format and datatype, return the number of bytes to
561 bytes_per_pixel(GLenum format, GLenum type)
567 case GL_STENCIL_INDEX:
568 case GL_DEPTH_COMPONENT:
576 case GL_LUMINANCE_ALPHA:
595 case GL_UNSIGNED_BYTE:
604 case GL_UNSIGNED_SHORT:
605 m = sizeof(GLushort);
610 case GL_UNSIGNED_INT:
630 * WARNING: This function isn't finished and has never been tested!!!!
633 mesa_gluBuild1DMipmaps(GLenum target, GLint components,
634 GLsizei width, GLenum format, GLenum type, const void *data)
637 GLint levels, max_levels;
638 GLint new_width, max_width;
642 return GLU_INVALID_VALUE;
644 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_width);
645 max_levels = ilog2(max_width) + 1;
647 /* Compute how many mipmap images to make */
648 levels = ilog2(width) + 1;
649 if (levels > max_levels) {
653 new_width = 1 << (levels - 1);
655 texture = (GLubyte *) malloc(new_width * components);
657 return GLU_OUT_OF_MEMORY;
660 if (width != new_width) {
661 /* initial rescaling */
663 case GL_UNSIGNED_BYTE:
665 GLubyte *ub_data = (GLubyte *) data;
666 for (i = 0; i < new_width; i++) {
667 j = i * width / new_width;
668 for (k = 0; k < components; k++) {
669 texture[i * components + k] = ub_data[j * components + k];
675 /* Not implemented */
680 /* generate and load mipmap images */
681 for (l = 0; l < levels; l++) {
682 glTexImage1D(GL_TEXTURE_1D, l, components, new_width, 0,
683 format, GL_UNSIGNED_BYTE, texture);
685 /* Scale image down to 1/2 size */
686 new_width = new_width / 2;
687 for (i = 0; i < new_width; i++) {
688 for (k = 0; k < components; k++) {
689 GLint sample1, sample2;
690 sample1 = (GLint) texture[i * 2 * components + k];
691 sample2 = (GLint) texture[(i * 2 + 1) * components + k];
692 texture[i * components + k] = (GLubyte) ((sample1 + sample2) / 2);
705 static GLint GLAPIENTRY
706 mesa_gluBuild2DMipmaps(GLenum target, GLint components,
707 GLsizei width, GLsizei height, GLenum format,
708 GLenum type, const void *data)
711 void *image, *newimage;
712 GLint neww, newh, level, bpp;
716 GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
717 GLint packrowlength, packalignment, packskiprows, packskippixels;
719 if (width < 1 || height < 1)
720 return GLU_INVALID_VALUE;
722 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
733 bpp = bytes_per_pixel(format, type);
735 /* probably a bad format or type enum */
736 return GLU_INVALID_ENUM;
739 /* Get current glPixelStore values */
740 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpackrowlength);
741 glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpackalignment);
742 glGetIntegerv(GL_UNPACK_SKIP_ROWS, &unpackskiprows);
743 glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &unpackskippixels);
744 glGetIntegerv(GL_PACK_ROW_LENGTH, &packrowlength);
745 glGetIntegerv(GL_PACK_ALIGNMENT, &packalignment);
746 glGetIntegerv(GL_PACK_SKIP_ROWS, &packskiprows);
747 glGetIntegerv(GL_PACK_SKIP_PIXELS, &packskippixels);
749 /* set pixel packing */
750 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
751 glPixelStorei(GL_PACK_ALIGNMENT, 1);
752 glPixelStorei(GL_PACK_SKIP_ROWS, 0);
753 glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
757 if (w != width || h != height) {
758 /* must rescale image to get "top" mipmap texture image */
759 image = malloc((w + 4) * h * bpp);
761 return GLU_OUT_OF_MEMORY;
763 error = mesa_gluScaleImage(format, width, height, type, data,
771 image = (void *) data;
777 /* set pixel unpacking */
778 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
779 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
780 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
781 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
784 glTexImage2D(target, level, components, w, h, 0, format, type, image);
786 if (w == 1 && h == 1)
789 neww = (w < 2) ? 1 : w / 2;
790 newh = (h < 2) ? 1 : h / 2;
791 newimage = malloc((neww + 4) * newh * bpp);
793 return GLU_OUT_OF_MEMORY;
796 error = mesa_gluScaleImage(format, w, h, type, image,
797 neww, newh, type, newimage);
817 /* Restore original glPixelStore state */
818 glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackrowlength);
819 glPixelStorei(GL_UNPACK_ALIGNMENT, unpackalignment);
820 glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackskiprows);
821 glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackskippixels);
822 glPixelStorei(GL_PACK_ROW_LENGTH, packrowlength);
823 glPixelStorei(GL_PACK_ALIGNMENT, packalignment);
824 glPixelStorei(GL_PACK_SKIP_ROWS, packskiprows);
825 glPixelStorei(GL_PACK_SKIP_PIXELS, packskippixels);