1 /* $Id: pb.c,v 1.14 1997/11/13 02:16:48 brianp Exp $ */ 2 3 /* 4 * Mesa 3-D graphics library 5 * Version: 2.4 6 * Copyright (C) 1995-1997 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: pb.c,v $ 26 * Revision 1.14 1997/11/13 02:16:48 brianp 27 * added lambda array, initialized to zeros 28 * 29 * Revision 1.13 1997/07/24 01:24:11 brianp 30 * changed precompiled header symbol from PCH to PC_HEADER 31 * 32 * Revision 1.12 1997/05/28 03:26:02 brianp 33 * added precompiled header (PCH) support 34 * 35 * Revision 1.11 1997/05/09 22:40:19 brianp 36 * added gl_alloc_pb() 37 * 38 * Revision 1.10 1997/05/03 00:51:30 brianp 39 * new texturing function call: gl_texture_pixels() 40 * 41 * Revision 1.9 1997/05/01 02:10:33 brianp 42 * removed manually unrolled loop to stop Purify uninitialized memory read 43 * 44 * Revision 1.8 1997/04/16 23:54:11 brianp 45 * do per-pixel fog if texturing is enabled 46 * 47 * Revision 1.7 1997/02/09 19:53:43 brianp 48 * now use TEXTURE_xD enable constants 49 * 50 * Revision 1.6 1997/02/09 18:43:14 brianp 51 * added GL_EXT_texture3D support 52 * 53 * Revision 1.5 1997/02/03 20:30:54 brianp 54 * added a few DEFARRAY macros for BeOS 55 * 56 * Revision 1.4 1997/01/28 22:17:44 brianp 57 * new RGBA mode logic op support 58 * 59 * Revision 1.3 1996/09/25 03:21:10 brianp 60 * added NO_DRAW_BIT support 61 * 62 * Revision 1.2 1996/09/15 14:18:37 brianp 63 * now use GLframebuffer and GLvisual 64 * 65 * Revision 1.1 1996/09/13 01:38:16 brianp 66 * Initial revision 67 * 68 */ 69 70 71 /* 72 * Pixel buffer: 73 * 74 * As fragments are produced (by point, line, and bitmap drawing) they 75 * are accumlated in a buffer. When the buffer is full or has to be 76 * flushed (glEnd), we apply all enabled rasterization functions to the 77 * pixels and write the results to the display buffer. The goal is to 78 * maximize the number of pixels processed inside loops and to minimize 79 * the number of function calls. 80 */ 81 82 83 84 #ifdef PC_HEADER 85 #include "all.h" 86 #else 87 #include <stdlib.h> 88 #include <string.h> 89 #include "alpha.h" 90 #include "alphabuf.h" 91 #include "blend.h" 92 #include "depth.h" 93 #include "fog.h" 94 #include "logic.h" 95 #include "macros.h" 96 #include "masking.h" 97 #include "pb.h" 98 #include "scissor.h" 99 #include "stencil.h" 100 #include "texture.h" 101 #include "types.h" 102 #endif 103 104 105 106 /* 107 * Allocate and initialize a new pixel buffer structure. 108 */ 109 struct pixel_buffer *gl_alloc_pb(void) 110 { 111 struct pixel_buffer *pb; 112 pb = (struct pixel_buffer *) calloc(sizeof(struct pixel_buffer), 1); 113 if (pb) { 114 int i; 115 /* set non-zero fields */ 116 pb->primitive = GL_BITMAP; 117 /* Set all lambda values to 0.0 since we don't do mipmapping for 118 * points or lines and want to use the level 0 texture image. 119 */ 120 for (i=0; i<PB_SIZE; i++) { 121 pb->lambda[i] = 0.0; 122 } 123 } 124 return pb; 125 } 126 127 128 129 130 /* 131 * When the pixel buffer is full, or needs to be flushed, call this 132 * function. All the pixels in the pixel buffer will be subjected 133 * to texturing, scissoring, stippling, alpha testing, stenciling, 134 * depth testing, blending, and finally written to the frame buffer. 135 */ 136 void gl_flush_pb( GLcontext *ctx ) 137 { 138 struct pixel_buffer* PB = ctx->PB; 139 140 DEFARRAY(GLubyte,mask,PB_SIZE); 141 DEFARRAY(GLubyte, rsave, PB_SIZE); 142 DEFARRAY(GLubyte, gsave, PB_SIZE); 143 DEFARRAY(GLubyte, bsave, PB_SIZE); 144 DEFARRAY(GLubyte, asave, PB_SIZE); 145 146 if (PB->count==0) goto CleanUp; 147 148 /* initialize mask array and clip pixels simultaneously */ 149 { 150 GLint xmin = ctx->Buffer->Xmin; 151 GLint xmax = ctx->Buffer->Xmax; 152 GLint ymin = ctx->Buffer->Ymin; 153 GLint ymax = ctx->Buffer->Ymax; 154 GLint *x = PB->x; 155 GLint *y = PB->y; 156 GLuint i, n = PB->count; 157 for (i=0;i<n;i++) { 158 mask[i] = (x[i]>=xmin) & (x[i]<=xmax) & (y[i]>=ymin) & (y[i]<=ymax); 159 } 160 } 161 162 if (ctx->Visual->RGBAflag) { 163 /* RGBA COLOR PIXELS */ 164 if (PB->mono && ctx->MutablePixels) { 165 /* Copy flat color to all pixels */ 166 MEMSET( PB->r, PB->color[0], PB->count ); 167 MEMSET( PB->g, PB->color[1], PB->count ); 168 MEMSET( PB->b, PB->color[2], PB->count ); 169 MEMSET( PB->a, PB->color[3], PB->count ); 170 } 171 172 /* If each pixel can be of a different color... */ 173 if (ctx->MutablePixels || !PB->mono) { 174 175 if (ctx->Texture.Enabled) { 176 /* TODO: need texture lambda valus */ 177 gl_texture_pixels( ctx, PB->count, PB->s, PB->t, PB->u, 178 PB->lambda, PB->r, PB->g, PB->b, PB->a); 179 } 180 181 if (ctx->Fog.Enabled 182 && (ctx->Hint.Fog==GL_NICEST || PB->primitive==GL_BITMAP 183 || ctx->Texture.Enabled)) { 184 gl_fog_color_pixels( ctx, PB->count, PB->z, 185 PB->r, PB->g, PB->b, PB->a ); 186 } 187 188 /* Scissoring already done above */ 189 190 if (ctx->Color.AlphaEnabled) { 191 if (gl_alpha_test( ctx, PB->count, PB->a, mask )==0) { 192 goto CleanUp; 193 } 194 } 195 196 if (ctx->Stencil.Enabled) { 197 /* first stencil test */ 198 if (gl_stencil_pixels( ctx, PB->count, PB->x, PB->y, mask )==0) { 199 goto CleanUp; 200 } 201 /* depth buffering w/ stencil */ 202 gl_depth_stencil_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); 203 } 204 else if (ctx->Depth.Test) { 205 /* regular depth testing */ 206 (*ctx->Driver.DepthTestPixels)( ctx, PB->count, PB->x, PB->y, PB->z, mask ); 207 } 208 209 if (ctx->RasterMask & NO_DRAW_BIT) { 210 goto CleanUp; 211 } 212 213 if (ctx->RasterMask & FRONT_AND_BACK_BIT) { 214 /* make a copy of the colors */ 215 MEMCPY( rsave, PB->r, PB->count * sizeof(GLubyte) ); 216 MEMCPY( gsave, PB->r, PB->count * sizeof(GLubyte) ); 217 MEMCPY( bsave, PB->r, PB->count * sizeof(GLubyte) ); 218 MEMCPY( asave, PB->r, PB->count * sizeof(GLubyte) ); 219 } 220 221 if (ctx->Color.SWLogicOpEnabled) { 222 gl_logicop_rgba_pixels( ctx, PB->count, PB->x, PB->y, 223 PB->r, PB->g, PB->b, PB->a, mask); 224 } 225 else if (ctx->Color.BlendEnabled) { 226 gl_blend_pixels( ctx, PB->count, PB->x, PB->y, 227 PB->r, PB->g, PB->b, PB->a, mask); 228 } 229 230 if (ctx->Color.SWmasking) { 231 gl_mask_color_pixels( ctx, PB->count, PB->x, PB->y, 232 PB->r, PB->g, PB->b, PB->a, mask ); 233 } 234 235 /* write pixels */ 236 (*ctx->Driver.WriteColorPixels)( ctx, PB->count, PB->x, PB->y, 237 PB->r, PB->g, PB->b, PB->a, mask ); 238 if (ctx->RasterMask & ALPHABUF_BIT) { 239 gl_write_alpha_pixels( ctx, PB->count, PB->x, PB->y, PB->a, mask ); 240 } 241 242 if (ctx->RasterMask & FRONT_AND_BACK_BIT) { 243 /*** Also draw to back buffer ***/ 244 (*ctx->Driver.SetBuffer)( ctx, GL_BACK ); 245 if (ctx->Color.SWLogicOpEnabled) { 246 gl_logicop_rgba_pixels( ctx, PB->count, PB->x, PB->y, 247 PB->r, PB->g, PB->b, PB->a, mask); 248 } 249 else if (ctx->Color.BlendEnabled) { 250 gl_blend_pixels( ctx, PB->count, PB->x, PB->y, 251 rsave, gsave, bsave, asave, mask ); 252 } 253 if (ctx->Color.SWmasking) { 254 gl_mask_color_pixels( ctx, PB->count, PB->x, PB->y, 255 rsave, gsave, bsave, asave, mask); 256 } 257 (*ctx->Driver.WriteColorPixels)( ctx, PB->count, PB->x, PB->y, 258 rsave, gsave, bsave, asave, mask); 259 if (ctx->RasterMask & ALPHABUF_BIT) { 260 ctx->Buffer->Alpha = ctx->Buffer->BackAlpha; 261 gl_write_alpha_pixels( ctx, PB->count, PB->x, PB->y, 262 asave, mask ); 263 ctx->Buffer->Alpha = ctx->Buffer->FrontAlpha; 264 } 265 (*ctx->Driver.SetBuffer)( ctx, GL_FRONT ); 266 /*** ALL DONE ***/ 267 } 268 } 269 else { 270 /* Same color for all pixels */ 271 272 /* Scissoring already done above */ 273 274 if (ctx->Color.AlphaEnabled) { 275 if (gl_alpha_test( ctx, PB->count, PB->a, mask )==0) { 276 goto CleanUp; 277 } 278 } 279 280 if (ctx->Stencil.Enabled) { 281 /* first stencil test */ 282 if (gl_stencil_pixels( ctx, PB->count, PB->x, PB->y, mask )==0) { 283 goto CleanUp; 284 } 285 /* depth buffering w/ stencil */ 286 gl_depth_stencil_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); 287 } 288 else if (ctx->Depth.Test) { 289 /* regular depth testing */ 290 (*ctx->Driver.DepthTestPixels)( ctx, PB->count, PB->x, PB->y, PB->z, mask ); 291 } 292 293 if (ctx->RasterMask & NO_DRAW_BIT) { 294 goto CleanUp; 295 } 296 297 /* write pixels */ 298 { 299 GLubyte red, green, blue, alpha; 300 red = PB->color[0]; 301 green = PB->color[1]; 302 blue = PB->color[2]; 303 alpha = PB->color[3]; 304 (*ctx->Driver.Color)( ctx, red, green, blue, alpha ); 305 } 306 (*ctx->Driver.WriteMonocolorPixels)( ctx, PB->count, PB->x, PB->y, mask ); 307 if (ctx->RasterMask & ALPHABUF_BIT) { 308 gl_write_mono_alpha_pixels( ctx, PB->count, PB->x, PB->y, 309 PB->color[3], mask ); 310 } 311 312 if (ctx->RasterMask & FRONT_AND_BACK_BIT) { 313 /*** Also render to back buffer ***/ 314 (*ctx->Driver.SetBuffer)( ctx, GL_BACK ); 315 (*ctx->Driver.WriteMonocolorPixels)( ctx, PB->count, PB->x, PB->y, mask ); 316 if (ctx->RasterMask & ALPHABUF_BIT) { 317 ctx->Buffer->Alpha = ctx->Buffer->BackAlpha; 318 gl_write_mono_alpha_pixels( ctx, PB->count, PB->x, PB->y, 319 PB->color[3], mask ); 320 ctx->Buffer->Alpha = ctx->Buffer->FrontAlpha; 321 } 322 (*ctx->Driver.SetBuffer)( ctx, GL_FRONT ); 323 } 324 /*** ALL DONE ***/ 325 } 326 } 327 else { 328 /* COLOR INDEX PIXELS */ 329 330 /* If we may be writting pixels with different indexes... */ 331 if (PB->mono && ctx->MutablePixels) { 332 /* copy index to all pixels */ 333 GLuint n = PB->count, indx = PB->index; 334 GLuint *pbindex = PB->i; 335 do { 336 *pbindex++ = indx; 337 n--; 338 } while (n); 339 } 340 341 if (ctx->MutablePixels || !PB->mono) { 342 /* Pixel color index may be modified */ 343 GLuint isave[PB_SIZE]; 344 345 if (ctx->Fog.Enabled 346 && (ctx->Hint.Fog==GL_NICEST || PB->primitive==GL_BITMAP)) { 347 gl_fog_index_pixels( ctx, PB->count, PB->z, PB->i ); 348 } 349 350 /* Scissoring already done above */ 351 352 if (ctx->Stencil.Enabled) { 353 /* first stencil test */ 354 if (gl_stencil_pixels( ctx, PB->count, PB->x, PB->y, mask )==0) { 355 goto CleanUp; 356 } 357 /* depth buffering w/ stencil */ 358 gl_depth_stencil_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); 359 } 360 else if (ctx->Depth.Test) { 361 /* regular depth testing */ 362 (*ctx->Driver.DepthTestPixels)( ctx, PB->count, PB->x, PB->y, PB->z, mask ); 363 } 364 365 if (ctx->RasterMask & NO_DRAW_BIT) { 366 goto CleanUp; 367 } 368 369 if (ctx->RasterMask & FRONT_AND_BACK_BIT) { 370 /* make a copy of the indexes */ 371 MEMCPY( isave, PB->i, PB->count * sizeof(GLuint) ); 372 } 373 374 if (ctx->Color.SWLogicOpEnabled) { 375 gl_logicop_ci_pixels( ctx, PB->count, PB->x, PB->y, PB->i, mask ); 376 } 377 378 if (ctx->Color.SWmasking) { 379 gl_mask_index_pixels( ctx, PB->count, PB->x, PB->y, PB->i, mask ); 380 } 381 382 /* write pixels */ 383 (*ctx->Driver.WriteIndexPixels)( ctx, PB->count, PB->x, PB->y, 384 PB->i, mask ); 385 386 if (ctx->RasterMask & FRONT_AND_BACK_BIT) { 387 /*** Also write to back buffer ***/ 388 (*ctx->Driver.SetBuffer)( ctx, GL_BACK ); 389 MEMCPY( PB->i, isave, PB->count * sizeof(GLuint) ); 390 if (ctx->Color.SWLogicOpEnabled) { 391 gl_logicop_ci_pixels( ctx, PB->count, PB->x, PB->y, PB->i, mask ); 392 } 393 if (ctx->Color.SWmasking) { 394 gl_mask_index_pixels( ctx, PB->count, PB->x, PB->y, 395 PB->i, mask ); 396 } 397 (*ctx->Driver.WriteIndexPixels)( ctx, PB->count, PB->x, PB->y, 398 PB->i, mask ); 399 (*ctx->Driver.SetBuffer)( ctx, GL_FRONT ); 400 } 401 402 /*** ALL DONE ***/ 403 } 404 else { 405 /* Same color index for all pixels */ 406 407 /* Scissoring already done above */ 408 409 if (ctx->Stencil.Enabled) { 410 /* first stencil test */ 411 if (gl_stencil_pixels( ctx, PB->count, PB->x, PB->y, mask )==0) { 412 goto CleanUp; 413 } 414 /* depth buffering w/ stencil */ 415 gl_depth_stencil_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); 416 } 417 else if (ctx->Depth.Test) { 418 /* regular depth testing */ 419 (*ctx->Driver.DepthTestPixels)( ctx, PB->count, PB->x, PB->y, PB->z, mask ); 420 } 421 422 if (ctx->RasterMask & NO_DRAW_BIT) { 423 goto CleanUp; 424 } 425 426 /* write pixels */ 427 (*ctx->Driver.Index)( ctx, PB->index ); 428 (*ctx->Driver.WriteMonoindexPixels)( ctx, PB->count, PB->x, PB->y, mask ); 429 430 if (ctx->RasterMask & FRONT_AND_BACK_BIT) { 431 /*** Also write to back buffer ***/ 432 (*ctx->Driver.SetBuffer)( ctx, GL_BACK ); 433 (*ctx->Driver.WriteMonoindexPixels)( ctx, PB->count, PB->x, PB->y, mask ); 434 (*ctx->Driver.SetBuffer)( ctx, GL_FRONT ); 435 } 436 /*** ALL DONE ***/ 437 } 438 } 439 440 CleanUp: 441 PB->count = 0; 442 UNDEFARRAY(mask); 443 UNDEFARRAY(rsave); 444 UNDEFARRAY(gsave); 445 UNDEFARRAY(bsave); 446 UNDEFARRAY(asave); 447 } 448 449 450