drawpix.c revision fa849a0e1622039bf66ef2b7506669aba8d77d91
1/* $Id: drawpix.c,v 1.37 2000/10/05 16:22:23 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 "context.h"
33#include "convolve.h"
34#include "drawpix.h"
35#include "feedback.h"
36#include "image.h"
37#include "macros.h"
38#include "mem.h"
39#include "mmath.h"
40#include "pixel.h"
41#include "pixeltex.h"
42#include "span.h"
43#include "state.h"
44#include "stencil.h"
45#include "texture.h"
46#include "types.h"
47#include "zoom.h"
48#endif
49
50
51
52/*
53 * Given the dest position, size and skipPixels and skipRows values
54 * for a glDrawPixels command, perform clipping of the image bounds
55 * so the result lies withing the context's buffer bounds.
56 * Return:  GL_TRUE if image is ready for drawing
57 *          GL_FALSE if image was completely clipped away (draw nothing)
58 */
59GLboolean
60_mesa_clip_pixelrect(const GLcontext *ctx,
61                     GLint *destX, GLint *destY,
62                     GLsizei *width, GLsizei *height,
63                     GLint *skipPixels, GLint *skipRows)
64{
65   const GLframebuffer *buffer = ctx->DrawBuffer;
66
67   /* left clipping */
68   if (*destX < buffer->Xmin) {
69      *skipPixels += (buffer->Xmin - *destX);
70      *width -= (buffer->Xmin - *destX);
71      *destX = buffer->Xmin;
72   }
73   /* right clipping */
74   if (*destX + *width > buffer->Xmax)
75      *width -= (*destX + *width - buffer->Xmax);
76
77   if (*width <= 0)
78      return GL_FALSE;
79
80   /* bottom clipping */
81   if (*destY < buffer->Ymin) {
82      *skipRows += (buffer->Ymin - *destY);
83      *height -= (buffer->Ymin - *destY);
84      *destY = buffer->Ymin;
85   }
86   /* top clipping */
87   if (*destY + *height > buffer->Ymax)
88      *height -= (*destY + *height - buffer->Ymax);
89
90   if (*height <= 0)
91      return GL_TRUE;
92
93   return GL_TRUE;
94}
95
96
97
98/*
99 * Try to do a fast and simple RGB(a) glDrawPixels.
100 * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
101 */
102static GLboolean
103fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
104                 GLsizei width, GLsizei height,
105                 GLenum format, GLenum type, const GLvoid *pixels)
106{
107   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
108   GLubyte rgb[MAX_WIDTH][3];
109   GLubyte rgba[MAX_WIDTH][4];
110
111   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH_WITH_RETVAL(ctx, "glDrawPixels",
112						  GL_FALSE);
113
114
115   if (!ctx->Current.RasterPosValid) {
116      return GL_TRUE;      /* no-op */
117   }
118
119   if ((ctx->RasterMask&(~(SCISSOR_BIT|WINCLIP_BIT)))==0
120       && ctx->Texture.ReallyEnabled == 0
121       && unpack->Alignment == 1
122       && !unpack->SwapBytes
123       && !unpack->LsbFirst) {
124
125      GLint destX = x;
126      GLint destY = y;
127      GLint drawWidth = width;           /* actual width drawn */
128      GLint drawHeight = height;         /* actual height drawn */
129      GLint skipPixels = unpack->SkipPixels;
130      GLint skipRows = unpack->SkipRows;
131      GLint rowLength;
132      GLdepth zSpan[MAX_WIDTH];  /* only used when zooming */
133      GLint zoomY0 = 0;
134
135      if (unpack->RowLength > 0)
136         rowLength = unpack->RowLength;
137      else
138         rowLength = width;
139
140      /* If we're not using pixel zoom then do all clipping calculations
141       * now.  Otherwise, we'll let the gl_write_zoomed_*_span() functions
142       * handle the clipping.
143       */
144      if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
145         /* horizontal clipping */
146         if (destX < ctx->DrawBuffer->Xmin) {
147            skipPixels += (ctx->DrawBuffer->Xmin - destX);
148            drawWidth  -= (ctx->DrawBuffer->Xmin - destX);
149            destX = ctx->DrawBuffer->Xmin;
150         }
151         if (destX + drawWidth > ctx->DrawBuffer->Xmax)
152            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax);
153         if (drawWidth <= 0)
154            return GL_TRUE;
155
156         /* vertical clipping */
157         if (destY < ctx->DrawBuffer->Ymin) {
158            skipRows   += (ctx->DrawBuffer->Ymin - destY);
159            drawHeight -= (ctx->DrawBuffer->Ymin - destY);
160            destY = ctx->DrawBuffer->Ymin;
161         }
162         if (destY + drawHeight > ctx->DrawBuffer->Ymax)
163            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->Ymax);
164         if (drawHeight <= 0)
165            return GL_TRUE;
166      }
167      else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
168         /* upside-down image */
169         /* horizontal clipping */
170         if (destX < ctx->DrawBuffer->Xmin) {
171            skipPixels += (ctx->DrawBuffer->Xmin - destX);
172            drawWidth  -= (ctx->DrawBuffer->Xmin - destX);
173            destX = ctx->DrawBuffer->Xmin;
174         }
175         if (destX + drawWidth > ctx->DrawBuffer->Xmax)
176            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->Xmax);
177         if (drawWidth <= 0)
178            return GL_TRUE;
179
180         /* vertical clipping */
181         if (destY > ctx->DrawBuffer->Ymax) {
182            skipRows   += (destY - ctx->DrawBuffer->Ymax);
183            drawHeight -= (destY - ctx->DrawBuffer->Ymax);
184            destY = ctx->DrawBuffer->Ymax;
185         }
186         if (destY - drawHeight < ctx->DrawBuffer->Ymin)
187            drawHeight -= (ctx->DrawBuffer->Ymin - (destY - drawHeight));
188         if (drawHeight <= 0)
189            return GL_TRUE;
190      }
191      else {
192         /* setup array of fragment Z value to pass to zoom function */
193         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
194         GLint i;
195         ASSERT(drawWidth < MAX_WIDTH);
196         for (i=0; i<drawWidth; i++)
197            zSpan[i] = z;
198
199         /* save Y value of first row */
200         zoomY0 = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
201      }
202
203
204      /*
205       * Ready to draw!
206       * The window region at (destX, destY) of size (drawWidth, drawHeight)
207       * will be written to.
208       * We'll take pixel data from buffer pointed to by "pixels" but we'll
209       * skip "skipRows" rows and skip "skipPixels" pixels/row.
210       */
211
212      if (format==GL_RGBA && type==GL_UNSIGNED_BYTE
213          && ctx->ImageTransferState==0) {
214         if (ctx->Visual.RGBAflag) {
215            GLubyte *src = (GLubyte *) pixels
216               + (skipRows * rowLength + skipPixels) * 4;
217            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
218               /* no zooming */
219               GLint row;
220               for (row=0; row<drawHeight; row++) {
221                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
222                                               (void *) src, NULL);
223                  src += rowLength * 4;
224                  destY++;
225               }
226            }
227            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
228               /* upside-down */
229               GLint row;
230               for (row=0; row<drawHeight; row++) {
231                  destY--;
232                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
233                                              (void *) src, NULL);
234                  src += rowLength * 4;
235               }
236            }
237            else {
238               /* with zooming */
239               GLint row;
240               for (row=0; row<drawHeight; row++) {
241                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
242                                            zSpan, (void *) src, zoomY0);
243                  src += rowLength * 4;
244                  destY++;
245               }
246            }
247         }
248         return GL_TRUE;
249      }
250      else if (format==GL_RGB && type==GL_UNSIGNED_BYTE
251               && ctx->ImageTransferState==0) {
252         if (ctx->Visual.RGBAflag) {
253            GLubyte *src = (GLubyte *) pixels
254               + (skipRows * rowLength + skipPixels) * 3;
255            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
256               GLint row;
257               for (row=0; row<drawHeight; row++) {
258                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
259                                              (void *) src, NULL);
260                  src += rowLength * 3;
261                  destY++;
262               }
263            }
264            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
265               /* upside-down */
266               GLint row;
267               for (row=0; row<drawHeight; row++) {
268                  destY--;
269                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
270                                              (void *) src, NULL);
271                  src += rowLength * 3;
272               }
273            }
274            else {
275               /* with zooming */
276               GLint row;
277               for (row=0; row<drawHeight; row++) {
278                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
279                                           zSpan, (void *) src, zoomY0);
280                  src += rowLength * 3;
281                  destY++;
282               }
283            }
284         }
285         return GL_TRUE;
286      }
287      else if (format==GL_LUMINANCE && type==GL_UNSIGNED_BYTE
288               && ctx->ImageTransferState==0) {
289         if (ctx->Visual.RGBAflag) {
290            GLubyte *src = (GLubyte *) pixels
291               + (skipRows * rowLength + skipPixels);
292            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
293               /* no zooming */
294               GLint row;
295               ASSERT(drawWidth < MAX_WIDTH);
296               for (row=0; row<drawHeight; row++) {
297                  GLint i;
298		  for (i=0;i<drawWidth;i++) {
299                     rgb[i][0] = src[i];
300                     rgb[i][1] = src[i];
301                     rgb[i][2] = src[i];
302		  }
303                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
304                                              (void *) rgb, NULL);
305                  src += rowLength;
306                  destY++;
307               }
308            }
309            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
310               /* upside-down */
311               GLint row;
312               ASSERT(drawWidth < MAX_WIDTH);
313               for (row=0; row<drawHeight; row++) {
314                  GLint i;
315                  for (i=0;i<drawWidth;i++) {
316                     rgb[i][0] = src[i];
317                     rgb[i][1] = src[i];
318                     rgb[i][2] = src[i];
319                  }
320                  destY--;
321                  (*ctx->Driver.WriteRGBSpan)(ctx, drawWidth, destX, destY,
322                                              (void *) rgb, NULL);
323                  src += rowLength;
324               }
325            }
326            else {
327               /* with zooming */
328               GLint row;
329               ASSERT(drawWidth < MAX_WIDTH);
330               for (row=0; row<drawHeight; row++) {
331                  GLint i;
332		  for (i=0;i<drawWidth;i++) {
333                     rgb[i][0] = src[i];
334                     rgb[i][1] = src[i];
335                     rgb[i][2] = src[i];
336		  }
337                  gl_write_zoomed_rgb_span(ctx, drawWidth, destX, destY,
338                                           zSpan, (void *) rgb, zoomY0);
339                  src += rowLength;
340                  destY++;
341               }
342            }
343         }
344         return GL_TRUE;
345      }
346      else if (format==GL_LUMINANCE_ALPHA && type==GL_UNSIGNED_BYTE
347               && ctx->ImageTransferState==0) {
348         if (ctx->Visual.RGBAflag) {
349            GLubyte *src = (GLubyte *) pixels
350               + (skipRows * rowLength + skipPixels)*2;
351            if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
352               /* no zooming */
353               GLint row;
354               ASSERT(drawWidth < MAX_WIDTH);
355               for (row=0; row<drawHeight; row++) {
356                  GLint i;
357                  GLubyte *ptr = src;
358		  for (i=0;i<drawWidth;i++) {
359                     rgba[i][0] = *ptr;
360                     rgba[i][1] = *ptr;
361                     rgba[i][2] = *ptr++;
362                     rgba[i][3] = *ptr++;
363		  }
364                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
365                                               (void *) rgba, NULL);
366                  src += rowLength*2;
367                  destY++;
368               }
369            }
370            else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
371               /* upside-down */
372               GLint row;
373               ASSERT(drawWidth < MAX_WIDTH);
374               for (row=0; row<drawHeight; row++) {
375                  GLint i;
376                  GLubyte *ptr = src;
377                  for (i=0;i<drawWidth;i++) {
378                     rgba[i][0] = *ptr;
379                     rgba[i][1] = *ptr;
380                     rgba[i][2] = *ptr++;
381                     rgba[i][3] = *ptr++;
382                  }
383                  destY--;
384                  (*ctx->Driver.WriteRGBASpan)(ctx, drawWidth, destX, destY,
385                                               (void *) rgba, NULL);
386                  src += rowLength*2;
387               }
388            }
389            else {
390               /* with zooming */
391               GLint row;
392               ASSERT(drawWidth < MAX_WIDTH);
393               for (row=0; row<drawHeight; row++) {
394                  GLubyte *ptr = src;
395                  GLint i;
396		  for (i=0;i<drawWidth;i++) {
397                     rgba[i][0] = *ptr;
398                     rgba[i][1] = *ptr;
399                     rgba[i][2] = *ptr++;
400                     rgba[i][3] = *ptr++;
401		  }
402                  gl_write_zoomed_rgba_span(ctx, drawWidth, destX, destY,
403                                            zSpan, (void *) rgba, zoomY0);
404                  src += rowLength*2;
405                  destY++;
406               }
407            }
408         }
409         return GL_TRUE;
410      }
411      else if (format==GL_COLOR_INDEX && type==GL_UNSIGNED_BYTE) {
412         GLubyte *src = (GLubyte *) pixels + skipRows * rowLength + skipPixels;
413         if (ctx->Visual.RGBAflag
414             && ctx->ImageTransferState==IMAGE_MAP_COLOR_BIT) {
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 GLubyte (*)[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 GLubyte (*)[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, (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, indexes, desty);
525      }
526      else {
527         gl_write_index_span(ctx, drawWidth, x, y, zspan, 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   GLubyte 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 = (GLint) (ctx->Current.RasterColor[0] * 255.0F);
618      GLint g = (GLint) (ctx->Current.RasterColor[1] * 255.0F);
619      GLint b = (GLint) (ctx->Current.RasterColor[2] * 255.0F);
620      GLint a = (GLint) (ctx->Current.RasterColor[3] * 255.0F);
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, 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, 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,
672                                         (const GLubyte (*)[4])rgba, desty);
673            }
674            else {
675               gl_write_rgba_span(ctx, width, x, y, zspan, rgba, GL_BITMAP);
676            }
677         }
678         else {
679            if (zoom) {
680               gl_write_zoomed_index_span(ctx, width, x, y, zspan,
681                                          ispan, GL_BITMAP);
682            }
683            else {
684               gl_write_index_span(ctx, width, x, y, zspan, ispan, GL_BITMAP);
685            }
686         }
687
688      }
689   }
690}
691
692
693/*
694 * Do glDrawPixels of RGBA pixels.
695 */
696static void
697draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
698                  GLsizei width, GLsizei height,
699                  GLenum format, GLenum type, const GLvoid *pixels )
700{
701   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
702   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
703   const GLint desty = y;
704   GLdepth zspan[MAX_WIDTH];
705   GLboolean quickDraw;
706   GLfloat *convImage = NULL;
707   GLuint transferOps = ctx->ImageTransferState;
708
709   if (!_mesa_is_legal_format_and_type(format, type)) {
710      gl_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
711      return;
712   }
713
714   /* Try an optimized glDrawPixels first */
715   if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
716      return;
717
718   /* Fragment depth values */
719   if (ctx->Depth.Test || ctx->Fog.Enabled) {
720      /* fill in array of z values */
721      GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual.DepthMaxF);
722      GLint i;
723      for (i=0;i<width;i++) {
724	 zspan[i] = z;
725      }
726   }
727
728
729   if (ctx->RasterMask == 0 && !zoom && x >= 0 && y >= 0
730       && x + width <= ctx->DrawBuffer->Width
731       && y + height <= ctx->DrawBuffer->Height) {
732      quickDraw = GL_TRUE;
733   }
734   else {
735      quickDraw = GL_FALSE;
736   }
737
738   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
739      /* Convolution has to be handled specially.  We'll create an
740       * intermediate image, applying all pixel transfer operations
741       * up to convolution.  Then we'll convolve the image.  Then
742       * we'll proceed with the rest of the transfer operations and
743       * rasterize the image.
744       */
745      GLint row;
746      GLfloat *dest, *tmpImage;
747
748      tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
749      if (!tmpImage) {
750         gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
751         return;
752      }
753      convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
754      if (!convImage) {
755         FREE(tmpImage);
756         gl_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
757         return;
758      }
759
760      /* Unpack the image and apply transfer ops up to convolution */
761      dest = tmpImage;
762      for (row = 0; row < height; row++) {
763         const GLvoid *source = _mesa_image_address(unpack,
764                  pixels, width, height, format, type, 0, row, 0);
765         _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (void *) dest,
766                                      format, type, source, unpack,
767                                      transferOps & IMAGE_PRE_CONVOLUTION_BITS,
768                                      GL_FALSE);
769         dest += width * 4;
770      }
771
772      /* do convolution */
773      if (ctx->Pixel.Convolution2DEnabled) {
774         _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
775      }
776      else {
777         ASSERT(ctx->Pixel.Separable2DEnabled);
778         _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
779      }
780      FREE(tmpImage);
781
782      /* continue transfer ops and draw the convolved image */
783      unpack = &_mesa_native_packing;
784      pixels = convImage;
785      format = GL_RGBA;
786      type = GL_FLOAT;
787      transferOps &= IMAGE_POST_CONVOLUTION_BITS;
788   }
789
790   /*
791    * General solution
792    */
793   {
794      GLubyte rgba[MAX_WIDTH][4];
795      GLint row;
796      if (width > MAX_WIDTH)
797         width = MAX_WIDTH;
798      for (row = 0; row < height; row++, y++) {
799         const GLvoid *source = _mesa_image_address(unpack,
800                  pixels, width, height, format, type, 0, row, 0);
801         _mesa_unpack_ubyte_color_span(ctx, width, GL_RGBA, (void*) rgba,
802                                       format, type, source, unpack,
803                                       transferOps);
804         if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
805             (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
806            continue;
807
808         if (ctx->Texture.ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
809            GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
810            GLubyte primary_rgba[MAX_WIDTH][4];
811            GLuint unit;
812            /* XXX not sure how multitexture is supposed to work here */
813
814            MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLubyte));
815
816            for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
817               if (ctx->Texture.Unit[unit].ReallyEnabled) {
818                  _mesa_pixeltexgen(ctx, width, (const GLubyte (*)[4]) rgba,
819                                    s, t, r, q);
820                  gl_texture_pixels(ctx, unit, width, s, t, r, NULL,
821                                    primary_rgba, rgba);
822               }
823            }
824         }
825
826         if (quickDraw) {
827            (*ctx->Driver.WriteRGBASpan)( ctx, width, x, y,
828                                          (CONST GLubyte (*)[]) rgba, NULL);
829         }
830         else if (zoom) {
831            gl_write_zoomed_rgba_span( ctx, width, x, y, zspan,
832				       (CONST GLubyte (*)[]) rgba, desty );
833         }
834         else {
835            gl_write_rgba_span( ctx, (GLuint) width, x, y, zspan, rgba, GL_BITMAP);
836         }
837      }
838   }
839
840   if (convImage) {
841      FREE(convImage);
842   }
843}
844
845
846
847/*
848 * Execute glDrawPixels
849 */
850void
851_mesa_DrawPixels( GLsizei width, GLsizei height,
852                  GLenum format, GLenum type, const GLvoid *pixels )
853{
854   GET_CURRENT_CONTEXT(ctx);
855   ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glDrawPixels");
856
857   if (ctx->RenderMode==GL_RENDER) {
858      GLint x, y;
859      if (!pixels || !ctx->Current.RasterPosValid) {
860	 return;
861      }
862
863      if (ctx->NewState) {
864         gl_update_state(ctx);
865      }
866
867      if (ctx->ImageTransferState == UPDATE_IMAGE_TRANSFER_STATE)
868         _mesa_update_image_transfer_state(ctx);
869
870      x = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
871      y = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
872
873      ctx->OcclusionResult = GL_TRUE;
874
875      /* see if device driver can do the drawpix */
876      if (ctx->Driver.DrawPixels
877          && (*ctx->Driver.DrawPixels)(ctx, x, y, width, height, format, type,
878                                       &ctx->Unpack, pixels)) {
879         return;
880      }
881
882      switch (format) {
883	 case GL_STENCIL_INDEX:
884	    draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
885	    break;
886	 case GL_DEPTH_COMPONENT:
887	    draw_depth_pixels( ctx, x, y, width, height, type, pixels );
888	    break;
889	 case GL_COLOR_INDEX:
890            if (ctx->Visual.RGBAflag)
891               draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
892            else
893               draw_index_pixels(ctx, x, y, width, height, type, pixels);
894	    break;
895	 case GL_RED:
896	 case GL_GREEN:
897	 case GL_BLUE:
898	 case GL_ALPHA:
899	 case GL_LUMINANCE:
900	 case GL_LUMINANCE_ALPHA:
901	 case GL_RGB:
902         case GL_BGR:
903	 case GL_RGBA:
904	 case GL_BGRA:
905	 case GL_ABGR_EXT:
906            draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
907	    break;
908	 default:
909	    gl_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
910            return;
911      }
912   }
913   else if (ctx->RenderMode==GL_FEEDBACK) {
914      if (ctx->Current.RasterPosValid) {
915         GLfloat color[4];
916	 GLfloat texcoord[4], invq;
917	 UBYTE_RGBA_TO_FLOAT_RGBA(color, ctx->Current.ByteColor);
918         invq = 1.0F / ctx->Current.Texcoord[0][3];
919         texcoord[0] = ctx->Current.Texcoord[0][0] * invq;
920         texcoord[1] = ctx->Current.Texcoord[0][1] * invq;
921         texcoord[2] = ctx->Current.Texcoord[0][2] * invq;
922         texcoord[3] = ctx->Current.Texcoord[0][3];
923         FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_DRAW_PIXEL_TOKEN );
924         gl_feedback_vertex( ctx,
925                             ctx->Current.RasterPos,
926                             color, ctx->Current.Index, texcoord );
927      }
928   }
929   else if (ctx->RenderMode==GL_SELECT) {
930      if (ctx->Current.RasterPosValid) {
931         gl_update_hitflag( ctx, ctx->Current.RasterPos[2] );
932      }
933   }
934}
935
936