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