1 /* $Id: copypix.c,v 1.7 1998/02/03 23:45:02 brianp Exp $ */ 2 3 /* 4 * Mesa 3-D graphics library 5 * Version: 2.4 6 * Copyright (C) 1995-1996 Brian Paul 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public 19 * License along with this library; if not, write to the Free 20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23 24 /* 25 * $Log: copypix.c,v $ 26 * Revision 1.7 1998/02/03 23:45:02 brianp 27 * added casts to prevent warnings with Amiga StormC compiler 28 * 29 * Revision 1.6 1997/07/24 01:24:45 brianp 30 * changed precompiled header symbol from PCH to PC_HEADER 31 * 32 * Revision 1.5 1997/06/20 02:20:04 brianp 33 * replaced Current.IntColor with Current.ByteColor 34 * 35 * Revision 1.4 1997/05/28 03:23:48 brianp 36 * added precompiled header (PCH) support 37 * 38 * Revision 1.3 1996/09/15 14:18:10 brianp 39 * now use GLframebuffer and GLvisual 40 * 41 * Revision 1.2 1996/09/15 01:48:58 brianp 42 * removed #define NULL 0 43 * 44 * Revision 1.1 1996/09/13 01:38:16 brianp 45 * Initial revision 46 * 47 */ 48 49 50 #ifdef PC_HEADER 51 #include "all.h" 52 #else 53 #include <string.h> 54 #include "context.h" 55 #include "copypix.h" 56 #include "depth.h" 57 #include "feedback.h" 58 #include "dlist.h" 59 #include "macros.h" 60 #include "pixel.h" 61 #include "span.h" 62 #include "stencil.h" 63 #include "types.h" 64 #endif 65 66 67 68 static void copy_rgb_pixels( GLcontext* ctx, 69 GLint srcx, GLint srcy, GLint width, GLint height, 70 GLint destx, GLint desty ) 71 { 72 DEFARRAY( GLdepth, zspan, MAX_WIDTH ); 73 DEFARRAY( GLubyte, red, MAX_WIDTH ); 74 DEFARRAY( GLubyte, green, MAX_WIDTH ); 75 DEFARRAY( GLubyte, blue, MAX_WIDTH ); 76 DEFARRAY( GLubyte, alpha, MAX_WIDTH ); 77 GLboolean scale_or_bias, quick_draw, zoom; 78 GLint sy, dy, stepy; 79 GLint i, j; 80 GLboolean setbuffer; 81 82 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 83 zoom = GL_FALSE; 84 } 85 else { 86 zoom = GL_TRUE; 87 } 88 89 /* Determine if copy should be done bottom-to-top or top-to-bottom */ 90 if (srcy<desty) { 91 /* top-down max-to-min */ 92 sy = srcy + height - 1; 93 dy = desty + height - 1; 94 stepy = -1; 95 } 96 else { 97 /* bottom-up min-to-max */ 98 sy = srcy; 99 dy = desty; 100 stepy = 1; 101 } 102 103 scale_or_bias = ctx->Pixel.RedScale!=1.0 || ctx->Pixel.RedBias!=0.0 104 || ctx->Pixel.GreenScale!=1.0 || ctx->Pixel.GreenBias!=0.0 105 || ctx->Pixel.BlueScale!=1.0 || ctx->Pixel.BlueBias!=0.0 106 || ctx->Pixel.AlphaScale!=1.0 || ctx->Pixel.AlphaBias!=0.0; 107 108 if (ctx->Depth.Test) { 109 /* fill in array of z values */ 110 GLint z = (GLint) (ctx->Current.RasterPos[2] * DEPTH_SCALE); 111 for (i=0;i<width;i++) { 112 zspan[i] = z; 113 } 114 } 115 116 if (ctx->RasterMask==0 && !zoom 117 && destx>=0 && destx+width<=ctx->Buffer->Width) { 118 quick_draw = GL_TRUE; 119 } 120 else { 121 quick_draw = GL_FALSE; 122 } 123 124 /* If read and draw buffer are different we must do buffer switching */ 125 setbuffer = ctx->Pixel.ReadBuffer!=ctx->Color.DrawBuffer; 126 127 for (j=0; j<height; j++, sy+=stepy, dy+=stepy) { 128 /* read */ 129 130 if (setbuffer) { 131 (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.ReadBuffer ); 132 } 133 gl_read_color_span( ctx, width, srcx, sy, red, green, blue, alpha ); 134 135 if (scale_or_bias) { 136 GLfloat rbias = ctx->Pixel.RedBias * ctx->Visual->RedScale; 137 GLfloat gbias = ctx->Pixel.GreenBias * ctx->Visual->GreenScale; 138 GLfloat bbias = ctx->Pixel.BlueBias * ctx->Visual->BlueScale; 139 GLfloat abias = ctx->Pixel.AlphaBias * ctx->Visual->AlphaScale; 140 GLint rmax = (GLint) ctx->Visual->RedScale; 141 GLint gmax = (GLint) ctx->Visual->GreenScale; 142 GLint bmax = (GLint) ctx->Visual->BlueScale; 143 GLint amax = (GLint) ctx->Visual->AlphaScale; 144 for (i=0;i<width;i++) { 145 GLint r = red[i] * ctx->Pixel.RedScale + rbias; 146 GLint g = green[i] * ctx->Pixel.GreenScale + gbias; 147 GLint b = blue[i] * ctx->Pixel.BlueScale + bbias; 148 GLint a = alpha[i] * ctx->Pixel.AlphaScale + abias; 149 red[i] = CLAMP( r, 0, rmax ); 150 green[i] = CLAMP( g, 0, gmax ); 151 blue[i] = CLAMP( b, 0, bmax ); 152 alpha[i] = CLAMP( a, 0, amax ); 153 } 154 } 155 156 if (ctx->Pixel.MapColorFlag) { 157 GLfloat r = (ctx->Pixel.MapRtoRsize-1) * ctx->Visual->InvRedScale; 158 GLfloat g = (ctx->Pixel.MapGtoGsize-1) * ctx->Visual->InvGreenScale; 159 GLfloat b = (ctx->Pixel.MapBtoBsize-1) * ctx->Visual->InvBlueScale; 160 GLfloat a = (ctx->Pixel.MapAtoAsize-1) * ctx->Visual->InvAlphaScale; 161 for (i=0;i<width;i++) { 162 GLint ir = red[i] * r; 163 GLint ig = green[i] * g; 164 GLint ib = blue[i] * b; 165 GLint ia = alpha[i] * a; 166 red[i] = (GLint) (ctx->Pixel.MapRtoR[ir]*ctx->Visual->RedScale); 167 green[i] = (GLint) (ctx->Pixel.MapGtoG[ig]*ctx->Visual->GreenScale); 168 blue[i] = (GLint) (ctx->Pixel.MapBtoB[ib]*ctx->Visual->BlueScale); 169 alpha[i] = (GLint) (ctx->Pixel.MapAtoA[ia]*ctx->Visual->AlphaScale); 170 } 171 } 172 173 /* write */ 174 if (setbuffer) { 175 (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DrawBuffer ); 176 } 177 if (quick_draw && dy>=0 && dy<ctx->Buffer->Height) { 178 (*ctx->Driver.WriteColorSpan)( ctx, width, destx, dy, 179 red, green, blue, alpha, NULL); 180 } 181 else if (zoom) { 182 gl_write_zoomed_color_span( ctx, width, destx, dy, zspan, 183 red, green, blue, alpha, desty ); 184 } 185 else { 186 gl_write_color_span( ctx, width, destx, dy, zspan, 187 red, green, blue, alpha, GL_BITMAP ); 188 } 189 } 190 UNDEFARRAY( zspan ); 191 UNDEFARRAY( red ); 192 UNDEFARRAY( green ); 193 UNDEFARRAY( blue ); 194 UNDEFARRAY( alpha ); 195 } 196 197 198 199 static void copy_ci_pixels( GLcontext* ctx, 200 GLint srcx, GLint srcy, GLint width, GLint height, 201 GLint destx, GLint desty ) 202 { 203 GLdepth zspan[MAX_WIDTH]; 204 GLuint indx[MAX_WIDTH]; 205 GLint sy, dy, stepy; 206 GLint i, j; 207 GLboolean setbuffer, zoom; 208 209 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 210 zoom = GL_FALSE; 211 } 212 else { 213 zoom = GL_TRUE; 214 } 215 216 /* Determine if copy should be bottom-to-top or top-to-bottom */ 217 if (srcy<desty) { 218 /* top-down max-to-min */ 219 sy = srcy + height - 1; 220 dy = desty + height - 1; 221 stepy = -1; 222 } 223 else { 224 /* bottom-up min-to-max */ 225 sy = srcy; 226 dy = desty; 227 stepy = 1; 228 } 229 230 if (ctx->Depth.Test) { 231 /* fill in array of z values */ 232 GLint z = (GLint) (ctx->Current.RasterPos[2] * DEPTH_SCALE); 233 for (i=0;i<width;i++) { 234 zspan[i] = z; 235 } 236 } 237 238 /* If read and draw buffer are different we must do buffer switching */ 239 setbuffer = ctx->Pixel.ReadBuffer!=ctx->Color.DrawBuffer; 240 241 for (j=0; j<height; j++, sy+=stepy, dy+=stepy) { 242 /* read */ 243 if (setbuffer) { 244 (*ctx->Driver.SetBuffer)( ctx, ctx->Pixel.ReadBuffer ); 245 } 246 gl_read_index_span( ctx, width, srcx, sy, indx ); 247 248 /* shift, offset */ 249 if (ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset) { 250 if (ctx->Pixel.IndexShift<0) { 251 for (i=0;i<width;i++) { 252 indx[i] = (indx[i] >> -ctx->Pixel.IndexShift) 253 + ctx->Pixel.IndexOffset; 254 } 255 } 256 else { 257 for (i=0;i<width;i++) { 258 indx[i] = (indx[i] << ctx->Pixel.IndexShift) 259 + ctx->Pixel.IndexOffset; 260 } 261 } 262 } 263 264 /* mapping */ 265 if (ctx->Pixel.MapColorFlag) { 266 for (i=0;i<width;i++) { 267 if (indx[i] < ctx->Pixel.MapItoIsize) { 268 indx[i] = ctx->Pixel.MapItoI[ indx[i] ]; 269 } 270 } 271 } 272 273 /* write */ 274 if (setbuffer) { 275 (*ctx->Driver.SetBuffer)( ctx, ctx->Color.DrawBuffer ); 276 } 277 if (zoom) { 278 gl_write_zoomed_index_span( ctx, width, destx, dy, zspan, indx, desty ); 279 } 280 else { 281 gl_write_index_span( ctx, width, destx, dy, zspan, indx, GL_BITMAP ); 282 } 283 } 284 } 285 286 287 288 /* 289 * TODO: Optimize!!!! 290 */ 291 static void copy_depth_pixels( GLcontext* ctx, GLint srcx, GLint srcy, 292 GLint width, GLint height, 293 GLint destx, GLint desty ) 294 { 295 GLfloat depth[MAX_WIDTH]; 296 GLdepth zspan[MAX_WIDTH]; 297 GLuint indx[MAX_WIDTH]; 298 GLubyte red[MAX_WIDTH], green[MAX_WIDTH]; 299 GLubyte blue[MAX_WIDTH], alpha[MAX_WIDTH]; 300 GLint sy, dy, stepy; 301 GLint i, j; 302 GLboolean zoom; 303 304 if (!ctx->Buffer->Depth) { 305 gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 306 return; 307 } 308 309 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 310 zoom = GL_FALSE; 311 } 312 else { 313 zoom = GL_TRUE; 314 } 315 316 /* Determine if copy should be bottom-to-top or top-to-bottom */ 317 if (srcy<desty) { 318 /* top-down max-to-min */ 319 sy = srcy + height - 1; 320 dy = desty + height - 1; 321 stepy = -1; 322 } 323 else { 324 /* bottom-up min-to-max */ 325 sy = srcy; 326 dy = desty; 327 stepy = 1; 328 } 329 330 /* setup colors or indexes */ 331 if (ctx->Visual->RGBAflag) { 332 GLubyte r, g, b, a; 333 r = ctx->Current.ByteColor[0]; 334 g = ctx->Current.ByteColor[1]; 335 b = ctx->Current.ByteColor[2]; 336 a = ctx->Current.ByteColor[3]; 337 MEMSET( red, (int) r, width ); 338 MEMSET( green, (int) g, width ); 339 MEMSET( blue, (int) b, width ); 340 MEMSET( alpha, (int) a, width ); 341 } 342 else { 343 for (i=0;i<width;i++) { 344 indx[i] = ctx->Current.Index; 345 } 346 } 347 348 for (j=0; j<height; j++, sy+=stepy, dy+=stepy) { 349 /* read */ 350 (*ctx->Driver.ReadDepthSpanFloat)( ctx, width, srcx, sy, depth ); 351 /* scale, bias, clamp */ 352 for (i=0;i<width;i++) { 353 GLfloat d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias; 354 zspan[i] = (GLint) (CLAMP( d, 0.0, 1.0 ) * DEPTH_SCALE); 355 } 356 /* write */ 357 if (ctx->Visual->RGBAflag) { 358 if (zoom) { 359 gl_write_zoomed_color_span( ctx, width, destx, dy, zspan, 360 red, green, blue, alpha, desty ); 361 } 362 else { 363 gl_write_color_span( ctx, width, destx, dy, zspan, 364 red, green, blue, alpha, GL_BITMAP ); 365 } 366 } 367 else { 368 if (zoom) { 369 gl_write_zoomed_index_span( ctx, width, destx, dy, 370 zspan, indx, desty); 371 } 372 else { 373 gl_write_index_span( ctx, width, destx, dy, 374 zspan, indx, GL_BITMAP ); 375 } 376 } 377 } 378 } 379 380 381 382 static void copy_stencil_pixels( GLcontext* ctx, GLint srcx, GLint srcy, 383 GLint width, GLint height, 384 GLint destx, GLint desty ) 385 { 386 GLubyte stencil[MAX_WIDTH]; 387 GLint sy, dy, stepy; 388 GLint i, j; 389 GLboolean zoom; 390 391 if (!ctx->Buffer->Stencil) { 392 gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 393 return; 394 } 395 396 if (ctx->Pixel.ZoomX==1.0F && ctx->Pixel.ZoomY==1.0F) { 397 zoom = GL_FALSE; 398 } 399 else { 400 zoom = GL_TRUE; 401 } 402 403 /* Determine if copy should be bottom-to-top or top-to-bottom */ 404 if (srcy<desty) { 405 /* top-down max-to-min */ 406 sy = srcy + height - 1; 407 dy = desty + height - 1; 408 stepy = -1; 409 } 410 else { 411 /* bottom-up min-to-max */ 412 sy = srcy; 413 dy = desty; 414 stepy = 1; 415 } 416 417 for (j=0; j<height; j++, sy+=stepy, dy+=stepy) { 418 /* read */ 419 gl_read_stencil_span( ctx, width, srcx, sy, stencil ); 420 /* shift, offset */ 421 if (ctx->Pixel.IndexShift<0) { 422 for (i=0;i<width;i++) { 423 stencil[i] = (stencil[i] >> -ctx->Pixel.IndexShift) 424 + ctx->Pixel.IndexOffset; 425 } 426 } 427 else { 428 for (i=0;i<width;i++) { 429 stencil[i] = (stencil[i] << ctx->Pixel.IndexShift) 430 + ctx->Pixel.IndexOffset; 431 } 432 } 433 /* mapping */ 434 if (ctx->Pixel.MapStencilFlag) { 435 for (i=0;i<width;i++) { 436 if ((GLint) stencil[i] < ctx->Pixel.MapStoSsize) { 437 stencil[i] = ctx->Pixel.MapStoS[ stencil[i] ]; 438 } 439 } 440 } 441 /* write */ 442 if (zoom) { 443 gl_write_zoomed_stencil_span( ctx, width, destx, dy, stencil, desty ); 444 } 445 else { 446 gl_write_stencil_span( ctx, width, destx, dy, stencil ); 447 } 448 } 449 } 450 451 452 453 454 void gl_CopyPixels( GLcontext* ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, 455 GLenum type ) 456 { 457 GLint destx, desty; 458 459 if (INSIDE_BEGIN_END(ctx)) { 460 gl_error( ctx, GL_INVALID_OPERATION, "glCopyPixels" ); 461 return; 462 } 463 464 if (width<0 || height<0) { 465 gl_error( ctx, GL_INVALID_VALUE, "glCopyPixels" ); 466 return; 467 } 468 469 if (ctx->NewState) { 470 gl_update_state(ctx); 471 } 472 473 if (ctx->RenderMode==GL_RENDER) { 474 /* Destination of copy: */ 475 if (!ctx->Current.RasterPosValid) { 476 return; 477 } 478 destx = (GLint) (ctx->Current.RasterPos[0] + 0.5F); 479 desty = (GLint) (ctx->Current.RasterPos[1] + 0.5F); 480 481 if (type==GL_COLOR && ctx->Visual->RGBAflag) { 482 copy_rgb_pixels( ctx, srcx, srcy, width, height, destx, desty ); 483 } 484 else if (type==GL_COLOR && !ctx->Visual->RGBAflag) { 485 copy_ci_pixels( ctx, srcx, srcy, width, height, destx, desty ); 486 } 487 else if (type==GL_DEPTH) { 488 copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty ); 489 } 490 else if (type==GL_STENCIL) { 491 copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty ); 492 } 493 else { 494 gl_error( ctx, GL_INVALID_ENUM, "glCopyPixels" ); 495 } 496 } 497 else if (ctx->RenderMode==GL_FEEDBACK) { 498 GLfloat color[4]; 499 color[0] = ctx->Current.ByteColor[0] * ctx->Visual->InvRedScale; 500 color[1] = ctx->Current.ByteColor[1] * ctx->Visual->InvGreenScale; 501 color[2] = ctx->Current.ByteColor[2] * ctx->Visual->InvBlueScale; 502 color[3] = ctx->Current.ByteColor[3] * ctx->Visual->InvAlphaScale; 503 FEEDBACK_TOKEN( ctx, (GLfloat) (GLint) GL_COPY_PIXEL_TOKEN ); 504 gl_feedback_vertex( ctx, ctx->Current.RasterPos[0], 505 ctx->Current.RasterPos[1], 506 ctx->Current.RasterPos[2], 507 ctx->Current.RasterPos[3], 508 color, ctx->Current.Index, 509 ctx->Current.TexCoord ); 510 } 511 else if (ctx->RenderMode==GL_SELECT) { 512 gl_update_hitflag( ctx, ctx->Current.RasterPos[2] ); 513 } 514 515 } 516 517 518