/* * When the pixel buffer is full, or needs to be flushed, call this * function. All the pixels in the pixel buffer will be subjected * to texturing, scissoring, stippling, alpha testing, stenciling, * depth testing, blending, and finally written to the frame buffer. */ void gl_flush_pb( GLcontext *ctx ) { struct pixel_buffer* PB = ctx->PB; DEFARRAY(GLubyte,mask,PB_SIZE+4); /* add 4 for manually unrolled loop, below */ DEFARRAY(GLubyte, rsave, PB_SIZE); DEFARRAY(GLubyte, gsave, PB_SIZE); DEFARRAY(GLubyte, bsave, PB_SIZE); DEFARRAY(GLubyte, asave, PB_SIZE); if (PB->count==0) goto CleanUp; /* initialize mask array and clip pixels simultaneously */ { GLint xmin = ctx->Buffer->Xmin; GLint xmax = ctx->Buffer->Xmax; GLint ymin = ctx->Buffer->Ymin; GLint ymax = ctx->Buffer->Ymax; GLint *x = PB->x; GLint *y = PB->y; GLuint i = 0; /* manually unrolled loop, OK to go past PB->count */ do { mask[i] = (x[i]>=xmin) & (x[i]<=xmax) & (y[i]>=ymin) & (y[i]<=ymax); i++; mask[i] = (x[i]>=xmin) & (x[i]<=xmax) & (y[i]>=ymin) & (y[i]<=ymax); i++; mask[i] = (x[i]>=xmin) & (x[i]<=xmax) & (y[i]>=ymin) & (y[i]<=ymax); i++; mask[i] = (x[i]>=xmin) & (x[i]<=xmax) & (y[i]>=ymin) & (y[i]<=ymax); i++; } while (i<PB->count); } if (ctx->Visual->RGBAflag) { /* RGBA COLOR PIXELS */ if (PB->mono && ctx->MutablePixels) { /* Copy flat color to all pixels */ MEMSET( PB->r, PB->color[0], PB->count ); MEMSET( PB->g, PB->color[1], PB->count ); MEMSET( PB->b, PB->color[2], PB->count ); MEMSET( PB->a, PB->color[3], PB->count ); } /* If each pixel can be of a different color... */ if (ctx->MutablePixels || !PB->mono) { if (ctx->Texture.Enabled & TEXTURE_3D) { /* TODO: need texture lambda valus */ gl_texture_pixels_3d( ctx, PB->count, PB->s, PB->t, PB->u, NULL, PB->r, PB->g, PB->b, PB->a); } else if (ctx->Texture.Enabled & TEXTURE_2D) { /* TODO: need texture lambda valus */ gl_texture_pixels_2d( ctx, PB->count, PB->s, PB->t, NULL, PB->r, PB->g, PB->b, PB->a); } else if (ctx->Texture.Enabled & TEXTURE_1D) { /* TODO: need texture lambda values */ gl_texture_pixels_1d( ctx, PB->count, PB->s, NULL, PB->r, PB->g, PB->b, PB->a ); } if (ctx->Fog.Enabled && (ctx->Hint.Fog==GL_NICEST || PB->primitive==GL_BITMAP)) { gl_fog_color_pixels( ctx, PB->count, PB->z, PB->r, PB->g, PB->b, PB->a ); } /* Scissoring already done above */ if (ctx->Color.AlphaEnabled) { if (gl_alpha_test( ctx, PB->count, PB->a, mask )==0) { goto CleanUp; } } if (ctx->Stencil.Enabled) { /* first stencil test */ if (gl_stencil_pixels( ctx, PB->count, PB->x, PB->y, mask )==0) { goto CleanUp; } /* depth buffering w/ stencil */ gl_depth_stencil_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } else if (ctx->Depth.Test) { /* regular depth testing */ (*ctx->Driver.DepthTestPixels)( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } if (ctx->RasterMask & NO_DRAW_BIT) { goto CleanUp; } if (ctx->RasterMask & FRONT_AND_BACK_BIT) { /* make a copy of the colors */ MEMCPY( rsave, PB->r, PB->count * sizeof(GLubyte) ); MEMCPY( gsave, PB->r, PB->count * sizeof(GLubyte) ); MEMCPY( bsave, PB->r, PB->count * sizeof(GLubyte) ); MEMCPY( asave, PB->r, PB->count * sizeof(GLubyte) ); } if (ctx->Color.SWLogicOpEnabled) { gl_logicop_rgba_pixels( ctx, PB->count, PB->x, PB->y, PB->r, PB->g, PB->b, PB->a, mask); } else if (ctx->Color.BlendEnabled) { gl_blend_pixels( ctx, PB->count, PB->x, PB->y, PB->r, PB->g, PB->b, PB->a, mask); } if (ctx->Color.SWmasking) { gl_mask_color_pixels( ctx, PB->count, PB->x, PB->y, PB->r, PB->g, PB->b, PB->a, mask ); } /* write pixels */ (*ctx->Driver.WriteColorPixels)( ctx, PB->count, PB->x, PB->y, PB->r, PB->g, PB->b, PB->a, mask ); if (ctx->RasterMask & ALPHABUF_BIT) { gl_write_alpha_pixels( ctx, PB->count, PB->x, PB->y, PB->a, mask ); } if (ctx->RasterMask & FRONT_AND_BACK_BIT) { /*** Also draw to back buffer ***/ (*ctx->Driver.SetBuffer)( ctx, GL_BACK ); if (ctx->Color.SWLogicOpEnabled) { gl_logicop_rgba_pixels( ctx, PB->count, PB->x, PB->y, PB->r, PB->g, PB->b, PB->a, mask); } else if (ctx->Color.BlendEnabled) { gl_blend_pixels( ctx, PB->count, PB->x, PB->y, rsave, gsave, bsave, asave, mask ); } if (ctx->Color.SWmasking) { gl_mask_color_pixels( ctx, PB->count, PB->x, PB->y, rsave, gsave, bsave, asave, mask); } (*ctx->Driver.WriteColorPixels)( ctx, PB->count, PB->x, PB->y, rsave, gsave, bsave, asave, mask); if (ctx->RasterMask & ALPHABUF_BIT) { ctx->Buffer->Alpha = ctx->Buffer->BackAlpha; gl_write_alpha_pixels( ctx, PB->count, PB->x, PB->y, asave, mask ); ctx->Buffer->Alpha = ctx->Buffer->FrontAlpha; } (*ctx->Driver.SetBuffer)( ctx, GL_FRONT ); /*** ALL DONE ***/ } } else { /* Same color for all pixels */ /* Scissoring already done above */ if (ctx->Color.AlphaEnabled) { if (gl_alpha_test( ctx, PB->count, PB->a, mask )==0) { goto CleanUp; } } if (ctx->Stencil.Enabled) { /* first stencil test */ if (gl_stencil_pixels( ctx, PB->count, PB->x, PB->y, mask )==0) { goto CleanUp; } /* depth buffering w/ stencil */ gl_depth_stencil_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } else if (ctx->Depth.Test) { /* regular depth testing */ (*ctx->Driver.DepthTestPixels)( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } if (ctx->RasterMask & NO_DRAW_BIT) { goto CleanUp; } /* write pixels */ { GLubyte red, green, blue, alpha; red = PB->color[0]; green = PB->color[1]; blue = PB->color[2]; alpha = PB->color[3]; (*ctx->Driver.Color)( ctx, red, green, blue, alpha ); } (*ctx->Driver.WriteMonocolorPixels)( ctx, PB->count, PB->x, PB->y, mask ); if (ctx->RasterMask & ALPHABUF_BIT) { gl_write_mono_alpha_pixels( ctx, PB->count, PB->x, PB->y, PB->color[3], mask ); } if (ctx->RasterMask & FRONT_AND_BACK_BIT) { /*** Also render to back buffer ***/ (*ctx->Driver.SetBuffer)( ctx, GL_BACK ); (*ctx->Driver.WriteMonocolorPixels)( ctx, PB->count, PB->x, PB->y, mask ); if (ctx->RasterMask & ALPHABUF_BIT) { ctx->Buffer->Alpha = ctx->Buffer->BackAlpha; gl_write_mono_alpha_pixels( ctx, PB->count, PB->x, PB->y, PB->color[3], mask ); ctx->Buffer->Alpha = ctx->Buffer->FrontAlpha; } (*ctx->Driver.SetBuffer)( ctx, GL_FRONT ); } /*** ALL DONE ***/ } } else { /* COLOR INDEX PIXELS */ /* If we may be writting pixels with different indexes... */ if (PB->mono && ctx->MutablePixels) { /* copy index to all pixels */ GLuint n = PB->count, indx = PB->index; GLuint *pbindex = PB->i; do { *pbindex++ = indx; n--; } while (n); } if (ctx->MutablePixels || !PB->mono) { /* Pixel color index may be modified */ GLuint isave[PB_SIZE]; if (ctx->Fog.Enabled && (ctx->Hint.Fog==GL_NICEST || PB->primitive==GL_BITMAP)) { gl_fog_index_pixels( ctx, PB->count, PB->z, PB->i ); } /* Scissoring already done above */ if (ctx->Stencil.Enabled) { /* first stencil test */ if (gl_stencil_pixels( ctx, PB->count, PB->x, PB->y, mask )==0) { goto CleanUp; } /* depth buffering w/ stencil */ gl_depth_stencil_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } else if (ctx->Depth.Test) { /* regular depth testing */ (*ctx->Driver.DepthTestPixels)( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } if (ctx->RasterMask & NO_DRAW_BIT) { goto CleanUp; } if (ctx->RasterMask & FRONT_AND_BACK_BIT) { /* make a copy of the indexes */ MEMCPY( isave, PB->i, PB->count * sizeof(GLuint) ); } if (ctx->Color.SWLogicOpEnabled) { gl_logicop_ci_pixels( ctx, PB->count, PB->x, PB->y, PB->i, mask ); } if (ctx->Color.SWmasking) { gl_mask_index_pixels( ctx, PB->count, PB->x, PB->y, PB->i, mask ); } /* write pixels */ (*ctx->Driver.WriteIndexPixels)( ctx, PB->count, PB->x, PB->y, PB->i, mask ); if (ctx->RasterMask & FRONT_AND_BACK_BIT) { /*** Also write to back buffer ***/ (*ctx->Driver.SetBuffer)( ctx, GL_BACK ); MEMCPY( PB->i, isave, PB->count * sizeof(GLuint) ); if (ctx->Color.SWLogicOpEnabled) { gl_logicop_ci_pixels( ctx, PB->count, PB->x, PB->y, PB->i, mask ); } if (ctx->Color.SWmasking) { gl_mask_index_pixels( ctx, PB->count, PB->x, PB->y, PB->i, mask ); } (*ctx->Driver.WriteIndexPixels)( ctx, PB->count, PB->x, PB->y, PB->i, mask ); (*ctx->Driver.SetBuffer)( ctx, GL_FRONT ); } /*** ALL DONE ***/ } else { /* Same color index for all pixels */ /* Scissoring already done above */ if (ctx->Stencil.Enabled) { /* first stencil test */ if (gl_stencil_pixels( ctx, PB->count, PB->x, PB->y, mask )==0) { goto CleanUp; } /* depth buffering w/ stencil */ gl_depth_stencil_pixels( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } else if (ctx->Depth.Test) { /* regular depth testing */ (*ctx->Driver.DepthTestPixels)( ctx, PB->count, PB->x, PB->y, PB->z, mask ); } if (ctx->RasterMask & NO_DRAW_BIT) { goto CleanUp; } /* write pixels */ (*ctx->Driver.Index)( ctx, PB->index ); (*ctx->Driver.WriteMonoindexPixels)( ctx, PB->count, PB->x, PB->y, mask ); if (ctx->RasterMask & FRONT_AND_BACK_BIT) { /*** Also write to back buffer ***/ (*ctx->Driver.SetBuffer)( ctx, GL_BACK ); (*ctx->Driver.WriteMonoindexPixels)( ctx, PB->count, PB->x, PB->y, mask ); (*ctx->Driver.SetBuffer)( ctx, GL_FRONT ); } /*** ALL DONE ***/ } } CleanUp: PB->count = 0; UNDEFARRAY(mask); UNDEFARRAY(rsave); UNDEFARRAY(gsave); UNDEFARRAY(bsave); UNDEFARRAY(asave); }
/* * Textured RGBA line: any width, smooth or flat, stippled, any raster ops * with texturing. */ static void textured_rgba_line( GLcontext *ctx, GLuint v1, GLuint v2, GLuint pv ) { struct vertex_buffer *VB = ctx->VB; struct pixel_buffer *PB = ctx->PB; GLint x1, y1, x2, y2; GLint x[MAXPOINTS], y[MAXPOINTS]; GLdepth z[MAXPOINTS]; GLubyte mask[MAXPOINTS]; /* Allocate arrays dynamically on Mac */ DEFARRAY(GLubyte,red,MAXPOINTS); DEFARRAY(GLubyte,green,MAXPOINTS); DEFARRAY(GLubyte,blue,MAXPOINTS); DEFARRAY(GLubyte,alpha,MAXPOINTS); DEFARRAY(GLfloat,s,MAXPOINTS); DEFARRAY(GLfloat,t,MAXPOINTS); DEFARRAY(GLfloat,u,MAXPOINTS); #if 0 DEFARRAY(GLfloat,v,MAXPOINTS); #endif GLint i, n; GLint dx, dy; x1 = (GLint) VB->Win[v1][0]; y1 = (GLint) VB->Win[v1][1]; x2 = (GLint) VB->Win[v2][0]; y2 = (GLint) VB->Win[v2][1]; /* compute the line */ if (ctx->Line.StippleFlag) { n = gl_stippled_bresenham( ctx, x1, y1, x2, y2, x, y, mask ); } else { n = gl_bresenham( ctx, x1, y1, x2, y2, x, y ); for (i=0;i<n;i++) { mask[i] = 1; } } if (ctx->Depth.Test) { GLint z1 = (GLint) (VB->Win[v1][2] + ctx->LineZoffset); GLint z2 = (GLint) (VB->Win[v2][2] + ctx->LineZoffset); GL_INTERPOLATE_Z( n, z1, z2, z ); } if (ctx->Light.ShadeModel==GL_FLAT) { GLint r, g, b, a; r = VB->Color[pv][0]; /* colors are ints, not in fixed point */ g = VB->Color[pv][1]; b = VB->Color[pv][2]; a = VB->Color[pv][3]; for (i=0;i<n;i++) { red[i] = r; green[i] = g; blue[i] = b; alpha[i] = a; } } else { /* interpolate color, VB->Colors are in fixed point */ gl_interpolate_rgba( n, VB->Color[v1][0], VB->Color[v2][0], red, VB->Color[v1][1], VB->Color[v2][1], green, VB->Color[v1][2], VB->Color[v2][2], blue, VB->Color[v1][3], VB->Color[v2][3], alpha ); } /* interpolate texture coordinates */ { GLfloat w1 = 1.0F / VB->Clip[v1][3]; GLfloat w2 = 1.0F / VB->Clip[v2][3]; GLfloat s1 = VB->TexCoord[v1][0] * w1; GLfloat s2 = VB->TexCoord[v2][0] * w2; GLfloat t1 = VB->TexCoord[v1][1] * w1; GLfloat t2 = VB->TexCoord[v2][1] * w2; GLfloat u1 = VB->TexCoord[v1][2] * w1; GLfloat u2 = VB->TexCoord[v2][2] * w2; /* don't interpolate r since we don't do 3-D textures, yet */ GLfloat q1 = VB->TexCoord[v1][3] * w1; GLfloat q2 = VB->TexCoord[v2][3] * w2; GLfloat inv_n = 1.0F / (GLfloat) n; GLfloat ds = (s2-s1) * inv_n; GLfloat dt = (t2-t1) * inv_n; GLfloat du = (u2-u1) * inv_n; GLfloat dq = (q2-q1) * inv_n; for (i=0;i<n;i++) { s[i] = s1 / q1; t[i] = t1 / q1; u[i] = u1 / q1; s1 += ds; t1 += dt; u1 += du; q1 += dq; } } /* compute delta x and delta y */ if (x1>x2) { dx = x1 - x2; } else { dx = x2 - x1; } if (y1>y2) { dy = y1 - y2; } else { dy = y2 - y1; } /* render */ if (ctx->Line.Width==2.0F) { /* special case, easy to optimize */ if (dx>dy) { /* X-major: duplicate pixels in Y direction */ for (i=0;i<n;i++) { if (mask[i]) { PB_WRITE_TEX_PIXEL( PB, x[i], y[i]-1, z[i], red[i], green[i], blue[i], alpha[i], s[i], t[i], u[i] ); PB_WRITE_TEX_PIXEL( PB, x[i], y[i], z[i], red[i], green[i], blue[i], alpha[i], s[i], t[i], u[i] ); } } } else { /* Y-major: duplicate pixels in X direction */ for (i=0;i<n;i++) { if (mask[i]) { PB_WRITE_TEX_PIXEL( PB, x[i]-1, y[i], z[i], red[i], green[i], blue[i], alpha[i], s[i], t[i], u[i] ); PB_WRITE_TEX_PIXEL( PB, x[i], y[i], z[i], red[i], green[i], blue[i], alpha[i], s[i], t[i], u[i] ); } } } PB_CHECK_FLUSH( ctx, PB ); } else { GLint width, w0, w1; width = (GLint) CLAMP( ctx->Line.Width, MIN_LINE_WIDTH, MAX_LINE_WIDTH ); w0 = -width / 2; w1 = w0 + width - 1; if (dx>dy) { /* X-major: duplicate pixels in Y direction */ for (i=0;i<n;i++) { if (mask[i]) { GLint yy; GLint y0 = y[i] + w0; GLint y1 = y[i] + w1; for (yy=y0;yy<=y1;yy++) { PB_WRITE_TEX_PIXEL( PB, x[i], yy, z[i], red[i], green[i], blue[i], alpha[i], s[i], t[i], u[i] ); } PB_CHECK_FLUSH( ctx, PB ); } } } else { /* Y-major: duplicate pixels in X direction */ for (i=0;i<n;i++) { if (mask[i]) { GLint xx; GLint x0 = x[i] + w0; GLint x1 = x[i] + w1; for (xx=x0;xx<=x1;xx++) { PB_WRITE_TEX_PIXEL( PB, xx, y[i], z[i], red[i], green[i], blue[i], alpha[i], s[i], t[i], u[i] ); } PB_CHECK_FLUSH( ctx, PB ); } } } } /* Deallocate dynamic arrays on Mac */ UNDEFARRAY(red); UNDEFARRAY(green); UNDEFARRAY(blue); UNDEFARRAY(alpha); UNDEFARRAY(s); UNDEFARRAY(t); UNDEFARRAY(u); #if 0 UNDEFARRAY(v); #endif }