drawpix.c revision d0130a989a3b331eb8114f1ee4addb95ce31e0e2
1/* $Id: drawpix.c,v 1.19 2000/04/11 20:42:22 brianp Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version:  3.3
6 *
7 * Copyright (C) 1999-2000  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28#ifdef PC_HEADER
29#include "all.h"
30#else
31#include "glheader.h"
32#include "context.h"
33#include "drawpix.h"
34#include "feedback.h"
35#include "image.h"
36#include "macros.h"
37#include "mem.h"
38#include "mmath.h"
39#include "pixel.h"
40#include "pixeltex.h"
41#include "span.h"
42#include "state.h"
43#include "stencil.h"
44#include "texture.h"
45#include "types.h"
46#include "zoom.h"
47#endif
48
49
50
51/*
52 * Given the dest position, size and skipPixels and skipRows values
53 * for a glDrawPixels command, perform clipping of the image bounds
54 * so the result lies withing the context's buffer bounds.
55 * Return:  GL_TRUE if image is ready for drawing
56 *          GL_FALSE if image was completely clipped away (draw nothing)
57 */
58GLboolean
59_mesa_clip_pixelrect(const GLcontext *ctx,
60                     GLint *destX, GLint *destY,
61                     GLsizei *width, GLsizei *height,
62                     GLint *skipPixels, GLint *skipRows)
63{
64   const GLframebuffer *buffer = ctx->DrawBuffer;
65
66   /* left clipping */
67   if (*destX < buffer->Xmin) {
68      *skipPixels += (buffer->Xmin - *destX);
69      *width -= (buffer->Xmin - *destX);
70      *destX = buffer->Xmin;
71   }
72   /* right clipping */
73   if (*destX + *width > buffer->Xmax)
74      *width -= (*destX + *width - buffer->Xmax - 1);
75
76   if (*width <= 0)
77      return GL_FALSE;
78
79   /* bottom clipping */
80   if (*destY < buffer->Ymin) {
81      *skipRows += (buffer->Ymin - *destY);
82      *height -= (buffer->Ymin - *destY);
83      *destY = buffer->Ymin;
84   }
85   /* top clipping */
86   if (*destY + *height > buffer->Ymax)
87      *height -= (*destY + *height - buffer->Ymax - 1);
88
89   if (*height <= 0)
90      return GL_TRUE;
91
92   return GL_TRUE;
93}
94
95
96
97/*
98 * Try to do a fast and simple RGB(a) glDrawPixels.
99 * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
100 */
101static GLboolean
102simple_DrawPixels( GLcontext *ctx, GLint x, GLint y,
103                   GLsizei width, GLsizei height, GLenum format, GLenum type,
104                   const GLvoid *pixels )
105{
106   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
107   GLubyte rgb[MAX_WIDTH][3];
108   GLubyte rgba[MAX_WIDTH][4];
109
110   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glDrawPixels",
111						  GL_FALSE);
112
113
114   if (!ctx->Current.RasterPosValid) {
115      /* no-op */
116      return GL_TRUE;
117   }
118
119   if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
120       && !ctx->Pixel.ScaleOrBiasRGBA
121       && !ctx->Pixel.ScaleOrBiasRGBApcm
122       && ctx->ColorMatrix.type == MATRIX_IDENTITY
123       && ctx->Pixel.IndexShift==0 && ctx->Pixel.IndexOffset==0
124       && ctx->Pixel.MapColorFlag==0
125       && ctx->Texture.ReallyEnabled == 0
126       && unpack->Alignment==1
127       && !unpack->SwapBytes
128       && !unpack->LsbFirst) {
129
130      GLint destX = x;
131      GLint destY = y;
132      GLint drawWidth = width;           /* actual width drawn */
133      GLint drawHeight = height;         /* actual height drawn */
134      GLint skipPixels = unpack->SkipPixels;
135      GLint skipRows = unpack->SkipRows;
136      GLint rowLength;
137      GLdepth zSpan[MAX_WIDTH];  /* only used when zooming */
138      GLint zoomY0;
139
140      if (unpack->RowLength > 0)
141         rowLength = unpack->RowLength;
142      else
143         rowLength = width;
144
145      /* If we're not using pixel zoom then do all clipping calculations
146       * now.  Otherwise, we'll let the gl_write_zoomed_*_span() functions
147       * handle the clipping.
148       */
149      if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
150         /* horizontal clipping */
151         if (destX < ctx->DrawBuffer->Xmin) {
152            skipPixels += (ctx->DrawBuffer->Xmin - destX);
153            drawWidth  -= (ctx->DrawBuffer->Xmin - destX);
154            destX = ctx->DrawBuffer->Xmin;
155         }
156         if (destX + drawWidth > ctx->DrawBuffer->Xmax)
157            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax - 1);
158         if (drawWidth <= 0)
159            return GL_TRUE;
160
161         /* vertical clipping */
162         if (destY < ctx->DrawBuffer->Ymin) {
163            skipRows   += (ctx->DrawBuffer->Ymin - destY);
164            drawHeight -= (ctx->DrawBuffer->Ymin - destY);
165            destY = ctx->DrawBuffer->Ymin;
166         }
167         if (destY + drawHeight > ctx->DrawBuffer->Ymax)
168            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax - 1);
169         if (drawHeight <= 0)
170            return GL_TRUE;
171
172         zoomY0 = 0;  /* not used - silence compiler warning */
173      }
174      else {
175         /* setup array of fragment Z value to pass to zoom function */
176         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
177         GLint i;
178         assert(drawWidth < MAX_WIDTH);
179         for (i=0; i<drawWidth; i++)
180            zSpan[i] = z;
181
182         /* save Y value of first row */
183         zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
184      }
185
186
187      /*
188       * Ready to draw!
189       * The window region at (destX, destY) of size (drawWidth, drawHeight)
190       * will be written to.
191       * We'll take pixel data from buffer pointed to by "pixels" but we'll
192       * skip "skipRows" rows and skip "skipPixels" pixels/row.
193       */
194
195      if (format==GL_RGBA && type==GL_UNSIGNED_BYTE) {
196         if (ctx->Visual->RGBAflag) {
197            GLubyte *src = (GLubyte *) pixels
198               + (skipRows * rowLength + skipPixels) * 4;
199            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
200               /* no zooming */
201               GLint row;
202               for (row=0; row<drawHeight; row++) {
203                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
204                                               (void *) src, NULL);
205                  src += rowLength * 4;
206                  destY++;
207               }
208            }
209            else {
210               /* with zooming */
211               GLint row;
212               for (row=0; row<drawHeight; row++) {
213                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
214                                            zSpan, (void *) src, zoomY0);
215                  src += rowLength * 4;
216                  destY++;
217               }
218            }
219         }
220         return GL_TRUE;
221      }
222      else if (format==GL_RGB && type==GL_UNSIGNED_BYTE) {
223         if (ctx->Visual->RGBAflag) {
224            GLubyte *src = (GLubyte *) pixels
225               + (skipRows * rowLength + skipPixels) * 3;
226            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
227               GLint row;
228               for (row=0; row<drawHeight; row++) {
229                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
230                                              (void *) src, NULL);
231                  src += rowLength * 3;
232                  destY++;
233               }
234            }
235            else {
236               /* with zooming */
237               GLint row;
238               for (row=0; row<drawHeight; row++) {
239                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
240                                           zSpan, (void *) src, zoomY0);
241                  src += rowLength * 3;
242                  destY++;
243               }
244            }
245         }
246         return GL_TRUE;
247      }
248      else if (format==GL_LUMINANCE && type==GL_UNSIGNED_BYTE) {
249         if (ctx->Visual->RGBAflag) {
250            GLubyte *src = (GLubyte *) pixels
251               + (skipRows * rowLength + skipPixels);
252            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
253               /* no zooming */
254               GLint row;
255               assert(drawWidth < MAX_WIDTH);
256               for (row=0; row<drawHeight; row++) {
257                  GLint i;
258		  for (i=0;i<drawWidth;i++) {
259                     rgb[i][0] = src[i];
260                     rgb[i][1] = src[i];
261                     rgb[i][2] = src[i];
262		  }
263                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
264                                              (void *) rgb, NULL);
265                  src += rowLength;
266                  destY++;
267               }
268            }
269            else {
270               /* with zooming */
271               GLint row;
272               assert(drawWidth < MAX_WIDTH);
273               for (row=0; row<drawHeight; row++) {
274                  GLint i;
275		  for (i=0;i<drawWidth;i++) {
276                     rgb[i][0] = src[i];
277                     rgb[i][1] = src[i];
278                     rgb[i][2] = src[i];
279		  }
280                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
281                                           zSpan, (void *) rgb, zoomY0);
282                  src += rowLength;
283                  destY++;
284               }
285            }
286         }
287         return GL_TRUE;
288      }
289      else if (format==GL_LUMINANCE_ALPHA && type==GL_UNSIGNED_BYTE) {
290         if (ctx->Visual->RGBAflag) {
291            GLubyte *src = (GLubyte *) pixels
292               + (skipRows * rowLength + skipPixels)*2;
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                  GLubyte *ptr = src;
300		  for (i=0;i<drawWidth;i++) {
301                     rgba[i][0] = *ptr;
302                     rgba[i][1] = *ptr;
303                     rgba[i][2] = *ptr++;
304                     rgba[i][3] = *ptr++;
305		  }
306                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
307                                               (void *) rgba, NULL);
308                  src += rowLength*2;
309                  destY++;
310               }
311            }
312            else {
313               /* with zooming */
314               GLint row;
315               assert(drawWidth < MAX_WIDTH);
316               for (row=0; row<drawHeight; row++) {
317                  GLubyte *ptr = src;
318                  GLint i;
319		  for (i=0;i<drawWidth;i++) {
320                     rgba[i][0] = *ptr;
321                     rgba[i][1] = *ptr;
322                     rgba[i][2] = *ptr++;
323                     rgba[i][3] = *ptr++;
324		  }
325                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
326                                            zSpan, (void *) rgba, zoomY0);
327                  src += rowLength*2;
328                  destY++;
329               }
330            }
331         }
332         return GL_TRUE;
333      }
334      else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
335         GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
336         if (ctx->Visual->RGBAflag) {
337            /* convert CI data to RGBA */
338            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
339               /* no zooming */
340               GLint row;
341               for (row=0; row<drawHeight; row++) {
342                  assert(drawWidth < MAX_WIDTH);
343                  gl_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
344                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
345                                               (const GLubyte (*)[4])rgba,
346					       NULL);
347                  src += rowLength;
348                  destY++;
349               }
350               return GL_TRUE;
351            }
352            else {
353               /* with zooming */
354               GLint row;
355               for (row=0; row<drawHeight; row++) {
356                  assert(drawWidth < MAX_WIDTH);
357                  gl_map_ci8_to_rgba(ctx, drawWidth, src, rgba);
358                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
359                                            zSpan, (void *) rgba, zoomY0);
360                  src += rowLength;
361                  destY++;
362               }
363               return GL_TRUE;
364            }
365         }
366         else {
367            /* write CI data to CI frame buffer */
368            GLint row;
369            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
370               /* no zooming */
371               for (row=0; row<drawHeight; row++) {
372                  (*ctx->Driver.WriteCI8Span)(ctx, drawWidth, destX, destY,
373                                              src, NULL);
374                  src += rowLength;
375                  destY++;
376               }
377               return GL_TRUE;
378            }
379            else {
380               /* with zooming */
381               return GL_FALSE;
382            }
383         }
384      }
385      else {
386         /* can't handle this pixel format and/or data type here */
387         return GL_FALSE;
388      }
389   }
390
391   /* can't do a simple draw, have to use slow path */
392   return GL_FALSE;
393}
394
395
396
397/*
398 * Do glDrawPixels of index pixels.
399 */
400static void
401draw_index_pixels( GLcontext *ctx, GLint x, GLint y,
402                   GLsizei width, GLsizei height,
403                   GLenum type, const GLvoid *pixels )
404{
405   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
406   const GLint desty = y;
407   GLint row, drawWidth;
408   GLdepth zspan[MAX_WIDTH];
409
410   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
411
412   /* Fragment depth values */
413   if (ctx->Depth.Test || ctx->Fog.Enabled) {
414      GLdepth zval = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
415      GLint i;
416      for (i = 0; i < drawWidth; i++) {
417	 zspan[i] = zval;
418      }
419   }
420
421   /*
422    * General solution
423    */
424   for (row = 0; row < height; row++, y++) {
425      GLuint indexes[MAX_WIDTH];
426      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
427                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
428      _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT, indexes,
429                              type, source, &ctx->Unpack, GL_TRUE);
430      if (zoom) {
431         gl_write_zoomed_index_span(ctx, drawWidth, x, y, zspan, indexes, desty);
432      }
433      else {
434         gl_write_index_span(ctx, drawWidth, x, y, zspan, indexes, GL_BITMAP);
435      }
436   }
437}
438
439
440
441/*
442 * Do glDrawPixels of stencil image.  The image datatype may either
443 * be GLubyte or GLbitmap.
444 */
445static void
446draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
447                     GLsizei width, GLsizei height,
448                     GLenum type, const GLvoid *pixels )
449{
450   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
451   const GLint desty = y;
452   GLint row, drawWidth;
453
454   if (type != GL_BYTE &&
455       type != GL_UNSIGNED_BYTE &&
456       type != GL_SHORT &&
457       type != GL_UNSIGNED_SHORT &&
458       type != GL_INT &&
459       type != GL_UNSIGNED_INT &&
460       type != GL_FLOAT &&
461       type != GL_BITMAP) {
462      gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
463      return;
464   }
465
466   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
467
468   for (row = 0; row < height; row++, y++) {
469      GLstencil values[MAX_WIDTH];
470      GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
471                      ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
472      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
473                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
474      _mesa_unpack_index_span(ctx, drawWidth, destType, values,
475                              type, source, &ctx->Unpack, GL_TRUE);
476
477      if (zoom) {
478         gl_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
479                                       values, desty );
480      }
481      else {
482         _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
483      }
484   }
485}
486
487
488
489/*
490 * Do a glDrawPixels of depth values.
491 */
492static void
493draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
494                   GLsizei width, GLsizei height,
495                   GLenum type, const GLvoid *pixels )
496{
497   const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
498   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
499   const GLint desty = y;
500   GLubyte rgba[MAX_WIDTH][4];
501   GLuint ispan[MAX_WIDTH];
502   GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
503
504   if (type != GL_UNSIGNED_BYTE
505       && type != GL_UNSIGNED_BYTE
506       && type != GL_UNSIGNED_SHORT
507       && type != GL_UNSIGNED_SHORT
508       && type != GL_UNSIGNED_INT
509       && type != GL_UNSIGNED_INT
510       && type != GL_FLOAT) {
511      gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
512      return;
513   }
514
515   /* Colors or indexes */
516   if (ctx->Visual->RGBAflag) {
517      GLint r = (GLint) (ctx->Current.RasterColor[0] * 255.0F);
518      GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0F);
519      GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0F);
520      GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0F);
521      GLint i;
522      for (i = 0; i < drawWidth; i++) {
523         rgba[i][RCOMP] = r;
524         rgba[i][GCOMP] = g;
525         rgba[i][BCOMP] = b;
526         rgba[i][ACOMP] = a;
527      }
528   }
529   else {
530      GLint i;
531      for (i = 0; i < drawWidth; i++) {
532	 ispan[i] = ctx->Current.RasterIndex;
533      }
534   }
535
536   if (type==GL_UNSIGNED_SHORT && sizeof(GLdepth)==sizeof(GLushort)
537       && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
538      /* Special case: directly write 16-bit depth values */
539      GLint row;
540      for (row = 0; row < height; row++, y++) {
541         GLdepth zspan[MAX_WIDTH];
542         const GLushort *zptr = _mesa_image_address(&ctx->Unpack,
543                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
544         GLint i;
545         for (i = 0; i < width; i++)
546            zspan[i] = zptr[i];
547         gl_write_rgba_span( ctx, width, x, y, zspan, rgba, GL_BITMAP );
548      }
549   }
550   else if (type==GL_UNSIGNED_INT && ctx->Visual->DepthBits == 32
551       && !bias_or_scale && !zoom && ctx->Visual->RGBAflag) {
552      /* Special case: directly write 32-bit depth values */
553      GLint row;
554      for (row = 0; row < height; row++, y++) {
555         const GLuint *zptr = _mesa_image_address(&ctx->Unpack,
556                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
557         gl_write_rgba_span( ctx, width, x, y, zptr, rgba, GL_BITMAP );
558      }
559   }
560   else {
561      /* General case */
562      GLint row;
563      for (row = 0; row < height; row++, y++) {
564         GLdepth zspan[MAX_WIDTH];
565         const GLvoid *src = _mesa_image_address(&ctx->Unpack,
566                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
567         _mesa_unpack_depth_span( ctx, drawWidth, zspan, type, src,
568                                  &ctx->Unpack, GL_TRUE );
569         if (ctx->Visual->RGBAflag) {
570            if (zoom) {
571               gl_write_zoomed_rgba_span(ctx, width, x, y, zspan,
572                                         (const GLubyte (*)[4])rgba, desty);
573            }
574            else {
575               gl_write_rgba_span(ctx, width, x, y, zspan, rgba, GL_BITMAP);
576            }
577         }
578         else {
579            if (zoom) {
580               gl_write_zoomed_index_span(ctx, width, x, y, zspan,
581                                          ispan, GL_BITMAP);
582            }
583            else {
584               gl_write_index_span(ctx, width, x, y, zspan, ispan, GL_BITMAP);
585            }
586         }
587
588      }
589   }
590}
591
592
593/*
594 * Do glDrawPixels of RGBA pixels.
595 */
596static void
597draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
598                  GLsizei width, GLsizei height,
599                  GLenum format, GLenum type, const GLvoid *pixels )
600{
601   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
602   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
603   const GLint desty = y;
604   GLdepth zspan[MAX_WIDTH];
605   GLboolean quickDraw;
606
607   /* Try an optimized glDrawPixels first */
608   if (simple_DrawPixels(ctx, x, y, width, height, format, type, pixels))
609      return;
610
611   /* Fragment depth values */
612   if (ctx->Depth.Test || ctx->Fog.Enabled) {
613      /* fill in array of z values */
614      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMaxF);
615      GLint i;
616      for (i=0;i<width;i++) {
617	 zspan[i] = z;
618      }
619   }
620
621
622   if (ctx->RasterMask == 0 && !zoom
623       && x >= 0 && y >= 0
624       && x + width <= ctx->DrawBuffer->Width
625       && y + height <= ctx->DrawBuffer->Height) {
626      quickDraw = GL_TRUE;
627   }
628   else {
629      quickDraw = GL_FALSE;
630   }
631
632   /*
633    * General solution
634    */
635   {
636      GLubyte rgba[MAX_WIDTH][4];
637      GLint row;
638      if (width > MAX_WIDTH)
639         width = MAX_WIDTH;
640      for (row = 0; row < height; row++, y++) {
641         const GLvoid *source = _mesa_image_address(unpack,
642                  pixels, width, height, format, type, 0, row, 0);
643         _mesa_unpack_ubyte_color_span(ctx, width, GL_RGBA, (void*) rgba,
644                   format, type, source, unpack, GL_TRUE);
645
646         if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
647            GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
648            GLuint unit;
649            /* XXX not sure how multitexture is supposed to work here */
650            for (unit = 0; unit < MAX_TEXTURE_UNITS; unit++) {
651               _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba,
652                                 s, t, r, q);
653               gl_texture_pixels(ctx, unit, width, s, t, r, NULL, rgba);
654            }
655         }
656
657         if (quickDraw) {
658            (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
659                                          (CONST GLubyte (*)[]) rgba, NULL);
660         }
661         else if (zoom) {
662            gl_write_zoomed_rgba_span( ctx, width, x, y, zspan,
663				       (CONST GLubyte (*)[]) rgba, desty );
664         }
665         else {
666            gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, rgba, GL_BITMAP);
667         }
668      }
669   }
670}
671
672
673
674/*
675 * Execute glDrawPixels
676 */
677void
678_mesa_DrawPixels( GLsizei width, GLsizei height,
679                  GLenum format, GLenum type, const GLvoid *pixels )
680{
681   GET_CURRENT_CONTEXT(ctx);
682   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels");
683
684   if (ctx->RenderMode==GL_RENDER) {
685      GLint x, y;
686      if (!pixels || !ctx->Current.RasterPosValid) {
687	 return;
688      }
689
690      if (ctx->NewState) {
691         gl_update_state(ctx);
692      }
693
694      x = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
695      y = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
696
697      ctx->OcclusionResult = GL_TRUE;
698
699      /* see if device driver can do the drawpix */
700      if (ctx->Driver.DrawPixels
701          && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type,
702                                       &ctx->Unpack, pixels)) {
703         return;
704      }
705
706      switch (format) {
707	 case GL_STENCIL_INDEX:
708	    draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
709	    break;
710	 case GL_DEPTH_COMPONENT:
711	    draw_depth_pixels( ctx, x, y, width, height, type, pixels );
712	    break;
713	 case GL_COLOR_INDEX:
714            if (ctx->Visual->RGBAflag)
715               draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
716            else
717               draw_index_pixels(ctx, x, y, width, height, type, pixels);
718	    break;
719	 case GL_RED:
720	 case GL_GREEN:
721	 case GL_BLUE:
722	 case GL_ALPHA:
723	 case GL_LUMINANCE:
724	 case GL_LUMINANCE_ALPHA:
725	 case GL_RGB:
726         case GL_BGR:
727	 case GL_RGBA:
728	 case GL_BGRA:
729	 case GL_ABGR_EXT:
730            draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
731	    break;
732	 default:
733	    gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
734            return;
735      }
736   }
737   else if (ctx->RenderMode==GL_FEEDBACK) {
738      if (ctx->Current.RasterPosValid) {
739         GLfloat color[4];
740	 GLfloat texcoord[4], invq;
741	 UBYTE_RGBA_TO_FLOAT_RGBA(color, ctx->Current.ByteColor);
742         invq = 1.0F / ctx->Current.Texcoord[0][3];
743         texcoord[0] = ctx->Current.Texcoord[0][0] * invq;
744         texcoord[1] = ctx->Current.Texcoord[0][1] * invq;
745         texcoord[2] = ctx->Current.Texcoord[0][2] * invq;
746         texcoord[3] = ctx->Current.Texcoord[0][3];
747         FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
748         gl_feedback_vertex( ctx,
749                             ctx->Current.RasterPos,
750                             color, ctx->Current.Index, texcoord );
751      }
752   }
753   else if (ctx->RenderMode==GL_SELECT) {
754      if (ctx->Current.RasterPosValid) {
755         gl_update_hitflag( ctx, ctx->Current.RasterPos[2] );
756      }
757   }
758}
759
760