first checkpoint commit of Klaus's new span code (struct sw_span)
[mesa.git] / src / mesa / swrast / s_copypix.c
1 /* $Id: s_copypix.c,v 1.26 2001/12/17 04:54:35 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2001 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 "mem.h"
35 #include "mmath.h"
36 #include "pixel.h"
37
38 #include "s_context.h"
39 #include "s_depth.h"
40 #include "s_fog.h"
41 #include "s_histogram.h"
42 #include "s_pixeltex.h"
43 #include "s_span.h"
44 #include "s_stencil.h"
45 #include "s_texture.h"
46 #include "s_zoom.h"
47
48
49
50 /*
51 * Determine if there's overlap in an image copy.
52 * This test also compensates for the fact that copies are done from
53 * bottom to top and overlaps can sometimes be handled correctly
54 * without making a temporary image copy.
55 */
56 static GLboolean
57 regions_overlap(GLint srcx, GLint srcy,
58 GLint dstx, GLint dsty,
59 GLint width, GLint height,
60 GLfloat zoomX, GLfloat zoomY)
61 {
62 if (zoomX == 1.0 && zoomY == 1.0) {
63 /* no zoom */
64 if (srcx >= dstx + width || (srcx + width <= dstx)) {
65 return GL_FALSE;
66 }
67 else if (srcy < dsty) { /* this is OK */
68 return GL_FALSE;
69 }
70 else {
71 return GL_TRUE;
72 }
73 }
74 else {
75 /* add one pixel of slop when zooming, just to be safe */
76 if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) {
77 return GL_FALSE;
78 }
79 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
80 return GL_FALSE;
81 }
82 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
83 return GL_FALSE;
84 }
85 else {
86 return GL_TRUE;
87 }
88 }
89 }
90
91
92
93 /*
94 * RGBA copypixels with convolution.
95 */
96 static void
97 copy_conv_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
98 GLint width, GLint height, GLint destx, GLint desty)
99 {
100 SWcontext *swrast = SWRAST_CONTEXT(ctx);
101 GLdepth zspan[MAX_WIDTH];
102 GLfloat fogSpan[MAX_WIDTH];
103 GLboolean quick_draw;
104 GLint row;
105 GLboolean changeBuffer;
106 GLchan *saveReadAlpha;
107 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
108 const GLuint transferOps = ctx->_ImageTransferState;
109 GLfloat *dest, *tmpImage, *convImage;
110
111 if (ctx->Depth.Test || ctx->Fog.Enabled) {
112 /* fill in array of z values */
113 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax);
114 GLfloat fog;
115 GLint i;
116
117 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
118 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
119 else
120 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
121
122 for (i = 0; i < width; i++) {
123 zspan[i] = z;
124 fogSpan[i] = fog;
125 }
126 }
127
128 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
129 && !zoom
130 && destx >= 0
131 && destx + width <= ctx->DrawBuffer->Width) {
132 quick_draw = GL_TRUE;
133 }
134 else {
135 quick_draw = GL_FALSE;
136 }
137
138 /* If read and draw buffer are different we must do buffer switching */
139 saveReadAlpha = ctx->ReadBuffer->Alpha;
140 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
141 || ctx->DrawBuffer != ctx->ReadBuffer;
142
143
144 /* allocate space for GLfloat image */
145 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
146 if (!tmpImage) {
147 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
148 return;
149 }
150 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
151 if (!convImage) {
152 FREE(tmpImage);
153 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
154 return;
155 }
156
157 dest = tmpImage;
158
159 if (changeBuffer) {
160 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
161 ctx->Pixel.DriverReadBuffer );
162 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
163 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
164 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
165 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
166 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
167 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
168 else
169 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
170 }
171
172 /* read source image */
173 dest = tmpImage;
174 for (row = 0; row < height; row++) {
175 GLchan rgba[MAX_WIDTH][4];
176 GLint i;
177 _mesa_read_rgba_span(ctx, ctx->ReadBuffer, width, srcx, srcy + row, rgba);
178 /* convert GLchan to GLfloat */
179 for (i = 0; i < width; i++) {
180 *dest++ = (GLfloat) rgba[i][RCOMP] * (1.0F / CHAN_MAXF);
181 *dest++ = (GLfloat) rgba[i][GCOMP] * (1.0F / CHAN_MAXF);
182 *dest++ = (GLfloat) rgba[i][BCOMP] * (1.0F / CHAN_MAXF);
183 *dest++ = (GLfloat) rgba[i][ACOMP] * (1.0F / CHAN_MAXF);
184 }
185 }
186
187 /* read from the draw buffer again (in case of blending) */
188 if (changeBuffer) {
189 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
190 ctx->Color.DriverDrawBuffer );
191 ctx->ReadBuffer->Alpha = saveReadAlpha;
192 }
193
194 /* do image transfer ops up until convolution */
195 for (row = 0; row < height; row++) {
196 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (tmpImage + row * width * 4);
197
198 /* scale & bias */
199 if (transferOps & IMAGE_SCALE_BIAS_BIT) {
200 _mesa_scale_and_bias_rgba(ctx, width, rgba,
201 ctx->Pixel.RedScale, ctx->Pixel.GreenScale,
202 ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale,
203 ctx->Pixel.RedBias, ctx->Pixel.GreenBias,
204 ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias);
205 }
206 /* color map lookup */
207 if (transferOps & IMAGE_MAP_COLOR_BIT) {
208 _mesa_map_rgba(ctx, width, rgba);
209 }
210 /* GL_COLOR_TABLE lookup */
211 if (transferOps & IMAGE_COLOR_TABLE_BIT) {
212 _mesa_lookup_rgba(&ctx->ColorTable, width, rgba);
213 }
214 }
215
216 /* do convolution */
217 if (ctx->Pixel.Convolution2DEnabled) {
218 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
219 }
220 else {
221 ASSERT(ctx->Pixel.Separable2DEnabled);
222 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
223 }
224 FREE(tmpImage);
225
226 /* do remaining image transfer ops */
227 for (row = 0; row < height; row++) {
228 GLfloat (*rgba)[4] = (GLfloat (*)[4]) (convImage + row * width * 4);
229
230 /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
231 if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
232 _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgba);
233 }
234 /* color matrix */
235 if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
236 _mesa_transform_rgba(ctx, width, rgba);
237 }
238 /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
239 if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
240 _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgba);
241 }
242 /* update histogram count */
243 if (transferOps & IMAGE_HISTOGRAM_BIT) {
244 _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgba);
245 }
246 /* update min/max */
247 if (transferOps & IMAGE_MIN_MAX_BIT) {
248 _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgba);
249 }
250 }
251
252 for (row = 0; row < height; row++) {
253 const GLfloat *src = convImage + row * width * 4;
254 GLchan rgba[MAX_WIDTH][4];
255 GLint i, dy;
256
257 /* clamp to [0,1] and convert float back to chan */
258 for (i = 0; i < width; i++) {
259 GLint r = (GLint) (src[i * 4 + RCOMP] * CHAN_MAXF);
260 GLint g = (GLint) (src[i * 4 + GCOMP] * CHAN_MAXF);
261 GLint b = (GLint) (src[i * 4 + BCOMP] * CHAN_MAXF);
262 GLint a = (GLint) (src[i * 4 + ACOMP] * CHAN_MAXF);
263 rgba[i][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
264 rgba[i][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
265 rgba[i][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
266 rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
267 }
268
269 if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
270 GLfloat s[MAX_WIDTH], t[MAX_WIDTH], r[MAX_WIDTH], q[MAX_WIDTH];
271 GLfloat texcoord[MAX_WIDTH][3];
272 GLchan primary_rgba[MAX_WIDTH][4];
273 GLuint unit;
274 /* XXX not sure how multitexture is supposed to work here */
275
276 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
277
278 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
279 GLint i;
280 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
281 s, t, r, q);
282 /* this is an ugly work-around. s,t,r has to be copied to
283 texcoords, because the functions need different
284 input. */
285 for (i=0; i<width; i++) {
286 texcoord[i][0] = s[i],
287 texcoord[i][1] = t[i],
288 texcoord[i][2] = r[i];
289 }
290 _old_swrast_texture_fragments( ctx, unit, width, texcoord, NULL,
291 (CONST GLchan (*)[4]) primary_rgba,
292 rgba);
293 }
294 }
295
296 /* write row to framebuffer */
297
298 dy = desty + row;
299 if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
300 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
301 (const GLchan (*)[4])rgba, NULL );
302 }
303 else if (zoom) {
304 _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, fogSpan,
305 (const GLchan (*)[4])rgba, desty);
306 }
307 else {
308 _old_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan, rgba,
309 NULL, GL_BITMAP );
310 }
311 }
312
313 FREE(convImage);
314 }
315
316
317 /*
318 * RGBA copypixels
319 */
320 static void
321 copy_rgba_pixels(GLcontext *ctx, GLint srcx, GLint srcy,
322 GLint width, GLint height, GLint destx, GLint desty)
323 {
324 SWcontext *swrast = SWRAST_CONTEXT(ctx);
325 GLdepth zspan[MAX_WIDTH];
326 GLfloat fogSpan[MAX_WIDTH];
327 GLchan rgba[MAX_WIDTH][4];
328 GLchan *tmpImage,*p;
329 GLboolean quick_draw;
330 GLint sy, dy, stepy;
331 GLint i, j;
332 GLboolean changeBuffer;
333 GLchan *saveReadAlpha;
334 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
335 GLint overlapping;
336 const GLuint transferOps = ctx->_ImageTransferState;
337
338 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
339 copy_conv_rgba_pixels(ctx, srcx, srcy, width, height, destx, desty);
340 return;
341 }
342
343 /* Determine if copy should be done bottom-to-top or top-to-bottom */
344 if (srcy < desty) {
345 /* top-down max-to-min */
346 sy = srcy + height - 1;
347 dy = desty + height - 1;
348 stepy = -1;
349 }
350 else {
351 /* bottom-up min-to-max */
352 sy = srcy;
353 dy = desty;
354 stepy = 1;
355 }
356
357 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
358 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
359
360 if (ctx->Depth.Test || ctx->Fog.Enabled) {
361 /* fill in array of z values */
362 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax);
363 GLfloat fog;
364
365 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
366 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
367 else
368 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
369
370 for (i=0;i<width;i++) {
371 zspan[i] = z;
372 fogSpan[i] = fog;
373 }
374 }
375
376 if (SWRAST_CONTEXT(ctx)->_RasterMask == 0
377 && !zoom
378 && destx >= 0
379 && destx + width <= ctx->DrawBuffer->Width) {
380 quick_draw = GL_TRUE;
381 }
382 else {
383 quick_draw = GL_FALSE;
384 }
385
386 /* If read and draw buffer are different we must do buffer switching */
387 saveReadAlpha = ctx->ReadBuffer->Alpha;
388 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
389 || ctx->DrawBuffer != ctx->ReadBuffer;
390
391 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
392 ctx->Pixel.DriverReadBuffer );
393
394 if (overlapping) {
395 GLint ssy = sy;
396 tmpImage = (GLchan *) MALLOC(width * height * sizeof(GLchan) * 4);
397 if (!tmpImage) {
398 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
399 return;
400 }
401 p = tmpImage;
402 if (changeBuffer) {
403 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
404 ctx->Pixel.DriverReadBuffer );
405 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
406 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
407 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
408 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
409 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
410 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
411 else
412 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
413 }
414 for (j = 0; j < height; j++, ssy += stepy) {
415 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy,
416 (GLchan (*)[4]) p );
417 p += (width * sizeof(GLchan) * 4);
418 }
419 p = tmpImage;
420 }
421 else {
422 tmpImage = NULL; /* silence compiler warnings */
423 p = NULL;
424 }
425
426 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
427 /* Get source pixels */
428 if (overlapping) {
429 /* get from buffered image */
430 MEMCPY(rgba, p, width * sizeof(GLchan) * 4);
431 p += (width * sizeof(GLchan) * 4);
432 }
433 else {
434 /* get from framebuffer */
435 if (changeBuffer) {
436 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
437 ctx->Pixel.DriverReadBuffer );
438 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) {
439 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
440 }
441 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) {
442 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
443 }
444 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) {
445 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
446 }
447 else {
448 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
449 }
450 }
451 _mesa_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, rgba );
452 }
453
454 if (changeBuffer) {
455 /* read from the draw buffer again (in case of blending) */
456 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
457 ctx->Color.DriverDrawBuffer );
458 ctx->ReadBuffer->Alpha = saveReadAlpha;
459 }
460
461 if (transferOps) {
462 const GLfloat scale = (1.0F / CHAN_MAXF);
463 GLint k;
464 DEFMARRAY(GLfloat, rgbaFloat, MAX_WIDTH, 4); /* mac 32k limitation */
465 CHECKARRAY(rgbaFloat, return);
466
467 /* convert chan to float */
468 for (k = 0; k < width; k++) {
469 rgbaFloat[k][RCOMP] = (GLfloat) rgba[k][RCOMP] * scale;
470 rgbaFloat[k][GCOMP] = (GLfloat) rgba[k][GCOMP] * scale;
471 rgbaFloat[k][BCOMP] = (GLfloat) rgba[k][BCOMP] * scale;
472 rgbaFloat[k][ACOMP] = (GLfloat) rgba[k][ACOMP] * scale;
473 }
474 /* scale & bias */
475 if (transferOps & IMAGE_SCALE_BIAS_BIT) {
476 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat,
477 ctx->Pixel.RedScale, ctx->Pixel.GreenScale,
478 ctx->Pixel.BlueScale, ctx->Pixel.AlphaScale,
479 ctx->Pixel.RedBias, ctx->Pixel.GreenBias,
480 ctx->Pixel.BlueBias, ctx->Pixel.AlphaBias);
481 }
482 /* color map lookup */
483 if (transferOps & IMAGE_MAP_COLOR_BIT) {
484 _mesa_map_rgba(ctx, width, rgbaFloat);
485 }
486 /* GL_COLOR_TABLE lookup */
487 if (transferOps & IMAGE_COLOR_TABLE_BIT) {
488 _mesa_lookup_rgba(&ctx->ColorTable, width, rgbaFloat);
489 }
490 /* convolution */
491 if (transferOps & IMAGE_CONVOLUTION_BIT) {
492 /* XXX to do */
493 }
494 /* GL_POST_CONVOLUTION_RED/GREEN/BLUE/ALPHA_SCALE/BIAS */
495 if (transferOps & IMAGE_POST_CONVOLUTION_SCALE_BIAS) {
496 _mesa_scale_and_bias_rgba(ctx, width, rgbaFloat,
497 ctx->Pixel.PostConvolutionScale[RCOMP],
498 ctx->Pixel.PostConvolutionScale[GCOMP],
499 ctx->Pixel.PostConvolutionScale[BCOMP],
500 ctx->Pixel.PostConvolutionScale[ACOMP],
501 ctx->Pixel.PostConvolutionBias[RCOMP],
502 ctx->Pixel.PostConvolutionBias[GCOMP],
503 ctx->Pixel.PostConvolutionBias[BCOMP],
504 ctx->Pixel.PostConvolutionBias[ACOMP]);
505 }
506 /* GL_POST_CONVOLUTION_COLOR_TABLE lookup */
507 if (transferOps & IMAGE_POST_CONVOLUTION_COLOR_TABLE_BIT) {
508 _mesa_lookup_rgba(&ctx->PostConvolutionColorTable, width, rgbaFloat);
509 }
510 /* color matrix */
511 if (transferOps & IMAGE_COLOR_MATRIX_BIT) {
512 _mesa_transform_rgba(ctx, width, rgbaFloat);
513 }
514 /* GL_POST_COLOR_MATRIX_COLOR_TABLE lookup */
515 if (transferOps & IMAGE_POST_COLOR_MATRIX_COLOR_TABLE_BIT) {
516 _mesa_lookup_rgba(&ctx->PostColorMatrixColorTable, width, rgbaFloat);
517 }
518 /* update histogram count */
519 if (transferOps & IMAGE_HISTOGRAM_BIT) {
520 _mesa_update_histogram(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
521 }
522 /* update min/max */
523 if (transferOps & IMAGE_MIN_MAX_BIT) {
524 _mesa_update_minmax(ctx, width, (CONST GLfloat (*)[4]) rgbaFloat);
525 }
526 /* clamp to [0,1] and convert float back to chan */
527 for (k = 0; k < width; k++) {
528 GLint r = (GLint) (rgbaFloat[k][RCOMP] * CHAN_MAXF);
529 GLint g = (GLint) (rgbaFloat[k][GCOMP] * CHAN_MAXF);
530 GLint b = (GLint) (rgbaFloat[k][BCOMP] * CHAN_MAXF);
531 GLint a = (GLint) (rgbaFloat[k][ACOMP] * CHAN_MAXF);
532 rgba[k][RCOMP] = (GLchan) CLAMP(r, 0, CHAN_MAX);
533 rgba[k][GCOMP] = (GLchan) CLAMP(g, 0, CHAN_MAX);
534 rgba[k][BCOMP] = (GLchan) CLAMP(b, 0, CHAN_MAX);
535 rgba[k][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
536 }
537 UNDEFARRAY(rgbaFloat); /* mac 32k limitation */
538 }
539
540 if (ctx->Texture._ReallyEnabled && ctx->Pixel.PixelTextureEnabled) {
541 GLuint unit;
542 GLchan primary_rgba[MAX_WIDTH][4];
543 GLfloat texcoord[MAX_WIDTH][3];
544 DEFARRAY(GLfloat, s, MAX_WIDTH); /* mac 32k limitation */
545 DEFARRAY(GLfloat, t, MAX_WIDTH); /* mac 32k limitation */
546 DEFARRAY(GLfloat, r, MAX_WIDTH); /* mac 32k limitation */
547 DEFARRAY(GLfloat, q, MAX_WIDTH); /* mac 32k limitation */
548 CHECKARRAY(s, return); /* mac 32k limitation */
549 CHECKARRAY(t, return);
550 CHECKARRAY(r, return);
551 CHECKARRAY(q, return);
552
553 /* XXX not sure how multitexture is supposed to work here */
554 MEMCPY(primary_rgba, rgba, 4 * width * sizeof(GLchan));
555
556 for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
557 _mesa_pixeltexgen(ctx, width, (const GLchan (*)[4]) rgba,
558 s, t, r, q);
559 /* this is an ugly work-around. s,t,r has to be copied to
560 texcoords, because the functions need different
561 input. */
562 for (i=0; i<width; i++) {
563 texcoord[i][0] = s[i],
564 texcoord[i][1] = t[i],
565 texcoord[i][2] = r[i];
566 }
567 _old_swrast_texture_fragments( ctx, unit, width, texcoord, NULL,
568 (CONST GLchan (*)[4]) primary_rgba,
569 rgba);
570 }
571
572 UNDEFARRAY(s); /* mac 32k limitation */
573 UNDEFARRAY(t);
574 UNDEFARRAY(r);
575 UNDEFARRAY(q);
576 }
577
578 if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
579 (*swrast->Driver.WriteRGBASpan)( ctx, width, destx, dy,
580 (const GLchan (*)[4])rgba, NULL );
581 }
582 else if (zoom) {
583 _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan, fogSpan,
584 (const GLchan (*)[4])rgba, desty);
585 }
586 else {
587 _old_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan, rgba,
588 NULL, GL_BITMAP );
589 }
590 }
591
592 /* Restore pixel source to be the draw buffer (for blending, etc) */
593 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
594 ctx->Color.DriverDrawBuffer );
595
596 if (overlapping)
597 FREE(tmpImage);
598 }
599
600
601 static void copy_ci_pixels( GLcontext *ctx,
602 GLint srcx, GLint srcy, GLint width, GLint height,
603 GLint destx, GLint desty )
604 {
605 SWcontext *swrast = SWRAST_CONTEXT(ctx);
606 GLdepth zspan[MAX_WIDTH];
607 GLfloat fogSpan[MAX_WIDTH];
608 GLuint *tmpImage,*p;
609 GLint sy, dy, stepy;
610 GLint i, j;
611 GLboolean changeBuffer;
612 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
613 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
614 GLint overlapping;
615
616 /* Determine if copy should be bottom-to-top or top-to-bottom */
617 if (srcy<desty) {
618 /* top-down max-to-min */
619 sy = srcy + height - 1;
620 dy = desty + height - 1;
621 stepy = -1;
622 }
623 else {
624 /* bottom-up min-to-max */
625 sy = srcy;
626 dy = desty;
627 stepy = 1;
628 }
629
630 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
631 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
632
633 if (ctx->Depth.Test || ctx->Fog.Enabled) {
634 /* fill in array of z values */
635 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->DepthMax);
636 GLfloat fog;
637
638 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
639 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
640 else
641 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
642
643 for (i=0;i<width;i++) {
644 zspan[i] = z;
645 fogSpan[i] = fog;
646 }
647 }
648
649 /* If read and draw buffer are different we must do buffer switching */
650 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
651 || ctx->DrawBuffer != ctx->ReadBuffer;
652
653 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
654 ctx->Pixel.DriverReadBuffer );
655
656 if (overlapping) {
657 GLint ssy = sy;
658 tmpImage = (GLuint *) MALLOC(width * height * sizeof(GLuint));
659 if (!tmpImage) {
660 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
661 return;
662 }
663 p = tmpImage;
664 if (changeBuffer) {
665 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
666 ctx->Pixel.DriverReadBuffer );
667 }
668 for (j = 0; j < height; j++, ssy += stepy) {
669 _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p );
670 p += width;
671 }
672 p = tmpImage;
673 }
674 else {
675 tmpImage = NULL; /* silence compiler warning */
676 p = NULL;
677 }
678
679 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
680 GLuint indexes[MAX_WIDTH];
681 if (overlapping) {
682 MEMCPY(indexes, p, width * sizeof(GLuint));
683 p += width;
684 }
685 else {
686 if (changeBuffer) {
687 (*swrast->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
688 ctx->Pixel.DriverReadBuffer );
689 }
690 _mesa_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, indexes );
691 }
692
693 if (changeBuffer) {
694 /* set read buffer back to draw buffer (in case of logicops) */
695 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
696 ctx->Color.DriverDrawBuffer );
697 }
698
699 if (shift_or_offset) {
700 _mesa_shift_and_offset_ci( ctx, width, indexes );
701 }
702 if (ctx->Pixel.MapColorFlag) {
703 _mesa_map_ci( ctx, width, indexes );
704 }
705
706 if (zoom) {
707 _mesa_write_zoomed_index_span(ctx, width, destx, dy, zspan, fogSpan,
708 indexes, desty );
709 }
710 else {
711 _old_write_index_span(ctx, width, destx, dy, zspan, fogSpan, indexes,
712 NULL, GL_BITMAP);
713 }
714 }
715
716 /* Restore pixel source to be the draw buffer (for blending, etc) */
717 (*swrast->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
718 ctx->Color.DriverDrawBuffer );
719
720 if (overlapping)
721 FREE(tmpImage);
722 }
723
724
725
726 /*
727 * TODO: Optimize!!!!
728 */
729 static void copy_depth_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
730 GLint width, GLint height,
731 GLint destx, GLint desty )
732 {
733 GLfloat depth[MAX_WIDTH];
734 GLdepth zspan[MAX_WIDTH];
735 GLfloat fogSpan[MAX_WIDTH];
736 GLfloat *p, *tmpImage;
737 GLuint indexes[MAX_WIDTH];
738 GLint sy, dy, stepy;
739 GLint i, j;
740 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
741 GLint overlapping;
742 DEFMARRAY(GLchan, rgba, MAX_WIDTH, 4); /* mac 32k limitation */
743 CHECKARRAY(rgba, return); /* mac 32k limitation */
744
745 if (!ctx->Visual.depthBits) {
746 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
747 UNDEFARRAY(rgba); /* mac 32k limitation */
748 return;
749 }
750
751 /* Determine if copy should be bottom-to-top or top-to-bottom */
752 if (srcy<desty) {
753 /* top-down max-to-min */
754 sy = srcy + height - 1;
755 dy = desty + height - 1;
756 stepy = -1;
757 }
758 else {
759 /* bottom-up min-to-max */
760 sy = srcy;
761 dy = desty;
762 stepy = 1;
763 }
764
765 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
766 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
767
768 /* setup colors or indexes */
769 if (ctx->Visual.rgbMode) {
770 GLchan r, g, b, a;
771 UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0]);
772 UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1]);
773 UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2]);
774 UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]);
775 for (i = 0; i < width; i++) {
776 rgba[i][RCOMP] = r;
777 rgba[i][GCOMP] = g;
778 rgba[i][BCOMP] = b;
779 rgba[i][ACOMP] = a;
780 }
781 }
782 else {
783 for (i = 0; i < width; i++) {
784 indexes[i] = ctx->Current.Index;
785 }
786 }
787
788 if (ctx->Fog.Enabled) {
789 GLfloat fog;
790
791 if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
792 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterFogCoord);
793 else
794 fog = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
795
796 for (i = 0; i < width; i++) {
797 fogSpan[i] = fog;
798 }
799 }
800
801 if (overlapping) {
802 GLint ssy = sy;
803 tmpImage = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
804 if (!tmpImage) {
805 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
806 UNDEFARRAY(rgba); /* mac 32k limitation */
807 return;
808 }
809 p = tmpImage;
810 for (j = 0; j < height; j++, ssy += stepy) {
811 _mesa_read_depth_span_float(ctx, width, srcx, ssy, p);
812 p += width;
813 }
814 p = tmpImage;
815 }
816 else {
817 tmpImage = NULL; /* silence compiler warning */
818 p = NULL;
819 }
820
821 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
822 if (overlapping) {
823 MEMCPY(depth, p, width * sizeof(GLfloat));
824 p += width;
825 }
826 else {
827 _mesa_read_depth_span_float(ctx, width, srcx, sy, depth);
828 }
829
830 for (i = 0; i < width; i++) {
831 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
832 zspan[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->DepthMax);
833 }
834
835 if (ctx->Visual.rgbMode) {
836 if (zoom) {
837 _mesa_write_zoomed_rgba_span( ctx, width, destx, dy, zspan,
838 fogSpan, (const GLchan (*)[4])rgba, desty );
839 }
840 else {
841 _old_write_rgba_span( ctx, width, destx, dy, zspan, fogSpan,
842 (GLchan (*)[4])rgba, NULL, GL_BITMAP);
843 }
844 }
845 else {
846 if (zoom) {
847 _mesa_write_zoomed_index_span( ctx, width, destx, dy,
848 zspan, fogSpan, indexes, desty );
849 }
850 else {
851 _old_write_index_span( ctx, width, destx, dy,
852 zspan, fogSpan, indexes, NULL, GL_BITMAP );
853 }
854 }
855 }
856
857 UNDEFARRAY(rgba); /* mac 32k limitation */
858
859 if (overlapping)
860 FREE(tmpImage);
861 }
862
863
864
865 static void copy_stencil_pixels( GLcontext *ctx, GLint srcx, GLint srcy,
866 GLint width, GLint height,
867 GLint destx, GLint desty )
868 {
869 GLint sy, dy, stepy;
870 GLint j;
871 GLstencil *p, *tmpImage;
872 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
873 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
874 GLint overlapping;
875
876 if (!ctx->Visual.stencilBits) {
877 _mesa_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
878 return;
879 }
880
881 /* Determine if copy should be bottom-to-top or top-to-bottom */
882 if (srcy < desty) {
883 /* top-down max-to-min */
884 sy = srcy + height - 1;
885 dy = desty + height - 1;
886 stepy = -1;
887 }
888 else {
889 /* bottom-up min-to-max */
890 sy = srcy;
891 dy = desty;
892 stepy = 1;
893 }
894
895 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
896 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
897
898 if (overlapping) {
899 GLint ssy = sy;
900 tmpImage = (GLstencil *) MALLOC(width * height * sizeof(GLstencil));
901 if (!tmpImage) {
902 _mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
903 return;
904 }
905 p = tmpImage;
906 for (j = 0; j < height; j++, ssy += stepy) {
907 _mesa_read_stencil_span( ctx, width, srcx, ssy, p );
908 p += width;
909 }
910 p = tmpImage;
911 }
912 else {
913 tmpImage = NULL; /* silence compiler warning */
914 p = NULL;
915 }
916
917 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
918 GLstencil stencil[MAX_WIDTH];
919
920 if (overlapping) {
921 MEMCPY(stencil, p, width * sizeof(GLstencil));
922 p += width;
923 }
924 else {
925 _mesa_read_stencil_span( ctx, width, srcx, sy, stencil );
926 }
927
928 if (shift_or_offset) {
929 _mesa_shift_and_offset_stencil( ctx, width, stencil );
930 }
931 if (ctx->Pixel.MapStencilFlag) {
932 _mesa_map_stencil( ctx, width, stencil );
933 }
934
935 if (zoom) {
936 _mesa_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty );
937 }
938 else {
939 _mesa_write_stencil_span( ctx, width, destx, dy, stencil );
940 }
941 }
942
943 if (overlapping)
944 FREE(tmpImage);
945 }
946
947
948
949
950 void
951 _swrast_CopyPixels( GLcontext *ctx,
952 GLint srcx, GLint srcy, GLsizei width, GLsizei height,
953 GLint destx, GLint desty,
954 GLenum type )
955 {
956 SWcontext *swrast = SWRAST_CONTEXT(ctx);
957 RENDER_START(swrast,ctx);
958
959 if (swrast->NewState)
960 _swrast_validate_derived( ctx );
961
962 if (type == GL_COLOR && ctx->Visual.rgbMode) {
963 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
964 }
965 else if (type == GL_COLOR && !ctx->Visual.rgbMode) {
966 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
967 }
968 else if (type == GL_DEPTH) {
969 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
970 }
971 else if (type == GL_STENCIL) {
972 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
973 }
974 else {
975 _mesa_error( ctx, GL_INVALID_ENUM, "glCopyPixels" );
976 }
977
978 RENDER_FINISH(swrast,ctx);
979 }