10508166982b99b8669b9c18fb592a60934d76cd
[mesa.git] / src / mesa / swrast / s_drawpix.c
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 */
52 GLboolean
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 */
95 static GLboolean
96 fast_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 */
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 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 */
557 static void
558 draw_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 */
626 static void
627 draw_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 */
751 static void
752 draw_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 */
914 void
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 */
969 void
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