source: trunk/src/opengl/mesa/copypix.c@ 3721

Last change on this file since 3721 was 3598, checked in by jeroen, 25 years ago

* empty log message *

File size: 17.2 KB
Line 
1/* $Id: copypix.c,v 1.3 2000-05-23 20:40:26 jeroen Exp $ */
2
3/*
4 * Mesa 3-D graphics library
5 * Version: 3.3
6 *
7 * Copyright (C) 1999 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
29
30
31#ifdef PC_HEADER
32#include "all.h"
33#else
34#include "glheader.h"
35#include "types.h"
36#include "mem.h"
37#include "context.h"
38#include "copypix.h"
39#include "depth.h"
40#include "feedback.h"
41#include "macros.h"
42#include "mmath.h"
43#include "pixel.h"
44#include "span.h"
45#include "state.h"
46#include "stencil.h"
47#include "zoom.h"
48#endif
49#ifdef __WIN32OS2__
50#include <malloc.h>
51#endif
52
53/*
54 * Determine if there's overlap in an image copy
55 */
56static GLboolean
57regions_overlap(int srcx, int srcy, int dstx, int dsty, int width, int height,
58 float zoomX, float zoomY)
59{
60 if ((srcx > dstx + (width * zoomX) + 1) || (srcx + width + 1 < dstx)) {
61 return GL_FALSE;
62 }
63 else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
64 return GL_FALSE;
65 }
66 else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
67 return GL_FALSE;
68 }
69 else {
70 return GL_TRUE;
71 }
72}
73
74
75
76static void copy_rgba_pixels( GLcontext* ctx,
77 GLint srcx, GLint srcy,
78 GLint width, GLint height,
79 GLint destx, GLint desty )
80{
81 GLdepth zspan[MAX_WIDTH];
82 GLubyte rgba[MAX_WIDTH][4];
83 GLubyte *prgba,*p;
84 GLboolean quick_draw;
85 GLint sy, dy, stepy;
86 GLint i, j;
87 GLboolean changeBuffer;
88 GLubyte *saveReadAlpha;
89 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
90 GLint overlapping;
91
92 /* Determine if copy should be done bottom-to-top or top-to-bottom */
93 if (srcy < desty) {
94 /* top-down max-to-min */
95 sy = srcy + height - 1;
96 dy = desty + height - 1;
97 stepy = -1;
98 }
99 else {
100 /* bottom-up min-to-max */
101 sy = srcy;
102 dy = desty;
103 stepy = 1;
104 }
105
106 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
107 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
108
109 if (ctx->Depth.Test || ctx->Fog.Enabled) {
110 /* fill in array of z values */
111 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMax);
112 for (i=0;i<width;i++) {
113 zspan[i] = z;
114 }
115 }
116
117 if (ctx->RasterMask == 0
118 && !zoom
119 && destx >= 0
120 && destx + width <= ctx->DrawBuffer->Width) {
121 quick_draw = GL_TRUE;
122 }
123 else {
124 quick_draw = GL_FALSE;
125 }
126
127 /* If read and draw buffer are different we must do buffer switching */
128 saveReadAlpha = ctx->ReadBuffer->Alpha;
129 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
130 || ctx->DrawBuffer != ctx->ReadBuffer;
131
132 if (overlapping) {
133 GLint ssy = sy;
134 prgba = (GLubyte *) MALLOC(width * height * sizeof(GLubyte) * 4);
135 if (!prgba) {
136 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
137 return;
138 }
139 p = prgba;
140 if (changeBuffer) {
141 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
142 ctx->Pixel.DriverReadBuffer );
143 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT)
144 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
145 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT)
146 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
147 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT)
148 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
149 else
150 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
151 }
152 for (j = 0; j < height; j++, ssy += stepy) {
153 gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, ssy,
154 (GLubyte (*)[4]) p );
155 p += (width * sizeof(GLubyte) * 4);
156 }
157 p = prgba;
158 }
159 else {
160 prgba = NULL; /* silence compiler warnings*/
161 p = NULL;
162 }
163
164 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
165 if (overlapping) {
166 MEMCPY(rgba, p, width * sizeof(GLubyte) * 4);
167 p += (width * sizeof(GLubyte) * 4);
168 }
169 else {
170 if (changeBuffer) {
171 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
172 ctx->Pixel.DriverReadBuffer );
173 if (ctx->Pixel.DriverReadBuffer == GL_FRONT_LEFT) {
174 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontLeftAlpha;
175 }
176 else if (ctx->Pixel.DriverReadBuffer == GL_BACK_LEFT) {
177 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackLeftAlpha;
178 }
179 else if (ctx->Pixel.DriverReadBuffer == GL_FRONT_RIGHT) {
180 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->FrontRightAlpha;
181 }
182 else {
183 ctx->ReadBuffer->Alpha = ctx->ReadBuffer->BackRightAlpha;
184 }
185 }
186 gl_read_rgba_span( ctx, ctx->ReadBuffer, width, srcx, sy, rgba );
187 }
188
189 if (changeBuffer) {
190 /* read from the draw buffer again (in case of blending) */
191 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
192 ctx->Color.DriverDrawBuffer );
193 ctx->ReadBuffer->Alpha = saveReadAlpha;
194 }
195
196 if (ctx->Pixel.ScaleOrBiasRGBA) {
197 gl_scale_and_bias_rgba( ctx, width, rgba );
198 }
199 if (ctx->Pixel.MapColorFlag) {
200 gl_map_rgba( ctx, width, rgba );
201 }
202 if (quick_draw && dy >= 0 && dy < ctx->DrawBuffer->Height) {
203 (*ctx->Driver.WriteRGBASpan)( ctx, width, destx, dy,
204 (const GLubyte (*)[4])rgba, NULL );
205 }
206 else if (zoom) {
207 gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan,
208 (const GLubyte (*)[4])rgba, desty);
209 }
210 else {
211 gl_write_rgba_span( ctx, width, destx, dy, zspan, rgba, GL_BITMAP );
212 }
213 }
214
215 if (overlapping)
216 FREE(prgba);
217}
218
219
220static void copy_ci_pixels( GLcontext* ctx,
221 GLint srcx, GLint srcy, GLint width, GLint height,
222 GLint destx, GLint desty )
223{
224 GLdepth zspan[MAX_WIDTH];
225 GLuint *pci,*p;
226 GLint sy, dy, stepy;
227 GLint i, j;
228 GLboolean changeBuffer;
229 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
230 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
231 GLint overlapping;
232
233 /* Determine if copy should be bottom-to-top or top-to-bottom */
234 if (srcy<desty) {
235 /* top-down max-to-min */
236 sy = srcy + height - 1;
237 dy = desty + height - 1;
238 stepy = -1;
239 }
240 else {
241 /* bottom-up min-to-max */
242 sy = srcy;
243 dy = desty;
244 stepy = 1;
245 }
246
247 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
248 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
249
250 if (ctx->Depth.Test || ctx->Fog.Enabled) {
251 /* fill in array of z values */
252 GLdepth z = (GLdepth) (ctx->Current.RasterPos[2] * ctx->Visual->DepthMax);
253 for (i=0;i<width;i++) {
254 zspan[i] = z;
255 }
256 }
257
258 /* If read and draw buffer are different we must do buffer switching */
259 changeBuffer = ctx->Pixel.ReadBuffer != ctx->Color.DrawBuffer
260 || ctx->DrawBuffer != ctx->ReadBuffer;
261
262 if (overlapping) {
263 GLint ssy = sy;
264 pci = (GLuint *) MALLOC(width * height * sizeof(GLuint));
265 if (!pci) {
266 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
267 return;
268 }
269 p = pci;
270 if (changeBuffer) {
271 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
272 ctx->Pixel.DriverReadBuffer );
273 }
274 for (j = 0; j < height; j++, ssy += stepy) {
275 gl_read_index_span( ctx, ctx->ReadBuffer, width, srcx, ssy, p );
276 p += width;
277 }
278 p = pci;
279 }
280 else {
281 pci = NULL; /* silence compiler warning*/
282 p = NULL;
283 }
284
285 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
286 GLuint indexes[MAX_WIDTH];
287 if (overlapping) {
288 MEMCPY(indexes, p, width * sizeof(GLuint));
289 p += width;
290 }
291 else {
292 if (changeBuffer) {
293 (*ctx->Driver.SetReadBuffer)( ctx, ctx->ReadBuffer,
294 ctx->Pixel.DriverReadBuffer );
295 }
296 gl_read_index_span( ctx, ctx->ReadBuffer, width, srcx, sy, indexes );
297 }
298
299 if (changeBuffer) {
300 /* set read buffer back to draw buffer (in case of logicops) */
301 (*ctx->Driver.SetReadBuffer)( ctx, ctx->DrawBuffer,
302 ctx->Color.DriverDrawBuffer );
303 }
304
305 if (shift_or_offset) {
306 gl_shift_and_offset_ci( ctx, width, indexes );
307 }
308 if (ctx->Pixel.MapColorFlag) {
309 gl_map_ci( ctx, width, indexes );
310 }
311
312 if (zoom) {
313 gl_write_zoomed_index_span( ctx, width, destx, dy, zspan, indexes, desty );
314 }
315 else {
316 gl_write_index_span(ctx, width, destx, dy, zspan, indexes, GL_BITMAP);
317 }
318 }
319
320 if (overlapping)
321 FREE(pci);
322}
323
324
325
326/*
327 * TODO: Optimize!!!!
328 */
329static void copy_depth_pixels( GLcontext* ctx, GLint srcx, GLint srcy,
330 GLint width, GLint height,
331 GLint destx, GLint desty )
332{
333 GLfloat depth[MAX_WIDTH];
334 GLdepth zspan[MAX_WIDTH];
335 GLfloat *p,*pdepth;
336 GLuint indexes[MAX_WIDTH];
337 GLubyte rgba[MAX_WIDTH][4];
338 GLint sy, dy, stepy;
339 GLint i, j;
340 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
341 GLint overlapping;
342
343 if (!ctx->ReadBuffer->DepthBuffer || !ctx->DrawBuffer->DepthBuffer) {
344 gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
345 return;
346 }
347
348 /* Determine if copy should be bottom-to-top or top-to-bottom */
349 if (srcy<desty) {
350 /* top-down max-to-min */
351 sy = srcy + height - 1;
352 dy = desty + height - 1;
353 stepy = -1;
354 }
355 else {
356 /* bottom-up min-to-max */
357 sy = srcy;
358 dy = desty;
359 stepy = 1;
360 }
361
362 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
363 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
364
365 /* setup colors or indexes */
366 if (ctx->Visual->RGBAflag) {
367 GLuint *rgba32 = (GLuint *) rgba;
368 GLuint color = *(GLuint*)( ctx->Current.ByteColor );
369 for (i = 0; i < width; i++) {
370 rgba32[i] = color;
371 }
372 }
373 else {
374 for (i = 0; i < width; i++) {
375 indexes[i] = ctx->Current.Index;
376 }
377 }
378
379 if (overlapping) {
380 GLint ssy = sy;
381 pdepth = (GLfloat *) MALLOC(width * height * sizeof(GLfloat));
382 if (!pdepth) {
383 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
384 return;
385 }
386 p = pdepth;
387 for (j = 0; j < height; j++, ssy += stepy) {
388 _mesa_read_depth_span_float(ctx, width, srcx, ssy, p);
389 p += width;
390 }
391 p = pdepth;
392 }
393 else {
394 pdepth = NULL; /* silence compiler warning*/
395 p = NULL;
396 }
397
398 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
399 if (overlapping) {
400 MEMCPY(depth, p, width * sizeof(GLfloat));
401 p += width;
402 }
403 else {
404 _mesa_read_depth_span_float(ctx, width, srcx, sy, depth);
405 }
406
407 for (i = 0; i < width; i++) {
408 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
409 zspan[i] = (GLdepth) (CLAMP(d, 0.0F, 1.0F) * ctx->Visual->DepthMax);
410 }
411
412 if (ctx->Visual->RGBAflag) {
413 if (zoom) {
414 gl_write_zoomed_rgba_span( ctx, width, destx, dy, zspan,
415 (const GLubyte (*)[4])rgba, desty );
416 }
417 else {
418 gl_write_rgba_span( ctx, width, destx, dy, zspan, rgba, GL_BITMAP);
419 }
420 }
421 else {
422 if (zoom) {
423 gl_write_zoomed_index_span( ctx, width, destx, dy,
424 zspan, indexes, desty );
425 }
426 else {
427 gl_write_index_span( ctx, width, destx, dy,
428 zspan, indexes, GL_BITMAP );
429 }
430 }
431 }
432
433 if (overlapping)
434 FREE(pdepth);
435}
436
437
438
439static void copy_stencil_pixels( GLcontext* ctx, GLint srcx, GLint srcy,
440 GLint width, GLint height,
441 GLint destx, GLint desty )
442{
443 GLint sy, dy, stepy;
444 GLint j;
445 GLstencil *p, *psten;
446 const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
447 const GLboolean shift_or_offset = ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset;
448 GLint overlapping;
449
450 if (!ctx->DrawBuffer->Stencil || !ctx->ReadBuffer->Stencil) {
451 gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" );
452 return;
453 }
454
455 /* Determine if copy should be bottom-to-top or top-to-bottom */
456 if (srcy < desty) {
457 /* top-down max-to-min */
458 sy = srcy + height - 1;
459 dy = desty + height - 1;
460 stepy = -1;
461 }
462 else {
463 /* bottom-up min-to-max */
464 sy = srcy;
465 dy = desty;
466 stepy = 1;
467 }
468
469 overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
470 ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
471
472 if (overlapping) {
473 GLint ssy = sy;
474 psten = (GLstencil *) MALLOC(width * height * sizeof(GLstencil));
475 if (!psten) {
476 gl_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
477 return;
478 }
479 p = psten;
480 for (j = 0; j < height; j++, ssy += stepy) {
481 gl_read_stencil_span( ctx, width, srcx, ssy, p );
482 p += width;
483 }
484 p = psten;
485 }
486 else {
487 psten = NULL; /* silence compiler warning*/
488 p = NULL;
489 }
490
491 for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
492 GLstencil stencil[MAX_WIDTH];
493
494 if (overlapping) {
495 MEMCPY(stencil, p, width * sizeof(GLstencil));
496 p += width;
497 }
498 else {
499 gl_read_stencil_span( ctx, width, srcx, sy, stencil );
500 }
501
502 if (shift_or_offset) {
503 gl_shift_and_offset_stencil( ctx, width, stencil );
504 }
505 if (ctx->Pixel.MapStencilFlag) {
506 gl_map_stencil( ctx, width, stencil );
507 }
508
509 if (zoom) {
510 gl_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty );
511 }
512 else {
513 gl_write_stencil_span( ctx, width, destx, dy, stencil );
514 }
515 }
516
517 if (overlapping)
518 FREE(psten);
519}
520
521
522
523
524void
525_mesa_CopyPixels( GLint srcx, GLint srcy, GLsizei width, GLsizei height,
526 GLenum type )
527{
528 GET_CURRENT_CONTEXT(ctx);
529 GLint destx, desty;
530
531 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glCopyPixels");
532
533 if (width < 0 || height < 0) {
534 gl_error( ctx, GL_INVALID_VALUE, "glCopyPixels" );
535 return;
536 }
537
538 if (ctx->NewState) {
539 gl_update_state(ctx);
540 }
541
542 if (ctx->RenderMode==GL_RENDER) {
543 /* Destination of copy: */
544 if (!ctx->Current.RasterPosValid) {
545 return;
546 }
547 destx = (GLint) (ctx->Current.RasterPos[0] + 0.5F);
548 desty = (GLint) (ctx->Current.RasterPos[1] + 0.5F);
549
550 if (ctx->Driver.CopyPixels &&
551 (*ctx->Driver.CopyPixels)( ctx, srcx, srcy, width, height,
552 destx, desty, type )) {
553 return;
554 }
555
556 if (type == GL_COLOR && ctx->Visual->RGBAflag) {
557 copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
558 }
559 else if (type == GL_COLOR && !ctx->Visual->RGBAflag) {
560 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty );
561 }
562 else if (type == GL_DEPTH) {
563 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
564 }
565 else if (type == GL_STENCIL) {
566 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
567 }
568 else {
569 gl_error( ctx, GL_INVALID_ENUM, "glCopyPixels" );
570 }
571 }
572 else if (ctx->RenderMode == GL_FEEDBACK) {
573 GLfloat color[4];
574 UBYTE_RGBA_TO_FLOAT_RGBA(color, ctx->Current.ByteColor );
575 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN );
576 gl_feedback_vertex( ctx, ctx->Current.RasterPos,
577 color, ctx->Current.Index,
578 ctx->Current.Texcoord[0] );
579 }
580 else if (ctx->RenderMode == GL_SELECT) {
581 gl_update_hitflag( ctx, ctx->Current.RasterPos[2] );
582 }
583
584}
Note: See TracBrowser for help on using the repository browser.