drawpix.c revision 1a1cf7ed75d799bbda34399ddab7949b8c06686e
1/* $Id: drawpix.c,v 1.22 2000/05/04 13:48:49 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.3
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.MinMaxEnabled
126       && !ctx->Pixel.HistogramEnabled
127       && ctx->Pixel.IndexShift==0 && ctx->Pixel.IndexOffset==0
128       && ctx->Pixel.MapColorFlag==0
129       && ctx->Texture.ReallyEnabled == 0
130       && unpack->Alignment==1
131       && !unpack->SwapBytes
132       && !unpack->LsbFirst) {
133
134      GLint destX = x;
135      GLint destY = y;
136      GLint drawWidth = width;           /* actual width drawn */
137      GLint drawHeight = height;         /* actual height drawn */
138      GLint skipPixels = unpack->SkipPixels;
139      GLint skipRows = unpack->SkipRows;
140      GLint rowLength;
141      GLdepth zSpan[MAX_WIDTH];  /* only used when zooming */
142      GLint zoomY0;
143
144      if (unpack->RowLength > 0)
145         rowLength = unpack->RowLength;
146      else
147         rowLength = width;
148
149      /* If we're not using pixel zoom then do all clipping calculations
150       * now.  Otherwise, we'll let the gl_write_zoomed_*_span() functions
151       * handle the clipping.
152       */
153      if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
154         /* horizontal clipping */
155         if (destX < ctx->DrawBuffer->Xmin) {
156            skipPixels += (ctx->DrawBuffer->Xmin - destX);
157            drawWidth  -= (ctx->DrawBuffer->Xmin - destX);
158            destX = ctx->DrawBuffer->Xmin;
159         }
160         if (destX + drawWidth > ctx->DrawBuffer->Xmax)
161            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax - 1);
162         if (drawWidth <= 0)
163            return GL_TRUE;
164
165         /* vertical clipping */
166         if (destY < ctx->DrawBuffer->Ymin) {
167            skipRows   += (ctx->DrawBuffer->Ymin - destY);
168            drawHeight -= (ctx->DrawBuffer->Ymin - destY);
169            destY = ctx->DrawBuffer->Ymin;
170         }
171         if (destY + drawHeight > ctx->DrawBuffer->Ymax)
172            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax - 1);
173         if (drawHeight <= 0)
174            return GL_TRUE;
175
176         zoomY0 = 0;  /* not used - silence compiler warning */
177      }
178      else {
179         /* setup array of fragment Z value to pass to zoom function */
180         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
181         GLint i;
182         assert(drawWidth < MAX_WIDTH);
183         for (i=0; i<drawWidth; i++)
184            zSpan[i] = z;
185
186         /* save Y value of first row */
187         zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
188      }
189
190
191      /*
192       * Ready to draw!
193       * The window region at (destX, destY) of size (drawWidth, drawHeight)
194       * will be written to.
195       * We'll take pixel data from buffer pointed to by "pixels" but we'll
196       * skip "skipRows" rows and skip "skipPixels" pixels/row.
197       */
198
199      if (format==GL_RGBA && type==GL_UNSIGNED_BYTE) {
200         if (ctx->Visual->RGBAflag) {
201            GLubyte *src = (GLubyte *) pixels
202               + (skipRows * rowLength + skipPixels) * 4;
203            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
204               /* no zooming */
205               GLint row;
206               for (row=0; row<drawHeight; row++) {
207                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
208                                               (void *) src, NULL);
209                  src += rowLength * 4;
210                  destY++;
211               }
212            }
213            else {
214               /* with zooming */
215               GLint row;
216               for (row=0; row<drawHeight; row++) {
217                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
218                                            zSpan, (void *) src, zoomY0);
219                  src += rowLength * 4;
220                  destY++;
221               }
222            }
223         }
224         return GL_TRUE;
225      }
226      else if (format==GL_RGB && type==GL_UNSIGNED_BYTE) {
227         if (ctx->Visual->RGBAflag) {
228            GLubyte *src = (GLubyte *) pixels
229               + (skipRows * rowLength + skipPixels) * 3;
230            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
231               GLint row;
232               for (row=0; row<drawHeight; row++) {
233                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
234                                              (void *) src, NULL);
235                  src += rowLength * 3;
236                  destY++;
237               }
238            }
239            else {
240               /* with zooming */
241               GLint row;
242               for (row=0; row<drawHeight; row++) {
243                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
244                                           zSpan, (void *) src, zoomY0);
245                  src += rowLength * 3;
246                  destY++;
247               }
248            }
249         }
250         return GL_TRUE;
251      }
252      else if (format==GL_LUMINANCE && type==GL_UNSIGNED_BYTE) {
253         if (ctx->Visual->RGBAflag) {
254            GLubyte *src = (GLubyte *) pixels
255               + (skipRows * rowLength + skipPixels);
256            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
257               /* no zooming */
258               GLint row;
259               assert(drawWidth < MAX_WIDTH);
260               for (row=0; row<drawHeight; row++) {
261                  GLint i;
262		  for (i=0;i<drawWidth;i++) {
263                     rgb[i][0] = src[i];
264                     rgb[i][1] = src[i];
265                     rgb[i][2] = src[i];
266		  }
267                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
268                                              (void *) rgb, NULL);
269                  src += rowLength;
270                  destY++;
271               }
272            }
273            else {
274               /* with zooming */
275               GLint row;
276               assert(drawWidth < MAX_WIDTH);
277               for (row=0; row<drawHeight; row++) {
278                  GLint i;
279		  for (i=0;i<drawWidth;i++) {
280                     rgb[i][0] = src[i];
281                     rgb[i][1] = src[i];
282                     rgb[i][2] = src[i];
283		  }
284                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
285                                           zSpan, (void *) rgb, zoomY0);
286                  src += rowLength;
287                  destY++;
288               }
289            }
290         }
291         return GL_TRUE;
292      }
293      else if (format==GL_LUMINANCE_ALPHA && type==GL_UNSIGNED_BYTE) {
294         if (ctx->Visual->RGBAflag) {
295            GLubyte *src = (GLubyte *) pixels
296               + (skipRows * rowLength + skipPixels)*2;
297            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
298               /* no zooming */
299               GLint row;
300               assert(drawWidth < MAX_WIDTH);
301               for (row=0; row<drawHeight; row++) {
302                  GLint i;
303                  GLubyte *ptr = src;
304		  for (i=0;i<drawWidth;i++) {
305                     rgba[i][0] = *ptr;
306                     rgba[i][1] = *ptr;
307                     rgba[i][2] = *ptr++;
308                     rgba[i][3] = *ptr++;
309		  }
310                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
311                                               (void *) rgba, NULL);
312                  src += rowLength*2;
313                  destY++;
314               }
315            }
316            else {
317               /* with zooming */
318               GLint row;
319               assert(drawWidth < MAX_WIDTH);
320               for (row=0; row<drawHeight; row++) {
321                  GLubyte *ptr = src;
322                  GLint i;
323		  for (i=0;i<drawWidth;i++) {
324                     rgba[i][0] = *ptr;
325                     rgba[i][1] = *ptr;
326                     rgba[i][2] = *ptr++;
327                     rgba[i][3] = *ptr++;
328		  }
329                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
330                                            zSpan, (void *) rgba, zoomY0);
331                  src += rowLength*2;
332                  destY++;
333               }
334            }
335         }
336         return GL_TRUE;
337      }
338      else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
339         GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
340         if (ctx->Visual->RGBAflag) {
341            /* convert CI data to RGBA */
342            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
343               /* no zooming */
344               GLint row;
345               for (row=0; row<drawHeight; row++) {
346                  assert(drawWidth < MAX_WIDTH);
347                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
348                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
349                                               (const GLubyte (*)[4])rgba,
350					       NULL);
351                  src += rowLength;
352                  destY++;
353               }
354               return GL_TRUE;
355            }
356            else {
357               /* with zooming */
358               GLint row;
359               for (row=0; row<drawHeight; row++) {
360                  assert(drawWidth < MAX_WIDTH);
361                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
362                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
363                                            zSpan, (void *) rgba, zoomY0);
364                  src += rowLength;
365                  destY++;
366               }
367               return GL_TRUE;
368            }
369         }
370         else {
371            /* write CI data to CI frame buffer */
372            GLint row;
373            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
374               /* no zooming */
375               for (row=0; row<drawHeight; row++) {
376                  (*ctx->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
377                                              src, NULL);
378                  src += rowLength;
379                  destY++;
380               }
381               return GL_TRUE;
382            }
383            else {
384               /* with zooming */
385               return GL_FALSE;
386            }
387         }
388      }
389      else {
390         /* can't handle this pixel format and/or data type here */
391         return GL_FALSE;
392      }
393   }
394
395   /* can't do a simple draw, have to use slow path */
396   return GL_FALSE;
397}
398
399
400
401/*
402 * Do glDrawPixels of index pixels.
403 */
404static void
405draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
406                   GLsizei width, GLsizei height,
407                   GLenum type, const GLvoid *pixels )
408{
409   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
410   const GLint desty = y;
411   GLint row, drawWidth;
412   GLdepth zspan[MAX_WIDTH];
413
414   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
415
416   /* Fragment depth values */
417   if (ctx->Depth.Test || ctx->Fog.Enabled) {
418      GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
419      GLint i;
420      for (i = 0; i < drawWidth; i++) {
421	 zspan[i] = zval;
422      }
423   }
424
425   /*
426    * General solution
427    */
428   for (row = 0; row < height; row++, y++) {
429      GLuint indexes[MAX_WIDTH];
430      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
431                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
432      _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
433                              type, source, &ctx->Unpack, GL_TRUE);
434      if (zoom) {
435         gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, indexes, desty);
436      }
437      else {
438         gl_write_index_span(ctx, drawWidth, x, y, zspan, indexes, GL_BITMAP);
439      }
440   }
441}
442
443
444
445/*
446 * Do glDrawPixels of stencil image.  The image datatype may either
447 * be GLubyte or GLbitmap.
448 */
449static void
450draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
451                     GLsizei width, GLsizei height,
452                     GLenum type, const GLvoid *pixels )
453{
454   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
455   const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
456   const GLint desty = y;
457   GLint row, drawWidth;
458
459   if (type != GL_BYTE &&
460       type != GL_UNSIGNED_BYTE &&
461       type != GL_SHORT &&
462       type != GL_UNSIGNED_SHORT &&
463       type != GL_INT &&
464       type != GL_UNSIGNED_INT &&
465       type != GL_FLOAT &&
466       type != GL_BITMAP) {
467      gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
468      return;
469   }
470
471   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
472
473   for (row = 0; row < height; row++, y++) {
474      GLstencil values[MAX_WIDTH];
475      GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
476                      ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
477      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
478                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
479      _mesa_unpack_index_span(ctx, drawWidth, destType, values,
480                              type, source, &ctx->Unpack, GL_FALSE);
481      if (shift_or_offset) {
482         _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
483      }
484      if (ctx->Pixel.MapStencilFlag) {
485         _mesa_map_stencil( ctx, drawWidth, values );
486      }
487
488      if (zoom) {
489         gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
490                                       values, desty );
491      }
492      else {
493         _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
494      }
495   }
496}
497
498
499
500/*
501 * Do a glDrawPixels of depth values.
502 */
503static void
504draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
505                   GLsizei width, GLsizei height,
506                   GLenum type, const GLvoid *pixels )
507{
508   const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
509   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
510   const GLint desty = y;
511   GLubyte rgba[MAX_WIDTH][4];
512   GLuint ispan[MAX_WIDTH];
513   GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
514
515   if (type != GL_UNSIGNED_BYTE
516       && type != GL_UNSIGNED_BYTE
517       && type != GL_UNSIGNED_SHORT
518       && type != GL_UNSIGNED_SHORT
519       && type != GL_UNSIGNED_INT
520       && type != GL_UNSIGNED_INT
521       && type != GL_FLOAT) {
522      gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
523      return;
524   }
525
526   /* Colors or indexes */
527   if (ctx->Visual->RGBAflag) {
528      GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0F);
529      GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0F);
530      GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0F);
531      GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0F);
532      GLint i;
533      for (i = 0; i < drawWidth; i++) {
534         rgba[i][RCOMP] = r;
535         rgba[i][GCOMP] = g;
536         rgba[i][BCOMP] = b;
537         rgba[i][ACOMP] = a;
538      }
539   }
540   else {
541      GLint i;
542      for (i = 0; i < drawWidth; i++) {
543	 ispan[i] = ctx->Current.RasterIndex;
544      }
545   }
546
547   if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
548       && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
549      /* Special case: directly write 16-bit depth values */
550      GLint row;
551      for (row = 0; row < height; row++, y++) {
552         GLdepth zspan[MAX_WIDTH];
553         const GLushort *zptr = _mesa_image_address(&ctx->Unpack,
554                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
555         GLint i;
556         for (i = 0; i < width; i++)
557            zspan[i] = zptr[i];
558         gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
559      }
560   }
561   else if (type==GL_UNSIGNED_INT && ctx->Visual->DepthBits == 32
562       && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
563      /* Special case: directly write 32-bit depth values */
564      GLint row;
565      for (row = 0; row < height; row++, y++) {
566         const GLuint *zptr = _mesa_image_address(&ctx->Unpack,
567                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
568         gl_write_rgba_span( ctx, width, x, y, zptr, rgba, GL_BITMAP );
569      }
570   }
571   else {
572      /* General case */
573      GLint row;
574      for (row = 0; row < height; row++, y++) {
575         GLdepth zspan[MAX_WIDTH];
576         const GLvoid *src = _mesa_image_address(&ctx->Unpack,
577                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
578         _mesa_unpack_depth_span( ctx, drawWidth, zspan, type, src,
579                                  &ctx->Unpack, GL_TRUE );
580         if (ctx->Visual->RGBAflag) {
581            if (zoom) {
582               gl_write_zoomed_rgba_span(ctx, width, x, y, zspan,
583                                         (const GLubyte (*)[4])rgba, desty);
584            }
585            else {
586               gl_write_rgba_span(ctx, width, x, y, zspan, rgba, GL_BITMAP);
587            }
588         }
589         else {
590            if (zoom) {
591               gl_write_zoomed_index_span(ctx, width, x, y, zspan,
592                                          ispan, GL_BITMAP);
593            }
594            else {
595               gl_write_index_span(ctx, width, x, y, zspan, ispan, GL_BITMAP);
596            }
597         }
598
599      }
600   }
601}
602
603
604/*
605 * Do glDrawPixels of RGBA pixels.
606 */
607static void
608draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
609                  GLsizei width, GLsizei height,
610                  GLenum format, GLenum type, const GLvoid *pixels )
611{
612   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
613   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
614   const GLint desty = y;
615   GLdepth zspan[MAX_WIDTH];
616   GLboolean quickDraw;
617
618   /* Try an optimized glDrawPixels first */
619   if (simple_DrawPixels(ctx, x, y, width, height, format, type, pixels))
620      return;
621
622   /* Fragment depth values */
623   if (ctx->Depth.Test || ctx->Fog.Enabled) {
624      /* fill in array of z values */
625      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
626      GLint i;
627      for (i=0;i<width;i++) {
628	 zspan[i] = z;
629      }
630   }
631
632
633   if (ctx->RasterMask == 0 && !zoom
634       && x >= 0 && y >= 0
635       && x + width <= ctx->DrawBuffer->Width
636       && y + height <= ctx->DrawBuffer->Height) {
637      quickDraw = GL_TRUE;
638   }
639   else {
640      quickDraw = GL_FALSE;
641   }
642
643   /*
644    * General solution
645    */
646   {
647      GLubyte rgba[MAX_WIDTH][4];
648      GLint row;
649      if (width > MAX_WIDTH)
650         width = MAX_WIDTH;
651      for (row = 0; row < height; row++, y++) {
652         const GLvoid *source = _mesa_image_address(unpack,
653                  pixels, width, height, format, type, 0, row, 0);
654         _mesa_unpack_ubyte_color_span(ctx, width, GL_RGBA, (void*) rgba,
655                   format, type, source, unpack, GL_TRUE);
656         if (ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink)
657            continue;
658
659         if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
660            GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
661            GLuint unit;
662            /* XXX not sure how multitexture is supposed to work here */
663            for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
664               _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba,
665                                 s, t, r, q);
666               gl_texture_pixels(ctx, unit, width, s, t, r, NULL, rgba);
667            }
668         }
669
670         if (quickDraw) {
671            (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
672                                          (CONST GLubyte (*)[]) rgba, NULL);
673         }
674         else if (zoom) {
675            gl_write_zoomed_rgba_span( ctx, width, x, y, zspan,
676				       (CONST GLubyte (*)[]) rgba, desty );
677         }
678         else {
679            gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, rgba, GL_BITMAP);
680         }
681      }
682   }
683}
684
685
686
687/*
688 * Execute glDrawPixels
689 */
690void
691_mesa_DrawPixels( GLsizei width, GLsizei height,
692                  GLenum format, GLenum type, const GLvoid *pixels )
693{
694   GET_CURRENT_CONTEXT(ctx);
695   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels");
696
697   if (ctx->RenderMode==GL_RENDER) {
698      GLint x, y;
699      if (!pixels || !ctx->Current.RasterPosValid) {
700	 return;
701      }
702
703      if (ctx->NewState) {
704         gl_update_state(ctx);
705      }
706
707      x = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
708      y = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
709
710      ctx->OcclusionResult = GL_TRUE;
711
712      /* see if device driver can do the drawpix */
713      if (ctx->Driver.DrawPixels
714          && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type,
715                                       &ctx->Unpack, pixels)) {
716         return;
717      }
718
719      switch (format) {
720	 case GL_STENCIL_INDEX:
721	    draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
722	    break;
723	 case GL_DEPTH_COMPONENT:
724	    draw_depth_pixels( ctx, x, y, width, height, type, pixels );
725	    break;
726	 case GL_COLOR_INDEX:
727            if (ctx->Visual->RGBAflag)
728               draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
729            else
730               draw_index_pixels(ctx, x, y, width, height, type, pixels);
731	    break;
732	 case GL_RED:
733	 case GL_GREEN:
734	 case GL_BLUE:
735	 case GL_ALPHA:
736	 case GL_LUMINANCE:
737	 case GL_LUMINANCE_ALPHA:
738	 case GL_RGB:
739         case GL_BGR:
740	 case GL_RGBA:
741	 case GL_BGRA:
742	 case GL_ABGR_EXT:
743            draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
744	    break;
745	 default:
746	    gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
747            return;
748      }
749   }
750   else if (ctx->RenderMode==GL_FEEDBACK) {
751      if (ctx->Current.RasterPosValid) {
752         GLfloat color[4];
753	 GLfloat texcoord[4], invq;
754	 UBYTE_RGBA_TO_FLOAT_RGBA(color, ctx->Current.ByteColor);
755         invq = 1.0F / ctx->Current.Texcoord[0][3];
756         texcoord[0] = ctx->Current.Texcoord[0][0] * invq;
757         texcoord[1] = ctx->Current.Texcoord[0][1] * invq;
758         texcoord[2] = ctx->Current.Texcoord[0][2] * invq;
759         texcoord[3] = ctx->Current.Texcoord[0][3];
760         FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
761         gl_feedback_vertex( ctx,
762                             ctx->Current.RasterPos,
763                             color, ctx->Current.Index, texcoord );
764      }
765   }
766   else if (ctx->RenderMode==GL_SELECT) {
767      if (ctx->Current.RasterPosValid) {
768         gl_update_hitflag( ctx, ctx->Current.RasterPos[2] );
769      }
770   }
771}
772
773