xref: /reactos/dll/opengl/mesa/texture.c (revision 5f2bebf7)
1 /* $Id: texture.c,v 1.36 1997/11/17 02:04:06 brianp Exp $ */
2 
3 /*
4  * Mesa 3-D graphics library
5  * Version:  2.5
6  * Copyright (C) 1995-1997  Brian Paul
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the Free
20  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 
23 
24 /*
25  * $Log: texture.c,v $
26  * Revision 1.36  1997/11/17 02:04:06  brianp
27  * fixed a typo in texture code
28  *
29  * Revision 1.35  1997/11/13 02:17:32  brianp
30  * added a few const keywords
31  *
32  * Revision 1.34  1997/10/16 01:59:08  brianp
33  * added GL_EXT_shared_texture_palette extension
34  *
35  * Revision 1.33  1997/09/27 00:14:39  brianp
36  * added GL_EXT_paletted_texture extension
37  *
38  * Revision 1.32  1997/08/14 01:03:12  brianp
39  * fixed small bug in GL_SPHERE_MAP texgen (Petri Nordlund)
40  *
41  * Revision 1.31  1997/07/24 01:25:34  brianp
42  * changed precompiled header symbol from PCH to PC_HEADER
43  *
44  * Revision 1.30  1997/07/22 01:23:48  brianp
45  * fixed negative texture coord sampling problem (Magnus Lundin)
46  *
47  * Revision 1.29  1997/07/09 00:32:26  brianp
48  * fixed bug involving sampling and incomplete texture objects
49  *
50  * Revision 1.28  1997/05/28 03:26:49  brianp
51  * added precompiled header (PCH) support
52  *
53  * Revision 1.27  1997/05/17 03:51:10  brianp
54  * fixed bug in PROD macro (Waldemar Celes)
55  *
56  * Revision 1.26  1997/05/03 00:53:56  brianp
57  * all-new texture sampling via gl_texture_object's SampleFunc pointer
58  *
59  * Revision 1.25  1997/05/01 01:40:14  brianp
60  * replaced sqrt() with GL_SQRT, use NORMALIZE_3FV instead of NORMALIZE_3V
61  *
62  * Revision 1.24  1997/04/28 02:04:18  brianp
63  * GL_SPHERE_MAP texgen was wrong (Eamon O'Dea)
64  *
65  * Revision 1.23  1997/04/20 20:29:11  brianp
66  * replaced abort() with gl_problem()
67  *
68  * Revision 1.22  1997/04/16 23:56:41  brianp
69  * added a few #include files
70  *
71  * Revision 1.21  1997/04/14 02:02:39  brianp
72  * moved many functions into new texstate.c file
73  *
74  * Revision 1.20  1997/04/01 04:19:14  brianp
75  * call gl_analyze_modelview_matrix instead of gl_compute_modelview_inverse
76  *
77  * Revision 1.19  1997/03/04 19:55:58  brianp
78  * small texture sampling optimizations.  better comments.
79  *
80  * Revision 1.18  1997/03/04 19:19:20  brianp
81  * fixed a number of problems with texture borders
82  *
83  * Revision 1.17  1997/02/27 19:58:08  brianp
84  * call gl_problem() instead of gl_warning()
85  *
86  * Revision 1.16  1997/02/09 19:53:43  brianp
87  * now use TEXTURE_xD enable constants
88  *
89  * Revision 1.15  1997/02/09 18:53:14  brianp
90  * added GL_EXT_texture3D support
91  *
92  * Revision 1.14  1997/01/30 21:06:03  brianp
93  * added some missing glGetTexLevelParameter() GLenums
94  *
95  * Revision 1.13  1997/01/16 03:36:01  brianp
96  * added calls to device driver TexParameter() and TexEnv() functions
97  *
98  * Revision 1.12  1997/01/09 19:48:30  brianp
99  * better error checking
100  * added gl_texturing_enabled()
101  *
102  * Revision 1.11  1996/12/20 20:22:30  brianp
103  * linear interpolation between mipmap levels was reverse weighted
104  * max mipmap level was incorrectly tested for
105  *
106  * Revision 1.10  1996/12/12 22:33:05  brianp
107  * minor changes to gl_texgen()
108  *
109  * Revision 1.9  1996/12/07 10:35:41  brianp
110  * implmented glGetTexGen*() functions
111  *
112  * Revision 1.8  1996/11/14 01:03:09  brianp
113  * removed const's from gl_texgen() function to avoid VMS compiler warning
114  *
115  * Revision 1.7  1996/11/08 02:19:52  brianp
116  * gl_do_texgen() replaced with gl_texgen()
117  *
118  * Revision 1.6  1996/10/26 17:17:30  brianp
119  * glTexGen GL_EYE_PLANE vector now transformed by inverse modelview matrix
120  *
121  * Revision 1.5  1996/10/11 03:42:38  brianp
122  * replaced old _EXT symbols
123  *
124  * Revision 1.4  1996/09/27 01:30:24  brianp
125  * added missing default cases to switches
126  *
127  * Revision 1.3  1996/09/15 14:18:55  brianp
128  * now use GLframebuffer and GLvisual
129  *
130  * Revision 1.2  1996/09/15 01:48:58  brianp
131  * removed #define NULL 0
132  *
133  * Revision 1.1  1996/09/13 01:38:16  brianp
134  * Initial revision
135  *
136  */
137 
138 
139 #ifdef PC_HEADER
140 #include "all.h"
141 #else
142 #include <math.h>
143 #include <stdlib.h>
144 #include "context.h"
145 #include "macros.h"
146 #include "mmath.h"
147 #include "pb.h"
148 #include "texture.h"
149 #include "types.h"
150 #endif
151 
152 
153 
154 /*
155  * Perform automatic texture coordinate generation.
156  * Input:  ctx - the context
157  *         n - number of texture coordinates to generate
158  *         obj - array of vertexes in object coordinate system
159  *         eye - array of vertexes in eye coordinate system
160  *         normal - array of normal vectores in eye coordinate system
161  * Output:  texcoord - array of resuling texture coordinates
162  */
gl_texgen(GLcontext * ctx,GLint n,GLfloat obj[][4],GLfloat eye[][4],GLfloat normal[][3],GLfloat texcoord[][4])163 void gl_texgen( GLcontext *ctx, GLint n,
164                 GLfloat obj[][4], GLfloat eye[][4],
165                 GLfloat normal[][3], GLfloat texcoord[][4] )
166 {
167    /* special case: S and T sphere mapping */
168    if (ctx->Texture.TexGenEnabled==(S_BIT|T_BIT)
169        && ctx->Texture.GenModeS==GL_SPHERE_MAP
170        && ctx->Texture.GenModeT==GL_SPHERE_MAP) {
171       GLint i;
172       for (i=0;i<n;i++) {
173          GLfloat u[3], two_nu, m, fx, fy, fz;
174          COPY_3V( u, eye[i] );
175          NORMALIZE_3FV( u );
176          two_nu = 2.0F * DOT3(normal[i],u);
177          fx = u[0] - normal[i][0] * two_nu;
178          fy = u[1] - normal[i][1] * two_nu;
179          fz = u[2] - normal[i][2] * two_nu;
180          m = 2.0F * GL_SQRT( fx*fx + fy*fy + (fz+1.0F)*(fz+1.0F) );
181          if (m==0.0F) {
182             texcoord[i][0] = 0.5F;
183             texcoord[i][1] = 0.5F;
184          }
185          else {
186             GLfloat mInv = 1.0F / m;
187             texcoord[i][0] = fx * mInv + 0.5F;
188             texcoord[i][1] = fy * mInv + 0.5F;
189          }
190       }
191       return;
192    }
193 
194    /* general solution */
195    if (ctx->Texture.TexGenEnabled & S_BIT) {
196       GLint i;
197       switch (ctx->Texture.GenModeS) {
198          case GL_OBJECT_LINEAR:
199             for (i=0;i<n;i++) {
200                texcoord[i][0] = DOT4( obj[i], ctx->Texture.ObjectPlaneS );
201             }
202             break;
203          case GL_EYE_LINEAR:
204             for (i=0;i<n;i++) {
205                texcoord[i][0] = DOT4( eye[i], ctx->Texture.EyePlaneS );
206             }
207             break;
208          case GL_SPHERE_MAP:
209             for (i=0;i<n;i++) {
210                GLfloat u[3], two_nu, m, fx, fy, fz;
211                COPY_3V( u, eye[i] );
212                NORMALIZE_3FV( u );
213                two_nu = 2.0*DOT3(normal[i],u);
214                fx = u[0] - normal[i][0] * two_nu;
215                fy = u[1] - normal[i][1] * two_nu;
216                fz = u[2] - normal[i][2] * two_nu;
217                m = 2.0F * GL_SQRT( fx*fx + fy*fy + (fz+1.0)*(fz+1.0) );
218                if (m==0.0F) {
219                   texcoord[i][0] = 0.5F;
220                }
221                else {
222                   texcoord[i][0] = fx / m + 0.5F;
223                }
224             }
225             break;
226          default:
227             gl_problem(ctx, "Bad S texgen");
228             return;
229       }
230    }
231 
232    if (ctx->Texture.TexGenEnabled & T_BIT) {
233       GLint i;
234       switch (ctx->Texture.GenModeT) {
235          case GL_OBJECT_LINEAR:
236             for (i=0;i<n;i++) {
237                texcoord[i][1] = DOT4( obj[i], ctx->Texture.ObjectPlaneT );
238             }
239             break;
240          case GL_EYE_LINEAR:
241             for (i=0;i<n;i++) {
242                texcoord[i][1] = DOT4( eye[i], ctx->Texture.EyePlaneT );
243             }
244             break;
245          case GL_SPHERE_MAP:
246             for (i=0;i<n;i++) {
247                GLfloat u[3], two_nu, m, fx, fy, fz;
248                COPY_3V( u, eye[i] );
249                NORMALIZE_3FV( u );
250                two_nu = 2.0*DOT3(normal[i],u);
251                fx = u[0] - normal[i][0] * two_nu;
252                fy = u[1] - normal[i][1] * two_nu;
253                fz = u[2] - normal[i][2] * two_nu;
254                m = 2.0F * GL_SQRT( fx*fx + fy*fy + (fz+1.0)*(fz+1.0) );
255                if (m==0.0F) {
256                   texcoord[i][1] = 0.5F;
257                }
258                else {
259                   texcoord[i][1] = fy / m + 0.5F;
260                }
261             }
262             break;
263          default:
264             gl_problem(ctx, "Bad T texgen");
265             return;
266       }
267    }
268 
269    if (ctx->Texture.TexGenEnabled & R_BIT) {
270       GLint i;
271       switch (ctx->Texture.GenModeR) {
272          case GL_OBJECT_LINEAR:
273             for (i=0;i<n;i++) {
274                texcoord[i][2] = DOT4( obj[i], ctx->Texture.ObjectPlaneR );
275             }
276             break;
277          case GL_EYE_LINEAR:
278             for (i=0;i<n;i++) {
279                texcoord[i][2] = DOT4( eye[i], ctx->Texture.EyePlaneR );
280             }
281             break;
282          default:
283             gl_problem(ctx, "Bad R texgen");
284             return;
285       }
286    }
287 
288    if (ctx->Texture.TexGenEnabled & Q_BIT) {
289       GLint i;
290       switch (ctx->Texture.GenModeQ) {
291          case GL_OBJECT_LINEAR:
292             for (i=0;i<n;i++) {
293                texcoord[i][3] = DOT4( obj[i], ctx->Texture.ObjectPlaneQ );
294             }
295             break;
296          case GL_EYE_LINEAR:
297             for (i=0;i<n;i++) {
298                texcoord[i][3] = DOT4( eye[i], ctx->Texture.EyePlaneQ );
299             }
300             break;
301          default:
302             gl_problem(ctx, "Bad Q texgen");
303             return;
304       }
305    }
306 }
307 
308 
309 
310 /*
311  * Paletted texture sampling.
312  * Input:  tObj - the texture object
313  *         index - the palette index (8-bit only)
314  * Output:  red, green, blue, alpha - the texel color
315  */
palette_sample(const struct gl_texture_object * tObj,GLubyte index,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)316 static void palette_sample(const struct gl_texture_object *tObj,
317                            GLubyte index, GLubyte *red, GLubyte *green,
318                            GLubyte *blue, GLubyte *alpha)
319 {
320    GLint i = index;
321    const GLubyte *palette;
322 
323    palette = tObj->Palette;
324 
325    switch (tObj->PaletteFormat) {
326       case GL_ALPHA:
327          *alpha = tObj->Palette[index];
328          return;
329       case GL_LUMINANCE:
330       case GL_INTENSITY:
331          *red = palette[index];
332          return;
333       case GL_LUMINANCE_ALPHA:
334          *red   = palette[(index << 1) + 0];
335          *alpha = palette[(index << 1) + 1];
336          return;
337       case GL_RGB:
338          *red   = palette[index * 3 + 0];
339          *green = palette[index * 3 + 1];
340          *blue  = palette[index * 3 + 2];
341          return;
342       case GL_RGBA:
343          *red   = palette[(i << 2) + 0];
344          *green = palette[(i << 2) + 1];
345          *blue  = palette[(i << 2) + 2];
346          *alpha = palette[(i << 2) + 3];
347          return;
348       default:
349          gl_problem(NULL, "Bad palette format in palette_sample");
350    }
351 }
352 
353 
354 
355 
356 /**********************************************************************/
357 /*                    1-D Texture Sampling Functions                  */
358 /**********************************************************************/
359 
360 
361 /*
362  * Return the fractional part of x.
363  */
364 #define frac(x) ((GLfloat)(x)-floor((GLfloat)x))
365 
366 
367 
368 /*
369  * Given 1-D texture image and an (i) texel column coordinate, return the
370  * texel color.
371  */
get_1d_texel(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLint i,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)372 static void get_1d_texel( const struct gl_texture_object *tObj,
373                           const struct gl_texture_image *img, GLint i,
374                           GLubyte *red, GLubyte *green, GLubyte *blue,
375                           GLubyte *alpha )
376 {
377    GLubyte *texel;
378 
379 #ifdef DEBUG
380    GLint width = img->Width;
381    if (i<0 || i>=width)  abort();
382 #endif
383 
384    switch (img->Format) {
385       case GL_COLOR_INDEX:
386          {
387             GLubyte index = img->Data[i];
388             palette_sample(tObj, index, red, green, blue, alpha);
389             return;
390          }
391          return;
392       case GL_ALPHA:
393          *alpha = img->Data[ i ];
394          return;
395       case GL_LUMINANCE:
396       case GL_INTENSITY:
397          *red   = img->Data[ i ];
398          return;
399       case GL_LUMINANCE_ALPHA:
400          texel = img->Data + i * 2;
401          *red   = texel[0];
402          *alpha = texel[1];
403          return;
404       case GL_RGB:
405          texel = img->Data + i * 3;
406          *red   = texel[0];
407          *green = texel[1];
408          *blue  = texel[2];
409          return;
410       case GL_RGBA:
411          texel = img->Data + i * 4;
412          *red   = texel[0];
413          *green = texel[1];
414          *blue  = texel[2];
415          *alpha = texel[3];
416          return;
417       default:
418          gl_problem(NULL, "Bad format in get_1d_texel");
419          return;
420    }
421 }
422 
423 
424 
425 /*
426  * Return the texture sample for coordinate (s) using GL_NEAREST filter.
427  */
sample_1d_nearest(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLfloat s,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)428 static void sample_1d_nearest( const struct gl_texture_object *tObj,
429                                const struct gl_texture_image *img,
430                                GLfloat s,
431                                GLubyte *red, GLubyte *green,
432                                GLubyte *blue, GLubyte *alpha )
433 {
434    GLint width = img->Width2;  /* without border, power of two */
435    GLint i;
436    GLubyte *texel;
437 
438    /* Clamp/Repeat S and convert to integer texel coordinate */
439    if (tObj->WrapS==GL_REPEAT) {
440       /* s limited to [0,1) */
441       /* i limited to [0,width-1] */
442       i = (GLint) (s * width);
443       if (s<0.0F)  i -= 1;
444       i &= (width-1);
445    }
446    else {
447       /* s limited to [0,1] */
448       /* i limited to [0,width-1] */
449       if (s<0.0F)        i = 0;
450       else if (s>1.0F)   i = width-1;
451       else               i = (GLint) (s * width);
452    }
453 
454    /* skip over the border, if any */
455    i += img->Border;
456 
457    /* Get the texel */
458    switch (img->Format) {
459       case GL_COLOR_INDEX:
460          {
461             GLubyte index = img->Data[i];
462             palette_sample(tObj, index, red, green, blue, alpha);
463             return;
464          }
465       case GL_ALPHA:
466          *alpha = img->Data[i];
467          return;
468       case GL_LUMINANCE:
469       case GL_INTENSITY:
470          *red   = img->Data[i];
471          return;
472       case GL_LUMINANCE_ALPHA:
473          texel = img->Data + i * 2;
474          *red   = texel[0];
475          *alpha = texel[1];
476          return;
477       case GL_RGB:
478          texel = img->Data + i * 3;
479          *red   = texel[0];
480          *green = texel[1];
481          *blue  = texel[2];
482          return;
483       case GL_RGBA:
484          texel = img->Data + i * 4;
485          *red   = texel[0];
486          *green = texel[1];
487          *blue  = texel[2];
488          *alpha = texel[3];
489          return;
490       default:
491          gl_problem(NULL, "Bad format in sample_1d_nearest");
492    }
493 }
494 
495 
496 
497 /*
498  * Return the texture sample for coordinate (s) using GL_LINEAR filter.
499  */
sample_1d_linear(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLfloat s,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)500 static void sample_1d_linear( const struct gl_texture_object *tObj,
501                               const struct gl_texture_image *img,
502                               GLfloat s,
503                               GLubyte *red, GLubyte *green,
504                               GLubyte *blue, GLubyte *alpha )
505 {
506    GLint width = img->Width2;
507    GLint i0, i1;
508    GLfloat u;
509    GLint i0border, i1border;
510 
511    u = s * width;
512    if (tObj->WrapS==GL_REPEAT) {
513       i0 = ((GLint) floor(u - 0.5F)) % width;
514       i1 = (i0 + 1) & (width-1);
515       i0border = i1border = 0;
516    }
517    else {
518       i0 = (GLint) floor(u - 0.5F);
519       i1 = i0 + 1;
520       i0border = (i0<0) | (i0>=width);
521       i1border = (i1<0) | (i1>=width);
522    }
523 
524    if (img->Border) {
525       i0 += img->Border;
526       i1 += img->Border;
527       i0border = i1border = 0;
528    }
529    else {
530       i0 &= (width-1);
531    }
532 
533    {
534       GLfloat a = frac(u - 0.5F);
535 
536       GLint w0 = (GLint) ((1.0F-a) * 256.0F);
537       GLint w1 = (GLint) (      a  * 256.0F);
538 
539       GLubyte red0, green0, blue0, alpha0;
540       GLubyte red1, green1, blue1, alpha1;
541 
542       if (i0border) {
543          red0   = tObj->BorderColor[0];
544          green0 = tObj->BorderColor[1];
545          blue0  = tObj->BorderColor[2];
546          alpha0 = tObj->BorderColor[3];
547       }
548       else {
549          get_1d_texel( tObj, img, i0, &red0, &green0, &blue0, &alpha0 );
550       }
551       if (i1border) {
552          red1   = tObj->BorderColor[0];
553          green1 = tObj->BorderColor[1];
554          blue1  = tObj->BorderColor[2];
555          alpha1 = tObj->BorderColor[3];
556       }
557       else {
558          get_1d_texel( tObj, img, i1, &red1, &green1, &blue1, &alpha1 );
559       }
560 
561       *red   = (w0*red0   + w1*red1)   >> 8;
562       *green = (w0*green0 + w1*green1) >> 8;
563       *blue  = (w0*blue0  + w1*blue1)  >> 8;
564       *alpha = (w0*alpha0 + w1*alpha1) >> 8;
565    }
566 }
567 
568 
569 static void
sample_1d_nearest_mipmap_nearest(const struct gl_texture_object * tObj,GLfloat s,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)570 sample_1d_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
571                                   GLfloat s, GLfloat lambda,
572                                   GLubyte *red, GLubyte *green,
573                                   GLubyte *blue, GLubyte *alpha )
574 {
575    GLint level;
576    if (lambda<=0.5F) {
577       level = 0;
578    }
579    else {
580       GLint widthlog2 = tObj->Image[0]->WidthLog2;
581       level = (GLint) (lambda + 0.499999F);
582       if (level>widthlog2 ) {
583          level = widthlog2;
584       }
585    }
586    sample_1d_nearest( tObj, tObj->Image[level],
587                       s, red, green, blue, alpha );
588 }
589 
590 
591 static void
sample_1d_linear_mipmap_nearest(const struct gl_texture_object * tObj,GLfloat s,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)592 sample_1d_linear_mipmap_nearest( const struct gl_texture_object *tObj,
593                                  GLfloat s, GLfloat lambda,
594                                  GLubyte *red, GLubyte *green,
595                                  GLubyte *blue, GLubyte *alpha )
596 {
597    GLint level;
598    if (lambda<=0.5F) {
599       level = 0;
600    }
601    else {
602       GLint widthlog2 = tObj->Image[0]->WidthLog2;
603       level = (GLint) (lambda + 0.499999F);
604       if (level>widthlog2 ) {
605          level = widthlog2;
606       }
607    }
608    sample_1d_linear( tObj, tObj->Image[level],
609                      s, red, green, blue, alpha );
610 }
611 
612 
613 
614 static void
sample_1d_nearest_mipmap_linear(const struct gl_texture_object * tObj,GLfloat s,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)615 sample_1d_nearest_mipmap_linear( const struct gl_texture_object *tObj,
616                                  GLfloat s, GLfloat lambda,
617                                  GLubyte *red, GLubyte *green,
618                                  GLubyte *blue, GLubyte *alpha )
619 {
620    GLint max = tObj->Image[0]->MaxLog2;
621 
622    if (lambda>=max) {
623       sample_1d_nearest( tObj, tObj->Image[max],
624                          s, red, green, blue, alpha );
625    }
626    else {
627       GLubyte red0, green0, blue0, alpha0;
628       GLubyte red1, green1, blue1, alpha1;
629       GLfloat f = frac(lambda);
630       GLint level = (GLint) (lambda + 1.0F);
631       level = CLAMP( level, 1, max );
632       sample_1d_nearest( tObj, tObj->Image[level-1],
633                          s, &red0, &green0, &blue0, &alpha0 );
634       sample_1d_nearest( tObj, tObj->Image[level],
635                          s, &red1, &green1, &blue1, &alpha1 );
636       *red   = (1.0F-f)*red0   + f*red1;
637       *green = (1.0F-f)*green0 + f*green1;
638       *blue  = (1.0F-f)*blue0  + f*blue1;
639       *alpha = (1.0F-f)*alpha0 + f*alpha1;
640    }
641 }
642 
643 
644 
645 static void
sample_1d_linear_mipmap_linear(const struct gl_texture_object * tObj,GLfloat s,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)646 sample_1d_linear_mipmap_linear( const struct gl_texture_object *tObj,
647                                 GLfloat s, GLfloat lambda,
648                                 GLubyte *red, GLubyte *green,
649                                 GLubyte *blue, GLubyte *alpha )
650 {
651    GLint max = tObj->Image[0]->MaxLog2;
652 
653    if (lambda>=max) {
654       sample_1d_linear( tObj, tObj->Image[max],
655                         s, red, green, blue, alpha );
656    }
657    else {
658       GLubyte red0, green0, blue0, alpha0;
659       GLubyte red1, green1, blue1, alpha1;
660       GLfloat f = frac(lambda);
661       GLint level = (GLint) (lambda + 1.0F);
662       level = CLAMP( level, 1, max );
663       sample_1d_linear( tObj, tObj->Image[level-1],
664                         s, &red0, &green0, &blue0, &alpha0 );
665       sample_1d_linear( tObj, tObj->Image[level],
666                         s, &red1, &green1, &blue1, &alpha1 );
667       *red   = (1.0F-f)*red0   + f*red1;
668       *green = (1.0F-f)*green0 + f*green1;
669       *blue  = (1.0F-f)*blue0  + f*blue1;
670       *alpha = (1.0F-f)*alpha0 + f*alpha1;
671    }
672 }
673 
674 
675 
sample_nearest_1d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])676 static void sample_nearest_1d( const struct gl_texture_object *tObj, GLuint n,
677                                const GLfloat s[], const GLfloat t[],
678                                const GLfloat u[], const GLfloat lambda[],
679                                GLubyte red[], GLubyte green[], GLubyte blue[],
680                                GLubyte alpha[] )
681 {
682    GLuint i;
683    for (i=0;i<n;i++) {
684       sample_1d_nearest( tObj, tObj->Image[0], s[i],
685                          &red[i], &green[i], &blue[i], &alpha[i]);
686    }
687 }
688 
689 
690 
sample_linear_1d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])691 static void sample_linear_1d( const struct gl_texture_object *tObj, GLuint n,
692                               const GLfloat s[], const GLfloat t[],
693                               const GLfloat u[], const GLfloat lambda[],
694                               GLubyte red[], GLubyte green[], GLubyte blue[],
695                               GLubyte alpha[] )
696 {
697    GLuint i;
698    for (i=0;i<n;i++) {
699       sample_1d_linear( tObj, tObj->Image[0], s[i],
700                         &red[i], &green[i], &blue[i], &alpha[i]);
701    }
702 }
703 
704 
705 /*
706  * Given an (s) texture coordinate and lambda (level of detail) value,
707  * return a texture sample.
708  *
709  */
sample_lambda_1d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])710 static void sample_lambda_1d( const struct gl_texture_object *tObj, GLuint n,
711                               const GLfloat s[], const GLfloat t[],
712                               const GLfloat u[], const GLfloat lambda[],
713                               GLubyte red[], GLubyte green[], GLubyte blue[],
714                               GLubyte alpha[] )
715 {
716    GLuint i;
717 
718    for (i=0;i<n;i++) {
719       if (lambda[i] > tObj->MinMagThresh) {
720          /* minification */
721          switch (tObj->MinFilter) {
722             case GL_NEAREST:
723                sample_1d_nearest( tObj, tObj->Image[0], s[i],
724                                   &red[i], &green[i], &blue[i], &alpha[i] );
725                break;
726             case GL_LINEAR:
727                sample_1d_linear( tObj, tObj->Image[0], s[i],
728                                  &red[i], &green[i], &blue[i], &alpha[i] );
729                break;
730             case GL_NEAREST_MIPMAP_NEAREST:
731                sample_1d_nearest_mipmap_nearest( tObj, lambda[i], s[i],
732                                  &red[i], &green[i], &blue[i], &alpha[i] );
733                break;
734             case GL_LINEAR_MIPMAP_NEAREST:
735                sample_1d_linear_mipmap_nearest( tObj, s[i], lambda[i],
736                                  &red[i], &green[i], &blue[i], &alpha[i] );
737                break;
738             case GL_NEAREST_MIPMAP_LINEAR:
739                sample_1d_nearest_mipmap_linear( tObj, s[i], lambda[i],
740                                  &red[i], &green[i], &blue[i], &alpha[i] );
741                break;
742             case GL_LINEAR_MIPMAP_LINEAR:
743                sample_1d_linear_mipmap_linear( tObj, s[i], lambda[i],
744                                  &red[i], &green[i], &blue[i], &alpha[i] );
745                break;
746             default:
747                gl_problem(NULL, "Bad min filter in sample_1d_texture");
748                return;
749          }
750       }
751       else {
752          /* magnification */
753          switch (tObj->MagFilter) {
754             case GL_NEAREST:
755                sample_1d_nearest( tObj, tObj->Image[0], s[i],
756                                   &red[i], &green[i], &blue[i], &alpha[i] );
757                break;
758             case GL_LINEAR:
759                sample_1d_linear( tObj, tObj->Image[0], s[i],
760                                  &red[i], &green[i], &blue[i], &alpha[i] );
761                break;
762             default:
763                gl_problem(NULL, "Bad mag filter in sample_1d_texture");
764                return;
765          }
766       }
767    }
768 }
769 
770 
771 
772 
773 /**********************************************************************/
774 /*                    2-D Texture Sampling Functions                  */
775 /**********************************************************************/
776 
777 
778 /*
779  * Given a texture image and an (i,j) integer texel coordinate, return the
780  * texel color.
781  */
get_2d_texel(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLint i,GLint j,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)782 static void get_2d_texel( const struct gl_texture_object *tObj,
783                           const struct gl_texture_image *img, GLint i, GLint j,
784                           GLubyte *red, GLubyte *green, GLubyte *blue,
785                           GLubyte *alpha )
786 {
787    GLint width = img->Width;    /* includes border */
788    GLubyte *texel;
789 
790 #ifdef DEBUG
791    GLint height = img->Height;  /* includes border */
792    if (i<0 || i>=width)  abort();
793    if (j<0 || j>=height)  abort();
794 #endif
795 
796    switch (img->Format) {
797       case GL_COLOR_INDEX:
798          {
799             GLubyte index = img->Data[ width *j + i ];
800             palette_sample(tObj, index, red, green, blue, alpha);
801             return;
802          }
803       case GL_ALPHA:
804          *alpha = img->Data[ width * j + i ];
805          return;
806       case GL_LUMINANCE:
807       case GL_INTENSITY:
808          *red   = img->Data[ width * j + i ];
809          return;
810       case GL_LUMINANCE_ALPHA:
811          texel = img->Data + (width * j + i) * 2;
812          *red   = texel[0];
813          *alpha = texel[1];
814          return;
815       case GL_RGB:
816          texel = img->Data + (width * j + i) * 3;
817          *red   = texel[0];
818          *green = texel[1];
819          *blue  = texel[2];
820          return;
821       case GL_RGBA:
822          texel = img->Data + (width * j + i) * 4;
823          *red   = texel[0];
824          *green = texel[1];
825          *blue  = texel[2];
826          *alpha = texel[3];
827          return;
828       default:
829          gl_problem(NULL, "Bad format in get_2d_texel");
830    }
831 }
832 
833 
834 
835 /*
836  * Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
837  */
sample_2d_nearest(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLfloat s,GLfloat t,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)838 static void sample_2d_nearest( const struct gl_texture_object *tObj,
839                                const struct gl_texture_image *img,
840                                GLfloat s, GLfloat t,
841                                GLubyte *red, GLubyte *green,
842                                GLubyte *blue, GLubyte *alpha )
843 {
844    GLint imgWidth = img->Width;  /* includes border */
845    GLint width = img->Width2;    /* without border, power of two */
846    GLint height = img->Height2;  /* without border, power of two */
847    GLint i, j;
848    GLubyte *texel;
849 
850    /* Clamp/Repeat S and convert to integer texel coordinate */
851    if (tObj->WrapS==GL_REPEAT) {
852       /* s limited to [0,1) */
853       /* i limited to [0,width-1] */
854       i = (GLint) (s * width);
855       if (s<0.0F)  i -= 1;
856       i &= (width-1);
857    }
858    else {
859       /* s limited to [0,1] */
860       /* i limited to [0,width-1] */
861       if (s<=0.0F)      i = 0;
862       else if (s>1.0F)  i = width-1;
863       else              i = (GLint) (s * width);
864    }
865 
866    /* Clamp/Repeat T and convert to integer texel coordinate */
867    if (tObj->WrapT==GL_REPEAT) {
868       /* t limited to [0,1) */
869       /* j limited to [0,height-1] */
870       j = (GLint) (t * height);
871       if (t<0.0F)  j -= 1;
872       j &= (height-1);
873    }
874    else {
875       /* t limited to [0,1] */
876       /* j limited to [0,height-1] */
877       if (t<=0.0F)      j = 0;
878       else if (t>1.0F)  j = height-1;
879       else              j = (GLint) (t * height);
880    }
881 
882    /* skip over the border, if any */
883    i += img->Border;
884    j += img->Border;
885 
886    switch (img->Format) {
887       case GL_COLOR_INDEX:
888          {
889             GLubyte index = img->Data[ j * imgWidth + i ];
890             palette_sample(tObj, index, red, green, blue, alpha);
891             return;
892          }
893       case GL_ALPHA:
894          *alpha = img->Data[ j * imgWidth + i ];
895          return;
896       case GL_LUMINANCE:
897       case GL_INTENSITY:
898          *red   = img->Data[ j * imgWidth + i ];
899          return;
900       case GL_LUMINANCE_ALPHA:
901          texel = img->Data + ((j * imgWidth + i) << 1);
902          *red   = texel[0];
903          *alpha = texel[1];
904          return;
905       case GL_RGB:
906          texel = img->Data + (j * imgWidth + i) * 3;
907          *red   = texel[0];
908          *green = texel[1];
909          *blue  = texel[2];
910          return;
911       case GL_RGBA:
912          texel = img->Data + ((j * imgWidth + i) << 2);
913          *red   = texel[0];
914          *green = texel[1];
915          *blue  = texel[2];
916          *alpha = texel[3];
917          return;
918       default:
919          gl_problem(NULL, "Bad format in sample_2d_nearest");
920    }
921 }
922 
923 
924 
925 /*
926  * Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
927  */
sample_2d_linear(const struct gl_texture_object * tObj,const struct gl_texture_image * img,GLfloat s,GLfloat t,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)928 static void sample_2d_linear( const struct gl_texture_object *tObj,
929                               const struct gl_texture_image *img,
930                               GLfloat s, GLfloat t,
931                               GLubyte *red, GLubyte *green,
932                               GLubyte *blue, GLubyte *alpha )
933 {
934    GLint width = img->Width2;
935    GLint height = img->Height2;
936    GLint i0, j0, i1, j1;
937    GLint i0border, j0border, i1border, j1border;
938    GLfloat u, v;
939 
940    u = s * width;
941    if (tObj->WrapS==GL_REPEAT) {
942       i0 = ((GLint) floor(u - 0.5F)) % width;
943       i1 = (i0 + 1) & (width-1);
944       i0border = i1border = 0;
945    }
946    else {
947       i0 = (GLint) floor(u - 0.5F);
948       i1 = i0 + 1;
949       i0border = (i0<0) | (i0>=width);
950       i1border = (i1<0) | (i1>=width);
951    }
952 
953    v = t * height;
954    if (tObj->WrapT==GL_REPEAT) {
955       j0 = ((GLint) floor(v - 0.5F)) % height;
956       j1 = (j0 + 1) & (height-1);
957       j0border = j1border = 0;
958    }
959    else {
960       j0 = (GLint) floor(v - 0.5F );
961       j1 = j0 + 1;
962       j0border = (j0<0) | (j0>=height);
963       j1border = (j1<0) | (j1>=height);
964    }
965 
966    if (img->Border) {
967       i0 += img->Border;
968       i1 += img->Border;
969       j0 += img->Border;
970       j1 += img->Border;
971       i0border = i1border = 0;
972       j0border = j1border = 0;
973    }
974    else {
975       i0 &= (width-1);
976       j0 &= (height-1);
977    }
978 
979    {
980       GLfloat a = frac(u - 0.5F);
981       GLfloat b = frac(v - 0.5F);
982 
983       GLint w00 = (GLint) ((1.0F-a)*(1.0F-b) * 256.0F);
984       GLint w10 = (GLint) (      a *(1.0F-b) * 256.0F);
985       GLint w01 = (GLint) ((1.0F-a)*      b  * 256.0F);
986       GLint w11 = (GLint) (      a *      b  * 256.0F);
987 
988       GLubyte red00, green00, blue00, alpha00;
989       GLubyte red10, green10, blue10, alpha10;
990       GLubyte red01, green01, blue01, alpha01;
991       GLubyte red11, green11, blue11, alpha11;
992 
993       if (i0border | j0border) {
994          red00   = tObj->BorderColor[0];
995          green00 = tObj->BorderColor[1];
996          blue00  = tObj->BorderColor[2];
997          alpha00 = tObj->BorderColor[3];
998       }
999       else {
1000          get_2d_texel( tObj, img, i0, j0, &red00, &green00, &blue00, &alpha00);
1001       }
1002       if (i1border | j0border) {
1003          red10   = tObj->BorderColor[0];
1004          green10 = tObj->BorderColor[1];
1005          blue10  = tObj->BorderColor[2];
1006          alpha10 = tObj->BorderColor[3];
1007       }
1008       else {
1009          get_2d_texel( tObj, img, i1, j0, &red10, &green10, &blue10, &alpha10);
1010       }
1011       if (i0border | j1border) {
1012          red01   = tObj->BorderColor[0];
1013          green01 = tObj->BorderColor[1];
1014          blue01  = tObj->BorderColor[2];
1015          alpha01 = tObj->BorderColor[3];
1016       }
1017       else {
1018          get_2d_texel( tObj, img, i0, j1, &red01, &green01, &blue01, &alpha01);
1019       }
1020       if (i1border | j1border) {
1021          red11   = tObj->BorderColor[0];
1022          green11 = tObj->BorderColor[1];
1023          blue11  = tObj->BorderColor[2];
1024          alpha11 = tObj->BorderColor[3];
1025       }
1026       else {
1027          get_2d_texel( tObj, img, i1, j1, &red11, &green11, &blue11, &alpha11);
1028       }
1029 
1030       *red   = (w00*red00   + w10*red10   + w01*red01   + w11*red11  ) >> 8;
1031       *green = (w00*green00 + w10*green10 + w01*green01 + w11*green11) >> 8;
1032       *blue  = (w00*blue00  + w10*blue10  + w01*blue01  + w11*blue11 ) >> 8;
1033       *alpha = (w00*alpha00 + w10*alpha10 + w01*alpha01 + w11*alpha11) >> 8;
1034    }
1035 }
1036 
1037 
1038 
1039 static void
sample_2d_nearest_mipmap_nearest(const struct gl_texture_object * tObj,GLfloat s,GLfloat t,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)1040 sample_2d_nearest_mipmap_nearest( const struct gl_texture_object *tObj,
1041                                   GLfloat s, GLfloat t, GLfloat lambda,
1042                                   GLubyte *red, GLubyte *green,
1043                                   GLubyte *blue, GLubyte *alpha )
1044 {
1045    GLint level;
1046    if (lambda<=0.5F) {
1047       level = 0;
1048    }
1049    else {
1050       GLint max = tObj->Image[0]->MaxLog2;
1051       level = (GLint) (lambda + 0.499999F);
1052       if (level>max) {
1053          level = max;
1054       }
1055    }
1056    sample_2d_nearest( tObj, tObj->Image[level],
1057                       s, t, red, green, blue, alpha );
1058 }
1059 
1060 
1061 
1062 static void
sample_2d_linear_mipmap_nearest(const struct gl_texture_object * tObj,GLfloat s,GLfloat t,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)1063 sample_2d_linear_mipmap_nearest( const struct gl_texture_object *tObj,
1064                                  GLfloat s, GLfloat t, GLfloat lambda,
1065                                  GLubyte *red, GLubyte *green,
1066                                  GLubyte *blue, GLubyte *alpha )
1067 {
1068    GLint level;
1069    if (lambda<=0.5F) {
1070       level = 0;
1071    }
1072    else {
1073       GLint max = tObj->Image[0]->MaxLog2;
1074       level = (GLint) (lambda + 0.499999F);
1075       if (level>max) {
1076          level = max;
1077       }
1078    }
1079    sample_2d_linear( tObj, tObj->Image[level],
1080                      s, t, red, green, blue, alpha );
1081 }
1082 
1083 
1084 
1085 static void
sample_2d_nearest_mipmap_linear(const struct gl_texture_object * tObj,GLfloat s,GLfloat t,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)1086 sample_2d_nearest_mipmap_linear( const struct gl_texture_object *tObj,
1087                                  GLfloat s, GLfloat t, GLfloat lambda,
1088                                  GLubyte *red, GLubyte *green,
1089                                  GLubyte *blue, GLubyte *alpha )
1090 {
1091    GLint max = tObj->Image[0]->MaxLog2;
1092 
1093    if (lambda>=max) {
1094       sample_2d_nearest( tObj, tObj->Image[max],
1095                          s, t, red, green, blue, alpha );
1096    }
1097    else {
1098       GLubyte red0, green0, blue0, alpha0;
1099       GLubyte red1, green1, blue1, alpha1;
1100       GLfloat f = frac(lambda);
1101       GLint level = (GLint) (lambda + 1.0F);
1102       level = CLAMP( level, 1, max );
1103       sample_2d_nearest( tObj, tObj->Image[level-1], s, t,
1104                          &red0, &green0, &blue0, &alpha0 );
1105       sample_2d_nearest( tObj, tObj->Image[level], s, t,
1106                          &red1, &green1, &blue1, &alpha1 );
1107       *red   = (1.0F-f)*red0   + f*red1;
1108       *green = (1.0F-f)*green0 + f*green1;
1109       *blue  = (1.0F-f)*blue0  + f*blue1;
1110       *alpha = (1.0F-f)*alpha0 + f*alpha1;
1111    }
1112 }
1113 
1114 
1115 
1116 static void
sample_2d_linear_mipmap_linear(const struct gl_texture_object * tObj,GLfloat s,GLfloat t,GLfloat lambda,GLubyte * red,GLubyte * green,GLubyte * blue,GLubyte * alpha)1117 sample_2d_linear_mipmap_linear( const struct gl_texture_object *tObj,
1118                                 GLfloat s, GLfloat t, GLfloat lambda,
1119                                 GLubyte *red, GLubyte *green,
1120                                 GLubyte *blue, GLubyte *alpha )
1121 {
1122    GLint max = tObj->Image[0]->MaxLog2;
1123 
1124    if (lambda>=max) {
1125       sample_2d_linear( tObj, tObj->Image[max],
1126                         s, t, red, green, blue, alpha );
1127    }
1128    else {
1129       GLubyte red0, green0, blue0, alpha0;
1130       GLubyte red1, green1, blue1, alpha1;
1131       GLfloat f = frac(lambda);
1132       GLint level = (GLint) (lambda + 1.0F);
1133       level = CLAMP( level, 1, max );
1134       sample_2d_linear( tObj, tObj->Image[level-1], s, t,
1135                         &red0, &green0, &blue0, &alpha0 );
1136       sample_2d_linear( tObj, tObj->Image[level], s, t,
1137                         &red1, &green1, &blue1, &alpha1 );
1138       *red   = (1.0F-f)*red0   + f*red1;
1139       *green = (1.0F-f)*green0 + f*green1;
1140       *blue  = (1.0F-f)*blue0  + f*blue1;
1141       *alpha = (1.0F-f)*alpha0 + f*alpha1;
1142    }
1143 }
1144 
1145 
1146 
sample_nearest_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])1147 static void sample_nearest_2d( const struct gl_texture_object *tObj, GLuint n,
1148                                const GLfloat s[], const GLfloat t[],
1149                                const GLfloat u[], const GLfloat lambda[],
1150                                GLubyte red[], GLubyte green[], GLubyte blue[],
1151                                GLubyte alpha[] )
1152 {
1153    GLuint i;
1154    for (i=0;i<n;i++) {
1155       sample_2d_nearest( tObj, tObj->Image[0], s[i], t[i],
1156                          &red[i], &green[i], &blue[i], &alpha[i]);
1157    }
1158 }
1159 
1160 
1161 
sample_linear_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])1162 static void sample_linear_2d( const struct gl_texture_object *tObj, GLuint n,
1163                               const GLfloat s[], const GLfloat t[],
1164                               const GLfloat u[], const GLfloat lambda[],
1165                               GLubyte red[], GLubyte green[], GLubyte blue[],
1166                               GLubyte alpha[] )
1167 {
1168    GLuint i;
1169    for (i=0;i<n;i++) {
1170       sample_2d_linear( tObj, tObj->Image[0], s[i], t[i],
1171                         &red[i], &green[i], &blue[i], &alpha[i]);
1172    }
1173 }
1174 
1175 
1176 /*
1177  * Given an (s,t) texture coordinate and lambda (level of detail) value,
1178  * return a texture sample.
1179  */
sample_lambda_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])1180 static void sample_lambda_2d( const struct gl_texture_object *tObj,
1181                               GLuint n,
1182                               const GLfloat s[], const GLfloat t[],
1183                               const GLfloat u[], const GLfloat lambda[],
1184                               GLubyte red[], GLubyte green[], GLubyte blue[],
1185                               GLubyte alpha[] )
1186 {
1187    GLuint i;
1188    for (i=0;i<n;i++) {
1189       if (lambda[i] > tObj->MinMagThresh) {
1190          /* minification */
1191          switch (tObj->MinFilter) {
1192             case GL_NEAREST:
1193                sample_2d_nearest( tObj, tObj->Image[0], s[i], t[i],
1194                                   &red[i], &green[i], &blue[i], &alpha[i] );
1195                break;
1196             case GL_LINEAR:
1197                sample_2d_linear( tObj, tObj->Image[0], s[i], t[i],
1198                                  &red[i], &green[i], &blue[i], &alpha[i] );
1199                break;
1200             case GL_NEAREST_MIPMAP_NEAREST:
1201                sample_2d_nearest_mipmap_nearest( tObj, s[i], t[i], lambda[i],
1202                                  &red[i], &green[i], &blue[i], &alpha[i] );
1203                break;
1204             case GL_LINEAR_MIPMAP_NEAREST:
1205                sample_2d_linear_mipmap_nearest( tObj, s[i], t[i], lambda[i],
1206                                  &red[i], &green[i], &blue[i], &alpha[i] );
1207                break;
1208             case GL_NEAREST_MIPMAP_LINEAR:
1209                sample_2d_nearest_mipmap_linear( tObj, s[i], t[i], lambda[i],
1210                                  &red[i], &green[i], &blue[i], &alpha[i] );
1211                break;
1212             case GL_LINEAR_MIPMAP_LINEAR:
1213                sample_2d_linear_mipmap_linear( tObj, s[i], t[i], lambda[i],
1214                                  &red[i], &green[i], &blue[i], &alpha[i] );
1215                break;
1216             default:
1217                gl_problem(NULL, "Bad min filter in sample_2d_texture");
1218                return;
1219          }
1220       }
1221       else {
1222          /* magnification */
1223          switch (tObj->MagFilter) {
1224             case GL_NEAREST:
1225                sample_2d_nearest( tObj, tObj->Image[0], s[i], t[i],
1226                                   &red[i], &green[i], &blue[i], &alpha[i] );
1227                break;
1228             case GL_LINEAR:
1229                sample_2d_linear( tObj, tObj->Image[0], s[i], t[i],
1230                                  &red[i], &green[i], &blue[i], &alpha[i] );
1231                break;
1232             default:
1233                gl_problem(NULL, "Bad mag filter in sample_2d_texture");
1234          }
1235       }
1236    }
1237 }
1238 
1239 
1240 /*
1241  * Optimized 2-D texture sampling:
1242  *    S and T wrap mode == GL_REPEAT
1243  *    No border
1244  *    Format = GL_RGB
1245  */
opt_sample_rgb_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lamda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])1246 static void opt_sample_rgb_2d( const struct gl_texture_object *tObj,
1247                                GLuint n, const GLfloat s[], const GLfloat t[],
1248                                const GLfloat u[], const GLfloat lamda[],
1249                                GLubyte red[], GLubyte green[],
1250                                GLubyte blue[], GLubyte alpha[] )
1251 {
1252    const struct gl_texture_image *img = tObj->Image[0];
1253    GLfloat width = img->Width, height = img->Height;
1254    GLint colMask = img->Width-1, rowMask = img->Height-1;
1255    GLint shift = img->WidthLog2;
1256    GLuint k;
1257 
1258    ASSERT(tObj->WrapS==GL_REPEAT);
1259    ASSERT(tObj->WrapT==GL_REPEAT);
1260    ASSERT(img->Border==0);
1261    ASSERT(img->Format==GL_RGB);
1262 
1263    for (k=0;k<n;k++) {
1264       GLint i = (GLint) (s[k] * width) & colMask;
1265       GLint j = (GLint) (t[k] * height) & rowMask;
1266       GLint pos = (j << shift) | i;
1267       GLubyte *texel = img->Data + pos + pos + pos;  /* pos*3 */
1268       red[k]   = texel[0];
1269       green[k] = texel[1];
1270       blue[k]  = texel[2];
1271    }
1272 }
1273 
1274 
1275 /*
1276  * Optimized 2-D texture sampling:
1277  *    S and T wrap mode == GL_REPEAT
1278  *    No border
1279  *    Format = GL_RGBA
1280  */
opt_sample_rgba_2d(const struct gl_texture_object * tObj,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat u[],const GLfloat lamda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])1281 static void opt_sample_rgba_2d( const struct gl_texture_object *tObj,
1282                                 GLuint n, const GLfloat s[], const GLfloat t[],
1283                                 const GLfloat u[], const GLfloat lamda[],
1284                                 GLubyte red[], GLubyte green[],
1285                                 GLubyte blue[], GLubyte alpha[] )
1286 {
1287    const struct gl_texture_image *img = tObj->Image[0];
1288    GLfloat width = img->Width, height = img->Height;
1289    GLint colMask = img->Width-1, rowMask = img->Height-1;
1290    GLint shift = img->WidthLog2;
1291    GLuint k;
1292 
1293    ASSERT(tObj->WrapS==GL_REPEAT);
1294    ASSERT(tObj->WrapT==GL_REPEAT);
1295    ASSERT(img->Border==0);
1296    ASSERT(img->Format==GL_RGBA);
1297 
1298    for (k=0;k<n;k++) {
1299       GLint i = (GLint) (s[k] * width) & colMask;
1300       GLint j = (GLint) (t[k] * height) & rowMask;
1301       GLint pos = (j << shift) | i;
1302       GLubyte *texel = img->Data + (pos << 2);    /* pos*4 */
1303       red[k]   = texel[0];
1304       green[k] = texel[1];
1305       blue[k]  = texel[2];
1306       alpha[k] = texel[3];
1307    }
1308 }
1309 
1310 
1311 /**********************************************************************/
1312 /*                       Texture Sampling Setup                       */
1313 /**********************************************************************/
1314 
1315 
1316 /*
1317  * Setup the texture sampling function for this texture object.
1318  */
gl_set_texture_sampler(struct gl_texture_object * t)1319 void gl_set_texture_sampler( struct gl_texture_object *t )
1320 {
1321    if (!t->Complete) {
1322       t->SampleFunc = NULL;
1323    }
1324    else {
1325       GLboolean needLambda = (t->MinFilter != t->MagFilter);
1326 
1327       if (needLambda) {
1328          /* Compute min/mag filter threshold */
1329          if (t->MagFilter==GL_LINEAR
1330              && (t->MinFilter==GL_NEAREST_MIPMAP_NEAREST ||
1331                  t->MinFilter==GL_LINEAR_MIPMAP_NEAREST)) {
1332             t->MinMagThresh = 0.5F;
1333          }
1334          else {
1335             t->MinMagThresh = 0.0F;
1336          }
1337       }
1338 
1339       switch (t->Dimensions) {
1340          case 1:
1341             if (needLambda) {
1342                t->SampleFunc = sample_lambda_1d;
1343             }
1344             else if (t->MinFilter==GL_LINEAR) {
1345                t->SampleFunc = sample_linear_1d;
1346             }
1347             else {
1348                ASSERT(t->MinFilter==GL_NEAREST);
1349                t->SampleFunc = sample_nearest_1d;
1350             }
1351             break;
1352          case 2:
1353             if (needLambda) {
1354                t->SampleFunc = sample_lambda_2d;
1355             }
1356             else if (t->MinFilter==GL_LINEAR) {
1357                t->SampleFunc = sample_linear_2d;
1358             }
1359             else {
1360                ASSERT(t->MinFilter==GL_NEAREST);
1361                if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT
1362                    && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGB) {
1363                   t->SampleFunc = opt_sample_rgb_2d;
1364                }
1365                else if (t->WrapS==GL_REPEAT && t->WrapT==GL_REPEAT
1366                    && t->Image[0]->Border==0 && t->Image[0]->Format==GL_RGBA) {
1367                   t->SampleFunc = opt_sample_rgba_2d;
1368                }
1369                else
1370                   t->SampleFunc = sample_nearest_2d;
1371             }
1372             break;
1373          default:
1374             gl_problem(NULL, "invalid dimensions in gl_set_texture_sampler");
1375       }
1376    }
1377 }
1378 
1379 
1380 
1381 /**********************************************************************/
1382 /*                      Texture Application                           */
1383 /**********************************************************************/
1384 
1385 
1386 /*
1387  * Combine incoming fragment color with texel color to produce output color.
1388  * Input:  n - number of fragments
1389  *         format - base internal texture format
1390  *         env_mode - texture environment mode
1391  *         Rt, Gt, Bt, At - array of texel colors
1392  * InOut:  red, green, blue, alpha - incoming fragment colors modified
1393  *                                   by texel colors according to the
1394  *                                   texture environment mode.
1395  */
apply_texture(GLcontext * ctx,GLuint n,GLint format,GLenum env_mode,GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[],GLubyte Rt[],GLubyte Gt[],GLubyte Bt[],GLubyte At[])1396 static void apply_texture( GLcontext *ctx,
1397          GLuint n, GLint format, GLenum env_mode,
1398 	 GLubyte red[], GLubyte green[], GLubyte blue[], GLubyte alpha[],
1399 	 GLubyte Rt[], GLubyte Gt[], GLubyte Bt[], GLubyte At[] )
1400 {
1401    GLuint i;
1402    GLint Rc, Gc, Bc, Ac;
1403 
1404    if (!ctx->Visual->EightBitColor) {
1405       /* This is a hack!  Rescale input colors from [0,scale] to [0,255]. */
1406       GLfloat rscale = 255.0 * ctx->Visual->InvRedScale;
1407       GLfloat gscale = 255.0 * ctx->Visual->InvGreenScale;
1408       GLfloat bscale = 255.0 * ctx->Visual->InvBlueScale;
1409       GLfloat ascale = 255.0 * ctx->Visual->InvAlphaScale;
1410       for (i=0;i<n;i++) {
1411 	 red[i]   = (GLint) (red[i]   * rscale);
1412 	 green[i] = (GLint) (green[i] * gscale);
1413 	 blue[i]  = (GLint) (blue[i]  * bscale);
1414 	 alpha[i] = (GLint) (alpha[i] * ascale);
1415       }
1416    }
1417 
1418 /*
1419  * Use (A*(B+1)) >> 8 as a fast approximation of (A*B)/255 for A
1420  * and B in [0,255]
1421  */
1422 #define PROD(A,B)   (((GLint)(A) * ((GLint)(B)+1)) >> 8)
1423 
1424    if (format==GL_COLOR_INDEX) {
1425       format = GL_RGBA;  /* XXXX a hack! */
1426    }
1427 
1428    switch (env_mode) {
1429       case GL_REPLACE:
1430 	 switch (format) {
1431 	    case GL_ALPHA:
1432 	       for (i=0;i<n;i++) {
1433 		  /* Cv = Cf */
1434                   /* Av = At */
1435                   alpha[i] = At[i];
1436 	       }
1437 	       break;
1438 	    case GL_LUMINANCE:
1439 	       for (i=0;i<n;i++) {
1440 		  /* Cv = Lt */
1441                   GLint Lt = Rt[i];
1442                   red[i] = green[i] = blue[i] = Lt;
1443                   /* Av = Af */
1444 	       }
1445 	       break;
1446 	    case GL_LUMINANCE_ALPHA:
1447 	       for (i=0;i<n;i++) {
1448                   GLint Lt = Rt[i];
1449 		  /* Cv = Lt */
1450 		  red[i] = green[i] = blue[i] = Lt;
1451 		  /* Av = At */
1452 		  alpha[i] = At[i];
1453 	       }
1454 	       break;
1455 	    case GL_INTENSITY:
1456 	       for (i=0;i<n;i++) {
1457 		  /* Cv = It */
1458                   GLint It = Rt[i];
1459                   red[i] = green[i] = blue[i] = It;
1460                   /* Av = It */
1461                   alpha[i] = It;
1462 	       }
1463 	       break;
1464 	    case GL_RGB:
1465 	       for (i=0;i<n;i++) {
1466 		  /* Cv = Ct */
1467 		  red[i]   = Rt[i];
1468 		  green[i] = Gt[i];
1469 		  blue[i]  = Bt[i];
1470 		  /* Av = Af */
1471 	       }
1472 	       break;
1473 	    case GL_RGBA:
1474 	       for (i=0;i<n;i++) {
1475 		  /* Cv = Ct */
1476 		  red[i]   = Rt[i];
1477 		  green[i] = Gt[i];
1478 		  blue[i]  = Bt[i];
1479 		  /* Av = At */
1480 		  alpha[i] = At[i];
1481 	       }
1482 	       break;
1483             default:
1484                gl_problem(ctx, "Bad format in apply_texture");
1485                return;
1486 	 }
1487 	 break;
1488 
1489       case GL_MODULATE:
1490          switch (format) {
1491 	    case GL_ALPHA:
1492 	       for (i=0;i<n;i++) {
1493 		  /* Cv = Cf */
1494 		  /* Av = AfAt */
1495 		  alpha[i] = PROD( alpha[i], At[i] );
1496 	       }
1497 	       break;
1498 	    case GL_LUMINANCE:
1499 	       for (i=0;i<n;i++) {
1500 		  /* Cv = LtCf */
1501                   GLint Lt = Rt[i];
1502 		  red[i]   = PROD( red[i],   Lt );
1503 		  green[i] = PROD( green[i], Lt );
1504 		  blue[i]  = PROD( blue[i],  Lt );
1505 		  /* Av = Af */
1506 	       }
1507 	       break;
1508 	    case GL_LUMINANCE_ALPHA:
1509 	       for (i=0;i<n;i++) {
1510 		  /* Cv = CfLt */
1511                   GLint Lt = Rt[i];
1512 		  red[i]   = PROD( red[i],   Lt );
1513 		  green[i] = PROD( green[i], Lt );
1514 		  blue[i]  = PROD( blue[i],  Lt );
1515 		  /* Av = AfAt */
1516 		  alpha[i] = PROD( alpha[i], At[i] );
1517 	       }
1518 	       break;
1519 	    case GL_INTENSITY:
1520 	       for (i=0;i<n;i++) {
1521 		  /* Cv = CfIt */
1522                   GLint It = Rt[i];
1523 		  red[i]   = PROD( red[i],   It );
1524 		  green[i] = PROD( green[i], It );
1525 		  blue[i]  = PROD( blue[i],  It );
1526 		  /* Av = AfIt */
1527 		  alpha[i] = PROD( alpha[i], It );
1528 	       }
1529 	       break;
1530 	    case GL_RGB:
1531 	       for (i=0;i<n;i++) {
1532 		  /* Cv = CfCt */
1533 		  red[i]   = PROD( red[i],   Rt[i] );
1534 		  green[i] = PROD( green[i], Gt[i] );
1535 		  blue[i]  = PROD( blue[i],  Bt[i] );
1536 		  /* Av = Af */
1537 	       }
1538 	       break;
1539 	    case GL_RGBA:
1540 	       for (i=0;i<n;i++) {
1541 		  /* Cv = CfCt */
1542 		  red[i]   = PROD( red[i],   Rt[i] );
1543 		  green[i] = PROD( green[i], Gt[i] );
1544 		  blue[i]  = PROD( blue[i],  Bt[i] );
1545 		  /* Av = AfAt */
1546 		  alpha[i] = PROD( alpha[i], At[i] );
1547 	       }
1548 	       break;
1549             default:
1550                gl_problem(ctx, "Bad format (2) in apply_texture");
1551                return;
1552 	 }
1553 	 break;
1554 
1555       case GL_DECAL:
1556          switch (format) {
1557             case GL_ALPHA:
1558             case GL_LUMINANCE:
1559             case GL_LUMINANCE_ALPHA:
1560             case GL_INTENSITY:
1561                /* undefined */
1562                break;
1563 	    case GL_RGB:
1564 	       for (i=0;i<n;i++) {
1565 		  /* Cv = Ct */
1566 		  red[i]   = Rt[i];
1567 		  green[i] = Gt[i];
1568 		  blue[i]  = Bt[i];
1569 		  /* Av = Af */
1570 	       }
1571 	       break;
1572 	    case GL_RGBA:
1573 	       for (i=0;i<n;i++) {
1574 		  /* Cv = Cf(1-At) + CtAt */
1575 		  GLint t = At[i], s = 255 - t;
1576 		  red[i]   = PROD(red[i],  s) + PROD(Rt[i],t);
1577 		  green[i] = PROD(green[i],s) + PROD(Gt[i],t);
1578 		  blue[i]  = PROD(blue[i], s) + PROD(Bt[i],t);
1579 		  /* Av = Af */
1580 	       }
1581 	       break;
1582             default:
1583                gl_problem(ctx, "Bad format (3) in apply_texture");
1584                return;
1585 	 }
1586 	 break;
1587 
1588       case GL_BLEND:
1589          Rc = (GLint) (ctx->Texture.EnvColor[0] * 255.0F);
1590          Gc = (GLint) (ctx->Texture.EnvColor[1] * 255.0F);
1591          Bc = (GLint) (ctx->Texture.EnvColor[2] * 255.0F);
1592          Ac = (GLint) (ctx->Texture.EnvColor[3] * 255.0F);
1593 	 switch (format) {
1594 	    case GL_ALPHA:
1595 	       for (i=0;i<n;i++) {
1596 		  /* Cv = Cf */
1597 		  /* Av = AfAt */
1598                   alpha[i] = PROD(alpha[i], At[i]);
1599 	       }
1600 	       break;
1601             case GL_LUMINANCE:
1602 	       for (i=0;i<n;i++) {
1603 		  /* Cv = Cf(1-Lt) + CcLt */
1604 		  GLint Lt = Rt[i], s = 255 - Lt;
1605 		  red[i]   = PROD(red[i],  s) + PROD(Rc,  Lt);
1606 		  green[i] = PROD(green[i],s) + PROD(Gc,Lt);
1607 		  blue[i]  = PROD(blue[i], s) + PROD(Bc, Lt);
1608 		  /* Av = Af */
1609 	       }
1610 	       break;
1611 	    case GL_LUMINANCE_ALPHA:
1612 	       for (i=0;i<n;i++) {
1613 		  /* Cv = Cf(1-Lt) + CcLt */
1614 		  GLint Lt = Rt[i], s = 255 - Lt;
1615 		  red[i]   = PROD(red[i],  s) + PROD(Rc,  Lt);
1616 		  green[i] = PROD(green[i],s) + PROD(Gc,Lt);
1617 		  blue[i]  = PROD(blue[i], s) + PROD(Bc, Lt);
1618 		  /* Av = AfAt */
1619 		  alpha[i] = PROD(alpha[i],At[i]);
1620 	       }
1621 	       break;
1622             case GL_INTENSITY:
1623 	       for (i=0;i<n;i++) {
1624 		  /* Cv = Cf(1-It) + CcLt */
1625 		  GLint It = Rt[i], s = 255 - It;
1626 		  red[i]   = PROD(red[i],  s) + PROD(Rc,It);
1627 		  green[i] = PROD(green[i],s) + PROD(Gc,It);
1628 		  blue[i]  = PROD(blue[i], s) + PROD(Bc,It);
1629                   /* Av = Af(1-It) + Ac*It */
1630                   alpha[i] = PROD(alpha[i],s) + PROD(Ac,It);
1631                }
1632                break;
1633 	    case GL_RGB:
1634 	       for (i=0;i<n;i++) {
1635 		  /* Cv = Cf(1-Ct) + CcCt */
1636 		  red[i]   = PROD(red[i],  (255-Rt[i])) + PROD(Rc,Rt[i]);
1637 		  green[i] = PROD(green[i],(255-Gt[i])) + PROD(Gc,Gt[i]);
1638 		  blue[i]  = PROD(blue[i], (255-Bt[i])) + PROD(Bc,Bt[i]);
1639 		  /* Av = Af */
1640 	       }
1641 	       break;
1642 	    case GL_RGBA:
1643 	       for (i=0;i<n;i++) {
1644 		  /* Cv = Cf(1-Ct) + CcCt */
1645 		  red[i]   = PROD(red[i],  (255-Rt[i])) + PROD(Rc,Rt[i]);
1646 		  green[i] = PROD(green[i],(255-Gt[i])) + PROD(Gc,Gt[i]);
1647 		  blue[i]  = PROD(blue[i], (255-Bt[i])) + PROD(Bc,Bt[i]);
1648 		  /* Av = AfAt */
1649 		  alpha[i] = PROD(alpha[i],At[i]);
1650 	       }
1651 	       break;
1652 	 }
1653 	 break;
1654 
1655       default:
1656          gl_problem(ctx, "Bad env mode in apply_texture");
1657          return;
1658    }
1659 #undef PROD
1660 
1661    if (!ctx->Visual->EightBitColor) {
1662       /* This is a hack!  Rescale input colors from [0,255] to [0,scale]. */
1663       GLfloat rscale = ctx->Visual->RedScale   * (1.0F/ 255.0F);
1664       GLfloat gscale = ctx->Visual->GreenScale * (1.0F/ 255.0F);
1665       GLfloat bscale = ctx->Visual->BlueScale  * (1.0F/ 255.0F);
1666       GLfloat ascale = ctx->Visual->AlphaScale * (1.0F/ 255.0F);
1667       for (i=0;i<n;i++) {
1668 	 red[i]   = (GLint) (red[i]   * rscale);
1669 	 green[i] = (GLint) (green[i] * gscale);
1670 	 blue[i]  = (GLint) (blue[i]  * bscale);
1671 	 alpha[i] = (GLint) (alpha[i] * ascale);
1672       }
1673    }
1674 }
1675 
1676 
1677 
gl_texture_pixels(GLcontext * ctx,GLuint n,const GLfloat s[],const GLfloat t[],const GLfloat r[],const GLfloat lambda[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[])1678 void gl_texture_pixels( GLcontext *ctx, GLuint n,
1679                         const GLfloat s[], const GLfloat t[],
1680                         const GLfloat r[], const GLfloat lambda[],
1681                         GLubyte red[], GLubyte green[],
1682                         GLubyte blue[], GLubyte alpha[] )
1683 {
1684    GLubyte tred[PB_SIZE];
1685    GLubyte tgreen[PB_SIZE];
1686    GLubyte tblue[PB_SIZE];
1687    GLubyte talpha[PB_SIZE];
1688 
1689    if (!ctx->Texture.Current || !ctx->Texture.Current->SampleFunc)
1690       return;
1691 
1692    /* Sample the texture. */
1693    (*ctx->Texture.Current->SampleFunc)( ctx->Texture.Current, n,
1694                                         s, t, r, lambda,
1695                                         tred, tgreen, tblue, talpha );
1696 
1697    apply_texture( ctx, n,
1698                   ctx->Texture.Current->Image[0]->Format,
1699                   ctx->Texture.EnvMode,
1700                   red, green, blue, alpha,
1701                   tred, tgreen, tblue, talpha );
1702 }
1703