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