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