pixel.c revision 4f6b704f9796775d8d9937c3cf75a2901b99b896
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26/**
27 * \file pixel.c
28 * Pixel transfer functions (glPixelZoom, glPixelMap, glPixelTransfer)
29 */
30
31#include "glheader.h"
32#include "bufferobj.h"
33#include "colormac.h"
34#include "context.h"
35#include "image.h"
36#include "macros.h"
37#include "pixel.h"
38#include "mtypes.h"
39
40
41/**********************************************************************/
42/*****                    glPixelZoom                             *****/
43/**********************************************************************/
44
45void GLAPIENTRY
46_mesa_PixelZoom( GLfloat xfactor, GLfloat yfactor )
47{
48   GET_CURRENT_CONTEXT(ctx);
49
50   if (ctx->Pixel.ZoomX == xfactor &&
51       ctx->Pixel.ZoomY == yfactor)
52      return;
53
54   FLUSH_VERTICES(ctx, _NEW_PIXEL);
55   ctx->Pixel.ZoomX = xfactor;
56   ctx->Pixel.ZoomY = yfactor;
57}
58
59
60
61/**********************************************************************/
62/*****                         glPixelMap                         *****/
63/**********************************************************************/
64
65/**
66 * Return pointer to a pixelmap by name.
67 */
68static struct gl_pixelmap *
69get_pixelmap(GLcontext *ctx, GLenum map)
70{
71   switch (map) {
72   case GL_PIXEL_MAP_I_TO_I:
73      return &ctx->PixelMaps.ItoI;
74   case GL_PIXEL_MAP_S_TO_S:
75      return &ctx->PixelMaps.StoS;
76   case GL_PIXEL_MAP_I_TO_R:
77      return &ctx->PixelMaps.ItoR;
78   case GL_PIXEL_MAP_I_TO_G:
79      return &ctx->PixelMaps.ItoG;
80   case GL_PIXEL_MAP_I_TO_B:
81      return &ctx->PixelMaps.ItoB;
82   case GL_PIXEL_MAP_I_TO_A:
83      return &ctx->PixelMaps.ItoA;
84   case GL_PIXEL_MAP_R_TO_R:
85      return &ctx->PixelMaps.RtoR;
86   case GL_PIXEL_MAP_G_TO_G:
87      return &ctx->PixelMaps.GtoG;
88   case GL_PIXEL_MAP_B_TO_B:
89      return &ctx->PixelMaps.BtoB;
90   case GL_PIXEL_MAP_A_TO_A:
91      return &ctx->PixelMaps.AtoA;
92   default:
93      return NULL;
94   }
95}
96
97
98/**
99 * Helper routine used by the other _mesa_PixelMap() functions.
100 */
101static void
102store_pixelmap(GLcontext *ctx, GLenum map, GLsizei mapsize,
103               const GLfloat *values)
104{
105   GLint i;
106   struct gl_pixelmap *pm = get_pixelmap(ctx, map);
107   if (!pm) {
108      _mesa_error(ctx, GL_INVALID_ENUM, "glPixelMap(map)");
109      return;
110   }
111
112   switch (map) {
113   case GL_PIXEL_MAP_S_TO_S:
114      /* special case */
115      ctx->PixelMaps.StoS.Size = mapsize;
116      for (i = 0; i < mapsize; i++) {
117         ctx->PixelMaps.StoS.Map[i] = (GLfloat)IROUND(values[i]);
118      }
119      break;
120   case GL_PIXEL_MAP_I_TO_I:
121      /* special case */
122      ctx->PixelMaps.ItoI.Size = mapsize;
123      for (i = 0; i < mapsize; i++) {
124         ctx->PixelMaps.ItoI.Map[i] = values[i];
125      }
126      break;
127   default:
128      /* general case */
129      pm->Size = mapsize;
130      for (i = 0; i < mapsize; i++) {
131         GLfloat val = CLAMP(values[i], 0.0F, 1.0F);
132         pm->Map[i] = val;
133         pm->Map8[i] = (GLint) (val * 255.0F);
134      }
135   }
136}
137
138
139void GLAPIENTRY
140_mesa_PixelMapfv( GLenum map, GLsizei mapsize, const GLfloat *values )
141{
142   GET_CURRENT_CONTEXT(ctx);
143   ASSERT_OUTSIDE_BEGIN_END(ctx);
144
145   /* XXX someday, test against ctx->Const.MaxPixelMapTableSize */
146   if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
147      _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" );
148      return;
149   }
150
151   if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
152      /* test that mapsize is a power of two */
153      if (!_mesa_is_pow_two(mapsize)) {
154	 _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapfv(mapsize)" );
155         return;
156      }
157   }
158
159   FLUSH_VERTICES(ctx, _NEW_PIXEL);
160
161   if (ctx->Unpack.BufferObj->Name) {
162      /* unpack pixelmap from PBO */
163      GLubyte *buf;
164      /* Note, need to use DefaultPacking and Unpack's buffer object */
165      ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj;
166      if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1,
167                                     GL_INTENSITY, GL_FLOAT, values)) {
168         _mesa_error(ctx, GL_INVALID_OPERATION,
169                     "glPixelMapfv(invalid PBO access)");
170         return;
171      }
172      /* restore */
173      ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj;
174      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
175                                              GL_READ_ONLY_ARB,
176                                              ctx->Unpack.BufferObj);
177      if (!buf) {
178         /* buffer is already mapped - that's an error */
179         _mesa_error(ctx, GL_INVALID_OPERATION,
180                     "glPixelMapfv(PBO is mapped)");
181         return;
182      }
183      values = (const GLfloat *) ADD_POINTERS(buf, values);
184   }
185   else if (!values) {
186      return;
187   }
188
189   store_pixelmap(ctx, map, mapsize, values);
190
191   if (ctx->Unpack.BufferObj->Name) {
192      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
193                              ctx->Unpack.BufferObj);
194   }
195}
196
197
198void GLAPIENTRY
199_mesa_PixelMapuiv(GLenum map, GLsizei mapsize, const GLuint *values )
200{
201   GLfloat fvalues[MAX_PIXEL_MAP_TABLE];
202   GET_CURRENT_CONTEXT(ctx);
203   ASSERT_OUTSIDE_BEGIN_END(ctx);
204
205   if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
206      _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
207      return;
208   }
209
210   if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
211      /* test that mapsize is a power of two */
212      if (!_mesa_is_pow_two(mapsize)) {
213	 _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
214         return;
215      }
216   }
217
218   FLUSH_VERTICES(ctx, _NEW_PIXEL);
219
220   if (ctx->Unpack.BufferObj->Name) {
221      /* unpack pixelmap from PBO */
222      GLubyte *buf;
223      /* Note, need to use DefaultPacking and Unpack's buffer object */
224      ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj;
225      if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1,
226                                     GL_INTENSITY, GL_UNSIGNED_INT, values)) {
227         _mesa_error(ctx, GL_INVALID_OPERATION,
228                     "glPixelMapuiv(invalid PBO access)");
229         return;
230      }
231      /* restore */
232      ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj;
233      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
234                                              GL_READ_ONLY_ARB,
235                                              ctx->Unpack.BufferObj);
236      if (!buf) {
237         /* buffer is already mapped - that's an error */
238         _mesa_error(ctx, GL_INVALID_OPERATION,
239                     "glPixelMapuiv(PBO is mapped)");
240         return;
241      }
242      values = (const GLuint *) ADD_POINTERS(buf, values);
243   }
244   else if (!values) {
245      return;
246   }
247
248   /* convert to floats */
249   if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) {
250      GLint i;
251      for (i = 0; i < mapsize; i++) {
252         fvalues[i] = (GLfloat) values[i];
253      }
254   }
255   else {
256      GLint i;
257      for (i = 0; i < mapsize; i++) {
258         fvalues[i] = UINT_TO_FLOAT( values[i] );
259      }
260   }
261
262   if (ctx->Unpack.BufferObj->Name) {
263      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
264                              ctx->Unpack.BufferObj);
265   }
266
267   store_pixelmap(ctx, map, mapsize, fvalues);
268}
269
270
271void GLAPIENTRY
272_mesa_PixelMapusv(GLenum map, GLsizei mapsize, const GLushort *values )
273{
274   GLfloat fvalues[MAX_PIXEL_MAP_TABLE];
275   GET_CURRENT_CONTEXT(ctx);
276   ASSERT_OUTSIDE_BEGIN_END(ctx);
277
278   if (mapsize < 1 || mapsize > MAX_PIXEL_MAP_TABLE) {
279      _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapusv(mapsize)" );
280      return;
281   }
282
283   if (map >= GL_PIXEL_MAP_S_TO_S && map <= GL_PIXEL_MAP_I_TO_A) {
284      /* test that mapsize is a power of two */
285      if (!_mesa_is_pow_two(mapsize)) {
286	 _mesa_error( ctx, GL_INVALID_VALUE, "glPixelMapuiv(mapsize)" );
287         return;
288      }
289   }
290
291   FLUSH_VERTICES(ctx, _NEW_PIXEL);
292
293   if (ctx->Unpack.BufferObj->Name) {
294      /* unpack pixelmap from PBO */
295      GLubyte *buf;
296      /* Note, need to use DefaultPacking and Unpack's buffer object */
297      ctx->DefaultPacking.BufferObj = ctx->Unpack.BufferObj;
298      if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1,
299                                     GL_INTENSITY, GL_UNSIGNED_SHORT,
300                                     values)) {
301         _mesa_error(ctx, GL_INVALID_OPERATION,
302                     "glPixelMapusv(invalid PBO access)");
303         return;
304      }
305      /* restore */
306      ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj;
307      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
308                                              GL_READ_ONLY_ARB,
309                                              ctx->Unpack.BufferObj);
310      if (!buf) {
311         /* buffer is already mapped - that's an error */
312         _mesa_error(ctx, GL_INVALID_OPERATION,
313                     "glPixelMapusv(PBO is mapped)");
314         return;
315      }
316      values = (const GLushort *) ADD_POINTERS(buf, values);
317   }
318   else if (!values) {
319      return;
320   }
321
322   /* convert to floats */
323   if (map == GL_PIXEL_MAP_I_TO_I || map == GL_PIXEL_MAP_S_TO_S) {
324      GLint i;
325      for (i = 0; i < mapsize; i++) {
326         fvalues[i] = (GLfloat) values[i];
327      }
328   }
329   else {
330      GLint i;
331      for (i = 0; i < mapsize; i++) {
332         fvalues[i] = USHORT_TO_FLOAT( values[i] );
333      }
334   }
335
336   if (ctx->Unpack.BufferObj->Name) {
337      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT,
338                              ctx->Unpack.BufferObj);
339   }
340
341   store_pixelmap(ctx, map, mapsize, fvalues);
342}
343
344
345void GLAPIENTRY
346_mesa_GetPixelMapfv( GLenum map, GLfloat *values )
347{
348   GET_CURRENT_CONTEXT(ctx);
349   GLuint mapsize, i;
350   const struct gl_pixelmap *pm;
351
352   ASSERT_OUTSIDE_BEGIN_END(ctx);
353
354   pm = get_pixelmap(ctx, map);
355   if (!pm) {
356      _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapfv(map)");
357      return;
358   }
359
360   mapsize = pm->Size;
361
362   if (ctx->Pack.BufferObj->Name) {
363      /* pack pixelmap into PBO */
364      GLubyte *buf;
365      /* Note, need to use DefaultPacking and Pack's buffer object */
366      ctx->DefaultPacking.BufferObj = ctx->Pack.BufferObj;
367      if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1,
368                                     GL_INTENSITY, GL_FLOAT, values)) {
369         _mesa_error(ctx, GL_INVALID_OPERATION,
370                     "glGetPixelMapfv(invalid PBO access)");
371         return;
372      }
373      /* restore */
374      ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj;
375      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
376                                              GL_WRITE_ONLY_ARB,
377                                              ctx->Pack.BufferObj);
378      if (!buf) {
379         /* buffer is already mapped - that's an error */
380         _mesa_error(ctx, GL_INVALID_OPERATION,
381                     "glGetPixelMapfv(PBO is mapped)");
382         return;
383      }
384      values = (GLfloat *) ADD_POINTERS(buf, values);
385   }
386   else if (!values) {
387      return;
388   }
389
390   if (map == GL_PIXEL_MAP_S_TO_S) {
391      /* special case */
392      for (i = 0; i < mapsize; i++) {
393         values[i] = (GLfloat) ctx->PixelMaps.StoS.Map[i];
394      }
395   }
396   else {
397      MEMCPY(values, pm->Map, mapsize * sizeof(GLfloat));
398   }
399
400   if (ctx->Pack.BufferObj->Name) {
401      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
402                              ctx->Pack.BufferObj);
403   }
404}
405
406
407void GLAPIENTRY
408_mesa_GetPixelMapuiv( GLenum map, GLuint *values )
409{
410   GET_CURRENT_CONTEXT(ctx);
411   GLint mapsize, i;
412   const struct gl_pixelmap *pm;
413
414   ASSERT_OUTSIDE_BEGIN_END(ctx);
415
416   pm = get_pixelmap(ctx, map);
417   if (!pm) {
418      _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapuiv(map)");
419      return;
420   }
421   mapsize = pm->Size;
422
423   if (ctx->Pack.BufferObj->Name) {
424      /* pack pixelmap into PBO */
425      GLubyte *buf;
426      /* Note, need to use DefaultPacking and Pack's buffer object */
427      ctx->DefaultPacking.BufferObj = ctx->Pack.BufferObj;
428      if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1,
429                                     GL_INTENSITY, GL_UNSIGNED_INT, values)) {
430         _mesa_error(ctx, GL_INVALID_OPERATION,
431                     "glGetPixelMapuiv(invalid PBO access)");
432         return;
433      }
434      /* restore */
435      ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj;
436      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
437                                              GL_WRITE_ONLY_ARB,
438                                              ctx->Pack.BufferObj);
439      if (!buf) {
440         /* buffer is already mapped - that's an error */
441         _mesa_error(ctx, GL_INVALID_OPERATION,
442                     "glGetPixelMapuiv(PBO is mapped)");
443         return;
444      }
445      values = (GLuint *) ADD_POINTERS(buf, values);
446   }
447   else if (!values) {
448      return;
449   }
450
451   if (map == GL_PIXEL_MAP_S_TO_S) {
452      /* special case */
453      MEMCPY(values, ctx->PixelMaps.StoS.Map, mapsize * sizeof(GLint));
454   }
455   else {
456      for (i = 0; i < mapsize; i++) {
457         values[i] = FLOAT_TO_UINT( pm->Map[i] );
458      }
459   }
460
461   if (ctx->Pack.BufferObj->Name) {
462      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
463                              ctx->Pack.BufferObj);
464   }
465}
466
467
468void GLAPIENTRY
469_mesa_GetPixelMapusv( GLenum map, GLushort *values )
470{
471   GET_CURRENT_CONTEXT(ctx);
472   GLint mapsize, i;
473   const struct gl_pixelmap *pm;
474
475   ASSERT_OUTSIDE_BEGIN_END(ctx);
476
477   pm = get_pixelmap(ctx, map);
478   if (!pm) {
479      _mesa_error(ctx, GL_INVALID_ENUM, "glGetPixelMapusv(map)");
480      return;
481   }
482   mapsize = pm ? pm->Size : 0;
483
484   if (ctx->Pack.BufferObj->Name) {
485      /* pack pixelmap into PBO */
486      GLubyte *buf;
487      /* Note, need to use DefaultPacking and Pack's buffer object */
488      ctx->DefaultPacking.BufferObj = ctx->Pack.BufferObj;
489      if (!_mesa_validate_pbo_access(1, &ctx->DefaultPacking, mapsize, 1, 1,
490                                     GL_INTENSITY, GL_UNSIGNED_SHORT,
491                                     values)) {
492         _mesa_error(ctx, GL_INVALID_OPERATION,
493                     "glGetPixelMapusv(invalid PBO access)");
494         return;
495      }
496      /* restore */
497      ctx->DefaultPacking.BufferObj = ctx->Shared->NullBufferObj;
498      buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
499                                              GL_WRITE_ONLY_ARB,
500                                              ctx->Pack.BufferObj);
501      if (!buf) {
502         /* buffer is already mapped - that's an error */
503         _mesa_error(ctx, GL_INVALID_OPERATION,
504                     "glGetPixelMapusv(PBO is mapped)");
505         return;
506      }
507      values = (GLushort *) ADD_POINTERS(buf, values);
508   }
509   else if (!values) {
510      return;
511   }
512
513   switch (map) {
514   /* special cases */
515   case GL_PIXEL_MAP_I_TO_I:
516      for (i = 0; i < mapsize; i++) {
517         values[i] = (GLushort) CLAMP(ctx->PixelMaps.ItoI.Map[i], 0.0, 65535.);
518      }
519      break;
520   case GL_PIXEL_MAP_S_TO_S:
521      for (i = 0; i < mapsize; i++) {
522         values[i] = (GLushort) CLAMP(ctx->PixelMaps.StoS.Map[i], 0.0, 65535.);
523      }
524      break;
525   default:
526      for (i = 0; i < mapsize; i++) {
527         CLAMPED_FLOAT_TO_USHORT(values[i], pm->Map[i] );
528      }
529   }
530
531   if (ctx->Pack.BufferObj->Name) {
532      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
533                              ctx->Pack.BufferObj);
534   }
535}
536
537
538
539/**********************************************************************/
540/*****                       glPixelTransfer                      *****/
541/**********************************************************************/
542
543
544/*
545 * Implements glPixelTransfer[fi] whether called immediately or from a
546 * display list.
547 */
548void GLAPIENTRY
549_mesa_PixelTransferf( GLenum pname, GLfloat param )
550{
551   GET_CURRENT_CONTEXT(ctx);
552   ASSERT_OUTSIDE_BEGIN_END(ctx);
553
554   switch (pname) {
555      case GL_MAP_COLOR:
556         if (ctx->Pixel.MapColorFlag == (param ? GL_TRUE : GL_FALSE))
557	    return;
558	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
559         ctx->Pixel.MapColorFlag = param ? GL_TRUE : GL_FALSE;
560	 break;
561      case GL_MAP_STENCIL:
562         if (ctx->Pixel.MapStencilFlag == (param ? GL_TRUE : GL_FALSE))
563	    return;
564	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
565         ctx->Pixel.MapStencilFlag = param ? GL_TRUE : GL_FALSE;
566	 break;
567      case GL_INDEX_SHIFT:
568         if (ctx->Pixel.IndexShift == (GLint) param)
569	    return;
570	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
571         ctx->Pixel.IndexShift = (GLint) param;
572	 break;
573      case GL_INDEX_OFFSET:
574         if (ctx->Pixel.IndexOffset == (GLint) param)
575	    return;
576	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
577         ctx->Pixel.IndexOffset = (GLint) param;
578	 break;
579      case GL_RED_SCALE:
580         if (ctx->Pixel.RedScale == param)
581	    return;
582	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
583         ctx->Pixel.RedScale = param;
584	 break;
585      case GL_RED_BIAS:
586         if (ctx->Pixel.RedBias == param)
587	    return;
588	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
589         ctx->Pixel.RedBias = param;
590	 break;
591      case GL_GREEN_SCALE:
592         if (ctx->Pixel.GreenScale == param)
593	    return;
594	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
595         ctx->Pixel.GreenScale = param;
596	 break;
597      case GL_GREEN_BIAS:
598         if (ctx->Pixel.GreenBias == param)
599	    return;
600	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
601         ctx->Pixel.GreenBias = param;
602	 break;
603      case GL_BLUE_SCALE:
604         if (ctx->Pixel.BlueScale == param)
605	    return;
606	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
607         ctx->Pixel.BlueScale = param;
608	 break;
609      case GL_BLUE_BIAS:
610         if (ctx->Pixel.BlueBias == param)
611	    return;
612	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
613         ctx->Pixel.BlueBias = param;
614	 break;
615      case GL_ALPHA_SCALE:
616         if (ctx->Pixel.AlphaScale == param)
617	    return;
618	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
619         ctx->Pixel.AlphaScale = param;
620	 break;
621      case GL_ALPHA_BIAS:
622         if (ctx->Pixel.AlphaBias == param)
623	    return;
624	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
625         ctx->Pixel.AlphaBias = param;
626	 break;
627      case GL_DEPTH_SCALE:
628         if (ctx->Pixel.DepthScale == param)
629	    return;
630	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
631         ctx->Pixel.DepthScale = param;
632	 break;
633      case GL_DEPTH_BIAS:
634         if (ctx->Pixel.DepthBias == param)
635	    return;
636	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
637         ctx->Pixel.DepthBias = param;
638	 break;
639      case GL_POST_COLOR_MATRIX_RED_SCALE:
640         if (ctx->Pixel.PostColorMatrixScale[0] == param)
641	    return;
642	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
643         ctx->Pixel.PostColorMatrixScale[0] = param;
644	 break;
645      case GL_POST_COLOR_MATRIX_RED_BIAS:
646         if (ctx->Pixel.PostColorMatrixBias[0] == param)
647	    return;
648	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
649         ctx->Pixel.PostColorMatrixBias[0] = param;
650	 break;
651      case GL_POST_COLOR_MATRIX_GREEN_SCALE:
652         if (ctx->Pixel.PostColorMatrixScale[1] == param)
653	    return;
654	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
655         ctx->Pixel.PostColorMatrixScale[1] = param;
656	 break;
657      case GL_POST_COLOR_MATRIX_GREEN_BIAS:
658         if (ctx->Pixel.PostColorMatrixBias[1] == param)
659	    return;
660	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
661         ctx->Pixel.PostColorMatrixBias[1] = param;
662	 break;
663      case GL_POST_COLOR_MATRIX_BLUE_SCALE:
664         if (ctx->Pixel.PostColorMatrixScale[2] == param)
665	    return;
666	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
667         ctx->Pixel.PostColorMatrixScale[2] = param;
668	 break;
669      case GL_POST_COLOR_MATRIX_BLUE_BIAS:
670         if (ctx->Pixel.PostColorMatrixBias[2] == param)
671	    return;
672	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
673         ctx->Pixel.PostColorMatrixBias[2] = param;
674	 break;
675      case GL_POST_COLOR_MATRIX_ALPHA_SCALE:
676         if (ctx->Pixel.PostColorMatrixScale[3] == param)
677	    return;
678	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
679         ctx->Pixel.PostColorMatrixScale[3] = param;
680	 break;
681      case GL_POST_COLOR_MATRIX_ALPHA_BIAS:
682         if (ctx->Pixel.PostColorMatrixBias[3] == param)
683	    return;
684	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
685         ctx->Pixel.PostColorMatrixBias[3] = param;
686	 break;
687      case GL_POST_CONVOLUTION_RED_SCALE:
688         if (ctx->Pixel.PostConvolutionScale[0] == param)
689	    return;
690	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
691         ctx->Pixel.PostConvolutionScale[0] = param;
692	 break;
693      case GL_POST_CONVOLUTION_RED_BIAS:
694         if (ctx->Pixel.PostConvolutionBias[0] == param)
695	    return;
696	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
697         ctx->Pixel.PostConvolutionBias[0] = param;
698	 break;
699      case GL_POST_CONVOLUTION_GREEN_SCALE:
700         if (ctx->Pixel.PostConvolutionScale[1] == param)
701	    return;
702	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
703         ctx->Pixel.PostConvolutionScale[1] = param;
704	 break;
705      case GL_POST_CONVOLUTION_GREEN_BIAS:
706         if (ctx->Pixel.PostConvolutionBias[1] == param)
707	    return;
708	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
709         ctx->Pixel.PostConvolutionBias[1] = param;
710	 break;
711      case GL_POST_CONVOLUTION_BLUE_SCALE:
712         if (ctx->Pixel.PostConvolutionScale[2] == param)
713	    return;
714	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
715         ctx->Pixel.PostConvolutionScale[2] = param;
716	 break;
717      case GL_POST_CONVOLUTION_BLUE_BIAS:
718         if (ctx->Pixel.PostConvolutionBias[2] == param)
719	    return;
720	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
721         ctx->Pixel.PostConvolutionBias[2] = param;
722	 break;
723      case GL_POST_CONVOLUTION_ALPHA_SCALE:
724         if (ctx->Pixel.PostConvolutionScale[3] == param)
725	    return;
726	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
727         ctx->Pixel.PostConvolutionScale[3] = param;
728	 break;
729      case GL_POST_CONVOLUTION_ALPHA_BIAS:
730         if (ctx->Pixel.PostConvolutionBias[3] == param)
731	    return;
732	 FLUSH_VERTICES(ctx, _NEW_PIXEL);
733         ctx->Pixel.PostConvolutionBias[3] = param;
734	 break;
735      default:
736         _mesa_error( ctx, GL_INVALID_ENUM, "glPixelTransfer(pname)" );
737         return;
738   }
739}
740
741
742void GLAPIENTRY
743_mesa_PixelTransferi( GLenum pname, GLint param )
744{
745   _mesa_PixelTransferf( pname, (GLfloat) param );
746}
747
748
749
750/**********************************************************************/
751/*****                    State Management                        *****/
752/**********************************************************************/
753
754/*
755 * Return a bitmask of IMAGE_*_BIT flags which to indicate which
756 * pixel transfer operations are enabled.
757 */
758static void
759update_image_transfer_state(GLcontext *ctx)
760{
761   GLuint mask = 0;
762
763   if (ctx->Pixel.RedScale   != 1.0F || ctx->Pixel.RedBias   != 0.0F ||
764       ctx->Pixel.GreenScale != 1.0F || ctx->Pixel.GreenBias != 0.0F ||
765       ctx->Pixel.BlueScale  != 1.0F || ctx->Pixel.BlueBias  != 0.0F ||
766       ctx->Pixel.AlphaScale != 1.0F || ctx->Pixel.AlphaBias != 0.0F)
767      mask |= IMAGE_SCALE_BIAS_BIT;
768
769   if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset)
770      mask |= IMAGE_SHIFT_OFFSET_BIT;
771
772   if (ctx->Pixel.MapColorFlag)
773      mask |= IMAGE_MAP_COLOR_BIT;
774
775   if (ctx->Pixel.ColorTableEnabled[COLORTABLE_PRECONVOLUTION])
776      mask |= IMAGE_COLOR_TABLE_BIT;
777
778   if (ctx->Pixel.Convolution1DEnabled ||
779       ctx->Pixel.Convolution2DEnabled ||
780       ctx->Pixel.Separable2DEnabled) {
781      mask |= IMAGE_CONVOLUTION_BIT;
782      if (ctx->Pixel.PostConvolutionScale[0] != 1.0F ||
783          ctx->Pixel.PostConvolutionScale[1] != 1.0F ||
784          ctx->Pixel.PostConvolutionScale[2] != 1.0F ||
785          ctx->Pixel.PostConvolutionScale[3] != 1.0F ||
786          ctx->Pixel.PostConvolutionBias[0] != 0.0F ||
787          ctx->Pixel.PostConvolutionBias[1] != 0.0F ||
788          ctx->Pixel.PostConvolutionBias[2] != 0.0F ||
789          ctx->Pixel.PostConvolutionBias[3] != 0.0F) {
790         mask |= IMAGE_POST_CONVOLUTION_SCALE_BIAS;
791      }
792   }
793
794   if (ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCONVOLUTION])
795      mask |= IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT;
796
797   if (ctx->ColorMatrixStack.Top->type != MATRIX_IDENTITY ||
798       ctx->Pixel.PostColorMatrixScale[0] != 1.0F ||
799       ctx->Pixel.PostColorMatrixBias[0]  != 0.0F ||
800       ctx->Pixel.PostColorMatrixScale[1] != 1.0F ||
801       ctx->Pixel.PostColorMatrixBias[1]  != 0.0F ||
802       ctx->Pixel.PostColorMatrixScale[2] != 1.0F ||
803       ctx->Pixel.PostColorMatrixBias[2]  != 0.0F ||
804       ctx->Pixel.PostColorMatrixScale[3] != 1.0F ||
805       ctx->Pixel.PostColorMatrixBias[3]  != 0.0F)
806      mask |= IMAGE_COLOR_MATRIX_BIT;
807
808   if (ctx->Pixel.ColorTableEnabled[COLORTABLE_POSTCOLORMATRIX])
809      mask |= IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT;
810
811   if (ctx->Pixel.HistogramEnabled)
812      mask |= IMAGE_HISTOGRAM_BIT;
813
814   if (ctx->Pixel.MinMaxEnabled)
815      mask |= IMAGE_MIN_MAX_BIT;
816
817   ctx->_ImageTransferState = mask;
818}
819
820
821/**
822 * Update mesa pixel transfer derived state.
823 */
824void _mesa_update_pixel( GLcontext *ctx, GLuint new_state )
825{
826   if (new_state & _NEW_COLOR_MATRIX)
827      _math_matrix_analyse( ctx->ColorMatrixStack.Top );
828
829   /* References ColorMatrix.type (derived above).
830    */
831   if (new_state & _MESA_NEW_TRANSFER_STATE)
832      update_image_transfer_state(ctx);
833}
834
835
836/**********************************************************************/
837/*****                      Initialization                        *****/
838/**********************************************************************/
839
840static void
841init_pixelmap(struct gl_pixelmap *map)
842{
843   map->Size = 1;
844   map->Map[0] = 0.0;
845   map->Map8[0] = 0;
846}
847
848
849/**
850 * Initialize the context's PIXEL attribute group.
851 */
852void
853_mesa_init_pixel( GLcontext *ctx )
854{
855   int i;
856
857   /* Pixel group */
858   ctx->Pixel.RedBias = 0.0;
859   ctx->Pixel.RedScale = 1.0;
860   ctx->Pixel.GreenBias = 0.0;
861   ctx->Pixel.GreenScale = 1.0;
862   ctx->Pixel.BlueBias = 0.0;
863   ctx->Pixel.BlueScale = 1.0;
864   ctx->Pixel.AlphaBias = 0.0;
865   ctx->Pixel.AlphaScale = 1.0;
866   ctx->Pixel.DepthBias = 0.0;
867   ctx->Pixel.DepthScale = 1.0;
868   ctx->Pixel.IndexOffset = 0;
869   ctx->Pixel.IndexShift = 0;
870   ctx->Pixel.ZoomX = 1.0;
871   ctx->Pixel.ZoomY = 1.0;
872   ctx->Pixel.MapColorFlag = GL_FALSE;
873   ctx->Pixel.MapStencilFlag = GL_FALSE;
874   init_pixelmap(&ctx->PixelMaps.StoS);
875   init_pixelmap(&ctx->PixelMaps.ItoI);
876   init_pixelmap(&ctx->PixelMaps.ItoR);
877   init_pixelmap(&ctx->PixelMaps.ItoG);
878   init_pixelmap(&ctx->PixelMaps.ItoB);
879   init_pixelmap(&ctx->PixelMaps.ItoA);
880   init_pixelmap(&ctx->PixelMaps.RtoR);
881   init_pixelmap(&ctx->PixelMaps.GtoG);
882   init_pixelmap(&ctx->PixelMaps.BtoB);
883   init_pixelmap(&ctx->PixelMaps.AtoA);
884   ctx->Pixel.HistogramEnabled = GL_FALSE;
885   ctx->Pixel.MinMaxEnabled = GL_FALSE;
886   ASSIGN_4V(ctx->Pixel.PostColorMatrixScale, 1.0, 1.0, 1.0, 1.0);
887   ASSIGN_4V(ctx->Pixel.PostColorMatrixBias, 0.0, 0.0, 0.0, 0.0);
888   for (i = 0; i < COLORTABLE_MAX; i++) {
889      ASSIGN_4V(ctx->Pixel.ColorTableScale[i], 1.0, 1.0, 1.0, 1.0);
890      ASSIGN_4V(ctx->Pixel.ColorTableBias[i], 0.0, 0.0, 0.0, 0.0);
891      ctx->Pixel.ColorTableEnabled[i] = GL_FALSE;
892   }
893   ctx->Pixel.Convolution1DEnabled = GL_FALSE;
894   ctx->Pixel.Convolution2DEnabled = GL_FALSE;
895   ctx->Pixel.Separable2DEnabled = GL_FALSE;
896   for (i = 0; i < 3; i++) {
897      ASSIGN_4V(ctx->Pixel.ConvolutionBorderColor[i], 0.0, 0.0, 0.0, 0.0);
898      ctx->Pixel.ConvolutionBorderMode[i] = GL_REDUCE;
899      ASSIGN_4V(ctx->Pixel.ConvolutionFilterScale[i], 1.0, 1.0, 1.0, 1.0);
900      ASSIGN_4V(ctx->Pixel.ConvolutionFilterBias[i], 0.0, 0.0, 0.0, 0.0);
901   }
902   for (i = 0; i < MAX_CONVOLUTION_WIDTH * MAX_CONVOLUTION_WIDTH * 4; i++) {
903      ctx->Convolution1D.Filter[i] = 0.0;
904      ctx->Convolution2D.Filter[i] = 0.0;
905      ctx->Separable2D.Filter[i] = 0.0;
906   }
907   ASSIGN_4V(ctx->Pixel.PostConvolutionScale, 1.0, 1.0, 1.0, 1.0);
908   ASSIGN_4V(ctx->Pixel.PostConvolutionBias, 0.0, 0.0, 0.0, 0.0);
909   /* GL_SGI_texture_color_table */
910   ASSIGN_4V(ctx->Pixel.TextureColorTableScale, 1.0, 1.0, 1.0, 1.0);
911   ASSIGN_4V(ctx->Pixel.TextureColorTableBias, 0.0, 0.0, 0.0, 0.0);
912
913   if (ctx->Visual.doubleBufferMode) {
914      ctx->Pixel.ReadBuffer = GL_BACK;
915   }
916   else {
917      ctx->Pixel.ReadBuffer = GL_FRONT;
918   }
919
920   /* Miscellaneous */
921   ctx->_ImageTransferState = 0;
922}
923