drawpix.c revision 6f0294ca4706f5edc70c825a4efde860c7ffb7d2
1/* $Id: drawpix.c,v 1.27 2000/08/16 17:32:42 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.4
6 *
7 * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28#ifdef PC_HEADER
29#include "all.h"
30#else
31#include "glheader.h"
32#include "context.h"
33#include "drawpix.h"
34#include "feedback.h"
35#include "image.h"
36#include "macros.h"
37#include "mem.h"
38#include "mmath.h"
39#include "pixel.h"
40#include "pixeltex.h"
41#include "span.h"
42#include "state.h"
43#include "stencil.h"
44#include "texture.h"
45#include "types.h"
46#include "zoom.h"
47#endif
48
49
50
51/*
52 * Given the dest position, size and skipPixels and skipRows values
53 * for a glDrawPixels command, perform clipping of the image bounds
54 * so the result lies withing the context's buffer bounds.
55 * Return:  GL_TRUE if image is ready for drawing
56 *          GL_FALSE if image was completely clipped away (draw nothing)
57 */
58GLboolean
59_mesa_clip_pixelrect(const GLcontext *ctx,
60                     GLint *destX, GLint *destY,
61                     GLsizei *width, GLsizei *height,
62                     GLint *skipPixels, GLint *skipRows)
63{
64   const GLframebuffer *buffer = ctx->DrawBuffer;
65
66   /* left clipping */
67   if (*destX < buffer->Xmin) {
68      *skipPixels += (buffer->Xmin - *destX);
69      *width -= (buffer->Xmin - *destX);
70      *destX = buffer->Xmin;
71   }
72   /* right clipping */
73   if (*destX + *width > buffer->Xmax)
74      *width -= (*destX + *width - buffer->Xmax - 1);
75
76   if (*width <= 0)
77      return GL_FALSE;
78
79   /* bottom clipping */
80   if (*destY < buffer->Ymin) {
81      *skipRows += (buffer->Ymin - *destY);
82      *height -= (buffer->Ymin - *destY);
83      *destY = buffer->Ymin;
84   }
85   /* top clipping */
86   if (*destY + *height > buffer->Ymax)
87      *height -= (*destY + *height - buffer->Ymax - 1);
88
89   if (*height <= 0)
90      return GL_TRUE;
91
92   return GL_TRUE;
93}
94
95
96
97/*
98 * Try to do a fast and simple RGB(a) glDrawPixels.
99 * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
100 */
101static GLboolean
102simple_DrawPixels( GLcontext *ctx, GLint x, GLint y,
103                   GLsizei width, GLsizei height, GLenum format, GLenum type,
104                   const GLvoid *pixels )
105{
106   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
107   GLubyte rgb[MAX_WIDTH][3];
108   GLubyte rgba[MAX_WIDTH][4];
109
110   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glDrawPixels",
111						  GL_FALSE);
112
113
114   if (!ctx->Current.RasterPosValid) {
115      /* no-op */
116      return GL_TRUE;
117   }
118
119   if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
120       && !ctx->Pixel.ScaleOrBiasRGBA
121       && !ctx->Pixel.ScaleOrBiasRGBApcm
122       && ctx->ColorMatrix.type == MATRIX_IDENTITY
123       && !ctx->Pixel.ColorTableEnabled
124       && !ctx->Pixel.PostColorMatrixColorTableEnabled
125       && !ctx->Pixel.PostConvolutionColorTableEnabled
126       && !ctx->Pixel.MinMaxEnabled
127       && !ctx->Pixel.HistogramEnabled
128       && ctx->Pixel.IndexShift==0 && ctx->Pixel.IndexOffset==0
129       && ctx->Pixel.MapColorFlag==0
130       && ctx->Texture.ReallyEnabled == 0
131       && unpack->Alignment==1
132       && !unpack->SwapBytes
133       && !unpack->LsbFirst) {
134
135      GLint destX = x;
136      GLint destY = y;
137      GLint drawWidth = width;           /* actual width drawn */
138      GLint drawHeight = height;         /* actual height drawn */
139      GLint skipPixels = unpack->SkipPixels;
140      GLint skipRows = unpack->SkipRows;
141      GLint rowLength;
142      GLdepth zSpan[MAX_WIDTH];  /* only used when zooming */
143      GLint zoomY0;
144
145      if (unpack->RowLength > 0)
146         rowLength = unpack->RowLength;
147      else
148         rowLength = width;
149
150      /* If we're not using pixel zoom then do all clipping calculations
151       * now.  Otherwise, we'll let the gl_write_zoomed_*_span() functions
152       * handle the clipping.
153       */
154      if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
155         /* horizontal clipping */
156         if (destX < ctx->DrawBuffer->Xmin) {
157            skipPixels += (ctx->DrawBuffer->Xmin - destX);
158            drawWidth  -= (ctx->DrawBuffer->Xmin - destX);
159            destX = ctx->DrawBuffer->Xmin;
160         }
161         if (destX + drawWidth > ctx->DrawBuffer->Xmax)
162            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax - 1);
163         if (drawWidth <= 0)
164            return GL_TRUE;
165
166         /* vertical clipping */
167         if (destY < ctx->DrawBuffer->Ymin) {
168            skipRows   += (ctx->DrawBuffer->Ymin - destY);
169            drawHeight -= (ctx->DrawBuffer->Ymin - destY);
170            destY = ctx->DrawBuffer->Ymin;
171         }
172         if (destY + drawHeight > ctx->DrawBuffer->Ymax)
173            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax - 1);
174         if (drawHeight <= 0)
175            return GL_TRUE;
176
177         zoomY0 = 0;  /* not used - silence compiler warning */
178      }
179      else {
180         /* setup array of fragment Z value to pass to zoom function */
181         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
182         GLint i;
183         assert(drawWidth < MAX_WIDTH);
184         for (i=0; i<drawWidth; i++)
185            zSpan[i] = z;
186
187         /* save Y value of first row */
188         zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
189      }
190
191
192      /*
193       * Ready to draw!
194       * The window region at (destX, destY) of size (drawWidth, drawHeight)
195       * will be written to.
196       * We'll take pixel data from buffer pointed to by "pixels" but we'll
197       * skip "skipRows" rows and skip "skipPixels" pixels/row.
198       */
199
200      if (format==GL_RGBA && type==GL_UNSIGNED_BYTE) {
201         if (ctx->Visual->RGBAflag) {
202            GLubyte *src = (GLubyte *) pixels
203               + (skipRows * rowLength + skipPixels) * 4;
204            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
205               /* no zooming */
206               GLint row;
207               for (row=0; row<drawHeight; row++) {
208                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
209                                               (void *) src, NULL);
210                  src += rowLength * 4;
211                  destY++;
212               }
213            }
214            else {
215               /* with zooming */
216               GLint row;
217               for (row=0; row<drawHeight; row++) {
218                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
219                                            zSpan, (void *) src, zoomY0);
220                  src += rowLength * 4;
221                  destY++;
222               }
223            }
224         }
225         return GL_TRUE;
226      }
227      else if (format==GL_RGB && type==GL_UNSIGNED_BYTE) {
228         if (ctx->Visual->RGBAflag) {
229            GLubyte *src = (GLubyte *) pixels
230               + (skipRows * rowLength + skipPixels) * 3;
231            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
232               GLint row;
233               for (row=0; row<drawHeight; row++) {
234                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
235                                              (void *) src, NULL);
236                  src += rowLength * 3;
237                  destY++;
238               }
239            }
240            else {
241               /* with zooming */
242               GLint row;
243               for (row=0; row<drawHeight; row++) {
244                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
245                                           zSpan, (void *) src, zoomY0);
246                  src += rowLength * 3;
247                  destY++;
248               }
249            }
250         }
251         return GL_TRUE;
252      }
253      else if (format==GL_LUMINANCE && type==GL_UNSIGNED_BYTE) {
254         if (ctx->Visual->RGBAflag) {
255            GLubyte *src = (GLubyte *) pixels
256               + (skipRows * rowLength + skipPixels);
257            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
258               /* no zooming */
259               GLint row;
260               assert(drawWidth < MAX_WIDTH);
261               for (row=0; row<drawHeight; row++) {
262                  GLint i;
263		  for (i=0;i<drawWidth;i++) {
264                     rgb[i][0] = src[i];
265                     rgb[i][1] = src[i];
266                     rgb[i][2] = src[i];
267		  }
268                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
269                                              (void *) rgb, NULL);
270                  src += rowLength;
271                  destY++;
272               }
273            }
274            else {
275               /* with zooming */
276               GLint row;
277               assert(drawWidth < MAX_WIDTH);
278               for (row=0; row<drawHeight; row++) {
279                  GLint i;
280		  for (i=0;i<drawWidth;i++) {
281                     rgb[i][0] = src[i];
282                     rgb[i][1] = src[i];
283                     rgb[i][2] = src[i];
284		  }
285                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
286                                           zSpan, (void *) rgb, zoomY0);
287                  src += rowLength;
288                  destY++;
289               }
290            }
291         }
292         return GL_TRUE;
293      }
294      else if (format==GL_LUMINANCE_ALPHA && type==GL_UNSIGNED_BYTE) {
295         if (ctx->Visual->RGBAflag) {
296            GLubyte *src = (GLubyte *) pixels
297               + (skipRows * rowLength + skipPixels)*2;
298            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
299               /* no zooming */
300               GLint row;
301               assert(drawWidth < MAX_WIDTH);
302               for (row=0; row<drawHeight; row++) {
303                  GLint i;
304                  GLubyte *ptr = src;
305		  for (i=0;i<drawWidth;i++) {
306                     rgba[i][0] = *ptr;
307                     rgba[i][1] = *ptr;
308                     rgba[i][2] = *ptr++;
309                     rgba[i][3] = *ptr++;
310		  }
311                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
312                                               (void *) rgba, NULL);
313                  src += rowLength*2;
314                  destY++;
315               }
316            }
317            else {
318               /* with zooming */
319               GLint row;
320               assert(drawWidth < MAX_WIDTH);
321               for (row=0; row<drawHeight; row++) {
322                  GLubyte *ptr = src;
323                  GLint i;
324		  for (i=0;i<drawWidth;i++) {
325                     rgba[i][0] = *ptr;
326                     rgba[i][1] = *ptr;
327                     rgba[i][2] = *ptr++;
328                     rgba[i][3] = *ptr++;
329		  }
330                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
331                                            zSpan, (void *) rgba, zoomY0);
332                  src += rowLength*2;
333                  destY++;
334               }
335            }
336         }
337         return GL_TRUE;
338      }
339      else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
340         GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
341         if (ctx->Visual->RGBAflag) {
342            /* convert CI data to RGBA */
343            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
344               /* no zooming */
345               GLint row;
346               for (row=0; row<drawHeight; row++) {
347                  assert(drawWidth < MAX_WIDTH);
348                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
349                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
350                                               (const GLubyte (*)[4])rgba,
351					       NULL);
352                  src += rowLength;
353                  destY++;
354               }
355               return GL_TRUE;
356            }
357            else {
358               /* with zooming */
359               GLint row;
360               for (row=0; row<drawHeight; row++) {
361                  assert(drawWidth < MAX_WIDTH);
362                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
363                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
364                                            zSpan, (void *) rgba, zoomY0);
365                  src += rowLength;
366                  destY++;
367               }
368               return GL_TRUE;
369            }
370         }
371         else {
372            /* write CI data to CI frame buffer */
373            GLint row;
374            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
375               /* no zooming */
376               for (row=0; row<drawHeight; row++) {
377                  (*ctx->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
378                                              src, NULL);
379                  src += rowLength;
380                  destY++;
381               }
382               return GL_TRUE;
383            }
384            else {
385               /* with zooming */
386               return GL_FALSE;
387            }
388         }
389      }
390      else {
391         /* can't handle this pixel format and/or data type here */
392         return GL_FALSE;
393      }
394   }
395
396   /* can't do a simple draw, have to use slow path */
397   return GL_FALSE;
398}
399
400
401
402/*
403 * Do glDrawPixels of index pixels.
404 */
405static void
406draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
407                   GLsizei width, GLsizei height,
408                   GLenum type, const GLvoid *pixels )
409{
410   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
411   const GLint desty = y;
412   GLint row, drawWidth;
413   GLdepth zspan[MAX_WIDTH];
414
415   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
416
417   /* Fragment depth values */
418   if (ctx->Depth.Test || ctx->Fog.Enabled) {
419      GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
420      GLint i;
421      for (i = 0; i < drawWidth; i++) {
422	 zspan[i] = zval;
423      }
424   }
425
426   /*
427    * General solution
428    */
429   for (row = 0; row < height; row++, y++) {
430      GLuint indexes[MAX_WIDTH];
431      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
432                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
433      _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
434                              type, source, &ctx->Unpack, GL_TRUE);
435      if (zoom) {
436         gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, indexes, desty);
437      }
438      else {
439         gl_write_index_span(ctx, drawWidth, x, y, zspan, indexes, GL_BITMAP);
440      }
441   }
442}
443
444
445
446/*
447 * Do glDrawPixels of stencil image.  The image datatype may either
448 * be GLubyte or GLbitmap.
449 */
450static void
451draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
452                     GLsizei width, GLsizei height,
453                     GLenum type, const GLvoid *pixels )
454{
455   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
456   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
457   const GLint desty = y;
458   GLint row, drawWidth;
459
460   if (type != GL_BYTE &&
461       type != GL_UNSIGNED_BYTE &&
462       type != GL_SHORT &&
463       type != GL_UNSIGNED_SHORT &&
464       type != GL_INT &&
465       type != GL_UNSIGNED_INT &&
466       type != GL_FLOAT &&
467       type != GL_BITMAP) {
468      gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
469      return;
470   }
471
472   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
473
474   for (row = 0; row < height; row++, y++) {
475      GLstencil values[MAX_WIDTH];
476      GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
477                      ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
478      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
479                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
480      _mesa_unpack_index_span(ctx, drawWidth, destType, values,
481                              type, source, &ctx->Unpack, GL_FALSE);
482      if (shift_or_offset) {
483         _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
484      }
485      if (ctx->Pixel.MapStencilFlag) {
486         _mesa_map_stencil( ctx, drawWidth, values );
487      }
488
489      if (zoom) {
490         gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
491                                       values, desty );
492      }
493      else {
494         _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
495      }
496   }
497}
498
499
500
501/*
502 * Do a glDrawPixels of depth values.
503 */
504static void
505draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
506                   GLsizei width, GLsizei height,
507                   GLenum type, const GLvoid *pixels )
508{
509   const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
510   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
511   const GLint desty = y;
512   GLubyte rgba[MAX_WIDTH][4];
513   GLuint ispan[MAX_WIDTH];
514   GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
515
516   if (type != GL_BYTE
517       && type != GL_UNSIGNED_BYTE
518       && type != GL_SHORT
519       && type != GL_UNSIGNED_SHORT
520       && type != GL_INT
521       && type != GL_UNSIGNED_INT
522       && type != GL_FLOAT) {
523      gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
524      return;
525   }
526
527   /* Colors or indexes */
528   if (ctx->Visual->RGBAflag) {
529      GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0F);
530      GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0F);
531      GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0F);
532      GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0F);
533      GLint i;
534      for (i = 0; i < drawWidth; i++) {
535         rgba[i][RCOMP] = r;
536         rgba[i][GCOMP] = g;
537         rgba[i][BCOMP] = b;
538         rgba[i][ACOMP] = a;
539      }
540   }
541   else {
542      GLint i;
543      for (i = 0; i < drawWidth; i++) {
544	 ispan[i] = ctx->Current.RasterIndex;
545      }
546   }
547
548   if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
549       && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
550      /* Special case: directly write 16-bit depth values */
551      GLint row;
552      for (row = 0; row < height; row++, y++) {
553         GLdepth zspan[MAX_WIDTH];
554         const GLushort *zptr = _mesa_image_address(&ctx->Unpack,
555                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
556         GLint i;
557         for (i = 0; i < width; i++)
558            zspan[i] = zptr[i];
559         gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
560      }
561   }
562   else if (type==GL_UNSIGNED_INT && ctx->Visual->DepthBits == 32
563       && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
564      /* Special case: directly write 32-bit depth values */
565      GLint row;
566      for (row = 0; row < height; row++, y++) {
567         const GLuint *zptr = _mesa_image_address(&ctx->Unpack,
568                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
569         gl_write_rgba_span( ctx, width, x, y, zptr, rgba, GL_BITMAP );
570      }
571   }
572   else {
573      /* General case */
574      GLint row;
575      for (row = 0; row < height; row++, y++) {
576         GLdepth zspan[MAX_WIDTH];
577         const GLvoid *src = _mesa_image_address(&ctx->Unpack,
578                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
579         _mesa_unpack_depth_span( ctx, drawWidth, zspan, type, src,
580                                  &ctx->Unpack, GL_TRUE );
581         if (ctx->Visual->RGBAflag) {
582            if (zoom) {
583               gl_write_zoomed_rgba_span(ctx, width, x, y, zspan,
584                                         (const GLubyte (*)[4])rgba, desty);
585            }
586            else {
587               gl_write_rgba_span(ctx, width, x, y, zspan, rgba, GL_BITMAP);
588            }
589         }
590         else {
591            if (zoom) {
592               gl_write_zoomed_index_span(ctx, width, x, y, zspan,
593                                          ispan, GL_BITMAP);
594            }
595            else {
596               gl_write_index_span(ctx, width, x, y, zspan, ispan, GL_BITMAP);
597            }
598         }
599
600      }
601   }
602}
603
604
605/*
606 * Do glDrawPixels of RGBA pixels.
607 */
608static void
609draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
610                  GLsizei width, GLsizei height,
611                  GLenum format, GLenum type, const GLvoid *pixels )
612{
613   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
614   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
615   const GLint desty = y;
616   GLdepth zspan[MAX_WIDTH];
617   GLboolean quickDraw;
618
619   /* Try an optimized glDrawPixels first */
620   if (simple_DrawPixels(ctx, x, y, width, height, format, type, pixels))
621      return;
622
623   /* Fragment depth values */
624   if (ctx->Depth.Test || ctx->Fog.Enabled) {
625      /* fill in array of z values */
626      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
627      GLint i;
628      for (i=0;i<width;i++) {
629	 zspan[i] = z;
630      }
631   }
632
633
634   if (ctx->RasterMask == 0 && !zoom
635       && x >= 0 && y >= 0
636       && x + width <= ctx->DrawBuffer->Width
637       && y + height <= ctx->DrawBuffer->Height) {
638      quickDraw = GL_TRUE;
639   }
640   else {
641      quickDraw = GL_FALSE;
642   }
643
644   /*
645    * General solution
646    */
647   {
648      GLubyte rgba[MAX_WIDTH][4];
649      GLint row;
650      if (width > MAX_WIDTH)
651         width = MAX_WIDTH;
652      for (row = 0; row < height; row++, y++) {
653         const GLvoid *source = _mesa_image_address(unpack,
654                  pixels, width, height, format, type, 0, row, 0);
655         _mesa_unpack_ubyte_color_span(ctx, width, GL_RGBA, (void*) rgba,
656                   format, type, source, unpack, GL_TRUE);
657         if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
658             (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
659            continue;
660
661         if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
662            GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
663            GLubyte primary_rgba[MAX_WIDTH][4];
664            GLuint unit;
665            /* XXX not sure how multitexture is supposed to work here */
666
667            MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLubyte));
668
669            for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
670               _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba,
671                                 s, t, r, q);
672               gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
673                                 primary_rgba, rgba);
674            }
675         }
676
677         if (quickDraw) {
678            (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
679                                          (CONST GLubyte (*)[]) rgba, NULL);
680         }
681         else if (zoom) {
682            gl_write_zoomed_rgba_span( ctx, width, x, y, zspan,
683				       (CONST GLubyte (*)[]) rgba, desty );
684         }
685         else {
686            gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, rgba, GL_BITMAP);
687         }
688      }
689   }
690}
691
692
693
694/*
695 * Execute glDrawPixels
696 */
697void
698_mesa_DrawPixels( GLsizei width, GLsizei height,
699                  GLenum format, GLenum type, const GLvoid *pixels )
700{
701   GET_CURRENT_CONTEXT(ctx);
702   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels");
703
704   if (ctx->RenderMode==GL_RENDER) {
705      GLint x, y;
706      if (!pixels || !ctx->Current.RasterPosValid) {
707	 return;
708      }
709
710      if (ctx->NewState) {
711         gl_update_state(ctx);
712      }
713
714      x = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
715      y = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
716
717      ctx->OcclusionResult = GL_TRUE;
718
719      /* see if device driver can do the drawpix */
720      if (ctx->Driver.DrawPixels
721          && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type,
722                                       &ctx->Unpack, pixels)) {
723         return;
724      }
725
726      switch (format) {
727	 case GL_STENCIL_INDEX:
728	    draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
729	    break;
730	 case GL_DEPTH_COMPONENT:
731	    draw_depth_pixels( ctx, x, y, width, height, type, pixels );
732	    break;
733	 case GL_COLOR_INDEX:
734            if (ctx->Visual->RGBAflag)
735               draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
736            else
737               draw_index_pixels(ctx, x, y, width, height, type, pixels);
738	    break;
739	 case GL_RED:
740	 case GL_GREEN:
741	 case GL_BLUE:
742	 case GL_ALPHA:
743	 case GL_LUMINANCE:
744	 case GL_LUMINANCE_ALPHA:
745	 case GL_RGB:
746         case GL_BGR:
747	 case GL_RGBA:
748	 case GL_BGRA:
749	 case GL_ABGR_EXT:
750            draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
751	    break;
752	 default:
753	    gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
754            return;
755      }
756   }
757   else if (ctx->RenderMode==GL_FEEDBACK) {
758      if (ctx->Current.RasterPosValid) {
759         GLfloat color[4];
760	 GLfloat texcoord[4], invq;
761	 UBYTE_RGBA_TO_FLOAT_RGBA(color, ctx->Current.ByteColor);
762         invq = 1.0F / ctx->Current.Texcoord[0][3];
763         texcoord[0] = ctx->Current.Texcoord[0][0] * invq;
764         texcoord[1] = ctx->Current.Texcoord[0][1] * invq;
765         texcoord[2] = ctx->Current.Texcoord[0][2] * invq;
766         texcoord[3] = ctx->Current.Texcoord[0][3];
767         FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
768         gl_feedback_vertex( ctx,
769                             ctx->Current.RasterPos,
770                             color, ctx->Current.Index, texcoord );
771      }
772   }
773   else if (ctx->RenderMode==GL_SELECT) {
774      if (ctx->Current.RasterPosValid) {
775         gl_update_hitflag( ctx, ctx->Current.RasterPos[2] );
776      }
777   }
778}
779
780