Rev 57 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
57 | pj | 1 | /* $Id: s_copypix.c,v 1.1 2003-02-28 11:49:41 pj Exp $ */ |
2 | |||
3 | /* |
||
4 | * Mesa 3-D graphics library |
||
5 | * Version: 5.0 |
||
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 "feedback.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_depth.h" |
||
40 | #include "s_histogram.h" |
||
41 | #include "s_pixeltex.h" |
||
42 | #include "s_span.h" |
||
43 | #include "s_stencil.h" |
||
44 | #include "s_texture.h" |
||
45 | #include "s_zoom.h" |
||
46 | |||
47 | |||
48 | |||
49 | /* |
||
50 | * Determine if there's overlap in an image copy. |
||
51 | * This test also compensates for the fact that copies are done from |
||
52 | * bottom to top and overlaps can sometimes be handled correctly |
||
53 | * without making a temporary image copy. |
||
54 | */ |
||
55 | static GLboolean |
||
56 | regions_overlap(GLint srcx, GLint srcy, |
||
57 | GLint dstx, GLint dsty, |
||
58 | GLint width, GLint height, |
||
59 | GLfloat zoomX, GLfloat zoomY) |
||
60 | { |
||
61 | if (zoomX == 1.0 && zoomY == 1.0) { |
||
62 | /* no zoom */ |
||
63 | if (srcx >= dstx + width || (srcx + width <= dstx)) { |
||
64 | return GL_FALSE; |
||
65 | } |
||
66 | else if (srcy < dsty) { /* this is OK */ |
||
67 | return GL_FALSE; |
||
68 | } |
||
69 | else if (srcy > dsty + height) { |
||
70 | return GL_FALSE; |
||
71 | } |
||
72 | else { |
||
73 | return GL_TRUE; |
||
74 | } |
||
75 | } |
||
76 | else { |
||
77 | /* add one pixel of slop when zooming, just to be safe */ |
||
78 | if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) { |
||
79 | return GL_FALSE; |
||
80 | } |
||
81 | else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) { |
||
82 | return GL_FALSE; |
||
83 | } |
||
84 | else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) { |
||
85 | return GL_FALSE; |
||
86 | } |
||
87 | else { |
||
88 | return GL_TRUE; |
||
89 | } |
||
90 | } |
||
91 | } |
||
92 | |||
93 | |||
94 | |||
95 | /* |
||
96 | * RGBA copypixels with convolution. |
||
97 | */ |
||
98 | static void |
||
99 | copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, |
||
100 | GLint width, GLint height, GLint destx, GLint desty) |
||
101 | { |
||
102 | SWcontext *swrast = SWRAST_CONTEXT(ctx); |
||
103 | GLboolean quick_draw; |
||
104 | GLint row; |
||
105 | GLboolean changeBuffer; |
||
106 | const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; |
||
107 | const GLuint transferOps = ctx->_ImageTransferState; |
||
108 | GLfloat *dest, *tmpImage, *convImage; |
||
109 | struct sw_span span; |
||
110 | |||
111 | INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); |
||
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 | |||
119 | if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 |
||
120 | && !zoom |
||
121 | && destx >= 0 |
||
122 | && destx + width <= (GLint) ctx->DrawBuffer->Width) { |
||
123 | quick_draw = GL_TRUE; |
||
124 | } |
||
125 | else { |
||
126 | quick_draw = GL_FALSE; |
||
127 | } |
||
128 | |||
129 | /* If read and draw buffer are different we must do buffer switching */ |
||
130 | changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer |
||
131 | || ctx->DrawBuffer != ctx->ReadBuffer; |
||
132 | |||
133 | |||
134 | /* allocate space for GLfloat image */ |
||
135 | tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); |
||
136 | if (!tmpImage) { |
||
137 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); |
||
138 | return; |
||
139 | } |
||
140 | convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat)); |
||
141 | if (!convImage) { |
||
142 | FREE(tmpImage); |
||
143 | _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels"); |
||
144 | return; |
||
145 | } |
||
146 | |||
147 | dest = tmpImage; |
||
148 | |||
149 | if (changeBuffer) { |
||
150 | /* choose the read buffer */ |
||
151 | _swrast_use_read_buffer(ctx); |
||
152 | } |
||
153 | |||
154 | /* read source image */ |
||
155 | dest = tmpImage; |
||
156 | for (row = 0; row < height; row++) { |
||
157 | GLchan rgba[MAX_WIDTH][4]; |
||
158 | GLint i; |
||
159 | _mesa_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, srcy + row, rgba); |
||
160 | /* convert GLchan to GLfloat */ |
||
161 | for (i = 0; i < width; i++) { |
||
162 | *dest++ = (GLfloat) rgba[i][RCOMP] * (1.0F / CHAN_MAXF); |
||
163 | *dest++ = (GLfloat) rgba[i][GCOMP] * (1.0F / CHAN_MAXF); |
||
164 | *dest++ = (GLfloat) rgba[i][BCOMP] * (1.0F / CHAN_MAXF); |
||
165 | *dest++ = (GLfloat) rgba[i][ACOMP] * (1.0F / CHAN_MAXF); |
||
166 | } |
||
167 | } |
||
168 | |||
169 | if (changeBuffer) { |
||
170 | /* restore default src/dst buffer */ |
||
171 | _swrast_use_draw_buffer(ctx); |
||
172 | } |
||
173 | |||
174 | /* do image transfer ops up until convolution */ |
||
175 | for (row = 0; row < height; row++) { |
||
176 | GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4); |
||
177 | |||
178 | /* scale & bias */ |
||
179 | if (transferOps & IMAGE_SCALE_BIAS_BIT) { |
||
180 | _mesa_scale_and_bias_rgba(ctx, width, rgba, |
||
181 | ctx->Pixel.RedScale, ctx->Pixel.GreenScale, |
||
182 | ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale, |
||
183 | ctx->Pixel.RedBias, ctx->Pixel.GreenBias, |
||
184 | ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias); |
||
185 | } |
||
186 | /* color map lookup */ |
||
187 | if (transferOps & IMAGE_MAP_COLOR_BIT) { |
||
188 | _mesa_map_rgba(ctx, width, rgba); |
||
189 | } |
||
190 | /* GL_COLOR_TABLE lookup */ |
||
191 | if (transferOps & IMAGE_COLOR_TABLE_BIT) { |
||
192 | _mesa_lookup_rgba(&ctx->ColorTable, width, rgba); |
||
193 | } |
||
194 | } |
||
195 | |||
196 | /* do convolution */ |
||
197 | if (ctx->Pixel.Convolution2DEnabled) { |
||
198 | _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage); |
||
199 | } |
||
200 | else { |
||
201 | ASSERT(ctx->Pixel.Separable2DEnabled); |
||
202 | _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage); |
||
203 | } |
||
204 | FREE(tmpImage); |
||
205 | |||
206 | /* do remaining image transfer ops */ |
||
207 | for (row = 0; row < height; row++) { |
||
208 | GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4); |
||
209 | |||
210 | /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ |
||
211 | if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { |
||
212 | _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgba); |
||
213 | } |
||
214 | /* color matrix */ |
||
215 | if (transferOps & IMAGE_COLOR_MATRIX_BIT) { |
||
216 | _mesa_transform_rgba(ctx, width, rgba); |
||
217 | } |
||
218 | /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ |
||
219 | if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { |
||
220 | _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgba); |
||
221 | } |
||
222 | /* update histogram count */ |
||
223 | if (transferOps & IMAGE_HISTOGRAM_BIT) { |
||
224 | _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgba); |
||
225 | } |
||
226 | /* update min/max */ |
||
227 | if (transferOps & IMAGE_MIN_MAX_BIT) { |
||
228 | _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgba); |
||
229 | } |
||
230 | } |
||
231 | |||
232 | for (row = 0; row < height; row++) { |
||
233 | const GLfloat *src = convImage + row * width * 4; |
||
234 | GLint i, dy; |
||
235 | |||
236 | /* clamp to [0,1] and convert float back to chan */ |
||
237 | for (i = 0; i < width; i++) { |
||
238 | GLint r = (GLint) (src[i * 4 + RCOMP] * CHAN_MAXF); |
||
239 | GLint g = (GLint) (src[i * 4 + GCOMP] * CHAN_MAXF); |
||
240 | GLint b = (GLint) (src[i * 4 + BCOMP] * CHAN_MAXF); |
||
241 | GLint a = (GLint) (src[i * 4 + ACOMP] * CHAN_MAXF); |
||
242 | span.array->rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX); |
||
243 | span.array->rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX); |
||
244 | span.array->rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX); |
||
245 | span.array->rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX); |
||
246 | } |
||
247 | |||
248 | if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { |
||
249 | span.end = width; |
||
250 | _swrast_pixel_texture(ctx, &span); |
||
251 | } |
||
252 | |||
253 | /* write row to framebuffer */ |
||
254 | |||
255 | dy = desty + row; |
||
256 | if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { |
||
257 | (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy, |
||
258 | (const GLchan (*)[4])span.array->rgba, NULL ); |
||
259 | } |
||
260 | else if (zoom) { |
||
261 | span.x = destx; |
||
262 | span.y = dy; |
||
263 | span.end = width; |
||
264 | _mesa_write_zoomed_rgba_span(ctx, &span, |
||
265 | (CONST GLchan (*)[4])span.array->rgba, |
||
266 | desty); |
||
267 | } |
||
268 | else { |
||
269 | span.x = destx; |
||
270 | span.y = dy; |
||
271 | span.end = width; |
||
272 | _mesa_write_rgba_span(ctx, &span); |
||
273 | } |
||
274 | } |
||
275 | |||
276 | FREE(convImage); |
||
277 | } |
||
278 | |||
279 | |||
280 | /* |
||
281 | * RGBA copypixels |
||
282 | */ |
||
283 | static void |
||
284 | copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy, |
||
285 | GLint width, GLint height, GLint destx, GLint desty) |
||
286 | { |
||
287 | SWcontext *swrast = SWRAST_CONTEXT(ctx); |
||
288 | GLchan *tmpImage,*p; |
||
289 | GLboolean quick_draw; |
||
290 | GLint sy, dy, stepy, j; |
||
291 | GLboolean changeBuffer; |
||
292 | const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; |
||
293 | GLint overlapping; |
||
294 | const GLuint transferOps = ctx->_ImageTransferState; |
||
295 | struct sw_span span; |
||
296 | |||
297 | INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_RGBA); |
||
298 | |||
299 | if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) { |
||
300 | copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty); |
||
301 | return; |
||
302 | } |
||
303 | |||
304 | /* Determine if copy should be done bottom-to-top or top-to-bottom */ |
||
305 | if (srcy < desty) { |
||
306 | /* top-down max-to-min */ |
||
307 | sy = srcy + height - 1; |
||
308 | dy = desty + height - 1; |
||
309 | stepy = -1; |
||
310 | } |
||
311 | else { |
||
312 | /* bottom-up min-to-max */ |
||
313 | sy = srcy; |
||
314 | dy = desty; |
||
315 | stepy = 1; |
||
316 | } |
||
317 | |||
318 | overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, |
||
319 | ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); |
||
320 | |||
321 | if (ctx->Depth.Test) |
||
322 | _mesa_span_default_z(ctx, &span); |
||
323 | if (ctx->Fog.Enabled) |
||
324 | _mesa_span_default_fog(ctx, &span); |
||
325 | |||
326 | if (SWRAST_CONTEXT(ctx)->_RasterMask == 0 |
||
327 | && !zoom |
||
328 | && destx >= 0 |
||
329 | && destx + width <= (GLint) ctx->DrawBuffer->Width) { |
||
330 | quick_draw = GL_TRUE; |
||
331 | } |
||
332 | else { |
||
333 | quick_draw = GL_FALSE; |
||
334 | } |
||
335 | |||
336 | /* If read and draw buffer are different we must do buffer switching */ |
||
337 | changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer |
||
338 | || ctx->DrawBuffer != ctx->ReadBuffer; |
||
339 | |||
340 | if (overlapping) { |
||
341 | GLint ssy = sy; |
||
342 | tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4); |
||
343 | if (!tmpImage) { |
||
344 | _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); |
||
345 | return; |
||
346 | } |
||
347 | /* setup source */ |
||
348 | if (changeBuffer) |
||
349 | _swrast_use_read_buffer(ctx); |
||
350 | /* read the source image */ |
||
351 | p = tmpImage; |
||
352 | for (j = 0; j < height; j++, ssy += stepy) { |
||
353 | _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy, |
||
354 | (GLchan (*)[4]) p ); |
||
355 | p += width * 4; |
||
356 | } |
||
357 | p = tmpImage; |
||
358 | /* restore dest */ |
||
359 | if (changeBuffer) { |
||
360 | _swrast_use_draw_buffer(ctx); |
||
361 | changeBuffer = GL_FALSE; |
||
362 | } |
||
363 | } |
||
364 | else { |
||
365 | tmpImage = NULL; /* silence compiler warnings */ |
||
366 | p = NULL; |
||
367 | } |
||
368 | |||
369 | for (j = 0; j < height; j++, sy += stepy, dy += stepy) { |
||
370 | /* Get source pixels */ |
||
371 | if (overlapping) { |
||
372 | /* get from buffered image */ |
||
373 | MEMCPY(span.array->rgba, p, width * sizeof(GLchan) * 4); |
||
374 | p += width * 4; |
||
375 | } |
||
376 | else { |
||
377 | /* get from framebuffer */ |
||
378 | if (changeBuffer) |
||
379 | _swrast_use_read_buffer(ctx); |
||
380 | _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, |
||
381 | span.array->rgba ); |
||
382 | if (changeBuffer) |
||
383 | _swrast_use_draw_buffer(ctx); |
||
384 | } |
||
385 | |||
386 | if (transferOps) { |
||
387 | const GLfloat scale = (1.0F / CHAN_MAXF); |
||
388 | GLint k; |
||
389 | DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4); /* mac 32k limitation */ |
||
390 | CHECKARRAY(rgbaFloat, return); |
||
391 | |||
392 | /* convert chan to float */ |
||
393 | for (k = 0; k < width; k++) { |
||
394 | rgbaFloat[k][RCOMP] = (GLfloat) span.array->rgba[k][RCOMP] * scale; |
||
395 | rgbaFloat[k][GCOMP] = (GLfloat) span.array->rgba[k][GCOMP] * scale; |
||
396 | rgbaFloat[k][BCOMP] = (GLfloat) span.array->rgba[k][BCOMP] * scale; |
||
397 | rgbaFloat[k][ACOMP] = (GLfloat) span.array->rgba[k][ACOMP] * scale; |
||
398 | } |
||
399 | /* scale & bias */ |
||
400 | if (transferOps & IMAGE_SCALE_BIAS_BIT) { |
||
401 | _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat, |
||
402 | ctx->Pixel.RedScale, ctx->Pixel.GreenScale, |
||
403 | ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale, |
||
404 | ctx->Pixel.RedBias, ctx->Pixel.GreenBias, |
||
405 | ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias); |
||
406 | } |
||
407 | /* color map lookup */ |
||
408 | if (transferOps & IMAGE_MAP_COLOR_BIT) { |
||
409 | _mesa_map_rgba(ctx, width, rgbaFloat); |
||
410 | } |
||
411 | /* GL_COLOR_TABLE lookup */ |
||
412 | if (transferOps & IMAGE_COLOR_TABLE_BIT) { |
||
413 | _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat); |
||
414 | } |
||
415 | /* convolution */ |
||
416 | if (transferOps & IMAGE_CONVOLUTION_BIT) { |
||
417 | _mesa_problem(ctx, "Convolution should not be enabled in copy_rgba_pixels()"); |
||
418 | return; |
||
419 | } |
||
420 | /* GL_POST_CONVOLUTION_RED/GREEN/BLUE/ALPHA_SCALE/BIAS */ |
||
421 | if (transferOps & IMAGE_POST_CONVOLUTION_SCALE_BIAS) { |
||
422 | _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat, |
||
423 | ctx->Pixel.PostConvolutionScale[RCOMP], |
||
424 | ctx->Pixel.PostConvolutionScale[GCOMP], |
||
425 | ctx->Pixel.PostConvolutionScale[BCOMP], |
||
426 | ctx->Pixel.PostConvolutionScale[ACOMP], |
||
427 | ctx->Pixel.PostConvolutionBias[RCOMP], |
||
428 | ctx->Pixel.PostConvolutionBias[GCOMP], |
||
429 | ctx->Pixel.PostConvolutionBias[BCOMP], |
||
430 | ctx->Pixel.PostConvolutionBias[ACOMP]); |
||
431 | } |
||
432 | /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */ |
||
433 | if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) { |
||
434 | _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat); |
||
435 | } |
||
436 | /* color matrix */ |
||
437 | if (transferOps & IMAGE_COLOR_MATRIX_BIT) { |
||
438 | _mesa_transform_rgba(ctx, width, rgbaFloat); |
||
439 | } |
||
440 | /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */ |
||
441 | if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) { |
||
442 | _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat); |
||
443 | } |
||
444 | /* update histogram count */ |
||
445 | if (transferOps & IMAGE_HISTOGRAM_BIT) { |
||
446 | _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat); |
||
447 | } |
||
448 | /* update min/max */ |
||
449 | if (transferOps & IMAGE_MIN_MAX_BIT) { |
||
450 | _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat); |
||
451 | } |
||
452 | /* clamp to [0,1] and convert float back to chan */ |
||
453 | for (k = 0; k < width; k++) { |
||
454 | GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF); |
||
455 | GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF); |
||
456 | GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF); |
||
457 | GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF); |
||
458 | span.array->rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX); |
||
459 | span.array->rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX); |
||
460 | span.array->rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX); |
||
461 | span.array->rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX); |
||
462 | } |
||
463 | UNDEFARRAY(rgbaFloat); /* mac 32k limitation */ |
||
464 | } |
||
465 | |||
466 | if (ctx->Pixel.PixelTextureEnabled && ctx->Texture._EnabledUnits) { |
||
467 | span.end = width; |
||
468 | _swrast_pixel_texture(ctx, &span); |
||
469 | } |
||
470 | |||
471 | if (quick_draw && dy >= 0 && dy < (GLint) ctx->DrawBuffer->Height) { |
||
472 | (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy, |
||
473 | (const GLchan (*)[4])span.array->rgba, NULL ); |
||
474 | } |
||
475 | else if (zoom) { |
||
476 | span.x = destx; |
||
477 | span.y = dy; |
||
478 | span.end = width; |
||
479 | _mesa_write_zoomed_rgba_span(ctx, &span, |
||
480 | (CONST GLchan (*)[4]) span.array->rgba, |
||
481 | desty); |
||
482 | } |
||
483 | else { |
||
484 | span.x = destx; |
||
485 | span.y = dy; |
||
486 | span.end = width; |
||
487 | _mesa_write_rgba_span(ctx, &span); |
||
488 | } |
||
489 | } |
||
490 | |||
491 | if (overlapping) |
||
492 | FREE(tmpImage); |
||
493 | } |
||
494 | |||
495 | |||
496 | static void copy_ci_pixels( GLcontext *ctx, |
||
497 | GLint srcx, GLint srcy, GLint width, GLint height, |
||
498 | GLint destx, GLint desty ) |
||
499 | { |
||
500 | GLuint *tmpImage,*p; |
||
501 | GLint sy, dy, stepy; |
||
502 | GLint j; |
||
503 | GLboolean changeBuffer; |
||
504 | const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; |
||
505 | const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; |
||
506 | GLint overlapping; |
||
507 | struct sw_span span; |
||
508 | |||
509 | INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_INDEX); |
||
510 | |||
511 | /* Determine if copy should be bottom-to-top or top-to-bottom */ |
||
512 | if (srcy<desty) { |
||
513 | /* top-down max-to-min */ |
||
514 | sy = srcy + height - 1; |
||
515 | dy = desty + height - 1; |
||
516 | stepy = -1; |
||
517 | } |
||
518 | else { |
||
519 | /* bottom-up min-to-max */ |
||
520 | sy = srcy; |
||
521 | dy = desty; |
||
522 | stepy = 1; |
||
523 | } |
||
524 | |||
525 | overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, |
||
526 | ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); |
||
527 | |||
528 | if (ctx->Depth.Test) |
||
529 | _mesa_span_default_z(ctx, &span); |
||
530 | if (ctx->Fog.Enabled) |
||
531 | _mesa_span_default_fog(ctx, &span); |
||
532 | |||
533 | /* If read and draw buffer are different we must do buffer switching */ |
||
534 | changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer |
||
535 | || ctx->DrawBuffer != ctx->ReadBuffer; |
||
536 | |||
537 | if (overlapping) { |
||
538 | GLint ssy = sy; |
||
539 | tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint)); |
||
540 | if (!tmpImage) { |
||
541 | _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); |
||
542 | return; |
||
543 | } |
||
544 | /* setup source */ |
||
545 | if (changeBuffer) |
||
546 | _swrast_use_read_buffer(ctx); |
||
547 | /* read the image */ |
||
548 | p = tmpImage; |
||
549 | for (j = 0; j < height; j++, ssy += stepy) { |
||
550 | _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p ); |
||
551 | p += width; |
||
552 | } |
||
553 | p = tmpImage; |
||
554 | /* restore to draw buffer */ |
||
555 | if (changeBuffer) { |
||
556 | _swrast_use_draw_buffer(ctx); |
||
557 | changeBuffer = GL_FALSE; |
||
558 | } |
||
559 | } |
||
560 | else { |
||
561 | tmpImage = NULL; /* silence compiler warning */ |
||
562 | p = NULL; |
||
563 | } |
||
564 | |||
565 | for (j = 0; j < height; j++, sy += stepy, dy += stepy) { |
||
566 | if (overlapping) { |
||
567 | MEMCPY(span.array->index, p, width * sizeof(GLuint)); |
||
568 | p += width; |
||
569 | } |
||
570 | else { |
||
571 | if (changeBuffer) |
||
572 | _swrast_use_read_buffer(ctx); |
||
573 | _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, |
||
574 | span.array->index ); |
||
575 | if (changeBuffer) |
||
576 | _swrast_use_draw_buffer(ctx); |
||
577 | } |
||
578 | |||
579 | if (shift_or_offset) { |
||
580 | _mesa_shift_and_offset_ci( ctx, width, span.array->index ); |
||
581 | } |
||
582 | if (ctx->Pixel.MapColorFlag) { |
||
583 | _mesa_map_ci( ctx, width, span.array->index ); |
||
584 | } |
||
585 | |||
586 | span.x = destx; |
||
587 | span.y = dy; |
||
588 | span.end = width; |
||
589 | if (zoom) |
||
590 | _mesa_write_zoomed_index_span(ctx, &span, desty); |
||
591 | else |
||
592 | _mesa_write_index_span(ctx, &span); |
||
593 | } |
||
594 | |||
595 | if (overlapping) |
||
596 | FREE(tmpImage); |
||
597 | } |
||
598 | |||
599 | |||
600 | |||
601 | /* |
||
602 | * TODO: Optimize!!!! |
||
603 | */ |
||
604 | static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy, |
||
605 | GLint width, GLint height, |
||
606 | GLint destx, GLint desty ) |
||
607 | { |
||
608 | GLfloat depth[MAX_WIDTH]; |
||
609 | GLfloat *p, *tmpImage; |
||
610 | GLint sy, dy, stepy; |
||
611 | GLint i, j; |
||
612 | const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; |
||
613 | GLint overlapping; |
||
614 | struct sw_span span; |
||
615 | |||
616 | INIT_SPAN(span, GL_BITMAP, 0, 0, SPAN_Z); |
||
617 | |||
618 | if (!ctx->Visual.depthBits) { |
||
619 | _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); |
||
620 | return; |
||
621 | } |
||
622 | |||
623 | /* Determine if copy should be bottom-to-top or top-to-bottom */ |
||
624 | if (srcy<desty) { |
||
625 | /* top-down max-to-min */ |
||
626 | sy = srcy + height - 1; |
||
627 | dy = desty + height - 1; |
||
628 | stepy = -1; |
||
629 | } |
||
630 | else { |
||
631 | /* bottom-up min-to-max */ |
||
632 | sy = srcy; |
||
633 | dy = desty; |
||
634 | stepy = 1; |
||
635 | } |
||
636 | |||
637 | overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, |
||
638 | ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); |
||
639 | |||
640 | _mesa_span_default_color(ctx, &span); |
||
641 | if (ctx->Fog.Enabled) |
||
642 | _mesa_span_default_fog(ctx, &span); |
||
643 | |||
644 | if (overlapping) { |
||
645 | GLint ssy = sy; |
||
646 | tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat)); |
||
647 | if (!tmpImage) { |
||
648 | _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); |
||
649 | return; |
||
650 | } |
||
651 | p = tmpImage; |
||
652 | for (j = 0; j < height; j++, ssy += stepy) { |
||
653 | _mesa_read_depth_span_float(ctx, width, srcx, ssy, p); |
||
654 | p += width; |
||
655 | } |
||
656 | p = tmpImage; |
||
657 | } |
||
658 | else { |
||
659 | tmpImage = NULL; /* silence compiler warning */ |
||
660 | p = NULL; |
||
661 | } |
||
662 | |||
663 | for (j = 0; j < height; j++, sy += stepy, dy += stepy) { |
||
664 | if (overlapping) { |
||
665 | MEMCPY(depth, p, width * sizeof(GLfloat)); |
||
666 | p += width; |
||
667 | } |
||
668 | else { |
||
669 | _mesa_read_depth_span_float(ctx, width, srcx, sy, depth); |
||
670 | } |
||
671 | |||
672 | for (i = 0; i < width; i++) { |
||
673 | GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; |
||
674 | span.array->z[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->DepthMax); |
||
675 | } |
||
676 | |||
677 | span.x = destx; |
||
678 | span.y = dy; |
||
679 | span.end = width; |
||
680 | if (ctx->Visual.rgbMode) { |
||
681 | if (zoom) |
||
682 | _mesa_write_zoomed_rgba_span( ctx, &span, |
||
683 | (const GLchan (*)[4])span.array->rgba, |
||
684 | desty ); |
||
685 | else |
||
686 | _mesa_write_rgba_span(ctx, &span); |
||
687 | } |
||
688 | else { |
||
689 | if (zoom) |
||
690 | _mesa_write_zoomed_index_span( ctx, &span, desty ); |
||
691 | else |
||
692 | _mesa_write_index_span(ctx, &span); |
||
693 | } |
||
694 | } |
||
695 | |||
696 | if (overlapping) |
||
697 | FREE(tmpImage); |
||
698 | } |
||
699 | |||
700 | |||
701 | |||
702 | static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy, |
||
703 | GLint width, GLint height, |
||
704 | GLint destx, GLint desty ) |
||
705 | { |
||
706 | GLint sy, dy, stepy; |
||
707 | GLint j; |
||
708 | GLstencil *p, *tmpImage; |
||
709 | const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F; |
||
710 | const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset; |
||
711 | GLint overlapping; |
||
712 | |||
713 | if (!ctx->Visual.stencilBits) { |
||
714 | _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); |
||
715 | return; |
||
716 | } |
||
717 | |||
718 | /* Determine if copy should be bottom-to-top or top-to-bottom */ |
||
719 | if (srcy < desty) { |
||
720 | /* top-down max-to-min */ |
||
721 | sy = srcy + height - 1; |
||
722 | dy = desty + height - 1; |
||
723 | stepy = -1; |
||
724 | } |
||
725 | else { |
||
726 | /* bottom-up min-to-max */ |
||
727 | sy = srcy; |
||
728 | dy = desty; |
||
729 | stepy = 1; |
||
730 | } |
||
731 | |||
732 | overlapping = regions_overlap(srcx, srcy, destx, desty, width, height, |
||
733 | ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); |
||
734 | |||
735 | if (overlapping) { |
||
736 | GLint ssy = sy; |
||
737 | tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil)); |
||
738 | if (!tmpImage) { |
||
739 | _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" ); |
||
740 | return; |
||
741 | } |
||
742 | p = tmpImage; |
||
743 | for (j = 0; j < height; j++, ssy += stepy) { |
||
744 | _mesa_read_stencil_span( ctx, width, srcx, ssy, p ); |
||
745 | p += width; |
||
746 | } |
||
747 | p = tmpImage; |
||
748 | } |
||
749 | else { |
||
750 | tmpImage = NULL; /* silence compiler warning */ |
||
751 | p = NULL; |
||
752 | } |
||
753 | |||
754 | for (j = 0; j < height; j++, sy += stepy, dy += stepy) { |
||
755 | GLstencil stencil[MAX_WIDTH]; |
||
756 | |||
757 | if (overlapping) { |
||
758 | MEMCPY(stencil, p, width * sizeof(GLstencil)); |
||
759 | p += width; |
||
760 | } |
||
761 | else { |
||
762 | _mesa_read_stencil_span( ctx, width, srcx, sy, stencil ); |
||
763 | } |
||
764 | |||
765 | if (shift_or_offset) { |
||
766 | _mesa_shift_and_offset_stencil( ctx, width, stencil ); |
||
767 | } |
||
768 | if (ctx->Pixel.MapStencilFlag) { |
||
769 | _mesa_map_stencil( ctx, width, stencil ); |
||
770 | } |
||
771 | |||
772 | if (zoom) { |
||
773 | _mesa_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty ); |
||
774 | } |
||
775 | else { |
||
776 | _mesa_write_stencil_span( ctx, width, destx, dy, stencil ); |
||
777 | } |
||
778 | } |
||
779 | |||
780 | if (overlapping) |
||
781 | FREE(tmpImage); |
||
782 | } |
||
783 | |||
784 | |||
785 | |||
786 | |||
787 | void |
||
788 | _swrast_CopyPixels( GLcontext *ctx, |
||
789 | GLint srcx, GLint srcy, GLsizei width, GLsizei height, |
||
790 | GLint destx, GLint desty, |
||
791 | GLenum type ) |
||
792 | { |
||
793 | SWcontext *swrast = SWRAST_CONTEXT(ctx); |
||
794 | RENDER_START(swrast,ctx); |
||
795 | |||
796 | if (swrast->NewState) |
||
797 | _swrast_validate_derived( ctx ); |
||
798 | |||
799 | if (type == GL_COLOR && ctx->Visual.rgbMode) { |
||
800 | copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty ); |
||
801 | } |
||
802 | else if (type == GL_COLOR && !ctx->Visual.rgbMode) { |
||
803 | copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); |
||
804 | } |
||
805 | else if (type == GL_DEPTH) { |
||
806 | copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); |
||
807 | } |
||
808 | else if (type == GL_STENCIL) { |
||
809 | copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); |
||
810 | } |
||
811 | else { |
||
812 | _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" ); |
||
813 | } |
||
814 | |||
815 | RENDER_FINISH(swrast,ctx); |
||
816 | } |