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