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 |