s_drawpix.c revision 709892459922a32096fe9dd8261d0d92337bb02f
1/* $Id: s_drawpix.c,v 1.15 2001/03/19 02:25:36 keithw Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.5
6 *
7 * Copyright (C) 1999-2001  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#include "glheader.h"
29#include "colormac.h"
30#include "context.h"
31#include "convolve.h"
32#include "image.h"
33#include "macros.h"
34#include "mem.h"
35#include "mmath.h"
36#include "pixel.h"
37
38#include "s_context.h"
39#include "s_drawpix.h"
40#include "s_pixeltex.h"
41#include "s_span.h"
42#include "s_stencil.h"
43#include "s_texture.h"
44#include "s_zoom.h"
45
46
47
48/*
49 * Given the dest position, size and skipPixels and skipRows values
50 * for a glDrawPixels command, perform clipping of the image bounds
51 * so the result lies withing the context's buffer bounds.
52 * Return:  GL_TRUE if image is ready for drawing
53 *          GL_FALSE if image was completely clipped away (draw nothing)
54 */
55GLboolean
56_mesa_clip_pixelrect(const GLcontext *ctx,
57                     GLint *destX, GLint *destY,
58                     GLsizei *width, GLsizei *height,
59                     GLint *skipPixels, GLint *skipRows)
60{
61   const GLframebuffer *buffer = ctx->DrawBuffer;
62
63   /* left clipping */
64   if (*destX < buffer->_Xmin) {
65      *skipPixels += (buffer->_Xmin - *destX);
66      *width -= (buffer->_Xmin - *destX);
67      *destX = buffer->_Xmin;
68   }
69   /* right clipping */
70   if (*destX + *width > buffer->_Xmax)
71      *width -= (*destX + *width - buffer->_Xmax);
72
73   if (*width <= 0)
74      return GL_FALSE;
75
76   /* bottom clipping */
77   if (*destY < buffer->_Ymin) {
78      *skipRows += (buffer->_Ymin - *destY);
79      *height -= (buffer->_Ymin - *destY);
80      *destY = buffer->_Ymin;
81   }
82   /* top clipping */
83   if (*destY + *height > buffer->_Ymax)
84      *height -= (*destY + *height - buffer->_Ymax);
85
86   if (*height <= 0)
87      return GL_TRUE;
88
89   return GL_TRUE;
90}
91
92
93
94/*
95 * Try to do a fast and simple RGB(a) glDrawPixels.
96 * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
97 */
98static GLboolean
99fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
100                 GLsizei width, GLsizei height,
101                 GLenum format, GLenum type, const GLvoid *pixels)
102{
103   SWcontext *swrast = SWRAST_CONTEXT(ctx);
104   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
105   GLchan rgb[MAX_WIDTH][3];
106   GLchan rgba[MAX_WIDTH][4];
107
108   if (!ctx->Current.RasterPosValid) {
109      return GL_TRUE;      /* no-op */
110   }
111
112   if ((SWRAST_CONTEXT(ctx)->_RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
113       && ctx->Texture._ReallyEnabled == 0
114       && unpack->Alignment == 1
115       && !unpack->SwapBytes
116       && !unpack->LsbFirst) {
117
118      GLint destX = x;
119      GLint destY = y;
120      GLint drawWidth = width;           /* actual width drawn */
121      GLint drawHeight = height;         /* actual height drawn */
122      GLint skipPixels = unpack->SkipPixels;
123      GLint skipRows = unpack->SkipRows;
124      GLint rowLength;
125      GLdepth zSpan[MAX_WIDTH];  /* only used when zooming */
126      GLint zoomY0 = 0;
127
128      if (unpack->RowLength > 0)
129         rowLength = unpack->RowLength;
130      else
131         rowLength = width;
132
133      /* If we're not using pixel zoom then do all clipping calculations
134       * now.  Otherwise, we'll let the _mesa_write_zoomed_*_span() functions
135       * handle the clipping.
136       */
137      if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
138         /* horizontal clipping */
139         if (destX < ctx->DrawBuffer->_Xmin) {
140            skipPixels += (ctx->DrawBuffer->_Xmin - destX);
141            drawWidth  -= (ctx->DrawBuffer->_Xmin - destX);
142            destX = ctx->DrawBuffer->_Xmin;
143         }
144         if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
145            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
146         if (drawWidth <= 0)
147            return GL_TRUE;
148
149         /* vertical clipping */
150         if (destY < ctx->DrawBuffer->_Ymin) {
151            skipRows   += (ctx->DrawBuffer->_Ymin - destY);
152            drawHeight -= (ctx->DrawBuffer->_Ymin - destY);
153            destY = ctx->DrawBuffer->_Ymin;
154         }
155         if (destY + drawHeight > ctx->DrawBuffer->_Ymax)
156            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax);
157         if (drawHeight <= 0)
158            return GL_TRUE;
159      }
160      else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
161         /* upside-down image */
162         /* horizontal clipping */
163         if (destX < ctx->DrawBuffer->_Xmin) {
164            skipPixels += (ctx->DrawBuffer->_Xmin - destX);
165            drawWidth  -= (ctx->DrawBuffer->_Xmin - destX);
166            destX = ctx->DrawBuffer->_Xmin;
167         }
168         if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
169            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
170         if (drawWidth <= 0)
171            return GL_TRUE;
172
173         /* vertical clipping */
174         if (destY > ctx->DrawBuffer->_Ymax) {
175            skipRows   += (destY - ctx->DrawBuffer->_Ymax);
176            drawHeight -= (destY - ctx->DrawBuffer->_Ymax);
177            destY = ctx->DrawBuffer->_Ymax;
178         }
179         if (destY - drawHeight < ctx->DrawBuffer->_Ymin)
180            drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight));
181         if (drawHeight <= 0)
182            return GL_TRUE;
183      }
184      else {
185         /* setup array of fragment Z value to pass to zoom function */
186         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF);
187         GLint i;
188         ASSERT(drawWidth < MAX_WIDTH);
189         for (i=0; i<drawWidth; i++)
190            zSpan[i] = z;
191
192         /* save Y value of first row */
193         zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
194      }
195
196
197      /*
198       * Ready to draw!
199       * The window region at (destX, destY) of size (drawWidth, drawHeight)
200       * will be written to.
201       * We'll take pixel data from buffer pointed to by "pixels" but we'll
202       * skip "skipRows" rows and skip "skipPixels" pixels/row.
203       */
204
205      if (format == GL_RGBA && type == CHAN_TYPE
206          && ctx->_ImageTransferState==0) {
207         if (ctx->Visual.rgbMode) {
208            GLchan *src = (GLchan *) pixels
209               + (skipRows * rowLength + skipPixels) * 4;
210            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
211               /* no zooming */
212               GLint row;
213               for (row=0; row<drawHeight; row++) {
214                  (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
215                                              (CONST GLchan (*)[4]) src, NULL);
216                  src += rowLength * 4;
217                  destY++;
218               }
219            }
220            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
221               /* upside-down */
222               GLint row;
223               for (row=0; row<drawHeight; row++) {
224                  destY--;
225                  (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
226                                              (CONST GLchan (*)[4]) src, NULL);
227                  src += rowLength * 4;
228               }
229            }
230            else {
231               /* with zooming */
232               GLint row;
233               for (row=0; row<drawHeight; row++) {
234                  _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
235                                  zSpan, 0, (CONST GLchan (*)[4]) src, zoomY0);
236                  src += rowLength * 4;
237                  destY++;
238               }
239            }
240         }
241         return GL_TRUE;
242      }
243      else if (format == GL_RGB && type == CHAN_TYPE
244               && ctx->_ImageTransferState == 0) {
245         if (ctx->Visual.rgbMode) {
246            GLchan *src = (GLchan *) pixels
247               + (skipRows * rowLength + skipPixels) * 3;
248            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
249               GLint row;
250               for (row=0; row<drawHeight; row++) {
251                  (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
252                                              (CONST GLchan (*)[3]) src, NULL);
253                  src += rowLength * 3;
254                  destY++;
255               }
256            }
257            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
258               /* upside-down */
259               GLint row;
260               for (row=0; row<drawHeight; row++) {
261                  destY--;
262                  (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
263                                              (CONST GLchan (*)[3]) src, NULL);
264                  src += rowLength * 3;
265               }
266            }
267            else {
268               /* with zooming */
269               GLint row;
270               for (row=0; row<drawHeight; row++) {
271                  _mesa_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
272                                  zSpan, 0, (CONST GLchan (*)[3]) src, zoomY0);
273                  src += rowLength * 3;
274                  destY++;
275               }
276            }
277         }
278         return GL_TRUE;
279      }
280      else if (format == GL_LUMINANCE && type == CHAN_TYPE
281               && ctx->_ImageTransferState==0) {
282         if (ctx->Visual.rgbMode) {
283            GLchan *src = (GLchan *) pixels
284               + (skipRows * rowLength + skipPixels);
285            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
286               /* no zooming */
287               GLint row;
288               ASSERT(drawWidth < MAX_WIDTH);
289               for (row=0; row<drawHeight; row++) {
290                  GLint i;
291		  for (i=0;i<drawWidth;i++) {
292                     rgb[i][0] = src[i];
293                     rgb[i][1] = src[i];
294                     rgb[i][2] = src[i];
295		  }
296                  (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
297                                              (CONST GLchan (*)[3]) rgb, NULL);
298                  src += rowLength;
299                  destY++;
300               }
301            }
302            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
303               /* upside-down */
304               GLint row;
305               ASSERT(drawWidth < MAX_WIDTH);
306               for (row=0; row<drawHeight; row++) {
307                  GLint i;
308                  for (i=0;i<drawWidth;i++) {
309                     rgb[i][0] = src[i];
310                     rgb[i][1] = src[i];
311                     rgb[i][2] = src[i];
312                  }
313                  destY--;
314                  (*swrast->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
315                                              (CONST GLchan (*)[3]) rgb, NULL);
316                  src += rowLength;
317               }
318            }
319            else {
320               /* with zooming */
321               GLint row;
322               ASSERT(drawWidth < MAX_WIDTH);
323               for (row=0; row<drawHeight; row++) {
324                  GLint i;
325		  for (i=0;i<drawWidth;i++) {
326                     rgb[i][0] = src[i];
327                     rgb[i][1] = src[i];
328                     rgb[i][2] = src[i];
329		  }
330                  _mesa_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
331                                  zSpan, 0, (CONST GLchan (*)[3]) rgb, zoomY0);
332                  src += rowLength;
333                  destY++;
334               }
335            }
336         }
337         return GL_TRUE;
338      }
339      else if (format == GL_LUMINANCE_ALPHA && type == CHAN_TYPE
340               && ctx->_ImageTransferState == 0) {
341         if (ctx->Visual.rgbMode) {
342            GLchan *src = (GLchan *) pixels
343               + (skipRows * rowLength + skipPixels)*2;
344            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
345               /* no zooming */
346               GLint row;
347               ASSERT(drawWidth < MAX_WIDTH);
348               for (row=0; row<drawHeight; row++) {
349                  GLint i;
350                  GLchan *ptr = src;
351		  for (i=0;i<drawWidth;i++) {
352                     rgba[i][0] = *ptr;
353                     rgba[i][1] = *ptr;
354                     rgba[i][2] = *ptr++;
355                     rgba[i][3] = *ptr++;
356		  }
357                  (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
358                                             (CONST GLchan (*)[4]) rgba, NULL);
359                  src += rowLength*2;
360                  destY++;
361               }
362            }
363            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
364               /* upside-down */
365               GLint row;
366               ASSERT(drawWidth < MAX_WIDTH);
367               for (row=0; row<drawHeight; row++) {
368                  GLint i;
369                  GLchan *ptr = src;
370                  for (i=0;i<drawWidth;i++) {
371                     rgba[i][0] = *ptr;
372                     rgba[i][1] = *ptr;
373                     rgba[i][2] = *ptr++;
374                     rgba[i][3] = *ptr++;
375                  }
376                  destY--;
377                  (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
378                                             (CONST GLchan (*)[4]) rgba, NULL);
379                  src += rowLength*2;
380               }
381            }
382            else {
383               /* with zooming */
384               GLint row;
385               ASSERT(drawWidth < MAX_WIDTH);
386               for (row=0; row<drawHeight; row++) {
387                  GLchan *ptr = src;
388                  GLint i;
389		  for (i=0;i<drawWidth;i++) {
390                     rgba[i][0] = *ptr;
391                     rgba[i][1] = *ptr;
392                     rgba[i][2] = *ptr++;
393                     rgba[i][3] = *ptr++;
394		  }
395                  _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
396                                 zSpan, 0, (CONST GLchan (*)[4]) rgba, zoomY0);
397                  src += rowLength*2;
398                  destY++;
399               }
400            }
401         }
402         return GL_TRUE;
403      }
404      else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
405         GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
406         if (ctx->Visual.rgbMode) {
407            /* convert CI data to RGBA */
408            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
409               /* no zooming */
410               GLint row;
411               for (row=0; row<drawHeight; row++) {
412                  ASSERT(drawWidth < MAX_WIDTH);
413                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
414                  (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
415                                               (const GLchan (*)[4]) rgba,
416					       NULL);
417                  src += rowLength;
418                  destY++;
419               }
420               return GL_TRUE;
421            }
422            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
423               /* upside-down */
424               GLint row;
425               for (row=0; row<drawHeight; row++) {
426                  ASSERT(drawWidth < MAX_WIDTH);
427                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
428                  destY--;
429                  (*swrast->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
430                                               (CONST GLchan (*)[4]) rgba,
431                                               NULL);
432                  src += rowLength;
433               }
434               return GL_TRUE;
435            }
436            else {
437               /* with zooming */
438               GLint row;
439               for (row=0; row<drawHeight; row++) {
440                  ASSERT(drawWidth < MAX_WIDTH);
441                  _mesa_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
442                  _mesa_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
443                                 zSpan, 0, (CONST GLchan (*)[4]) rgba, zoomY0);
444                  src += rowLength;
445                  destY++;
446               }
447               return GL_TRUE;
448            }
449         }
450         else if (ctx->_ImageTransferState==0) {
451            /* write CI data to CI frame buffer */
452            GLint row;
453            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
454               /* no zooming */
455               for (row=0; row<drawHeight; row++) {
456                  (*swrast->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
457                                              src, NULL);
458                  src += rowLength;
459                  destY++;
460               }
461               return GL_TRUE;
462            }
463            else {
464               /* with zooming */
465               return GL_FALSE;
466            }
467         }
468      }
469      else {
470         /* can't handle this pixel format and/or data type here */
471         return GL_FALSE;
472      }
473   }
474
475   /* can't do a simple draw, have to use slow path */
476   return GL_FALSE;
477}
478
479
480
481/*
482 * Do glDrawPixels of index pixels.
483 */
484static void
485draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
486                   GLsizei width, GLsizei height,
487                   GLenum type, const GLvoid *pixels )
488{
489   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
490   const GLint desty = y;
491   GLint row, drawWidth;
492   GLdepth zspan[MAX_WIDTH];
493
494   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
495
496   /* Fragment depth values */
497   if (ctx->Depth.Test || ctx->Fog.Enabled) {
498      GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF);
499      GLint i;
500      for (i = 0; i < drawWidth; i++) {
501	 zspan[i] = zval;
502      }
503   }
504
505   /*
506    * General solution
507    */
508   for (row = 0; row < height; row++, y++) {
509      GLuint indexes[MAX_WIDTH];
510      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
511                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
512      _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
513                              type, source, &ctx->Unpack,
514                              ctx->_ImageTransferState);
515      if (zoom) {
516         _mesa_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, 0, indexes, desty);
517      }
518      else {
519         _mesa_write_index_span(ctx, drawWidth, x, y, zspan, 0, indexes, GL_BITMAP);
520      }
521   }
522}
523
524
525
526/*
527 * Do glDrawPixels of stencil image.  The image datatype may either
528 * be GLubyte or GLbitmap.
529 */
530static void
531draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
532                     GLsizei width, GLsizei height,
533                     GLenum type, const GLvoid *pixels )
534{
535   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
536   const GLint desty = y;
537   GLint row, drawWidth;
538
539   if (type != GL_BYTE &&
540       type != GL_UNSIGNED_BYTE &&
541       type != GL_SHORT &&
542       type != GL_UNSIGNED_SHORT &&
543       type != GL_INT &&
544       type != GL_UNSIGNED_INT &&
545       type != GL_FLOAT &&
546       type != GL_BITMAP) {
547      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
548      return;
549   }
550
551   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
552
553   for (row = 0; row < height; row++, y++) {
554      GLstencil values[MAX_WIDTH];
555      GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
556                      ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
557      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
558                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
559      _mesa_unpack_index_span(ctx, drawWidth, destType, values,
560                              type, source, &ctx->Unpack,
561                              ctx->_ImageTransferState);
562      if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
563         _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
564      }
565      if (ctx->Pixel.MapStencilFlag) {
566         _mesa_map_stencil( ctx, drawWidth, values );
567      }
568
569      if (zoom) {
570         _mesa_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
571                                       values, desty );
572      }
573      else {
574         _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
575      }
576   }
577}
578
579
580
581/*
582 * Do a glDrawPixels of depth values.
583 */
584static void
585draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
586                   GLsizei width, GLsizei height,
587                   GLenum type, const GLvoid *pixels )
588{
589   const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
590   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
591   const GLint desty = y;
592   GLchan rgba[MAX_WIDTH][4];
593   GLuint ispan[MAX_WIDTH];
594   GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
595
596   if (type != GL_BYTE
597       && type != GL_UNSIGNED_BYTE
598       && type != GL_SHORT
599       && type != GL_UNSIGNED_SHORT
600       && type != GL_INT
601       && type != GL_UNSIGNED_INT
602       && type != GL_FLOAT) {
603      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
604      return;
605   }
606
607   /* Colors or indexes */
608   if (ctx->Visual.rgbMode) {
609      GLint i;
610      GLint r, g, b, a;
611      UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
612      UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
613      UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
614      UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
615      for (i = 0; i < drawWidth; i++) {
616         rgba[i][RCOMP] = r;
617         rgba[i][GCOMP] = g;
618         rgba[i][BCOMP] = b;
619         rgba[i][ACOMP] = a;
620      }
621   }
622   else {
623      GLint i;
624      for (i = 0; i < drawWidth; i++) {
625	 ispan[i] = ctx->Current.RasterIndex;
626      }
627   }
628
629   if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
630       && !bias_or_scale && !zoom && ctx->Visual.rgbMode) {
631      /* Special case: directly write 16-bit depth values */
632      GLint row;
633      for (row = 0; row < height; row++, y++) {
634         GLdepth zspan[MAX_WIDTH];
635         const GLushort *zptr = (const GLushort *)
636            _mesa_image_address(&ctx->Unpack, pixels, width, height,
637                                GL_DEPTH_COMPONENT, type, 0, row, 0);
638         GLint i;
639         for (i = 0; i < width; i++)
640            zspan[i] = zptr[i];
641         _mesa_write_rgba_span( ctx, width, x, y, zspan, 0, rgba, GL_BITMAP );
642      }
643   }
644   else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
645       && !bias_or_scale && !zoom && ctx->Visual.rgbMode) {
646      /* Special case: directly write 32-bit depth values */
647      GLint row;
648      for (row = 0; row < height; row++, y++) {
649         const GLuint *zptr = (const GLuint *)
650            _mesa_image_address(&ctx->Unpack, pixels, width, height,
651                                GL_DEPTH_COMPONENT, type, 0, row, 0);
652         _mesa_write_rgba_span( ctx, width, x, y, zptr, 0, rgba, GL_BITMAP );
653      }
654   }
655   else {
656      /* General case */
657      GLint row;
658      for (row = 0; row < height; row++, y++) {
659         GLfloat fspan[MAX_WIDTH];
660         GLdepth zspan[MAX_WIDTH];
661         const GLvoid *src = _mesa_image_address(&ctx->Unpack,
662                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
663         _mesa_unpack_depth_span( ctx, drawWidth, fspan, type, src,
664                                  &ctx->Unpack );
665         /* clamp depth values to [0,1] and convert from floats to integers */
666         {
667            const GLfloat zs = ctx->DepthMaxF;
668            GLint i;
669            for (i = 0; i < drawWidth; i++) {
670               zspan[i] = (GLdepth) (fspan[i] * zs);
671            }
672         }
673
674         if (ctx->Visual.rgbMode) {
675            if (zoom) {
676               _mesa_write_zoomed_rgba_span(ctx, width, x, y, zspan, 0,
677                                         (const GLchan (*)[4]) rgba, desty);
678            }
679            else {
680               _mesa_write_rgba_span(ctx, width, x, y, zspan, 0, rgba, GL_BITMAP);
681            }
682         }
683         else {
684            if (zoom) {
685               _mesa_write_zoomed_index_span(ctx, width, x, y, zspan, 0,
686                                          ispan, GL_BITMAP);
687            }
688            else {
689               _mesa_write_index_span(ctx, width, x, y, zspan, 0,
690				   ispan, GL_BITMAP);
691            }
692         }
693
694      }
695   }
696}
697
698
699/*
700 * Do glDrawPixels of RGBA pixels.
701 */
702static void
703draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
704                  GLsizei width, GLsizei height,
705                  GLenum format, GLenum type, const GLvoid *pixels )
706{
707   SWcontext *swrast = SWRAST_CONTEXT(ctx);
708   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
709   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
710   const GLint desty = y;
711   GLdepth zspan[MAX_WIDTH];
712   GLboolean quickDraw;
713   GLfloat *convImage = NULL;
714   GLuint transferOps = ctx->_ImageTransferState;
715
716   if (!_mesa_is_legal_format_and_type(format, type)) {
717      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
718      return;
719   }
720
721   /* Try an optimized glDrawPixels first */
722   if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
723      return;
724
725   /* Fragment depth values */
726   if (ctx->Depth.Test || ctx->Fog.Enabled) {
727      /* fill in array of z values */
728      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF);
729      GLint i;
730      for (i=0;i<width;i++) {
731	 zspan[i] = z;
732      }
733   }
734
735
736   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0
737       && x + width <= ctx->DrawBuffer->Width
738       && y + height <= ctx->DrawBuffer->Height) {
739      quickDraw = GL_TRUE;
740   }
741   else {
742      quickDraw = GL_FALSE;
743   }
744
745   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
746      /* Convolution has to be handled specially.  We'll create an
747       * intermediate image, applying all pixel transfer operations
748       * up to convolution.  Then we'll convolve the image.  Then
749       * we'll proceed with the rest of the transfer operations and
750       * rasterize the image.
751       */
752      GLint row;
753      GLfloat *dest, *tmpImage;
754
755      tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
756      if (!tmpImage) {
757         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
758         return;
759      }
760      convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
761      if (!convImage) {
762         FREE(tmpImage);
763         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
764         return;
765      }
766
767      /* Unpack the image and apply transfer ops up to convolution */
768      dest = tmpImage;
769      for (row = 0; row < height; row++) {
770         const GLvoid *source = _mesa_image_address(unpack,
771                  pixels, width, height, format, type, 0, row, 0);
772         _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (GLfloat *) dest,
773                                      format, type, source, unpack,
774                                      transferOps & IMAGE_PRE_CONVOLUTION_BITS,
775                                      GL_FALSE);
776         dest += width * 4;
777      }
778
779      /* do convolution */
780      if (ctx->Pixel.Convolution2DEnabled) {
781         _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
782      }
783      else {
784         ASSERT(ctx->Pixel.Separable2DEnabled);
785         _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
786      }
787      FREE(tmpImage);
788
789      /* continue transfer ops and draw the convolved image */
790      unpack = &_mesa_native_packing;
791      pixels = convImage;
792      format = GL_RGBA;
793      type = GL_FLOAT;
794      transferOps &= IMAGE_POST_CONVOLUTION_BITS;
795   }
796
797   /*
798    * General solution
799    */
800   {
801      GLchan rgba[MAX_WIDTH][4];
802      GLint row;
803      if (width > MAX_WIDTH)
804         width = MAX_WIDTH;
805      for (row = 0; row < height; row++, y++) {
806         const GLvoid *source = _mesa_image_address(unpack,
807                  pixels, width, height, format, type, 0, row, 0);
808         _mesa_unpack_chan_color_span(ctx, width, GL_RGBA, (GLchan *) rgba,
809                                      format, type, source, unpack,
810                                      transferOps);
811         if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
812             (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
813            continue;
814
815         if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
816            GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
817            GLchan primary_rgba[MAX_WIDTH][4];
818            GLuint unit;
819            /* XXX not sure how multitexture is supposed to work here */
820
821            MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
822
823            for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
824               if (ctx->Texture.Unit[unit]._ReallyEnabled) {
825                  _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
826                                    s, t, r, q);
827                  _swrast_texture_fragments(ctx, unit, width, s, t, r, NULL,
828                                            (CONST GLchan (*)[4]) primary_rgba,
829                                            rgba);
830               }
831            }
832         }
833
834         if (quickDraw) {
835            (*swrast->Driver.WriteRGBASpan)( ctx, width, x, y,
836                                          (CONST GLchan (*)[]) rgba, NULL);
837         }
838         else if (zoom) {
839            _mesa_write_zoomed_rgba_span( ctx, width, x, y, zspan, 0,
840				       (CONST GLchan (*)[]) rgba, desty );
841         }
842         else {
843            _mesa_write_rgba_span( ctx, (GLuint) width, x, y, zspan, 0,
844				rgba, GL_BITMAP);
845         }
846      }
847   }
848
849   if (convImage) {
850      FREE(convImage);
851   }
852}
853
854
855
856/*
857 * Execute glDrawPixels
858 */
859void
860_swrast_DrawPixels( GLcontext *ctx,
861		    GLint x, GLint y,
862		    GLsizei width, GLsizei height,
863		    GLenum format, GLenum type,
864		    const struct gl_pixelstore_attrib *unpack,
865		    const GLvoid *pixels )
866{
867   SWcontext *swrast = SWRAST_CONTEXT(ctx);
868   (void) unpack;
869
870
871   if (swrast->NewState)
872      _swrast_validate_derived( ctx );
873
874   RENDER_START(swrast,ctx);
875
876   switch (format) {
877   case GL_STENCIL_INDEX:
878      draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
879      break;
880   case GL_DEPTH_COMPONENT:
881      draw_depth_pixels( ctx, x, y, width, height, type, pixels );
882      break;
883   case GL_COLOR_INDEX:
884      if (ctx->Visual.rgbMode)
885	 draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
886      else
887	 draw_index_pixels(ctx, x, y, width, height, type, pixels);
888      break;
889   case GL_RED:
890   case GL_GREEN:
891   case GL_BLUE:
892   case GL_ALPHA:
893   case GL_LUMINANCE:
894   case GL_LUMINANCE_ALPHA:
895   case GL_RGB:
896   case GL_BGR:
897   case GL_RGBA:
898   case GL_BGRA:
899   case GL_ABGR_EXT:
900      draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
901      break;
902   default:
903      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
904   }
905
906   RENDER_FINISH(swrast,ctx);
907}
908