2
* SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3
* Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
5
* Permission is hereby granted, free of charge, to any person obtaining a
6
* copy of this software and associated documentation files (the "Software"),
7
* to deal in the Software without restriction, including without limitation
8
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
* and/or sell copies of the Software, and to permit persons to whom the
10
* Software is furnished to do so, subject to the following conditions:
12
* The above copyright notice including the dates of first publication and
13
* either this permission notice or a reference to
14
* http://oss.sgi.com/projects/FreeB/
15
* shall be included in all copies or substantial portions of the Software.
17
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20
* SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
* Except as contained in this notice, the name of Silicon Graphics, Inc.
26
* shall not be used in advertising or otherwise to promote the sale, use or
27
* other dealings in this Software without prior written authorization from
28
* Silicon Graphics, Inc.
30
* OpenGL ES CM 1.0 port of part of GLUES by Mike Gorchak <mike@malva.ua>
37
#include <limits.h> /* UINT_MAX */
45
#include "glues_mipmap.h"
58
/* Pixel storage modes */
62
GLint pack_row_length;
64
GLint pack_skip_pixels;
65
GLint pack_swap_bytes;
66
GLint pack_image_height;
68
GLint unpack_alignment;
69
GLint unpack_row_length;
70
GLint unpack_skip_rows;
71
GLint unpack_skip_pixels;
72
GLint unpack_swap_bytes;
73
GLint unpack_image_height;
76
static int gluesBuild2DMipmapLevelsCore(GLenum, GLint, GLsizei, GLsizei,
77
GLsizei, GLsizei, GLenum, GLenum,
78
GLint, GLint, GLint, const void*);
81
* internal function declarations
83
static GLfloat bytes_per_element(GLenum type);
84
static GLint elements_per_group(GLenum format, GLenum type);
85
static GLint image_size(GLint width, GLint height, GLenum format, GLenum type);
87
static void scale_internal_ubyte(GLint components, GLint widthin,
88
GLint heightin, const GLubyte* datain,
89
GLint widthout, GLint heightout,
90
GLubyte* dataout, GLint element_size,
91
GLint ysize, GLint group_size);
93
static int checkMipmapArgs(GLenum, GLenum, GLenum);
94
static GLboolean legalFormat(GLenum);
95
static GLboolean legalType(GLenum);
96
static GLboolean isTypePackedPixel(GLenum);
97
static GLboolean isLegalFormatForPackedPixelType(GLenum, GLenum);
98
static GLboolean isLegalLevels(GLint, GLint, GLint, GLint);
99
static void closestFit(GLenum, GLint, GLint, GLint, GLenum, GLenum,
102
/* packedpixel type scale routines */
103
static void extract565(int, const void*, GLfloat []);
104
static void shove565(const GLfloat [], int ,void*);
105
static void extract4444(int, const void*, GLfloat []);
106
static void shove4444(const GLfloat [], int ,void*);
107
static void extract5551(int, const void*, GLfloat []);
108
static void shove5551(const GLfloat [], int ,void*);
109
static void scaleInternalPackedPixel(int,
110
void (*)(int, const void*,GLfloat []),
111
void (*)(const GLfloat [],int, void*),
112
GLint,GLint, const void*,
113
GLint,GLint,void*,GLint,GLint,GLint);
114
static void halveImagePackedPixel(int,
115
void (*)(int, const void*,GLfloat []),
116
void (*)(const GLfloat [],int, void*),
117
GLint, GLint, const void*,
118
void*, GLint, GLint, GLint);
119
static void halve1DimagePackedPixel(int,
120
void (*)(int, const void*,GLfloat []),
121
void (*)(const GLfloat [],int, void*),
122
GLint, GLint, const void*,
123
void*, GLint, GLint, GLint);
125
static void halve1Dimage_ubyte(GLint, GLuint, GLuint,const GLubyte*,
126
GLubyte*, GLint, GLint, GLint);
128
static void retrieveStoreModes(PixelStorageModes* psm)
130
psm->unpack_alignment=1;
131
psm->unpack_row_length=0;
132
psm->unpack_skip_rows=0;
133
psm->unpack_skip_pixels=0;
134
psm->unpack_swap_bytes=0;
136
psm->pack_alignment=1;
137
psm->pack_row_length=0;
138
psm->pack_skip_rows=0;
139
psm->pack_skip_pixels=0;
140
psm->pack_swap_bytes=0;
143
static int computeLog(GLuint value)
170
** Compute the nearest power of 2 number. This algorithm is a little
171
** strange, but it works quite well.
173
static int nearestPower(GLuint value)
201
#define __GLUES_SWAP_2_BYTES(s)\
202
(GLushort)(((GLushort)((const GLubyte*)(s))[1])<<8 | ((const GLubyte*)(s))[0])
204
#define __GLUES_SWAP_4_BYTES(s)\
205
(GLuint)(((GLuint)((const GLubyte*)(s))[3])<<24 | \
206
((GLuint)((const GLubyte*)(s))[2])<<16 | \
207
((GLuint)((const GLubyte*)(s))[1])<<8 | ((const GLubyte*)(s))[0])
209
static void halveImage_ubyte(GLint components, GLuint width, GLuint height,
210
const GLubyte* datain, GLubyte* dataout,
211
GLint element_size, GLint ysize, GLint group_size)
214
int newwidth, newheight;
219
/* handle case where there is only 1 column/row */
220
if (width==1 || height==1)
222
assert(!(width==1 && height==1) ); /* can't be 1x1 */
223
halve1Dimage_ubyte(components, width, height, datain, dataout, element_size, ysize, group_size);
229
padBytes=ysize-(width*group_size);
231
t=(const char*)datain;
234
for (i=0; i<newheight; i++)
236
for (j=0; j<newwidth; j++)
238
for (k=0; k<components; k++)
240
s[0]=(*(const GLubyte*)t+
241
*(const GLubyte*)(t+group_size)+
242
*(const GLubyte*)(t+ysize)+
243
*(const GLubyte*)(t+ysize+group_size)+2)/4;
244
s++; t+=element_size;
254
static void halve1Dimage_ubyte(GLint components, GLuint width, GLuint height,
255
const GLubyte* dataIn, GLubyte* dataOut,
256
GLint element_size, GLint ysize,
259
GLint halfWidth=width/2;
260
GLint halfHeight=height/2;
261
const char* src=(const char*)dataIn;
262
GLubyte* dest=dataOut;
265
assert(width==1 || height==1); /* must be 1D */
266
assert(width!=height); /* can't be square */
270
assert(width!=1); /* widthxheight can't be 1x1 */
273
for (jj=0; jj<halfWidth; jj++)
276
for (kk=0; kk<components; kk++)
278
*dest=(*(const GLubyte*)src+
279
*(const GLubyte*)(src+group_size))/2;
284
src+=group_size; /* skip to next 2 */
287
int padBytes=ysize-(width*group_size);
288
src+=padBytes; /* for assertion only */
295
int padBytes=ysize-(width*group_size);
296
assert(height!=1); /* widthxheight can't be 1x1 */
299
/* one vertical column with possible pad bytes per row */
300
/* average two at a time */
301
for (jj=0; jj<halfHeight; jj++)
305
for (kk=0; kk<components; kk++)
307
*dest=(*(const GLubyte*)src+*(const GLubyte*)(src+ysize))/2;
312
src+=padBytes; /* add pad bytes, if any, to get to end to row */
318
assert(src==&((const char*)dataIn)[ysize*height]);
319
assert((char*)dest==&((char*)dataOut)[components*element_size*halfWidth*halfHeight]);
320
} /* halve1Dimage_ubyte() */
323
static void scale_internal_ubyte(GLint components, GLint widthin,
324
GLint heightin, const GLubyte* datain,
325
GLint widthout, GLint heightout,
326
GLubyte* dataout, GLint element_size,
327
GLint ysize, GLint group_size)
333
/* Max components in a format is 4, so... */
340
const char* temp_index;
343
int lowx_int, highx_int, lowy_int, highy_int;
344
float x_percent, y_percent;
345
float lowx_float, highx_float, lowy_float, highy_float;
346
float convy_float, convx_float;
347
int convy_int, convx_int;
352
if (widthin==widthout*2 && heightin==heightout*2)
354
halveImage_ubyte(components, widthin, heightin, (const GLubyte*)datain,
355
(GLubyte*)dataout, element_size, ysize, group_size);
359
convy=(float)heightin/heightout;
360
convx=(float)widthin/widthout;
361
convy_int=(int)floor(convy);
362
convy_float=convy-convy_int;
363
convx_int=(int)floor(convx);
364
convx_float=convx-convx_int;
371
highy_float=convy_float;
373
for (i=0; i<heightout; i++)
375
/* Clamp here to be sure we don't read beyond input buffer. */
376
if (highy_int>=heightin)
378
highy_int=heightin-1;
382
highx_int = convx_int;
383
highx_float = convx_float;
385
for (j=0; j<widthout; j++)
388
** Ok, now apply box filter to box that goes from (lowx, lowy)
389
** to (highx, highy) on input data into this pixel on output
392
totals[0] = totals[1] = totals[2] = totals[3] = 0.0;
394
/* calculate the value for pixels in the 1st row */
395
xindex=lowx_int*group_size;
396
if ((highy_int>lowy_int) && (highx_int>lowx_int))
398
y_percent=1-lowy_float;
399
temp=(const char*)datain+xindex+lowy_int*ysize;
400
percent=y_percent*(1-lowx_float);
401
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
403
totals[k]+=(GLubyte)(*(temp_index))*percent;
407
for(l=lowx_int+1; l<highx_int; l++)
410
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
412
totals[k]+=(GLubyte)(*(temp_index))*y_percent;
418
percent=y_percent*highx_float;
419
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
421
totals[k]+=(GLubyte)(*(temp_index))*percent;
424
/* calculate the value for pixels in the last row */
425
y_percent=highy_float;
426
percent=y_percent*(1-lowx_float);
427
temp=(const char*)datain+xindex+highy_int*ysize;
428
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
430
totals[k]+=(GLubyte)(*(temp_index))*percent;
432
for (l=lowx_int+1; l<highx_int; l++)
435
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
437
totals[k]+=(GLubyte)(*(temp_index))*y_percent;
441
percent=y_percent*highx_float;
442
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
444
totals[k]+=(GLubyte)(*(temp_index))*percent;
447
/* calculate the value for pixels in the 1st and last column */
448
for (m=lowy_int+1; m<highy_int; m++)
452
for (k=0; k<components; k++, left+=element_size, right+=element_size)
454
totals[k]+=(GLubyte)(*(left))*(1-lowx_float)+(GLubyte)(*(right))*highx_float;
460
if (highy_int>lowy_int)
462
x_percent=highx_float-lowx_float;
463
percent=(1-lowy_float)*x_percent;
464
temp=(const char*)datain+xindex+lowy_int*ysize;
465
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
467
totals[k]+=(GLubyte)(*(temp_index))*percent;
469
for (m=lowy_int+1; m<highy_int; m++)
472
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
474
totals[k]+=(GLubyte)(*(temp_index))*x_percent;
477
percent = x_percent * highy_float;
479
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
481
totals[k]+=(GLubyte)(*(temp_index))*percent;
486
if (highx_int>lowx_int)
488
y_percent=highy_float-lowy_float;
489
percent=(1-lowx_float)*y_percent;
490
temp=(const char*)datain+xindex+lowy_int*ysize;
491
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
493
totals[k]+=(GLubyte)(*(temp_index))*percent;
495
for (l=lowx_int+1; l<highx_int; l++)
498
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
500
totals[k]+=(GLubyte)(*(temp_index))*y_percent;
504
percent=y_percent*highx_float;
505
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
507
totals[k] += (GLubyte)(*(temp_index)) * percent;
512
percent=(highy_float-lowy_float)*(highx_float-lowx_float);
513
temp=(const char*)datain+xindex+lowy_int*ysize;
514
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
516
totals[k]+=(GLubyte)(*(temp_index))*percent;
522
/* this is for the pixels in the body */
523
temp0=(const char*)datain+xindex+group_size+(lowy_int+1)*ysize;
524
for (m=lowy_int+1; m<highy_int; m++)
527
for(l=lowx_int+1; l<highx_int; l++)
529
for (k=0, temp_index=temp; k<components; k++, temp_index+=element_size)
531
totals[k]+=(GLubyte)(*(temp_index));
538
outindex=(j+(i*widthout))*components;
539
for (k=0; k<components; k++)
541
dataout[outindex+k]=(GLubyte)(totals[k]/area);
544
lowx_float=highx_float;
545
highx_int += convx_int;
546
highx_float += convx_float;
554
lowy_float=highy_float;
555
highy_int+=convy_int;
556
highy_float+=convy_float;
565
static int checkMipmapArgs(GLenum internalFormat, GLenum format, GLenum type)
567
if (!legalFormat(format) || !legalType(type))
569
return GLUES_INVALID_ENUM;
572
if (!isLegalFormatForPackedPixelType(format, type))
574
return GLUES_INVALID_OPERATION;
578
} /* checkMipmapArgs() */
580
static GLboolean legalFormat(GLenum format)
588
case GL_LUMINANCE_ALPHA:
595
static GLboolean legalType(GLenum type)
599
case GL_UNSIGNED_BYTE:
600
case GL_UNSIGNED_SHORT_5_6_5:
601
case GL_UNSIGNED_SHORT_4_4_4_4:
602
case GL_UNSIGNED_SHORT_5_5_5_1:
610
static GLboolean isTypePackedPixel(GLenum type)
612
assert(legalType(type));
614
if (type==GL_UNSIGNED_SHORT_5_6_5 ||
615
type==GL_UNSIGNED_SHORT_4_4_4_4 ||
616
type==GL_UNSIGNED_SHORT_5_5_5_1)
624
} /* isTypePackedPixel() */
626
/* Determines if the packed pixel type is compatible with the format */
627
static GLboolean isLegalFormatForPackedPixelType(GLenum format, GLenum type)
629
/* if not a packed pixel type then return true */
630
if (!isTypePackedPixel(type))
635
/* 5_6_5 is only compatible with RGB */
636
if ((type==GL_UNSIGNED_SHORT_5_6_5) && format!=GL_RGB)
642
* are only compatible with RGBA
644
if ((type==GL_UNSIGNED_SHORT_4_4_4_4 || type==GL_UNSIGNED_SHORT_5_5_5_1) &&
651
} /* isLegalFormatForPackedPixelType() */
653
static GLboolean isLegalLevels(GLint userLevel,GLint baseLevel,GLint maxLevel,
656
if (baseLevel < 0 || baseLevel < userLevel || maxLevel < baseLevel ||
657
totalLevels < maxLevel)
665
} /* isLegalLevels() */
667
/* Given user requested texture size, determine if it fits. If it
668
* doesn't then halve both sides and make the determination again
669
* until it does fit (for IR only).
671
static void closestFit(GLenum target, GLint width, GLint height,
672
GLint internalFormat, GLenum format, GLenum type,
673
GLint *newWidth, GLint *newHeight)
677
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
679
/* clamp user's texture sizes to maximum sizes, if necessary */
680
*newWidth=nearestPower(width);
681
if (*newWidth>maxsize)
685
*newHeight=nearestPower(height);
686
if (*newHeight>maxsize)
688
*newHeight = maxsize;
693
/* To make swapping images less error prone */
694
#define __GLUES_INIT_SWAP_IMAGE void* tmpImage
695
#define __GLUES_SWAP_IMAGE(a,b) tmpImage=a; a=b; b=tmpImage;
697
static int gluesBuild2DMipmapLevelsCore(GLenum target, GLint internalFormat,
698
GLsizei width, GLsizei height,
699
GLsizei widthPowerOf2,
700
GLsizei heightPowerOf2,
701
GLenum format, GLenum type,
703
GLint baseLevel,GLint maxLevel,
706
GLint newwidth, newheight;
708
const void* usersImage; /* passed from user. Don't touch! */
710
void* dstImage; /* scratch area to build mipmapped images */
711
__GLUES_INIT_SWAP_IMAGE;
715
GLint myswap_bytes, groups_per_line, element_size, group_size;
716
GLint rowsize, padding;
717
PixelStorageModes psm;
719
assert(checkMipmapArgs(internalFormat,format,type)==0);
720
assert(width>=1 && height>=1);
722
srcImage=dstImage=NULL;
724
newwidth=widthPowerOf2;
725
newheight=heightPowerOf2;
726
levels=computeLog(newwidth);
727
level=computeLog(newheight);
735
retrieveStoreModes(&psm);
736
myswap_bytes=psm.unpack_swap_bytes;
737
cmpts=elements_per_group(format,type);
738
if (psm.unpack_row_length>0)
740
groups_per_line=psm.unpack_row_length;
744
groups_per_line=width;
747
element_size=(GLint)bytes_per_element(type);
748
group_size=element_size*cmpts;
751
/* Nothing to swap */
755
rowsize=groups_per_line*group_size;
756
padding=(rowsize%psm.unpack_alignment);
759
rowsize+=psm.unpack_alignment-padding;
761
usersImage=(const GLubyte*)data+psm.unpack_skip_rows*rowsize+psm.unpack_skip_pixels*group_size;
765
/* already power-of-two square */
766
if (width==newwidth && height==newheight)
768
/* Use usersImage for level userLevel */
769
if (baseLevel<=level && level<=maxLevel)
771
glTexImage2D(target, level, internalFormat, width,
772
height, 0, format, type, usersImage);
776
/* we're done. clean up and return */
777
glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
782
int nextWidth=newwidth/2;
783
int nextHeight=newheight/2;
794
memreq=image_size(nextWidth, nextHeight, format, type);
799
case GL_UNSIGNED_BYTE:
800
dstImage = (GLubyte *)malloc(memreq);
802
case GL_UNSIGNED_SHORT_5_6_5:
803
case GL_UNSIGNED_SHORT_4_4_4_4:
804
case GL_UNSIGNED_SHORT_5_5_5_1:
805
dstImage = (GLushort *)malloc(memreq);
808
return GLUES_INVALID_ENUM;
812
glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
813
return GLUES_OUT_OF_MEMORY;
819
case GL_UNSIGNED_BYTE:
820
halveImage_ubyte(cmpts, width, height, (const GLubyte*)usersImage,
821
(GLubyte*)dstImage, element_size, rowsize, group_size);
823
case GL_UNSIGNED_SHORT_5_6_5:
824
halveImagePackedPixel(3, extract565, shove565, width, height,
825
usersImage, dstImage, element_size,
826
rowsize, myswap_bytes);
828
case GL_UNSIGNED_SHORT_4_4_4_4:
829
halveImagePackedPixel(4, extract4444, shove4444, width, height,
830
usersImage, dstImage, element_size,
831
rowsize, myswap_bytes);
833
case GL_UNSIGNED_SHORT_5_5_5_1:
834
halveImagePackedPixel(4, extract5551, shove5551, width, height,
835
usersImage, dstImage, element_size,
836
rowsize, myswap_bytes);
858
rowsize=newwidth*group_size;
859
memreq=image_size(newwidth, newheight, format, type);
860
/* Swap srcImage and dstImage */
861
__GLUES_SWAP_IMAGE(srcImage,dstImage);
864
case GL_UNSIGNED_BYTE:
865
dstImage=(GLubyte*)malloc(memreq);
867
case GL_UNSIGNED_SHORT_5_6_5:
868
case GL_UNSIGNED_SHORT_4_4_4_4:
869
case GL_UNSIGNED_SHORT_5_5_5_1:
870
dstImage=(GLushort*)malloc(memreq);
873
return GLUES_INVALID_ENUM;
877
glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
878
return GLUES_OUT_OF_MEMORY;
881
/* level userLevel+1 is in srcImage; level userLevel already saved */
886
/* user's image is *not* nice power-of-2 sized square */
887
memreq=image_size(newwidth, newheight, format, type);
890
case GL_UNSIGNED_BYTE:
891
dstImage=(GLubyte*)malloc(memreq);
893
case GL_UNSIGNED_SHORT_5_6_5:
894
case GL_UNSIGNED_SHORT_4_4_4_4:
895
case GL_UNSIGNED_SHORT_5_5_5_1:
896
dstImage=(GLushort*)malloc(memreq);
899
return GLUES_INVALID_ENUM;
904
glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
905
return GLUES_OUT_OF_MEMORY;
910
case GL_UNSIGNED_BYTE:
911
scale_internal_ubyte(cmpts, width, height,
912
(const GLubyte*)usersImage, newwidth, newheight,
913
(GLubyte*)dstImage, element_size, rowsize, group_size);
915
case GL_UNSIGNED_SHORT_5_6_5:
916
scaleInternalPackedPixel(3, extract565, shove565, width, height,
917
usersImage, newwidth, newheight, (void*)dstImage, element_size,
918
rowsize, myswap_bytes);
920
case GL_UNSIGNED_SHORT_4_4_4_4:
921
scaleInternalPackedPixel(4, extract4444, shove4444, width, height,
922
usersImage, newwidth, newheight, (void*)dstImage, element_size,
923
rowsize,myswap_bytes);
925
case GL_UNSIGNED_SHORT_5_5_5_1:
926
scaleInternalPackedPixel(4,extract5551, shove5551, width, height,
927
usersImage, newwidth, newheight, (void*)dstImage, element_size,
928
rowsize, myswap_bytes);
935
rowsize=newwidth*group_size;
937
/* Swap dstImage and srcImage */
938
__GLUES_SWAP_IMAGE(srcImage,dstImage);
940
/* use as little memory as possible */
944
int nextWidth=newwidth/2;
945
int nextHeight=newheight/2;
956
memreq=image_size(nextWidth, nextHeight, format, type);
961
case GL_UNSIGNED_BYTE:
962
dstImage = (GLubyte *)malloc(memreq);
964
case GL_UNSIGNED_SHORT_5_6_5:
965
case GL_UNSIGNED_SHORT_4_4_4_4:
966
case GL_UNSIGNED_SHORT_5_5_5_1:
967
dstImage = (GLushort *)malloc(memreq);
970
return GLUES_INVALID_ENUM;
974
glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
975
return GLUES_OUT_OF_MEMORY;
979
/* level userLevel is in srcImage; nothing saved yet */
983
if (baseLevel<=level && level<=maxLevel)
985
glTexImage2D(target, level, internalFormat, newwidth, newheight, 0,
986
format, type, (void*)srcImage);
989
level++; /* update current level for the loop */
990
for (; level<=levels; level++)
994
case GL_UNSIGNED_BYTE:
995
halveImage_ubyte(cmpts, newwidth, newheight, (GLubyte*)srcImage,
996
(GLubyte *)dstImage, element_size, rowsize, group_size);
998
case GL_UNSIGNED_SHORT_5_6_5:
999
halveImagePackedPixel(3, extract565, shove565, newwidth,
1000
newheight, srcImage, dstImage, element_size, rowsize,
1003
case GL_UNSIGNED_SHORT_4_4_4_4:
1004
halveImagePackedPixel(4, extract4444, shove4444, newwidth,
1005
newheight, srcImage, dstImage, element_size, rowsize,
1008
case GL_UNSIGNED_SHORT_5_5_5_1:
1009
halveImagePackedPixel(4, extract5551, shove5551, newwidth,
1010
newheight, srcImage, dstImage, element_size, rowsize,
1018
__GLUES_SWAP_IMAGE(srcImage,dstImage);
1031
/* compute amount to pad per row, if any */
1032
int rowPad=rowsize%psm.unpack_alignment;
1034
/* should row be padded? */
1036
{ /* nope, row should not be padded */
1037
/* call tex image with srcImage untouched since it's not padded */
1038
if (baseLevel<=level && level<=maxLevel)
1040
glTexImage2D(target, level, internalFormat, newwidth, newheight,
1041
0, format, type, (void*) srcImage);
1045
{ /* yes, row should be padded */
1046
/* compute length of new row in bytes, including padding */
1047
int newRowLength=rowsize+psm.unpack_alignment-rowPad;
1049
unsigned char* dstTrav;
1050
unsigned char* srcTrav; /* indices for copying */
1052
/* allocate new image for mipmap of size newRowLength x newheight */
1053
void* newMipmapImage=malloc((size_t)(newRowLength*newheight));
1054
if (newMipmapImage==NULL)
1056
/* out of memory so return */
1057
glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
1058
return GLUES_OUT_OF_MEMORY;
1061
/* copy image from srcImage into newMipmapImage by rows */
1063
dstTrav=(unsigned char*) newMipmapImage,
1064
srcTrav=(unsigned char*) srcImage;
1066
ii++, dstTrav+= newRowLength, /* make sure the correct distance... */
1068
{ /* ...is skipped */
1069
memcpy(dstTrav, srcTrav, rowsize);
1070
/* note that the pad bytes are not visited and will contain
1071
* garbage, which is ok.
1074
/* ...and use this new image for mipmapping instead */
1075
if (baseLevel<=level && level<=maxLevel)
1077
glTexImage2D(target, level, internalFormat, newwidth, newheight,
1078
0, format, type, newMipmapImage);
1080
free(newMipmapImage); /* don't forget to free it! */
1085
glPixelStorei(GL_UNPACK_ALIGNMENT, psm.unpack_alignment);
1087
free(srcImage); /*if you get to here, a srcImage has always been malloc'ed*/
1090
{ /* if it's non-rectangular and only 1 level */
1095
} /* gluesBuild2DMipmapLevelsCore() */
1098
gluesBuild2DMipmapLevels(GLenum target, GLint internalFormat,
1099
GLsizei width, GLsizei height, GLenum format,
1100
GLenum type, GLint userLevel, GLint baseLevel,
1101
GLint maxLevel, const void* data)
1105
int rc=checkMipmapArgs(internalFormat,format,type);
1112
if (width<1 || height<1)
1114
return GLUES_INVALID_VALUE;
1117
levels=computeLog(width);
1118
level=computeLog(height);
1125
if (!isLegalLevels(userLevel, baseLevel, maxLevel, levels))
1127
return GLUES_INVALID_VALUE;
1130
return gluesBuild2DMipmapLevelsCore(target, internalFormat, width, height,
1131
width, height, format, type,
1132
userLevel, baseLevel, maxLevel, data);
1133
} /* gluesBuild2DMipmapLevels() */
1135
GLint gluesBuild2DMipmaps(GLenum target, GLint internalFormat, GLsizei width,
1136
GLsizei height, GLenum format, GLenum type, const void* data)
1138
GLint widthPowerOf2, heightPowerOf2;
1141
int rc=checkMipmapArgs(internalFormat,format,type);
1147
if (width<1 || height<1)
1149
return GLUES_INVALID_VALUE;
1152
closestFit(target, width, height, internalFormat, format, type,
1153
&widthPowerOf2,&heightPowerOf2);
1155
levels=computeLog(widthPowerOf2);
1156
level=computeLog(heightPowerOf2);
1162
return gluesBuild2DMipmapLevelsCore(target,internalFormat, width, height,
1163
widthPowerOf2, heightPowerOf2, format,
1164
type, 0, 0, levels, data);
1165
} /* gluesBuild2DMipmaps() */
1170
static GLint elements_per_group(GLenum format, GLenum type)
1173
* Return the number of elements per group of a specified format
1176
/* If the type is packedpixels then answer is 1 (ignore format) */
1177
if (type==GL_UNSIGNED_SHORT_5_6_5 ||
1178
type==GL_UNSIGNED_SHORT_4_4_4_4 ||
1179
type==GL_UNSIGNED_SHORT_5_5_5_1)
1184
/* Types are not packed pixels, so get elements per group */
1189
case GL_LUMINANCE_ALPHA:
1198
static GLfloat bytes_per_element(GLenum type)
1201
* Return the number of bytes per element, based on the element type
1205
case GL_UNSIGNED_BYTE:
1206
return(sizeof(GLubyte));
1207
case GL_UNSIGNED_SHORT_5_6_5:
1208
case GL_UNSIGNED_SHORT_4_4_4_4:
1209
case GL_UNSIGNED_SHORT_5_5_5_1:
1210
return(sizeof(GLushort));
1217
** Compute memory required for internal packed array of data of given type
1220
static GLint image_size(GLint width, GLint height, GLenum format, GLenum type)
1227
components=elements_per_group(format, type);
1229
bytes_per_row=(int)(bytes_per_element(type)*width);
1231
return bytes_per_row*height*components;
1235
/*--------------------------------------------------------------------------
1236
* Decimation of packed pixel types
1237
*--------------------------------------------------------------------------
1239
static void extract565(int isSwap, const void* packedPixel, GLfloat extractComponents[])
1241
GLushort ushort=*(const GLushort*)packedPixel;
1245
ushort=__GLUES_SWAP_2_BYTES(packedPixel);
1249
ushort=*(const GLushort*)packedPixel;
1252
/* 11111000,00000000 == 0xf800 */
1253
/* 00000111,11100000 == 0x07e0 */
1254
/* 00000000,00011111 == 0x001f */
1256
extractComponents[0]=(float)((ushort&0xf800)>>11)/31.0f; /* 31 = 2^5-1*/
1257
extractComponents[1]=(float)((ushort&0x07e0)>>5)/63.0f; /* 63 = 2^6-1*/
1258
extractComponents[2]=(float)((ushort&0x001f))/31.0f;
1259
} /* extract565() */
1261
static void shove565(const GLfloat shoveComponents[], int index, void* packedPixel)
1263
/* 11111000,00000000 == 0xf800 */
1264
/* 00000111,11100000 == 0x07e0 */
1265
/* 00000000,00011111 == 0x001f */
1267
assert(0.0<=shoveComponents[0] && shoveComponents[0]<=1.0);
1268
assert(0.0<=shoveComponents[1] && shoveComponents[1]<=1.0);
1269
assert(0.0<=shoveComponents[2] && shoveComponents[2]<=1.0);
1271
/* due to limited precision, need to round before shoving */
1272
((GLushort*)packedPixel)[index]=((GLushort)((shoveComponents[0]*31)+0.5)<<11)&0xf800;
1273
((GLushort*)packedPixel)[index]|=((GLushort)((shoveComponents[1]*63)+0.5)<<5)&0x07e0;
1274
((GLushort*)packedPixel)[index]|=((GLushort)((shoveComponents[2]*31)+0.5))&0x001f;
1277
static void extract4444(int isSwap,const void* packedPixel, GLfloat extractComponents[])
1283
ushort=__GLUES_SWAP_2_BYTES(packedPixel);
1287
ushort=*(const GLushort*)packedPixel;
1290
/* 11110000,00000000 == 0xf000 */
1291
/* 00001111,00000000 == 0x0f00 */
1292
/* 00000000,11110000 == 0x00f0 */
1293
/* 00000000,00001111 == 0x000f */
1295
extractComponents[0]=(float)((ushort&0xf000)>>12)/15.0f;/* 15=2^4-1 */
1296
extractComponents[1]=(float)((ushort&0x0f00)>>8)/15.0f;
1297
extractComponents[2]=(float)((ushort&0x00f0)>>4)/15.0f;
1298
extractComponents[3]=(float)((ushort&0x000f))/15.0f;
1299
} /* extract4444() */
1301
static void shove4444(const GLfloat shoveComponents[], int index,void* packedPixel)
1303
assert(0.0<=shoveComponents[0] && shoveComponents[0]<=1.0);
1304
assert(0.0<=shoveComponents[1] && shoveComponents[1]<=1.0);
1305
assert(0.0<=shoveComponents[2] && shoveComponents[2]<=1.0);
1306
assert(0.0<=shoveComponents[3] && shoveComponents[3]<=1.0);
1308
/* due to limited precision, need to round before shoving */
1309
((GLushort*)packedPixel)[index]=((GLushort)((shoveComponents[0]*15)+0.5)<<12)&0xf000;
1310
((GLushort*)packedPixel)[index]|=((GLushort)((shoveComponents[1]*15)+0.5)<<8)&0x0f00;
1311
((GLushort*)packedPixel)[index]|=((GLushort)((shoveComponents[2]*15)+0.5)<<4)&0x00f0;
1312
((GLushort*)packedPixel)[index]|=((GLushort)((shoveComponents[3]*15)+0.5))&0x000f;
1315
static void extract5551(int isSwap,const void* packedPixel, GLfloat extractComponents[])
1321
ushort=__GLUES_SWAP_2_BYTES(packedPixel);
1325
ushort=*(const GLushort*)packedPixel;
1328
/* 11111000,00000000 == 0xf800 */
1329
/* 00000111,11000000 == 0x07c0 */
1330
/* 00000000,00111110 == 0x003e */
1331
/* 00000000,00000001 == 0x0001 */
1333
extractComponents[0]=(float)((ushort&0xf800)>>11)/31.0f;/* 31 = 2^5-1*/
1334
extractComponents[1]=(float)((ushort&0x07c0)>>6)/31.0f;
1335
extractComponents[2]=(float)((ushort&0x003e)>>1)/31.0f;
1336
extractComponents[3]=(float)((ushort&0x0001));
1337
} /* extract5551() */
1339
static void shove5551(const GLfloat shoveComponents[], int index,void* packedPixel)
1341
/* 11111000,00000000 == 0xf800 */
1342
/* 00000111,11000000 == 0x07c0 */
1343
/* 00000000,00111110 == 0x003e */
1344
/* 00000000,00000001 == 0x0001 */
1346
assert(0.0<=shoveComponents[0] && shoveComponents[0]<=1.0);
1347
assert(0.0<=shoveComponents[1] && shoveComponents[1]<=1.0);
1348
assert(0.0<=shoveComponents[2] && shoveComponents[2]<=1.0);
1349
assert(0.0<=shoveComponents[3] && shoveComponents[3]<=1.0);
1351
/* due to limited precision, need to round before shoving */
1352
((GLushort*)packedPixel)[index]=((GLushort)((shoveComponents[0]*31)+0.5)<<11)&0xf800;
1353
((GLushort*)packedPixel)[index]|=((GLushort)((shoveComponents[1]*31)+0.5)<<6)&0x07c0;
1354
((GLushort*)packedPixel)[index]|=((GLushort)((shoveComponents[2]*31)+0.5)<<1)&0x003e;
1355
((GLushort*)packedPixel)[index]|=((GLushort)((shoveComponents[3])+0.5))&0x0001;
1358
static void scaleInternalPackedPixel(int components,
1359
void (*extractPackedPixel)
1360
(int, const void*,GLfloat []),
1361
void (*shovePackedPixel)
1362
(const GLfloat [], int, void*),
1363
GLint widthIn,GLint heightIn,
1365
GLint widthOut,GLint heightOut,
1367
GLint pixelSizeInBytes,
1368
GLint rowSizeInBytes, GLint isSwap)
1374
/* Max components in a format is 4, so... */
1376
float extractTotals[4], extractMoreTotals[4], shoveTotals[4];
1381
const char *temp, *temp0;
1384
int lowx_int, highx_int, lowy_int, highy_int;
1385
float x_percent, y_percent;
1386
float lowx_float, highx_float, lowy_float, highy_float;
1387
float convy_float, convx_float;
1388
int convy_int, convx_int;
1393
if (widthIn==widthOut*2 && heightIn==heightOut*2)
1395
halveImagePackedPixel(components,extractPackedPixel,shovePackedPixel,
1396
widthIn, heightIn, dataIn, dataOut,
1397
pixelSizeInBytes,rowSizeInBytes,isSwap);
1400
convy=(float)heightIn/heightOut;
1401
convx=(float)widthIn/widthOut;
1402
convy_int=(int)floor(convy);
1403
convy_float=convy-convy_int;
1404
convx_int=(int)floor(convx);
1405
convx_float=convx-convx_int;
1411
highy_int=convy_int;
1412
highy_float=convy_float;
1414
for (i=0; i<heightOut; i++)
1418
highx_int=convx_int;
1419
highx_float=convx_float;
1421
for (j=0; j<widthOut; j++)
1424
** Ok, now apply box filter to box that goes from (lowx, lowy)
1425
** to (highx, highy) on input data into this pixel on output
1428
totals[0]=totals[1]=totals[2]=totals[3]=0.0;
1430
/* calculate the value for pixels in the 1st row */
1431
xindex=lowx_int*pixelSizeInBytes;
1432
if ((highy_int>lowy_int) && (highx_int>lowx_int))
1434
y_percent=1-lowy_float;
1435
temp=(const char*)dataIn+xindex+lowy_int*rowSizeInBytes;
1436
percent=y_percent*(1-lowx_float);
1437
(*extractPackedPixel)(isSwap, temp, extractTotals);
1438
for (k=0; k<components; k++)
1440
totals[k]+=extractTotals[k]*percent;
1443
for (l=lowx_int+1; l<highx_int; l++)
1445
temp+=pixelSizeInBytes;
1446
(*extractPackedPixel)(isSwap, temp, extractTotals);
1447
for (k=0; k<components; k++)
1449
totals[k]+=extractTotals[k]*y_percent;
1452
temp+=pixelSizeInBytes;
1454
percent=y_percent*highx_float;
1455
(*extractPackedPixel)(isSwap, temp, extractTotals);
1456
for (k=0; k<components; k++)
1458
totals[k]+=extractTotals[k]*percent;
1461
/* calculate the value for pixels in the last row */
1462
y_percent=highy_float;
1463
percent=y_percent*(1-lowx_float);
1464
temp=(const char*)dataIn+xindex+highy_int*rowSizeInBytes;
1465
(*extractPackedPixel)(isSwap, temp, extractTotals);
1466
for (k=0; k<components; k++)
1468
totals[k]+=extractTotals[k]*percent;
1470
for (l=lowx_int+1; l<highx_int; l++)
1472
temp+=pixelSizeInBytes;
1473
(*extractPackedPixel)(isSwap, temp, extractTotals);
1474
for (k=0; k<components; k++)
1476
totals[k]+=extractTotals[k]*y_percent;
1479
temp+=pixelSizeInBytes;
1480
percent=y_percent*highx_float;
1481
(*extractPackedPixel)(isSwap, temp, extractTotals);
1482
for (k=0; k<components; k++)
1484
totals[k]+=extractTotals[k]*percent;
1487
/* calculate the value for pixels in the 1st and last column */
1488
for (m=lowy_int+1; m<highy_int; m++)
1490
left+=rowSizeInBytes;
1491
right+=rowSizeInBytes;
1492
(*extractPackedPixel)(isSwap, left, extractTotals);
1493
(*extractPackedPixel)(isSwap, right, extractMoreTotals);
1494
for (k=0; k<components; k++)
1496
totals[k]+=(extractTotals[k]*(1-lowx_float)+extractMoreTotals[k]*highx_float);
1502
if (highy_int>lowy_int)
1504
x_percent=highx_float-lowx_float;
1505
percent=(1-lowy_float)*x_percent;
1506
temp=(const char*)dataIn+xindex+lowy_int*rowSizeInBytes;
1507
(*extractPackedPixel)(isSwap, temp, extractTotals);
1508
for (k=0; k<components; k++)
1510
totals[k]+=extractTotals[k]*percent;
1512
for (m=lowy_int+1; m<highy_int; m++)
1514
temp+=rowSizeInBytes;
1515
(*extractPackedPixel)(isSwap, temp, extractTotals);
1516
for (k=0; k<components; k++)
1518
totals[k]+=extractTotals[k]*x_percent;
1521
percent=x_percent*highy_float;
1522
temp+=rowSizeInBytes;
1523
(*extractPackedPixel)(isSwap, temp, extractTotals);
1524
for (k=0; k<components; k++)
1526
totals[k]+=extractTotals[k]*percent;
1531
if (highx_int > lowx_int)
1533
y_percent=highy_float-lowy_float;
1534
percent=(1-lowx_float)*y_percent;
1535
temp=(const char*)dataIn+xindex+lowy_int*rowSizeInBytes;
1536
(*extractPackedPixel)(isSwap, temp, extractTotals);
1537
for (k=0; k<components; k++)
1539
totals[k]+= extractTotals[k] * percent;
1541
for (l=lowx_int+1; l<highx_int; l++)
1543
temp+=pixelSizeInBytes;
1544
(*extractPackedPixel)(isSwap, temp, extractTotals);
1545
for (k=0; k<components; k++)
1547
totals[k]+=extractTotals[k]*y_percent;
1550
temp+=pixelSizeInBytes;
1551
percent=y_percent*highx_float;
1552
(*extractPackedPixel)(isSwap, temp, extractTotals);
1553
for (k=0; k<components; k++)
1555
totals[k]+=extractTotals[k]*percent;
1560
percent=(highy_float-lowy_float)*(highx_float-lowx_float);
1561
temp=(const char*)dataIn+xindex+lowy_int*rowSizeInBytes;
1562
(*extractPackedPixel)(isSwap, temp, extractTotals);
1563
for (k=0; k<components; k++)
1565
totals[k]+=extractTotals[k]*percent;
1571
/* this is for the pixels in the body */
1572
temp0=(const char*)dataIn+xindex+pixelSizeInBytes+(lowy_int+1)*rowSizeInBytes;
1573
for (m=lowy_int+1; m<highy_int; m++)
1576
for (l=lowx_int+1; l<highx_int; l++)
1578
(*extractPackedPixel)(isSwap, temp, extractTotals);
1579
for (k=0; k<components; k++)
1581
totals[k]+=extractTotals[k];
1583
temp+=pixelSizeInBytes;
1585
temp0 += rowSizeInBytes;
1588
outindex=(j+(i*widthOut));
1589
for (k=0; k<components; k++)
1591
shoveTotals[k]=totals[k]/area;
1593
(*shovePackedPixel)(shoveTotals, outindex, (void*)dataOut);
1595
lowx_float=highx_float;
1596
highx_int+=convx_int;
1597
highx_float+=convx_float;
1605
lowy_float=highy_float;
1606
highy_int+=convy_int;
1607
highy_float+=convy_float;
1616
assert(outindex==(widthOut*heightOut-1));
1617
} /* scaleInternalPackedPixel() */
1619
/* rowSizeInBytes is at least the width (in bytes) due to padding on
1620
* inputs; not always equal. Output NEVER has row padding.
1622
static void halveImagePackedPixel(int components,
1623
void (*extractPackedPixel)
1624
(int, const void*,GLfloat []),
1625
void (*shovePackedPixel)
1626
(const GLfloat [],int, void*),
1627
GLint width, GLint height,
1628
const void* dataIn, void* dataOut,
1629
GLint pixelSizeInBytes,
1630
GLint rowSizeInBytes, GLint isSwap)
1632
/* handle case where there is only 1 column/row */
1633
if (width==1 || height==1)
1635
assert(!(width==1 && height==1)); /* can't be 1x1 */
1636
halve1DimagePackedPixel(components,extractPackedPixel,shovePackedPixel,
1637
width,height,dataIn,dataOut,pixelSizeInBytes,
1638
rowSizeInBytes,isSwap);
1645
int halfWidth=width/2;
1646
int halfHeight=height/2;
1647
const char* src=(const char*)dataIn;
1648
int padBytes=rowSizeInBytes-(width*pixelSizeInBytes);
1651
for (ii=0; ii<halfHeight; ii++)
1653
for (jj=0; jj<halfWidth; jj++)
1656
float totals[4]; /* 4 is maximum components */
1657
float extractTotals[BOX4][4]; /* 4 is maximum components */
1660
(*extractPackedPixel)(isSwap, src, &extractTotals[0][0]);
1661
(*extractPackedPixel)(isSwap, (src+pixelSizeInBytes), &extractTotals[1][0]);
1662
(*extractPackedPixel)(isSwap, (src+rowSizeInBytes), &extractTotals[2][0]);
1663
(*extractPackedPixel)(isSwap, (src+rowSizeInBytes+pixelSizeInBytes), &extractTotals[3][0]);
1664
for (cc=0; cc<components; cc++)
1668
/* grab 4 pixels to average */
1670
for (kk=0; kk<BOX4; kk++)
1672
totals[cc]+=extractTotals[kk][cc];
1674
totals[cc]/=(float)BOX4;
1676
(*shovePackedPixel)(totals, outIndex, dataOut);
1679
/* skip over to next square of 4 */
1680
src+=pixelSizeInBytes+pixelSizeInBytes;
1682
/* skip past pad bytes, if any, to get to next row */
1685
/* src is at beginning of a row here, but it's the second row of
1686
* the square block of 4 pixels that we just worked on so we
1687
* need to go one more row.
1695
src+=rowSizeInBytes;
1698
/* both pointers must reach one byte after the end */
1699
assert(src==&((const char*)dataIn)[rowSizeInBytes*height]);
1700
assert(outIndex==halfWidth*halfHeight);
1702
} /* halveImagePackedPixel() */
1704
static void halve1DimagePackedPixel(int components,
1705
void (*extractPackedPixel)
1706
(int, const void*,GLfloat []),
1707
void (*shovePackedPixel)
1708
(const GLfloat [],int, void*),
1709
GLint width, GLint height,
1710
const void* dataIn, void* dataOut,
1711
GLint pixelSizeInBytes,
1712
GLint rowSizeInBytes, GLint isSwap)
1714
int halfWidth=width/2;
1715
int halfHeight=height/2;
1716
const char *src=(const char*)dataIn;
1719
assert(width==1 || height==1); /* must be 1D */
1720
assert(width!= height); /* can't be square */
1727
assert(width!=1); /* widthxheight can't be 1x1 */
1730
/* one horizontal row with possible pad bytes */
1731
for (jj=0; jj<halfWidth; jj++)
1734
float totals[4]; /* 4 is maximum components */
1735
float extractTotals[BOX2][4]; /* 4 is maximum components */
1738
/* average two at a time, instead of four */
1739
(*extractPackedPixel)(isSwap, src, &extractTotals[0][0]);
1740
(*extractPackedPixel)(isSwap, (src+pixelSizeInBytes), &extractTotals[1][0]);
1741
for (cc=0; cc<components; cc++)
1745
/* grab 2 pixels to average */
1747
for (kk=0; kk<BOX2; kk++)
1749
totals[cc]+=extractTotals[kk][cc];
1751
totals[cc]/=(float)BOX2;
1753
(*shovePackedPixel)(totals, outIndex, dataOut);
1756
/* skip over to next group of 2 */
1757
src+= pixelSizeInBytes + pixelSizeInBytes;
1761
int padBytes=rowSizeInBytes-(width*pixelSizeInBytes);
1762
src+=padBytes; /* for assertion only */
1764
assert(src==&((const char*)dataIn)[rowSizeInBytes]);
1765
assert(outIndex==halfWidth*halfHeight);
1769
if (width==1) /* 1 column */
1773
assert(height!=1); /* widthxheight can't be 1x1 */
1775
/* one vertical column with possible pad bytes per row */
1776
/* average two at a time */
1778
for (jj=0; jj<halfHeight; jj++)
1781
float totals[4]; /* 4 is maximum components */
1782
float extractTotals[BOX2][4]; /* 4 is maximum components */
1785
/* average two at a time, instead of four */
1786
(*extractPackedPixel)(isSwap, src, &extractTotals[0][0]);
1787
(*extractPackedPixel)(isSwap, (src+rowSizeInBytes), &extractTotals[1][0]);
1788
for (cc=0; cc<components; cc++)
1792
/* grab 2 pixels to average */
1794
for (kk=0; kk<BOX2; kk++)
1796
totals[cc]+=extractTotals[kk][cc];
1798
totals[cc]/=(float)BOX2;
1800
(*shovePackedPixel)(totals, outIndex, dataOut);
1803
src+=rowSizeInBytes+rowSizeInBytes; /* go to row after next */
1806
assert(src==&((const char*)dataIn)[rowSizeInBytes*height]);
1807
assert(outIndex==halfWidth*halfHeight);
1810
} /* halve1DimagePackedPixel() */
1812
/*===========================================================================*/