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