Remove CVS keywords.
[mesa.git] / src / glu / mini / mipmap.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 3.4
5 * Copyright (C) 1995-2000 Brian Paul
6 *
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.
11 *
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.
16 *
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.
20 */
21
22
23 #ifdef PC_HEADER
24 #include "all.h"
25 #else
26 #include <assert.h>
27 #include <math.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include "gluP.h"
31 #endif
32
33
34 /*
35 * Compute ceiling of integer quotient of A divided by B:
36 */
37 #define CEILING( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 )
38
39
40
41 #ifdef EPSILON
42 #undef EPSILON
43 #endif
44 #define EPSILON 0.001
45
46
47 /* To work around optimizer bug in MSVC4.1 */
48 #if defined(__WIN32__) && !defined(OPENSTEP)
49 void
50 dummy(GLuint j, GLuint k)
51 {
52 }
53 #else
54 #define dummy(J, K)
55 #endif
56
57
58 GLint GLAPIENTRY
59 gluScaleImage(GLenum format,
60 GLsizei widthin, GLsizei heightin,
61 GLenum typein, const void *datain,
62 GLsizei widthout, GLsizei heightout,
63 GLenum typeout, void *dataout)
64 {
65 GLint components, i, j, k;
66 GLfloat *tempin, *tempout, f;
67 GLfloat sx, sy;
68 GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
69 GLint packrowlength, packalignment, packskiprows, packskippixels;
70 GLint sizein, sizeout;
71 GLint rowstride, rowlen;
72
73
74 /* Determine number of components per pixel */
75 switch (format) {
76 case GL_COLOR_INDEX:
77 case GL_STENCIL_INDEX:
78 case GL_DEPTH_COMPONENT:
79 case GL_RED:
80 case GL_GREEN:
81 case GL_BLUE:
82 case GL_ALPHA:
83 case GL_LUMINANCE:
84 components = 1;
85 break;
86 case GL_LUMINANCE_ALPHA:
87 components = 2;
88 break;
89 case GL_RGB:
90 case GL_BGR:
91 components = 3;
92 break;
93 case GL_RGBA:
94 case GL_BGRA:
95 #ifdef GL_EXT_abgr
96 case GL_ABGR_EXT:
97 #endif
98 components = 4;
99 break;
100 default:
101 return GLU_INVALID_ENUM;
102 }
103
104 /* Determine bytes per input datum */
105 switch (typein) {
106 case GL_UNSIGNED_BYTE:
107 sizein = sizeof(GLubyte);
108 break;
109 case GL_BYTE:
110 sizein = sizeof(GLbyte);
111 break;
112 case GL_UNSIGNED_SHORT:
113 sizein = sizeof(GLushort);
114 break;
115 case GL_SHORT:
116 sizein = sizeof(GLshort);
117 break;
118 case GL_UNSIGNED_INT:
119 sizein = sizeof(GLuint);
120 break;
121 case GL_INT:
122 sizein = sizeof(GLint);
123 break;
124 case GL_FLOAT:
125 sizein = sizeof(GLfloat);
126 break;
127 case GL_BITMAP:
128 /* not implemented yet */
129 default:
130 return GL_INVALID_ENUM;
131 }
132
133 /* Determine bytes per output datum */
134 switch (typeout) {
135 case GL_UNSIGNED_BYTE:
136 sizeout = sizeof(GLubyte);
137 break;
138 case GL_BYTE:
139 sizeout = sizeof(GLbyte);
140 break;
141 case GL_UNSIGNED_SHORT:
142 sizeout = sizeof(GLushort);
143 break;
144 case GL_SHORT:
145 sizeout = sizeof(GLshort);
146 break;
147 case GL_UNSIGNED_INT:
148 sizeout = sizeof(GLuint);
149 break;
150 case GL_INT:
151 sizeout = sizeof(GLint);
152 break;
153 case GL_FLOAT:
154 sizeout = sizeof(GLfloat);
155 break;
156 case GL_BITMAP:
157 /* not implemented yet */
158 default:
159 return GL_INVALID_ENUM;
160 }
161
162 /* Get glPixelStore state */
163 glGetFloatv(GL_UNPACK_ROW_LENGTH, &f); unpackrowlength = (int)f;
164 glGetFloatv(GL_UNPACK_ALIGNMENT, &f); unpackalignment = (int)f;
165 glGetFloatv(GL_UNPACK_SKIP_ROWS, &f); unpackskiprows = (int)f;
166 glGetFloatv(GL_UNPACK_SKIP_PIXELS, &f); unpackskippixels = (int)f;
167 glGetFloatv(GL_PACK_ROW_LENGTH, &f); packrowlength = (int)f;
168 glGetFloatv(GL_PACK_ALIGNMENT, &f); packalignment = (int)f;
169 glGetFloatv(GL_PACK_SKIP_ROWS, &f); packskiprows = (int)f;
170 glGetFloatv(GL_PACK_SKIP_PIXELS, &f); packskippixels = (int)f;
171
172 /* Allocate storage for intermediate images */
173 tempin = (GLfloat *) malloc(widthin * heightin
174 * components * sizeof(GLfloat));
175 if (!tempin) {
176 return GLU_OUT_OF_MEMORY;
177 }
178 tempout = (GLfloat *) malloc(widthout * heightout
179 * components * sizeof(GLfloat));
180 if (!tempout) {
181 free(tempin);
182 return GLU_OUT_OF_MEMORY;
183 }
184
185
186 /*
187 * Unpack the pixel data and convert to floating point
188 */
189
190 if (unpackrowlength > 0) {
191 rowlen = unpackrowlength;
192 }
193 else {
194 rowlen = widthin;
195 }
196 if (sizein >= unpackalignment) {
197 rowstride = components * rowlen;
198 }
199 else {
200 rowstride = unpackalignment / sizein
201 * CEILING(components * rowlen * sizein, unpackalignment);
202 }
203
204 switch (typein) {
205 case GL_UNSIGNED_BYTE:
206 k = 0;
207 for (i = 0; i < heightin; i++) {
208 GLubyte *ubptr = (GLubyte *) datain
209 + i * rowstride
210 + unpackskiprows * rowstride + unpackskippixels * components;
211 for (j = 0; j < widthin * components; j++) {
212 dummy(j, k);
213 tempin[k++] = (GLfloat) * ubptr++;
214 }
215 }
216 break;
217 case GL_BYTE:
218 k = 0;
219 for (i = 0; i < heightin; i++) {
220 GLbyte *bptr = (GLbyte *) datain
221 + i * rowstride
222 + unpackskiprows * rowstride + unpackskippixels * components;
223 for (j = 0; j < widthin * components; j++) {
224 dummy(j, k);
225 tempin[k++] = (GLfloat) * bptr++;
226 }
227 }
228 break;
229 case GL_UNSIGNED_SHORT:
230 k = 0;
231 for (i = 0; i < heightin; i++) {
232 GLushort *usptr = (GLushort *) datain
233 + i * rowstride
234 + unpackskiprows * rowstride + unpackskippixels * components;
235 for (j = 0; j < widthin * components; j++) {
236 dummy(j, k);
237 tempin[k++] = (GLfloat) * usptr++;
238 }
239 }
240 break;
241 case GL_SHORT:
242 k = 0;
243 for (i = 0; i < heightin; i++) {
244 GLshort *sptr = (GLshort *) datain
245 + i * rowstride
246 + unpackskiprows * rowstride + unpackskippixels * components;
247 for (j = 0; j < widthin * components; j++) {
248 dummy(j, k);
249 tempin[k++] = (GLfloat) * sptr++;
250 }
251 }
252 break;
253 case GL_UNSIGNED_INT:
254 k = 0;
255 for (i = 0; i < heightin; i++) {
256 GLuint *uiptr = (GLuint *) datain
257 + i * rowstride
258 + unpackskiprows * rowstride + unpackskippixels * components;
259 for (j = 0; j < widthin * components; j++) {
260 dummy(j, k);
261 tempin[k++] = (GLfloat) * uiptr++;
262 }
263 }
264 break;
265 case GL_INT:
266 k = 0;
267 for (i = 0; i < heightin; i++) {
268 GLint *iptr = (GLint *) datain
269 + i * rowstride
270 + unpackskiprows * rowstride + unpackskippixels * components;
271 for (j = 0; j < widthin * components; j++) {
272 dummy(j, k);
273 tempin[k++] = (GLfloat) * iptr++;
274 }
275 }
276 break;
277 case GL_FLOAT:
278 k = 0;
279 for (i = 0; i < heightin; i++) {
280 GLfloat *fptr = (GLfloat *) datain
281 + i * rowstride
282 + unpackskiprows * rowstride + unpackskippixels * components;
283 for (j = 0; j < widthin * components; j++) {
284 dummy(j, k);
285 tempin[k++] = *fptr++;
286 }
287 }
288 break;
289 default:
290 return GLU_INVALID_ENUM;
291 }
292
293
294 /*
295 * Scale the image!
296 */
297
298 if (widthout > 1)
299 sx = (GLfloat) (widthin - 1) / (GLfloat) (widthout - 1);
300 else
301 sx = (GLfloat) (widthin - 1);
302 if (heightout > 1)
303 sy = (GLfloat) (heightin - 1) / (GLfloat) (heightout - 1);
304 else
305 sy = (GLfloat) (heightin - 1);
306
307 /*#define POINT_SAMPLE*/
308 #ifdef POINT_SAMPLE
309 for (i = 0; i < heightout; i++) {
310 GLint ii = i * sy;
311 for (j = 0; j < widthout; j++) {
312 GLint jj = j * sx;
313
314 GLfloat *src = tempin + (ii * widthin + jj) * components;
315 GLfloat *dst = tempout + (i * widthout + j) * components;
316
317 for (k = 0; k < components; k++) {
318 *dst++ = *src++;
319 }
320 }
321 }
322 #else
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;
326 GLfloat alpha, beta;
327 GLfloat *src00, *src01, *src10, *src11;
328 GLfloat s1, s2;
329 GLfloat *dst;
330
331 for (i = 0; i < heightout; i++) {
332 i0 = i * sy;
333 i1 = i0 + 1;
334 if (i1 >= heightin)
335 i1 = heightin - 1;
336 /* i1 = (i+1) * sy - EPSILON;*/
337 alpha = i * sy - i0;
338 for (j = 0; j < widthout; j++) {
339 j0 = j * sx;
340 j1 = j0 + 1;
341 if (j1 >= widthin)
342 j1 = widthin - 1;
343 /* j1 = (j+1) * sx - EPSILON; */
344 beta = j * sx - j0;
345
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;
351
352 dst = tempout + (i * widthout + j) * components;
353
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;
358 }
359 }
360 }
361 }
362 else {
363 /* shrink width and/or height: use an unweighted box filter */
364 GLint i0, i1;
365 GLint j0, j1;
366 GLint ii, jj;
367 GLfloat sum, *dst;
368
369 for (i = 0; i < heightout; i++) {
370 i0 = i * sy;
371 i1 = i0 + 1;
372 if (i1 >= heightin)
373 i1 = heightin - 1;
374 /* i1 = (i+1) * sy - EPSILON; */
375 for (j = 0; j < widthout; j++) {
376 j0 = j * sx;
377 j1 = j0 + 1;
378 if (j1 >= widthin)
379 j1 = widthin - 1;
380 /* j1 = (j+1) * sx - EPSILON; */
381
382 dst = tempout + (i * widthout + j) * components;
383
384 /* compute average of pixels in the rectangle (i0,j0)-(i1,j1) */
385 for (k = 0; k < components; k++) {
386 sum = 0.0;
387 for (ii = i0; ii <= i1; ii++) {
388 for (jj = j0; jj <= j1; jj++) {
389 sum += *(tempin + (ii * widthin + jj) * components + k);
390 }
391 }
392 sum /= (j1 - j0 + 1) * (i1 - i0 + 1);
393 *dst++ = sum;
394 }
395 }
396 }
397 }
398 #endif
399
400
401 /*
402 * Return output image
403 */
404
405 if (packrowlength > 0) {
406 rowlen = packrowlength;
407 }
408 else {
409 rowlen = widthout;
410 }
411 if (sizeout >= packalignment) {
412 rowstride = components * rowlen;
413 }
414 else {
415 rowstride = packalignment / sizeout
416 * CEILING(components * rowlen * sizeout, packalignment);
417 }
418
419 switch (typeout) {
420 case GL_UNSIGNED_BYTE:
421 k = 0;
422 for (i = 0; i < heightout; i++) {
423 GLubyte *ubptr = (GLubyte *) dataout
424 + i * rowstride
425 + packskiprows * rowstride + packskippixels * components;
426 for (j = 0; j < widthout * components; j++) {
427 dummy(j, k + i);
428 *ubptr++ = (GLubyte) tempout[k++];
429 }
430 }
431 break;
432 case GL_BYTE:
433 k = 0;
434 for (i = 0; i < heightout; i++) {
435 GLbyte *bptr = (GLbyte *) dataout
436 + i * rowstride
437 + packskiprows * rowstride + packskippixels * components;
438 for (j = 0; j < widthout * components; j++) {
439 dummy(j, k + i);
440 *bptr++ = (GLbyte) tempout[k++];
441 }
442 }
443 break;
444 case GL_UNSIGNED_SHORT:
445 k = 0;
446 for (i = 0; i < heightout; i++) {
447 GLushort *usptr = (GLushort *) dataout
448 + i * rowstride
449 + packskiprows * rowstride + packskippixels * components;
450 for (j = 0; j < widthout * components; j++) {
451 dummy(j, k + i);
452 *usptr++ = (GLushort) tempout[k++];
453 }
454 }
455 break;
456 case GL_SHORT:
457 k = 0;
458 for (i = 0; i < heightout; i++) {
459 GLshort *sptr = (GLshort *) dataout
460 + i * rowstride
461 + packskiprows * rowstride + packskippixels * components;
462 for (j = 0; j < widthout * components; j++) {
463 dummy(j, k + i);
464 *sptr++ = (GLshort) tempout[k++];
465 }
466 }
467 break;
468 case GL_UNSIGNED_INT:
469 k = 0;
470 for (i = 0; i < heightout; i++) {
471 GLuint *uiptr = (GLuint *) dataout
472 + i * rowstride
473 + packskiprows * rowstride + packskippixels * components;
474 for (j = 0; j < widthout * components; j++) {
475 dummy(j, k + i);
476 *uiptr++ = (GLuint) tempout[k++];
477 }
478 }
479 break;
480 case GL_INT:
481 k = 0;
482 for (i = 0; i < heightout; i++) {
483 GLint *iptr = (GLint *) dataout
484 + i * rowstride
485 + packskiprows * rowstride + packskippixels * components;
486 for (j = 0; j < widthout * components; j++) {
487 dummy(j, k + i);
488 *iptr++ = (GLint) tempout[k++];
489 }
490 }
491 break;
492 case GL_FLOAT:
493 k = 0;
494 for (i = 0; i < heightout; i++) {
495 GLfloat *fptr = (GLfloat *) dataout
496 + i * rowstride
497 + packskiprows * rowstride + packskippixels * components;
498 for (j = 0; j < widthout * components; j++) {
499 dummy(j, k + i);
500 *fptr++ = tempout[k++];
501 }
502 }
503 break;
504 default:
505 return GLU_INVALID_ENUM;
506 }
507
508
509 /* free temporary image storage */
510 free(tempin);
511 free(tempout);
512
513 return 0;
514 }
515
516
517
518 /*
519 * Return the largest k such that 2^k <= n.
520 */
521 static GLint
522 ilog2(GLint n)
523 {
524 GLint k;
525
526 if (n <= 0)
527 return 0;
528 for (k = 0; n >>= 1; k++);
529 return k;
530 }
531
532
533
534 /*
535 * Find the value nearest to n which is also a power of two.
536 */
537 static GLint
538 round2(GLint n)
539 {
540 GLint m;
541
542 for (m = 1; m < n; m *= 2);
543
544 /* m>=n */
545 if (m - n <= n - m / 2) {
546 return m;
547 }
548 else {
549 return m / 2;
550 }
551 }
552
553
554 /*
555 * Given an pixel format and data type, return the number of bytes to
556 * store one pixel.
557 */
558 static GLint
559 bytes_per_pixel(GLenum format, GLenum type)
560 {
561 GLint n, m;
562
563 switch (format) {
564 case GL_COLOR_INDEX:
565 case GL_STENCIL_INDEX:
566 case GL_DEPTH_COMPONENT:
567 case GL_RED:
568 case GL_GREEN:
569 case GL_BLUE:
570 case GL_ALPHA:
571 case GL_LUMINANCE:
572 n = 1;
573 break;
574 case GL_LUMINANCE_ALPHA:
575 n = 2;
576 break;
577 case GL_RGB:
578 case GL_BGR:
579 n = 3;
580 break;
581 case GL_RGBA:
582 case GL_BGRA:
583 #ifdef GL_EXT_abgr
584 case GL_ABGR_EXT:
585 #endif
586 n = 4;
587 break;
588 default:
589 n = 0;
590 }
591
592 switch (type) {
593 case GL_UNSIGNED_BYTE:
594 m = sizeof(GLubyte);
595 break;
596 case GL_BYTE:
597 m = sizeof(GLbyte);
598 break;
599 case GL_BITMAP:
600 m = 1;
601 break;
602 case GL_UNSIGNED_SHORT:
603 m = sizeof(GLushort);
604 break;
605 case GL_SHORT:
606 m = sizeof(GLshort);
607 break;
608 case GL_UNSIGNED_INT:
609 m = sizeof(GLuint);
610 break;
611 case GL_INT:
612 m = sizeof(GLint);
613 break;
614 case GL_FLOAT:
615 m = sizeof(GLfloat);
616 break;
617 default:
618 m = 0;
619 }
620
621 return n * m;
622 }
623
624
625
626 /*
627 * WARNING: This function isn't finished and has never been tested!!!!
628 */
629 GLint GLAPIENTRY
630 gluBuild1DMipmaps(GLenum target, GLint components,
631 GLsizei width, GLenum format, GLenum type, const void *data)
632 {
633 return 0;
634 }
635
636
637
638 GLint GLAPIENTRY
639 gluBuild2DMipmaps(GLenum target, GLint components,
640 GLsizei width, GLsizei height, GLenum format,
641 GLenum type, const void *data)
642 {
643 GLint w, h;
644 GLint maxsize;
645 void *image, *newimage;
646 GLint neww, newh, level, bpp;
647 int error;
648 GLboolean done;
649 GLint retval = 0;
650 GLint unpackrowlength, unpackalignment, unpackskiprows, unpackskippixels;
651 GLint packrowlength, packalignment, packskiprows, packskippixels;
652 GLfloat f;
653
654 if (width < 1 || height < 1)
655 return GLU_INVALID_VALUE;
656
657 glGetFloatv(GL_MAX_TEXTURE_SIZE, &f); maxsize = (int)f;
658
659 w = round2(width);
660 if (w > maxsize) {
661 w = maxsize;
662 }
663 h = round2(height);
664 if (h > maxsize) {
665 h = maxsize;
666 }
667
668 bpp = bytes_per_pixel(format, type);
669 if (bpp == 0) {
670 /* probably a bad format or type enum */
671 return GLU_INVALID_ENUM;
672 }
673
674 /* Get current glPixelStore values */
675 glGetFloatv(GL_UNPACK_ROW_LENGTH, &f); unpackrowlength = (int)f;
676 glGetFloatv(GL_UNPACK_ALIGNMENT, &f); unpackalignment = (int)f;
677 glGetFloatv(GL_UNPACK_SKIP_ROWS, &f); unpackskiprows = (int)f;
678 glGetFloatv(GL_UNPACK_SKIP_PIXELS, &f); unpackskippixels = (int)f;
679 glGetFloatv(GL_PACK_ROW_LENGTH, &f); packrowlength = (int)f;
680 glGetFloatv(GL_PACK_ALIGNMENT, &f); packalignment = (int)f;
681 glGetFloatv(GL_PACK_SKIP_ROWS, &f); packskiprows = (int)f;
682 glGetFloatv(GL_PACK_SKIP_PIXELS, &f); packskippixels = (int)f;
683
684 /* set pixel packing */
685 glPixelStorei(GL_PACK_ROW_LENGTH, 0);
686 glPixelStorei(GL_PACK_ALIGNMENT, 1);
687 glPixelStorei(GL_PACK_SKIP_ROWS, 0);
688 glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
689
690 done = GL_FALSE;
691
692 if (w != width || h != height) {
693 /* must rescale image to get "top" mipmap texture image */
694 image = malloc((w + 4) * h * bpp);
695 if (!image) {
696 return GLU_OUT_OF_MEMORY;
697 }
698 error = gluScaleImage(format, width, height, type, data,
699 w, h, type, image);
700 if (error) {
701 retval = error;
702 done = GL_TRUE;
703 }
704 }
705 else {
706 image = (void *) data;
707 }
708
709 level = 0;
710 while (!done) {
711 if (image != data) {
712 /* set pixel unpacking */
713 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
714 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
715 glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
716 glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
717 }
718
719 glTexImage2D(target, level, components, w, h, 0, format, type, image);
720
721 if (w == 1 && h == 1)
722 break;
723
724 neww = (w < 2) ? 1 : w / 2;
725 newh = (h < 2) ? 1 : h / 2;
726 newimage = malloc((neww + 4) * newh * bpp);
727 if (!newimage) {
728 return GLU_OUT_OF_MEMORY;
729 }
730
731 error = gluScaleImage(format, w, h, type, image,
732 neww, newh, type, newimage);
733 if (error) {
734 retval = error;
735 done = GL_TRUE;
736 }
737
738 if (image != data) {
739 free(image);
740 }
741 image = newimage;
742
743 w = neww;
744 h = newh;
745 level++;
746 }
747
748 if (image != data) {
749 free(image);
750 }
751
752 /* Restore original glPixelStore state */
753 glPixelStorei(GL_UNPACK_ROW_LENGTH, unpackrowlength);
754 glPixelStorei(GL_UNPACK_ALIGNMENT, unpackalignment);
755 glPixelStorei(GL_UNPACK_SKIP_ROWS, unpackskiprows);
756 glPixelStorei(GL_UNPACK_SKIP_PIXELS, unpackskippixels);
757 glPixelStorei(GL_PACK_ROW_LENGTH, packrowlength);
758 glPixelStorei(GL_PACK_ALIGNMENT, packalignment);
759 glPixelStorei(GL_PACK_SKIP_ROWS, packskiprows);
760 glPixelStorei(GL_PACK_SKIP_PIXELS, packskippixels);
761
762 return retval;
763 }