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