Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
57 pj 1
/* $Id: s_drawpix.c,v 1.1 2003-02-28 11:49:41 pj Exp $ */
2
 
3
/*
4
 * Mesa 3-D graphics library
5
 * Version:  4.1
6
 *
7
 * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a
10
 * copy of this software and associated documentation files (the "Software"),
11
 * to deal in the Software without restriction, including without limitation
12
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
 * and/or sell copies of the Software, and to permit persons to whom the
14
 * Software is furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included
17
 * in all copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22
 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23
 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
 */
26
 
27
 
28
#include "glheader.h"
29
#include "colormac.h"
30
#include "context.h"
31
#include "convolve.h"
32
#include "image.h"
33
#include "macros.h"
34
#include "imports.h"
35
#include "mmath.h"
36
#include "pixel.h"
37
 
38
#include "s_context.h"
39
#include "s_drawpix.h"
40
#include "s_pixeltex.h"
41
#include "s_span.h"
42
#include "s_stencil.h"
43
#include "s_texture.h"
44
#include "s_zoom.h"
45
 
46
 
47
 
48
/*
49
 * Given the dest position, size and skipPixels and skipRows values
50
 * for a glDrawPixels command, perform clipping of the image bounds
51
 * so the result lies withing the context's buffer bounds.
52
 * Return:  GL_TRUE if image is ready for drawing
53
 *          GL_FALSE if image was completely clipped away (draw nothing)
54
 */
55
GLboolean
56
_mesa_clip_pixelrect(const GLcontext *ctx,
57
                     GLint *destX, GLint *destY,
58
                     GLsizei *width, GLsizei *height,
59
                     GLint *skipPixels, GLint *skipRows)
60
{
61
   const GLframebuffer *buffer = ctx->DrawBuffer;
62
 
63
   /* left clipping */
64
   if (*destX < buffer->_Xmin) {
65
      *skipPixels += (buffer->_Xmin - *destX);
66
      *width -= (buffer->_Xmin - *destX);
67
      *destX = buffer->_Xmin;
68
   }
69
   /* right clipping */
70
   if (*destX + *width > buffer->_Xmax)
71
      *width -= (*destX + *width - buffer->_Xmax);
72
 
73
   if (*width <= 0)
74
      return GL_FALSE;
75
 
76
   /* bottom clipping */
77
   if (*destY < buffer->_Ymin) {
78
      *skipRows += (buffer->_Ymin - *destY);
79
      *height -= (buffer->_Ymin - *destY);
80
      *destY = buffer->_Ymin;
81
   }
82
   /* top clipping */
83
   if (*destY + *height > buffer->_Ymax)
84
      *height -= (*destY + *height - buffer->_Ymax);
85
 
86
   if (*height <= 0)
87
      return GL_TRUE;
88
 
89
   return GL_TRUE;
90
}
91
 
92
 
93
 
94
/*
95
 * Try to do a fast and simple RGB(a) glDrawPixels.
96
 * Return:  GL_TRUE if success, GL_FALSE if slow path must be used instead
97
 */
98
static GLboolean
99
fast_draw_pixels(GLcontext *ctx, GLint x, GLint y,
100
                 GLsizei width, GLsizei height,
101
                 GLenum format, GLenum type, const GLvoid *pixels)
102
{
103
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
104
   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
105
   struct sw_span span;
106
 
107
   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
108
 
109
   if (!ctx->Current.RasterPosValid) {
110
      return GL_TRUE;      /* no-op */
111
   }
112
 
113
   if (ctx->Depth.Test)
114
      _mesa_span_default_z(ctx, &span);
115
   if (ctx->Fog.Enabled)
116
      _mesa_span_default_fog(ctx, &span);
117
 
118
   if ((SWRAST_CONTEXT(ctx)->_RasterMask & ~CLIP_BIT) == 0
119
       && ctx->Texture._EnabledUnits == 0
120
       && unpack->Alignment == 1
121
       && !unpack->SwapBytes
122
       && !unpack->LsbFirst) {
123
 
124
      GLint destX = x;
125
      GLint destY = y;
126
      GLint drawWidth = width;           /* actual width drawn */
127
      GLint drawHeight = height;         /* actual height drawn */
128
      GLint skipPixels = unpack->SkipPixels;
129
      GLint skipRows = unpack->SkipRows;
130
      GLint rowLength;
131
      GLdepth zSpan[MAX_WIDTH];  /* only used when zooming */
132
      GLint zoomY0 = 0;
133
 
134
      if (unpack->RowLength > 0)
135
         rowLength = unpack->RowLength;
136
      else
137
         rowLength = width;
138
 
139
      /* If we're not using pixel zoom then do all clipping calculations
140
       * now.  Otherwise, we'll let the _mesa_write_zoomed_*_span() functions
141
       * handle the clipping.
142
       */
143
      if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) {
144
         /* horizontal clipping */
145
         if (destX < ctx->DrawBuffer->_Xmin) {
146
            skipPixels += (ctx->DrawBuffer->_Xmin - destX);
147
            drawWidth  -= (ctx->DrawBuffer->_Xmin - destX);
148
            destX = ctx->DrawBuffer->_Xmin;
149
         }
150
         if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
151
            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
152
         if (drawWidth <= 0)
153
            return GL_TRUE;
154
 
155
         /* vertical clipping */
156
         if (destY < ctx->DrawBuffer->_Ymin) {
157
            skipRows   += (ctx->DrawBuffer->_Ymin - destY);
158
            drawHeight -= (ctx->DrawBuffer->_Ymin - destY);
159
            destY = ctx->DrawBuffer->_Ymin;
160
         }
161
         if (destY + drawHeight > ctx->DrawBuffer->_Ymax)
162
            drawHeight -= (destY + drawHeight - ctx->DrawBuffer->_Ymax);
163
         if (drawHeight <= 0)
164
            return GL_TRUE;
165
      }
166
      else if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==-1.0F) {
167
         /* upside-down image */
168
         /* horizontal clipping */
169
         if (destX < ctx->DrawBuffer->_Xmin) {
170
            skipPixels += (ctx->DrawBuffer->_Xmin - destX);
171
            drawWidth  -= (ctx->DrawBuffer->_Xmin - destX);
172
            destX = ctx->DrawBuffer->_Xmin;
173
         }
174
         if (destX + drawWidth > ctx->DrawBuffer->_Xmax)
175
            drawWidth -= (destX + drawWidth - ctx->DrawBuffer->_Xmax);
176
         if (drawWidth <= 0)
177
            return GL_TRUE;
178
 
179
         /* vertical clipping */
180
         if (destY > ctx->DrawBuffer->_Ymax) {
181
            skipRows   += (destY - ctx->DrawBuffer->_Ymax);
182
            drawHeight -= (destY - ctx->DrawBuffer->_Ymax);
183
            destY = ctx->DrawBuffer->_Ymax;
184
         }
185
         if (destY - drawHeight < ctx->DrawBuffer->_Ymin)
186
            drawHeight -= (ctx->DrawBuffer->_Ymin - (destY - drawHeight));
187
         if (drawHeight <= 0)
188
            return GL_TRUE;
189
      }
190
      else {
191
         /* setup array of fragment Z value to pass to zoom function */
192
         GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMaxF);
193
         GLint i;
194
         ASSERT(drawWidth < MAX_WIDTH);
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);
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);
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);
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);
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);
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
 * Do glDrawPixels of index pixels.
502
 */
503
static void
504
draw_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
   const GLint desty = y;
510
   GLint row, drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
511
   struct sw_span span;
512
 
513
   INIT_SPAN(span, GL_BITMAP, drawWidth, 0, SPAN_INDEX);
514
 
515
   if (ctx->Depth.Test)
516
      _mesa_span_default_z(ctx, &span);
517
   if (ctx->Fog.Enabled)
518
      _mesa_span_default_fog(ctx, &span);
519
 
520
   /*
521
    * General solution
522
    */
523
   for (row = 0; row < height; row++, y++) {
524
      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
525
                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
526
      _mesa_unpack_index_span(ctx, drawWidth, GL_UNSIGNED_INT,
527
                              span.array->index,
528
                              type, source, &ctx->Unpack,
529
                              ctx->_ImageTransferState);
530
      span.x = x;
531
      span.y = y;
532
      span.end = drawWidth;
533
      if (zoom)
534
         _mesa_write_zoomed_index_span(ctx, &span, desty);
535
      else
536
         _mesa_write_index_span(ctx, &span);
537
   }
538
}
539
 
540
 
541
 
542
/*
543
 * Do glDrawPixels of stencil image.  The image datatype may either
544
 * be GLubyte or GLbitmap.
545
 */
546
static void
547
draw_stencil_pixels( GLcontext *ctx, GLint x, GLint y,
548
                     GLsizei width, GLsizei height,
549
                     GLenum type, const GLvoid *pixels )
550
{
551
   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
552
   const GLint desty = y;
553
   GLint row, drawWidth;
554
 
555
   if (type != GL_BYTE &&
556
       type != GL_UNSIGNED_BYTE &&
557
       type != GL_SHORT &&
558
       type != GL_UNSIGNED_SHORT &&
559
       type != GL_INT &&
560
       type != GL_UNSIGNED_INT &&
561
       type != GL_FLOAT &&
562
       type != GL_BITMAP) {
563
      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(stencil type)");
564
      return;
565
   }
566
 
567
   if (ctx->Visual.stencilBits == 0) {
568
      _mesa_error( ctx, GL_INVALID_OPERATION, "glDrawPixels(no stencil buffer)");
569
      return;
570
   }
571
 
572
   drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
573
 
574
   for (row = 0; row < height; row++, y++) {
575
      GLstencil values[MAX_WIDTH];
576
      GLenum destType = (sizeof(GLstencil) == sizeof(GLubyte))
577
                      ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT;
578
      const GLvoid *source = _mesa_image_address(&ctx->Unpack,
579
                    pixels, width, height, GL_COLOR_INDEX, type, 0, row, 0);
580
      _mesa_unpack_index_span(ctx, drawWidth, destType, values,
581
                              type, source, &ctx->Unpack,
582
                              ctx->_ImageTransferState);
583
      if (ctx->_ImageTransferState & IMAGE_SHIFT_OFFSET_BIT) {
584
         _mesa_shift_and_offset_stencil( ctx, drawWidth, values );
585
      }
586
      if (ctx->Pixel.MapStencilFlag) {
587
         _mesa_map_stencil( ctx, drawWidth, values );
588
      }
589
 
590
      if (zoom) {
591
         _mesa_write_zoomed_stencil_span( ctx, (GLuint) drawWidth, x, y,
592
                                       values, desty );
593
      }
594
      else {
595
         _mesa_write_stencil_span( ctx, (GLuint) drawWidth, x, y, values );
596
      }
597
   }
598
}
599
 
600
 
601
/*
602
 * Do a glDrawPixels of depth values.
603
 */
604
static void
605
draw_depth_pixels( GLcontext *ctx, GLint x, GLint y,
606
                   GLsizei width, GLsizei height,
607
                   GLenum type, const GLvoid *pixels )
608
{
609
   const GLboolean bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
610
   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
611
   const GLint desty = y;
612
   GLint drawWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
613
   struct sw_span span;
614
 
615
   INIT_SPAN(span, GL_BITMAP, drawWidth, 0, SPAN_Z);
616
 
617
   if (type != GL_BYTE
618
       && type != GL_UNSIGNED_BYTE
619
       && type != GL_SHORT
620
       && type != GL_UNSIGNED_SHORT
621
       && type != GL_INT
622
       && type != GL_UNSIGNED_INT
623
       && type != GL_FLOAT) {
624
      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(type)");
625
      return;
626
   }
627
 
628
   _mesa_span_default_color(ctx, &span);
629
 
630
   if (ctx->Fog.Enabled)
631
      _mesa_span_default_fog(ctx, &span);
632
   if (ctx->Texture._EnabledUnits)
633
      _mesa_span_default_texcoords(ctx, &span);
634
 
635
   if (type==GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16
636
       && !bias_or_scale && !zoom && ctx->Visual.rgbMode) {
637
      /* Special case: directly write 16-bit depth values */
638
      GLint row;
639
      span.x = x;
640
      span.y = y;
641
      span.end = drawWidth;
642
      for (row = 0; row < height; row++, span.y++) {
643
         const GLushort *zptr = (const GLushort *)
644
            _mesa_image_address(&ctx->Unpack, pixels, width, height,
645
                                GL_DEPTH_COMPONENT, type, 0, row, 0);
646
         GLint i;
647
         for (i = 0; i < drawWidth; i++)
648
            span.array->z[i] = zptr[i];
649
         _mesa_write_rgba_span(ctx, &span);
650
      }
651
   }
652
   else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
653
       && !bias_or_scale && !zoom && ctx->Visual.rgbMode) {
654
      /* Special case: directly write 32-bit depth values */
655
      GLint row;
656
      span.x = x;
657
      span.y = y;
658
      span.end = drawWidth;
659
      for (row = 0; row < height; row++, span.y++) {
660
         const GLuint *zptr = (const GLuint *)
661
            _mesa_image_address(&ctx->Unpack, pixels, width, height,
662
                                GL_DEPTH_COMPONENT, type, 0, row, 0);
663
         MEMCPY(span.array->z, zptr, drawWidth * sizeof(GLdepth));
664
         _mesa_write_rgba_span(ctx, &span);
665
      }
666
   }
667
   else {
668
      /* General case */
669
      GLint row;
670
      span.x = x;
671
      span.y = y;
672
      span.end = drawWidth;
673
      for (row = 0; row < height; row++, span.y++) {
674
         GLfloat fspan[MAX_WIDTH];
675
         const GLvoid *src = _mesa_image_address(&ctx->Unpack,
676
                pixels, width, height, GL_DEPTH_COMPONENT, type, 0, row, 0);
677
         _mesa_unpack_depth_span( ctx, drawWidth, fspan, type, src,
678
                                  &ctx->Unpack );
679
         /* clamp depth values to [0,1] and convert from floats to integers */
680
         {
681
            const GLfloat zs = ctx->DepthMaxF;
682
            GLint i;
683
            for (i = 0; i < drawWidth; i++) {
684
               span.array->z[i] = (GLdepth) (fspan[i] * zs + 0.5F);
685
            }
686
         }
687
         if (ctx->Visual.rgbMode) {
688
            if (zoom) {
689
               _mesa_write_zoomed_rgba_span(ctx, &span,
690
                                 (const GLchan (*)[4]) span.array->rgba, desty);
691
            }
692
            else
693
               _mesa_write_rgba_span(ctx, &span);
694
         }
695
         else {
696
            if (zoom)
697
               _mesa_write_zoomed_index_span(ctx, &span, desty);
698
            else
699
               _mesa_write_index_span(ctx, &span);
700
         }
701
      }
702
   }
703
}
704
 
705
 
706
/*
707
 * Do glDrawPixels of RGBA pixels.
708
 */
709
static void
710
draw_rgba_pixels( GLcontext *ctx, GLint x, GLint y,
711
                  GLsizei width, GLsizei height,
712
                  GLenum format, GLenum type, const GLvoid *pixels )
713
{
714
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
715
   const struct gl_pixelstore_attrib *unpack = &ctx->Unpack;
716
   const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
717
   const GLint desty = y;
718
   GLboolean quickDraw;
719
   GLfloat *convImage = NULL;
720
   GLuint transferOps = ctx->_ImageTransferState;
721
   struct sw_span span;
722
 
723
   INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA);
724
 
725
   if (!_mesa_is_legal_format_and_type(format, type)) {
726
      _mesa_error(ctx, GL_INVALID_ENUM, "glDrawPixels(format or type)");
727
      return;
728
   }
729
 
730
   /* Try an optimized glDrawPixels first */
731
   if (fast_draw_pixels(ctx, x, y, width, height, format, type, pixels))
732
      return;
733
 
734
   if (ctx->Depth.Test)
735
      _mesa_span_default_z(ctx, &span);
736
   if (ctx->Fog.Enabled)
737
      _mesa_span_default_fog(ctx, &span);
738
   if (ctx->Texture._EnabledUnits)
739
      _mesa_span_default_texcoords(ctx, &span);
740
 
741
   if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 && !zoom && x >= 0 && y >= 0
742
       && x + width <= (GLint) ctx->DrawBuffer->Width
743
       && y + height <= (GLint) ctx->DrawBuffer->Height) {
744
      quickDraw = GL_TRUE;
745
   }
746
   else {
747
      quickDraw = GL_FALSE;
748
   }
749
 
750
   if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
751
      /* Convolution has to be handled specially.  We'll create an
752
       * intermediate image, applying all pixel transfer operations
753
       * up to convolution.  Then we'll convolve the image.  Then
754
       * we'll proceed with the rest of the transfer operations and
755
       * rasterize the image.
756
       */
757
      GLint row;
758
      GLfloat *dest, *tmpImage;
759
 
760
      tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
761
      if (!tmpImage) {
762
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
763
         return;
764
      }
765
      convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
766
      if (!convImage) {
767
         FREE(tmpImage);
768
         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
769
         return;
770
      }
771
 
772
      /* Unpack the image and apply transfer ops up to convolution */
773
      dest = tmpImage;
774
      for (row = 0; row < height; row++) {
775
         const GLvoid *source = _mesa_image_address(unpack,
776
                  pixels, width, height, format, type, 0, row, 0);
777
         _mesa_unpack_float_color_span(ctx, width, GL_RGBA, (GLfloat *) dest,
778
                                      format, type, source, unpack,
779
                                      transferOps & IMAGE_PRE_CONVOLUTION_BITS,
780
                                      GL_FALSE);
781
         dest += width * 4;
782
      }
783
 
784
      /* do convolution */
785
      if (ctx->Pixel.Convolution2DEnabled) {
786
         _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
787
      }
788
      else {
789
         ASSERT(ctx->Pixel.Separable2DEnabled);
790
         _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
791
      }
792
      FREE(tmpImage);
793
 
794
      /* continue transfer ops and draw the convolved image */
795
      unpack = &_mesa_native_packing;
796
      pixels = convImage;
797
      format = GL_RGBA;
798
      type = GL_FLOAT;
799
      transferOps &= IMAGE_POST_CONVOLUTION_BITS;
800
   }
801
 
802
   /*
803
    * General solution
804
    */
805
   {
806
      GLint row;
807
      if (width > MAX_WIDTH)
808
         width = MAX_WIDTH;
809
 
810
      for (row = 0; row < height; row++, y++) {
811
         const GLvoid *source = _mesa_image_address(unpack,
812
                  pixels, width, height, format, type, 0, row, 0);
813
 
814
         _mesa_unpack_chan_color_span(ctx, width, GL_RGBA,
815
                                      (GLchan *) span.array->rgba,
816
                                      format, type, source, unpack,
817
                                      transferOps);
818
 
819
         if ((ctx->Pixel.MinMaxEnabled && ctx->MinMax.Sink) ||
820
             (ctx->Pixel.HistogramEnabled && ctx->Histogram.Sink))
821
            continue;
822
 
823
         if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) {
824
            span.end = width;
825
            _swrast_pixel_texture(ctx, &span);
826
         }
827
 
828
         if (quickDraw) {
829
            (*swrast->Driver.WriteRGBASpan)(ctx, width, x, y,
830
                                 (CONST GLchan (*)[4]) span.array->rgba, NULL);
831
         }
832
         else if (zoom) {
833
            span.x = x;
834
            span.y = y;
835
            span.end = width;
836
            _mesa_write_zoomed_rgba_span(ctx, &span,
837
                                (CONST GLchan (*)[4]) span.array->rgba, desty);
838
         }
839
         else {
840
            span.x = x;
841
            span.y = y;
842
            span.end = width;
843
            _mesa_write_rgba_span(ctx, &span);
844
         }
845
      }
846
   }
847
 
848
   if (convImage) {
849
      FREE(convImage);
850
   }
851
}
852
 
853
 
854
 
855
/*
856
 * Execute glDrawPixels
857
 */
858
void
859
_swrast_DrawPixels( GLcontext *ctx,
860
                    GLint x, GLint y,
861
                    GLsizei width, GLsizei height,
862
                    GLenum format, GLenum type,
863
                    const struct gl_pixelstore_attrib *unpack,
864
                    const GLvoid *pixels )
865
{
866
   SWcontext *swrast = SWRAST_CONTEXT(ctx);
867
   (void) unpack;
868
 
869
   if (swrast->NewState)
870
      _swrast_validate_derived( ctx );
871
 
872
   RENDER_START(swrast,ctx);
873
 
874
   switch (format) {
875
   case GL_STENCIL_INDEX:
876
      draw_stencil_pixels( ctx, x, y, width, height, type, pixels );
877
      break;
878
   case GL_DEPTH_COMPONENT:
879
      draw_depth_pixels( ctx, x, y, width, height, type, pixels );
880
      break;
881
   case GL_COLOR_INDEX:
882
      if (ctx->Visual.rgbMode)
883
         draw_rgba_pixels(ctx, x,y, width, height, format, type, pixels);
884
      else
885
         draw_index_pixels(ctx, x, y, width, height, type, pixels);
886
      break;
887
   case GL_RED:
888
   case GL_GREEN:
889
   case GL_BLUE:
890
   case GL_ALPHA:
891
   case GL_LUMINANCE:
892
   case GL_LUMINANCE_ALPHA:
893
   case GL_RGB:
894
   case GL_BGR:
895
   case GL_RGBA:
896
   case GL_BGRA:
897
   case GL_ABGR_EXT:
898
      draw_rgba_pixels(ctx, x, y, width, height, format, type, pixels);
899
      break;
900
   default:
901
      _mesa_error( ctx, GL_INVALID_ENUM, "glDrawPixels(format)" );
902
   }
903
 
904
   RENDER_FINISH(swrast,ctx);
905
}
906
 
907
 
908
 
909
#if 0  /* experimental */
910
/*
911
 * Execute glDrawDepthPixelsMESA().
912
 */
913
void
914
_swrast_DrawDepthPixelsMESA( GLcontext *ctx,
915
                             GLint x, GLint y,
916
                             GLsizei width, GLsizei height,
917
                             GLenum colorFormat, GLenum colorType,
918
                             const GLvoid *colors,
919
                             GLenum depthType, const GLvoid *depths,
920
                             const struct gl_pixelstore_attrib *unpack )
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 (colorFormat) {
931
   case GL_COLOR_INDEX:
932
      if (ctx->Visual.rgbMode)
933
         draw_rgba_pixels(ctx, x,y, width, height, colorFormat, colorType, colors);
934
      else
935
         draw_index_pixels(ctx, x, y, width, height, colorType, colors);
936
      break;
937
   case GL_RED:
938
   case GL_GREEN:
939
   case GL_BLUE:
940
   case GL_ALPHA:
941
   case GL_LUMINANCE:
942
   case GL_LUMINANCE_ALPHA:
943
   case GL_RGB:
944
   case GL_BGR:
945
   case GL_RGBA:
946
   case GL_BGRA:
947
   case GL_ABGR_EXT:
948
      draw_rgba_pixels(ctx, x, y, width, height, colorFormat, colorType, colors);
949
      break;
950
   default:
951
      _mesa_error( ctx, GL_INVALID_ENUM,
952
                   "glDrawDepthPixelsMESA(colorFormat)" );
953
   }
954
 
955
   RENDER_FINISH(swrast,ctx);
956
}
957
#endif