This is draw.c in view mode; [Download] [Up]
/* $Id: draw.c,v 1.7 1996/10/12 18:23:06 brianp Exp $ */ /* * Mesa 3-D graphics library * Version: 2.0 * Copyright (C) 1995-1996 Brian Paul * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * $Log: draw.c,v $ * Revision 1.7 1996/10/12 18:23:06 brianp * window Z coord was incorrectly computed in render_clipped_line() * * Revision 1.6 1996/10/11 03:44:34 brianp * cleaned up the polygon offset code * * Revision 1.5 1996/09/27 01:26:16 brianp * removed unused variables * * Revision 1.4 1996/09/20 02:55:17 brianp * updated profiling code, removed old polygon offset code * * Revision 1.3 1996/09/15 14:17:30 brianp * now use GLframebuffer and GLvisual * * Revision 1.2 1996/09/15 01:48:58 brianp * removed #define NULL 0 * * Revision 1.1 1996/09/13 01:38:16 brianp * Initial revision * */ /* * Draw points, lines, and polygons. */ #ifdef DEBUG # include <assert.h> #endif #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "clip.h" #include "context.h" #include "draw.h" #include "feedback.h" #include "fog.h" #include "light.h" #include "lines.h" #include "dlist.h" #include "macros.h" #include "matrix.h" #include "pb.h" #include "points.h" #include "texture.h" #include "types.h" #include "vb.h" #include "xform.h" #ifdef DEBUG # define ASSERT(X) assert(X) #else # define ASSERT(X) #endif #ifdef PROFILE # define START_PROFILE \ { \ GLdouble t0 = gl_time(); # define END_PROFILE( TIMER, COUNTER, INCR ) \ TIMER += (gl_time() - t0); \ COUNTER += INCR; \ } #else # define START_PROFILE # define END_PROFILE( TIMER, COUNTER, INCR ) #endif /* * Check if the global material has to be updated with info that was * associated with a vertex via glMaterial. */ static void update_material( GLcontext* ctx, GLuint i ) { struct vertex_buffer *VB = ctx->VB; if (VB->MaterialMask[i]) { if (VB->MaterialMask[i] & FRONT_AMBIENT_BIT) { COPY_4V( ctx->Light.Material[0].Ambient, VB->Material[i][0].Ambient ); } if (VB->MaterialMask[i] & BACK_AMBIENT_BIT) { COPY_4V( ctx->Light.Material[1].Ambient, VB->Material[i][1].Ambient ); } if (VB->MaterialMask[i] & FRONT_DIFFUSE_BIT) { COPY_4V( ctx->Light.Material[0].Diffuse, VB->Material[i][0].Diffuse ); } if (VB->MaterialMask[i] & BACK_DIFFUSE_BIT) { COPY_4V( ctx->Light.Material[1].Diffuse, VB->Material[i][1].Diffuse ); } if (VB->MaterialMask[i] & FRONT_SPECULAR_BIT) { COPY_4V( ctx->Light.Material[0].Specular, VB->Material[i][0].Specular ); } if (VB->MaterialMask[i] & BACK_SPECULAR_BIT) { COPY_4V( ctx->Light.Material[1].Specular, VB->Material[i][1].Specular ); } if (VB->MaterialMask[i] & FRONT_EMISSION_BIT) { COPY_4V( ctx->Light.Material[0].Emission, VB->Material[i][0].Emission ); } if (VB->MaterialMask[i] & BACK_EMISSION_BIT) { COPY_4V( ctx->Light.Material[1].Emission, VB->Material[i][1].Emission ); } if (VB->MaterialMask[i] & FRONT_SHININESS_BIT) { ctx->Light.Material[0].Shininess = VB->Material[i][0].Shininess; } if (VB->MaterialMask[i] & BACK_SHININESS_BIT) { ctx->Light.Material[1].Shininess = VB->Material[i][1].Shininess; } if (VB->MaterialMask[i] & FRONT_INDEXES_BIT) { ctx->Light.Material[0].AmbientIndex = VB->Material[i][0].AmbientIndex; ctx->Light.Material[0].DiffuseIndex = VB->Material[i][0].DiffuseIndex; ctx->Light.Material[0].SpecularIndex = VB->Material[i][0].SpecularIndex; } if (VB->MaterialMask[i] & BACK_INDEXES_BIT) { ctx->Light.Material[1].AmbientIndex = VB->Material[i][1].AmbientIndex; ctx->Light.Material[1].DiffuseIndex = VB->Material[i][1].DiffuseIndex; ctx->Light.Material[1].SpecularIndex = VB->Material[i][1].SpecularIndex; } VB->MaterialMask[i] = 0; /* reset now */ } } /* * Render a line segment from VB[v1] to VB[v2] when either one or both * endpoints must be clipped. */ static void render_clipped_line( GLcontext* ctx, GLuint v1, GLuint v2 ) { GLfloat d; GLfloat ndc_x, ndc_y, ndc_z; GLuint provoking_vertex; struct vertex_buffer *VB = ctx->VB; /* which vertex dictates the color when flat shading: */ provoking_vertex = v2; /* * Clipping may introduce new vertices. New vertices will be stored * in the vertex buffer arrays starting with location VB->Free. After * we've rendered the line, these extra vertices can be overwritten. */ VB->Free = VB_MAX; /* Clip against user clipping planes */ if (ctx->Transform.AnyClip) { GLuint orig_v1 = v1, orig_v2 = v2; if (gl_userclip_line( ctx, &v1, &v2 )==0) return; /* Apply projection matrix: clip = Proj * eye */ if (v1!=orig_v1) { TRANSFORM_POINT( VB->Clip[v1], ctx->ProjectionMatrix, VB->Eye[v1] ); } if (v2!=orig_v2) { TRANSFORM_POINT( VB->Clip[v2], ctx->ProjectionMatrix, VB->Eye[v2] ); } } /* Clip against view volume */ if (gl_viewclip_line( ctx, &v1, &v2 )==0) return; /* Transform from clip coords to ndc: ndc = clip / W */ ASSERT( VB->Clip[v1][3] != 0.0 ); ASSERT( VB->Clip[v2][3] != 0.0 ); d = 1.0F / VB->Clip[v1][3]; ndc_x = VB->Clip[v1][0] * d; ndc_y = VB->Clip[v1][1] * d; ndc_z = VB->Clip[v1][2] * d; /* Map ndc coord to window coords. */ VB->Win[v1][0] = MAP_X( ctx, ndc_x ); VB->Win[v1][1] = MAP_Y( ctx, ndc_y ); VB->Win[v1][2] = MAP_Z( ctx, ndc_z ) * DEPTH_SCALE; /* Transform from clip coords to ndc: ndc = clip / W */ d = 1.0F / VB->Clip[v2][3]; ndc_x = VB->Clip[v2][0] * d; ndc_y = VB->Clip[v2][1] * d; ndc_z = VB->Clip[v2][2] * d; /* Map ndc coord to window coords. */ VB->Win[v2][0] = MAP_X( ctx, ndc_x ); VB->Win[v2][1] = MAP_Y( ctx, ndc_y ); VB->Win[v2][2] = MAP_Z( ctx, ndc_z ) * DEPTH_SCALE; START_PROFILE (*ctx->LineFunc)( ctx, v1, v2, provoking_vertex ); END_PROFILE( ctx->LineTime, ctx->LineCount, 1 ) } /* * Compute Z offsets for a polygon with plane defined by (A,B,C,D) * D is not needed. */ static void offset_polygon( GLcontext *ctx, GLfloat a, GLfloat b, GLfloat c ) { GLfloat ac, bc, m; GLfloat offset; if (c<0.001F && c>-0.001F) { /* to prevent underflow problems */ offset = 0.0F; } else { ac = a / c; bc = b / c; if (ac<0.0F) ac = -ac; if (bc<0.0F) bc = -bc; m = MAX2( ac, bc ); /* m = sqrt( ac*ac + bc*bc ); */ offset = m * ctx->Polygon.OffsetFactor + ctx->Polygon.OffsetUnits; } ctx->PointZoffset = ctx->Polygon.OffsetPoint ? offset : 0.0F; ctx->LineZoffset = ctx->Polygon.OffsetLine ? offset : 0.0F; ctx->PolygonZoffset = ctx->Polygon.OffsetFill ? offset : 0.0F; } /* * When glPolygonMode() is used to specify that the front/back rendering * mode for polygons is not GL_FILL we end up calling this function. */ static void unfilled_polygon( GLcontext *ctx, GLuint n, GLuint vlist[], GLuint pv, GLuint facing ) { GLenum mode = facing ? ctx->Polygon.BackMode : ctx->Polygon.FrontMode; struct vertex_buffer *VB = ctx->VB; if (mode==GL_POINT) { GLint i, j; GLboolean edge; if ( ctx->Primitive==GL_TRIANGLES || ctx->Primitive==GL_QUADS || ctx->Primitive==GL_POLYGON) { edge = GL_FALSE; } else { edge = GL_TRUE; } for (i=0;i<n;i++) { j = vlist[i]; if (edge || VB->Edgeflag[j]) { (*ctx->PointsFunc)( ctx, j, j ); } } } else if (mode==GL_LINE) { GLuint i, j0, j1; GLboolean edge; ctx->StippleCounter = 0; if ( ctx->Primitive==GL_TRIANGLES || ctx->Primitive==GL_QUADS || ctx->Primitive==GL_POLYGON) { edge = GL_FALSE; } else { edge = GL_TRUE; } /* draw the edges */ for (i=0;i<n;i++) { j0 = (i==0) ? vlist[n-1] : vlist[i-1]; j1 = vlist[i]; if (edge || VB->Edgeflag[j0]) { START_PROFILE (*ctx->LineFunc)( ctx, j0, j1, pv ); END_PROFILE( ctx->LineTime, ctx->LineCount, 1 ) } } } else { /* Fill the polygon */ GLuint j0, i; j0 = vlist[0]; for (i=2;i<n;i++) { START_PROFILE (*ctx->TriangleFunc)( ctx, j0, vlist[i-1], vlist[i], pv ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } } } /* * Render a polygon in which doesn't have to be clipped. * Input: n - number of vertices * vlist - list of vertices in the polygon. * odd_flag - if non-zero, reverse the orientation of the polygon */ static void render_polygon( GLcontext* ctx, GLuint n, GLuint vlist[], GLuint odd_flag ) { GLuint pv; struct vertex_buffer *VB = ctx->VB; GLint i; /* which vertex dictates the color when flat shading: */ pv = (ctx->Primitive==GL_POLYGON) ? vlist[0] : vlist[n-1]; /* Compute the plane equation of polygon: ax + by + cz = d */ { GLuint j0 = vlist[0]; GLuint j1 = vlist[1]; GLuint j2 = vlist[2]; GLuint j3 = vlist[ (n==3) ? 0 : 3 ]; GLfloat ex = VB->Win[j1][0] - VB->Win[j3][0]; GLfloat ey = VB->Win[j1][1] - VB->Win[j3][1]; GLfloat fx = VB->Win[j2][0] - VB->Win[j0][0]; GLfloat fy = VB->Win[j2][1] - VB->Win[j0][1]; GLfloat c = ex*fy-ey*fx; GLuint facing; /* 0=front, 1=back */ if (c==0.0F) { /* polygon is perpindicular to view plane, don't draw it */ return; } facing = (c<0.0F) ^ odd_flag ^ (ctx->Polygon.FrontFace==GL_CW); if ((facing+1) & ctx->Polygon.CullBits) { return; /* culled */ } if (ctx->Polygon.OffsetAny) { /* finish computing plane equation of polygon, compute offset */ GLfloat ez = VB->Win[j1][2] - VB->Win[j3][2]; GLfloat fz = VB->Win[j2][2] - VB->Win[j0][2]; GLfloat a = ey*fz-ez*fy; GLfloat b = ez*fx-ex*fz; offset_polygon( ctx, a, b, c ); } if (ctx->Light.Model.TwoSide) { if (facing==1 && ctx->Light.Enabled) { /* use back color or index */ VB->Color = VB->Bcolor; VB->Index = VB->Bindex; } else { /* use front color or index */ VB->Color = VB->Fcolor; VB->Index = VB->Findex; } } /* Render the polygon! */ if (ctx->Polygon.Unfilled) { unfilled_polygon( ctx, n, vlist, pv, facing ); } else { /* Draw filled polygon as a triangle fan */ j0 = vlist[0]; for (i=2;i<n;i++) { START_PROFILE (*ctx->TriangleFunc)( ctx, j0, vlist[i-1], vlist[i], pv ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } } } } /* * Render a polygon in which at least one vertex has to be clipped. * Input: n - number of vertices * vlist - list of vertices in the polygon. * odd_flag - if non-zero, reverse the orientation of the polygon */ static void render_clipped_polygon( GLcontext* ctx, GLuint n, GLuint vlist[], GLuint odd_flag ) { GLuint pv; struct vertex_buffer *VB = ctx->VB; GLfloat (*win)[3] = VB->Win; /* which vertex dictates the color when flat shading: */ pv = (ctx->Primitive==GL_POLYGON) ? vlist[0] : vlist[n-1]; /* * Clipping may introduce new vertices. New vertices will be stored * in the vertex buffer arrays starting with location VB->Free. After * we've rendered the polygon, these extra vertices can be overwritten. */ VB->Free = VB_MAX; /* Clip against user clipping planes in eye coord space. */ if (ctx->Transform.AnyClip) { GLfloat *proj = ctx->ProjectionMatrix; GLuint i; n = gl_userclip_polygon( ctx, n, vlist ); if (n<3) return; /* Transform vertices from eye to clip coordinates: clip = Proj * eye */ for (i=0;i<n;i++) { GLuint j = vlist[i]; TRANSFORM_POINT( VB->Clip[j], proj, VB->Eye[j] ); } } /* Clip against view volume in clip coord space */ n = gl_viewclip_polygon( ctx, n, vlist ); if (n<3) return; /* Transform vertices from clip to ndc to window coords. */ /* ndc = clip / W window = viewport_mapping(ndc) */ /* Note that window Z values are scaled to the range of integer */ /* depth buffer values. */ { GLfloat sx = ctx->Viewport.Sx; GLfloat tx = ctx->Viewport.Tx; GLfloat sy = ctx->Viewport.Sy; GLfloat ty = ctx->Viewport.Ty; GLfloat sz = ctx->Viewport.Sz * DEPTH_SCALE; GLfloat tz = ctx->Viewport.Tz * DEPTH_SCALE; GLuint i; for (i=0;i<n;i++) { GLuint j = vlist[i]; GLfloat d; ASSERT( VB->Clip[j][3] != 0.0 ); d = 1.0F / VB->Clip[j][3]; win[j][0] = VB->Clip[j][0] * d * sx + tx; win[j][1] = VB->Clip[j][1] * d * sy + ty; win[j][2] = VB->Clip[j][2] * d * sz + tz; } } /* Compute orientation of polygon, do cull test, offset, etc */ { GLuint j0 = vlist[0]; GLuint j1 = vlist[1]; GLuint j2 = vlist[2]; GLuint j3 = vlist[ (n==3) ? 0 : 3 ]; GLfloat ex = win[j1][0] - win[j3][0]; GLfloat ey = win[j1][1] - win[j3][1]; GLfloat fx = win[j2][0] - win[j0][0]; GLfloat fy = win[j2][1] - win[j0][1]; GLfloat c = ex*fy-ey*fx; GLint i; GLuint facing; /* 0=front, 1=back */ if (c==0.0F) { /* polygon is perpindicular to view plane, don't draw it */ return; } facing = (c<0.0F) ^ odd_flag ^ (ctx->Polygon.FrontFace==GL_CW); if ((facing+1) & ctx->Polygon.CullBits) { return; /* culled */ } if (ctx->Polygon.OffsetAny) { /* finish computing plane equation of polygon, compute offset */ GLfloat ez = win[j1][2] - win[j3][2]; GLfloat fz = win[j2][2] - win[j0][2]; GLfloat a = ey*fz-ez*fy; GLfloat b = ez*fx-ex*fz; offset_polygon( ctx, a, b, c ); } if (ctx->Light.Model.TwoSide) { if (facing==1 && ctx->Light.Enabled) { /* use back color or index */ VB->Color = VB->Bcolor; VB->Index = VB->Bindex; } else { /* use front color or index */ VB->Color = VB->Fcolor; VB->Index = VB->Findex; } } /* Render the polygon! */ if (ctx->Polygon.Unfilled) { unfilled_polygon( ctx, n, vlist, pv, facing ); } else { /* Draw filled polygon as a triangle fan */ j0 = vlist[0]; for (i=2;i<n;i++) { START_PROFILE (*ctx->TriangleFunc)( ctx, j0, vlist[i-1], vlist[i], pv ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } } } } /* * Render an un-clipped triangle. */ static void render_triangle( GLcontext* ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv, GLuint odd_flag ) { struct vertex_buffer *VB = ctx->VB; GLfloat ex, ey, fx, fy, c; GLuint facing; /* 0=front, 1=back */ /* Compute orientation of triangle */ ex = VB->Win[v1][0] - VB->Win[v0][0]; ey = VB->Win[v1][1] - VB->Win[v0][1]; fx = VB->Win[v2][0] - VB->Win[v0][0]; fy = VB->Win[v2][1] - VB->Win[v0][1]; c = ex*fy-ey*fx; if (c==0.0F) { /* polygon is perpindicular to view plane, don't draw it */ return; } facing = (c<0.0F) ^ odd_flag ^ (ctx->Polygon.FrontFace==GL_CW); if ((facing+1) & ctx->Polygon.CullBits) { return; /* culled */ } if (ctx->Polygon.OffsetAny) { /* finish computing plane equation of polygon, compute offset */ GLfloat fz = VB->Win[v2][2] - VB->Win[v0][2]; GLfloat ez = VB->Win[v1][2] - VB->Win[v0][2]; GLfloat a = ey*fz-ez*fy; GLfloat b = ez*fx-ex*fz; offset_polygon( ctx, a, b, c ); } if (ctx->Light.Model.TwoSide) { if (facing==1 && ctx->Light.Enabled) { /* use back color or index */ VB->Color = VB->Bcolor; VB->Index = VB->Bindex; } else { /* use front color or index */ VB->Color = VB->Fcolor; VB->Index = VB->Findex; } } if (ctx->Polygon.Unfilled) { GLuint vlist[3]; vlist[0] = v0; vlist[1] = v1; vlist[2] = v2; unfilled_polygon( ctx, 3, vlist, pv, facing ); } else { START_PROFILE (*ctx->TriangleFunc)( ctx, v0, v1, v2, pv ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } } /* * Render an un-clipped quadrilateral. */ static void render_quad( GLcontext* ctx, GLuint v0, GLuint v1, GLuint v2, GLuint v3, GLuint pv, GLuint odd_flag ) { struct vertex_buffer *VB = ctx->VB; GLfloat ex, ey, fx, fy, c; GLuint facing; /* 0=front, 1=back */ /* Compute polygon orientation */ ex = VB->Win[v2][0] - VB->Win[v0][0]; ey = VB->Win[v2][1] - VB->Win[v0][1]; fx = VB->Win[v3][0] - VB->Win[v1][0]; fy = VB->Win[v3][1] - VB->Win[v1][1]; c = ex*fy-ey*fx; if (c==0.0F) { /* polygon is perpindicular to view plane, don't draw it */ return; } facing = (c<0.0F) ^ odd_flag ^ (ctx->Polygon.FrontFace==GL_CW); if ((facing+1) & ctx->Polygon.CullBits) { return; /* culled */ } if (ctx->Polygon.OffsetAny) { /* finish computing plane equation of polygon, compute offset */ GLfloat ez = VB->Win[v2][2] - VB->Win[v0][2]; GLfloat fz = VB->Win[v3][2] - VB->Win[v1][2]; GLfloat a = ey*fz-ez*fy; GLfloat b = ez*fx-ex*fz; offset_polygon( ctx, a, b, c ); } if (ctx->Light.Model.TwoSide) { if (facing==1 && ctx->Light.Enabled) { /* use back color or index */ VB->Color = VB->Bcolor; VB->Index = VB->Bindex; } else { /* use front color or index */ VB->Color = VB->Fcolor; VB->Index = VB->Findex; } } /* Render the quad! */ if (ctx->Polygon.Unfilled) { GLuint vlist[4]; vlist[0] = v0; vlist[1] = v1; vlist[2] = v2; vlist[3] = v3; unfilled_polygon( ctx, 4, vlist, pv, facing ); } else { START_PROFILE (*ctx->TriangleFunc)( ctx, v0, v1, v3, pv ); (*ctx->TriangleFunc)( ctx, v1, v2, v3, pv ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 ) } } /* * When the vertex buffer is full, we transform/render it. Sometimes we * have to copy the last vertex (or two) to the front of the vertex list * to "continue" the primitive. For example: line or triangle strips. * This function is a helper for that. */ static void copy_vertex( struct vertex_buffer *vb, GLuint dst, GLuint src ) { COPY_3V( vb->Win[dst], vb->Win[src] ); COPY_4V( vb->Eye[dst], vb->Eye[src] ); COPY_4V( vb->Fcolor[dst], vb->Fcolor[src] ); COPY_4V( vb->Bcolor[dst], vb->Bcolor[src] ); COPY_4V( vb->TexCoord[dst], vb->TexCoord[src] ); vb->Findex[dst] = vb->Findex[src]; vb->Bindex[dst] = vb->Bindex[src]; vb->Edgeflag[dst] = vb->Edgeflag[src]; vb->Unclipped[dst] = vb->Unclipped[src]; } /* * Either the vertex buffer is full (VB->Count==VB_MAX) or glEnd() has been * called. Render the primitives defined by the vertices and reset the * buffer. * Input: alldone - GL_TRUE = caller is glEnd() * GL_FALSE = calling because buffer is full. */ static void render_vb( GLcontext* ctx, GLboolean alldone ) { struct vertex_buffer *VB = ctx->VB; GLuint vlist[VB_MAX]; switch (ctx->Primitive) { case GL_POINTS: START_PROFILE (*ctx->PointsFunc)( ctx, 0, VB->Count-1 ); END_PROFILE( ctx->PointTime, ctx->PointCount, VB->Count ) VB->Count = 0; VB->AnyClipped = GL_FALSE; break; case GL_LINES: if (VB->AnyClipped) { GLuint i; for (i=1;i<VB->Count;i+=2) { if (VB->Unclipped[i-1] & VB->Unclipped[i]) { START_PROFILE (*ctx->LineFunc)( ctx, i-1, i, i ); END_PROFILE( ctx->LineTime, ctx->LineCount, 1 ) } else { render_clipped_line( ctx, i-1, i ); } ctx->StippleCounter = 0; } } else { GLuint i; for (i=1;i<VB->Count;i+=2) { START_PROFILE (*ctx->LineFunc)( ctx, i-1, i, i ); END_PROFILE( ctx->LineTime, ctx->LineCount, 1 ) ctx->StippleCounter = 0; } } VB->Count = 0; VB->AnyClipped = GL_FALSE; break; case GL_LINE_STRIP: if (VB->AnyClipped) { GLuint i; for (i=1;i<VB->Count;i++) { if (VB->Unclipped[i-1] & VB->Unclipped[i]) { START_PROFILE (*ctx->LineFunc)( ctx, i-1, i, i ); END_PROFILE( ctx->LineTime, ctx->LineCount, 1 ) } else { render_clipped_line( ctx, i-1, i ); } } } else { /* no clipping needed */ GLuint i; for (i=1;i<VB->Count;i++) { START_PROFILE (*ctx->LineFunc)( ctx, i-1, i, i ); END_PROFILE( ctx->LineTime, ctx->LineCount, 1 ) } } if (!alldone) { copy_vertex( VB, 0, VB->Count-1 ); /* copy last vertex to front */ VB->Count = 1; VB->AnyClipped = VB->Unclipped[0] ? GL_FALSE : GL_TRUE; } break; case GL_LINE_LOOP: { GLuint i; if (VB->Start==0) { i = 1; /* start at 0th vertex */ } else { i = 2; /* skip first vertex, we're saving it until glEnd */ } while (i<VB->Count) { if (VB->Unclipped[i-1] & VB->Unclipped[i]) { START_PROFILE (*ctx->LineFunc)( ctx, i-1, i, i ); END_PROFILE( ctx->LineTime, ctx->LineCount, 1 ) } else { render_clipped_line( ctx, i-1, i ); } i++; } } if (alldone) { if (VB->Unclipped[VB->Count-1] & VB->Unclipped[0]) { START_PROFILE (*ctx->LineFunc)( ctx, VB->Count-1, 0, 0 ); END_PROFILE( ctx->LineTime, ctx->LineCount, 1 ) } else { render_clipped_line( ctx, VB->Count-1, 0 ); } } else { ASSERT(VB->Count==VB_MAX); /* recycle the vertex list */ copy_vertex( VB, 1, VB_MAX-1 ); VB->Count = 2; VB->AnyClipped = !VB->Unclipped[0] || !VB->Unclipped[1]; } break; case GL_TRIANGLES: if (VB->AnyClipped) { GLuint i; for (i=2;i<VB->Count;i+=3) { if (VB->Unclipped[i-2] & VB->Unclipped[i-1] & VB->Unclipped[i]) { if (ctx->DirectTriangles) { START_PROFILE (*ctx->TriangleFunc)( ctx, i-2, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } else { render_triangle( ctx, i-2, i-1, i, i, 0 ); } } else { vlist[0] = i-2; vlist[1] = i-1; vlist[2] = i-0; render_clipped_polygon( ctx, 3, vlist, 0 ); } } } else { /* no clipping needed */ GLuint i; if (ctx->DirectTriangles) { for (i=2;i<VB->Count;i+=3) { START_PROFILE (*ctx->TriangleFunc)( ctx, i-2, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } } else { for (i=2;i<VB->Count;i+=3) { render_triangle( ctx, i-2, i-1, i, i, 0 ); } } } VB->Count = 0; VB->AnyClipped = GL_FALSE; break; case GL_TRIANGLE_STRIP: if (VB->AnyClipped) { GLuint i; for (i=2;i<VB->Count;i++) { if (VB->Unclipped[i-2] & VB->Unclipped[i-1] & VB->Unclipped[i]) { /* TODO: if direct triangle... */ if (ctx->DirectTriangles) { START_PROFILE (*ctx->TriangleFunc)( ctx, i-2, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } else { render_triangle( ctx, i-2, i-1, i, i, i&1 ); } } else { vlist[0] = i-2; vlist[1] = i-1; vlist[2] = i-0; render_clipped_polygon( ctx, 3, vlist, i&1 ); } } } else { /* no vertices were clipped */ GLuint i; if (ctx->DirectTriangles) { for (i=2;i<VB->Count;i++) { START_PROFILE (*ctx->TriangleFunc)( ctx, i-2, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } } else { for (i=2;i<VB->Count;i++) { render_triangle( ctx, i-2, i-1, i, i, i&1 ); } } } if (!alldone) { /* get ready for more vertices in this triangle strip */ copy_vertex( VB, 0, VB_MAX-2 ); copy_vertex( VB, 1, VB_MAX-1 ); VB->Count = 2; VB->AnyClipped = !VB->Unclipped[0] || !VB->Unclipped[1]; } break; case GL_TRIANGLE_FAN: if (VB->AnyClipped) { GLuint i; for (i=2;i<VB->Count;i++) { if (VB->Unclipped[0] & VB->Unclipped[i-1] & VB->Unclipped[i]) { if (ctx->DirectTriangles) { START_PROFILE (*ctx->TriangleFunc)( ctx, 0, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } else { render_triangle( ctx, 0, i-1, i, i, 0 ); } } else { vlist[0] = 0; vlist[1] = i-1; vlist[2] = i; render_clipped_polygon( ctx, 3, vlist, 0 ); } } } else { /* no clipping needed */ GLuint i; if (ctx->DirectTriangles) { for (i=2;i<VB->Count;i++) { START_PROFILE (*ctx->TriangleFunc)( ctx, 0, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 1 ) } } else { for (i=2;i<VB->Count;i++) { render_triangle( ctx, 0, i-1, i, i, 0 ); } } } if (!alldone) { /* get ready for more vertices in this triangle fan */ copy_vertex( VB, 1, VB_MAX-1 ); VB->Count = 2; VB->AnyClipped = !VB->Unclipped[0] || !VB->Unclipped[1]; } break; case GL_QUADS: if (VB->AnyClipped) { GLuint i; for (i=3;i<VB->Count;i+=4) { if ( VB->Unclipped[i-3] & VB->Unclipped[i-2] & VB->Unclipped[i-1] & VB->Unclipped[i]) { if (ctx->DirectTriangles) { START_PROFILE (*ctx->TriangleFunc)( ctx, i-3, i-2, i, i ); (*ctx->TriangleFunc)( ctx, i-2, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 ) } else { render_quad( ctx, i-3, i-2, i-1, i, i, 0 ); } } else { vlist[0] = i-3; vlist[1] = i-2; vlist[2] = i-1; vlist[3] = i-0; render_clipped_polygon( ctx, 4, vlist, 0 ); } } } else { /* no vertices were clipped */ GLuint i; if (ctx->DirectTriangles) { for (i=3;i<VB->Count;i+=4) { START_PROFILE (*ctx->TriangleFunc)( ctx, i-3, i-2, i, i ); (*ctx->TriangleFunc)( ctx, i-2, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 ) } } else { for (i=3;i<VB->Count;i+=4) { render_quad( ctx, i-3, i-2, i-1, i, i, 0 ); } } } VB->Count = 0; VB->AnyClipped = GL_FALSE; break; case GL_QUAD_STRIP: if (VB->AnyClipped) { GLuint i; for (i=3;i<VB->Count;i+=2) { if ( VB->Unclipped[i-2] & VB->Unclipped[i-3] & VB->Unclipped[i-1] & VB->Unclipped[i]) { if (ctx->DirectTriangles) { START_PROFILE (*ctx->TriangleFunc)( ctx, i-2, i-3, i, i ); (*ctx->TriangleFunc)( ctx, i-3, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 ) } else { render_quad( ctx, i-2, i-3, i-1, i, i, 1 ); } } else { vlist[0] = i-2; vlist[1] = i-3; vlist[2] = i-1; vlist[3] = i-0; render_clipped_polygon( ctx, 4, vlist, 1 ); } } } else { /* no clipping needed */ GLuint i; if (ctx->DirectTriangles) { for (i=3;i<VB->Count;i+=2) { START_PROFILE (*ctx->TriangleFunc)( ctx, i-2, i-3, i, i ); (*ctx->TriangleFunc)( ctx, i-3, i-1, i, i ); END_PROFILE( ctx->PolygonTime, ctx->PolygonCount, 2 ) } } else { for (i=3;i<VB->Count;i+=2) { render_quad( ctx, i-2, i-3, i-1, i, i, 1 ); } } } if (!alldone) { /* get ready for more vertices in this quad strip */ copy_vertex( VB, 0, VB_MAX-2 ); copy_vertex( VB, 1, VB_MAX-1 ); VB->Count = 2; VB->AnyClipped = !VB->Unclipped[0] || !VB->Unclipped[1]; } break; case GL_POLYGON: if (VB->Count>2) { GLuint i; for (i=0;i<VB->Count;i++) { vlist[i] = i; } if (VB->AnyClipped) { render_clipped_polygon( ctx, VB->Count, vlist, 0 ); } else { render_polygon( ctx, VB->Count, vlist, 0 ); } } if (!alldone) { /* get ready for more vertices just like a triangle fan */ copy_vertex( VB, 1, VB_MAX-1 ); VB->Count = 2; VB->AnyClipped = !VB->Unclipped[0] || !VB->Unclipped[1]; } break; default: /* should never get here */ abort(); } /* Start = first vertex which hasn't been transformed yet */ VB->Start = VB->Count; } /* * Part 2 of Vertex Buffer transformation: compute lighting, clipflags, * fog, texture coords, etc. Then call render_vb()... * The function is called either by xform_vb_part1() or by glDrawArraysEXT(). */ void gl_transform_vb_part2( GLcontext* ctx, GLboolean alldone ) { struct vertex_buffer *VB = ctx->VB; #ifdef PROFILE GLdouble t0 = gl_time(); #endif ASSERT( VB->Count>0 ); /* Lighting */ if (ctx->Light.Enabled) { if (ctx->Visual->RGBAflag) { if (VB->MaterialChanges) { GLuint i; /* NOTE the <= here. This is needed in case glColor/glMaterial * is called after the last glVertex inside a glBegin/glEnd pair. */ for (i=VB->Start;i<=VB->Count;i++) { update_material( ctx, i ); gl_color_shade_vertices( ctx, 1, &VB->Eye[i], &VB->Normal[i], ctx->LightTwoSide, &VB->Fcolor[i], &VB->Bcolor[i] ); } } else { if (ctx->Light.Fast) { /* call optimized shader */ gl_color_shade_vertices_fast( ctx, VB->Count-VB->Start, VB->Eye + VB->Start, VB->Normal + VB->Start, ctx->LightTwoSide, VB->Fcolor + VB->Start, VB->Bcolor + VB->Start ); } else { /* call full-featured shader */ gl_color_shade_vertices( ctx, VB->Count-VB->Start, VB->Eye + VB->Start, VB->Normal + VB->Start, ctx->LightTwoSide, VB->Fcolor + VB->Start, VB->Bcolor + VB->Start ); } } } else { if (VB->MaterialChanges) { GLuint i; /* NOTE the <= here. This is needed in case glColor/glMaterial * is called after the last glVertex inside a glBegin/glEnd pair. */ for (i=VB->Start;i<=VB->Count;i++) { update_material( ctx, i ); gl_index_shade_vertices( ctx, 1, &VB->Eye[i], &VB->Normal[i], ctx->LightTwoSide, &VB->Findex[i], &VB->Bindex[i] ); } } else { gl_index_shade_vertices( ctx, VB->Count-VB->Start, VB->Eye + VB->Start, VB->Normal + VB->Start, ctx->LightTwoSide, VB->Findex + VB->Start, VB->Bindex + VB->Start ); } } } /* Per-vertex fog */ if (ctx->Fog.Enabled && ctx->Hint.Fog!=GL_NICEST) { if (ctx->Visual->RGBAflag) { /* Fog RGB colors */ gl_fog_color_vertices( ctx, VB->Count - VB->Start, VB->Eye + VB->Start, VB->Fcolor + VB->Start ); if (ctx->LightTwoSide) { gl_fog_color_vertices( ctx, VB->Count - VB->Start, VB->Eye + VB->Start, VB->Bcolor + VB->Start ); } } else { /* Fog color indexes */ gl_fog_index_vertices( ctx, VB->Count - VB->Start, VB->Eye + VB->Start, VB->Findex + VB->Start ); if (ctx->LightTwoSide) { gl_fog_index_vertices( ctx, VB->Count - VB->Start, VB->Eye + VB->Start, VB->Bindex + VB->Start ); } } } /* Compute/transform texture coords */ if (ctx->Texture.Enabled) { GLuint i; for (i=VB->Start;i<VB->Count;i++) { if (ctx->Texture.TexGenEnabled) { gl_do_texgen( ctx, VB->Obj[i], VB->Eye[i], VB->Normal[i], VB->TexCoord[i] ); } if (!ctx->IdentityTexMat) { /* transform current texture coordinate by texture matrix */ /* tc = TexMat * TexCoord */ GLfloat tc[4]; TRANSFORM_POINT( tc, ctx->TextureMatrix, VB->TexCoord[i] ); COPY_4V( VB->TexCoord[i], tc ); } } } /* Initialize clip flags */ MEMSET( VB->Unclipped+VB->Start, GL_TRUE, VB->Count-VB->Start ); if (ctx->Transform.AnyClip) { /* Clip against user-defined clip planes */ GLuint p; for (p=0;p<MAX_CLIP_PLANES;p++) { if (ctx->Transform.ClipEnabled[p]) { GLuint i; GLfloat a = ctx->Transform.ClipEquation[p][0]; GLfloat b = ctx->Transform.ClipEquation[p][1]; GLfloat c = ctx->Transform.ClipEquation[p][2]; GLfloat d = ctx->Transform.ClipEquation[p][3]; for (i=VB->Start;i<VB->Count;i++) { GLfloat dot = VB->Eye[i][0] * a + VB->Eye[i][1] * b + VB->Eye[i][2] * c + VB->Eye[i][3] * d; if (dot < 0.0F) { VB->Unclipped[i] = GL_FALSE; VB->AnyClipped = GL_TRUE; } } } } } /* Transform vertices from eye to clip coords */ /* Even transform clipped vertices because it's usually faster. */ gl_xform_points_4fv( VB->Count-VB->Start, VB->Clip+VB->Start, ctx->ProjectionMatrix, VB->Eye+VB->Start ); /* * Combined clip testing with clip-to-window coordinate mapping. */ { GLfloat sx = ctx->Viewport.Sx; GLfloat tx = ctx->Viewport.Tx; GLfloat sy = ctx->Viewport.Sy; GLfloat ty = ctx->Viewport.Ty; GLfloat sz = ctx->Viewport.Sz * DEPTH_SCALE; GLfloat tz = ctx->Viewport.Tz * DEPTH_SCALE; GLuint i, start = VB->Start, n = VB->Count; for (i=start;i<n;i++) { GLfloat clipx = VB->Clip[i][0], clipy = VB->Clip[i][1]; GLfloat clipz = VB->Clip[i][2], clipw = VB->Clip[i][3]; if (clipx > clipw || clipx < -clipw || clipy > clipw || clipy < -clipw || clipz > clipw || clipz < -clipw ) { /* vertex is clipped */ VB->Unclipped[i] = GL_FALSE; VB->AnyClipped = GL_TRUE; } else { /* vertex not clipped */ GLfloat d = 1.0F / clipw; VB->Win[i][0] = clipx * d * sx + tx; VB->Win[i][1] = clipy * d * sy + ty; VB->Win[i][2] = clipz * d * sz + tz; } } } #ifdef PROFILE ctx->VertexTime += gl_time() - t0; ctx->VertexCount += VB->Count - VB->Start; #endif /* Render the primitives */ render_vb( ctx, alldone ); } /* * When the Vertex Buffer is full, this function transforms all the * vertices and normals then calls xform_vb_part2()... */ void gl_transform_vb_part1( GLcontext* ctx, GLboolean alldone ) { struct vertex_buffer *VB = ctx->VB; #ifdef PROFILE GLdouble t0 = gl_time(); #endif ASSERT( VB->Count>0 ); /* Transform vertexes from object to eye coords */ gl_xform_points_4fv( VB->Count-VB->Start, VB->Eye+VB->Start, ctx->ModelViewMatrix, VB->Obj+VB->Start ); /* Transform normals from object to eye coords */ if (ctx->NeedNormals) { gl_xform_normals_3fv( VB->Count-VB->Start, VB->Normal+VB->Start, ctx->ModelViewInv, VB->Normal+VB->Start, ctx->Transform.Normalize ); } #ifdef PROFILE ctx->VertexTime += gl_time() - t0; #endif gl_transform_vb_part2( ctx, alldone ); } /**********************************************************************/ /**** Vertex functions. These are called via ctx->Exec.Vertex4f() ****/ /**********************************************************************/ /* * Save a glVertex call into a display list AND execute it. */ void gl_save_and_execute_vertex( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { struct vertex_buffer *VB = ctx->VB; GLuint count = VB->Count; /* copy to local var to encourage optimization */ /* Put vertex into display list */ gl_save_Vertex4f( ctx, x, y, z, w ); /* Exectue vertex command */ ASSIGN_4V( VB->Obj[count], x, y, z, w ); if (ctx->Visual->RGBAflag) { if (ctx->Light.Enabled) { /* need normal vector, vertex color is computed from material */ COPY_3V( VB->Normal[count], ctx->Current.Normal ); } else { /* not lighting, need vertex color */ GLint shift = ctx->ColorShift; VB->Fcolor[count][0] = ctx->Current.IntColor[0] << shift; VB->Fcolor[count][1] = ctx->Current.IntColor[1] << shift; VB->Fcolor[count][2] = ctx->Current.IntColor[2] << shift; VB->Fcolor[count][3] = ctx->Current.IntColor[3] << shift; } if (ctx->Texture.Enabled) { COPY_4V( VB->TexCoord[count], ctx->Current.TexCoord ); } } else { if (ctx->Light.Enabled) { /* need normal vector, vertex color index computed from material*/ COPY_3V( VB->Normal[count], ctx->Current.Normal ); } else { /* not lighting, new vertex color index */ VB->Findex[count] = ctx->Current.Index; } } VB->Edgeflag[count] = ctx->Current.EdgeFlag; count++; VB->Count = count; if (count==VB_MAX) { gl_transform_vb_part1( ctx, GL_FALSE ); } } /* RGB, lit, textured vertex */ static void vertex_normal_texture( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { struct vertex_buffer *VB = ctx->VB; GLuint count = VB->Count; ASSIGN_4V( VB->Obj[count], x, y, z, w ); COPY_3V( VB->Normal[count], ctx->Current.Normal ); COPY_4V( VB->TexCoord[count], ctx->Current.TexCoord ); VB->Edgeflag[count] = ctx->Current.EdgeFlag; count++; VB->Count = count; if (count==VB_MAX) { gl_transform_vb_part1( ctx, GL_FALSE ); } } /* RGB or CI, lit, untextured vertex */ static void vertex_normal( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { struct vertex_buffer *VB = ctx->VB; GLuint count = VB->Count; ASSIGN_4V( VB->Obj[count], x, y, z, w ); COPY_3V( VB->Normal[count], ctx->Current.Normal ); VB->Edgeflag[count] = ctx->Current.EdgeFlag; count++; VB->Count = count; if (count==VB_MAX) { gl_transform_vb_part1( ctx, GL_FALSE ); } } /* RGB, unlit, textured vertex */ static void vertex_texture( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { struct vertex_buffer *VB = ctx->VB; GLuint count = VB->Count; GLint shift = ctx->ColorShift; ASSIGN_4V( VB->Obj[count], x, y, z, w ); VB->Fcolor[count][0] = ctx->Current.IntColor[0] << shift; VB->Fcolor[count][1] = ctx->Current.IntColor[1] << shift; VB->Fcolor[count][2] = ctx->Current.IntColor[2] << shift; VB->Fcolor[count][3] = ctx->Current.IntColor[3] << shift; COPY_4V( VB->TexCoord[count], ctx->Current.TexCoord ); VB->Edgeflag[count] = ctx->Current.EdgeFlag; count++; VB->Count = count; if (count==VB_MAX) { gl_transform_vb_part1( ctx, GL_FALSE ); } } /* RGB, unlit, untextured vertex */ static void vertex_color( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { struct vertex_buffer *VB = ctx->VB; GLuint count = VB->Count; GLint shift = ctx->ColorShift; ASSIGN_4V( VB->Obj[count], x, y, z, w ); VB->Fcolor[count][0] = ctx->Current.IntColor[0] << shift; VB->Fcolor[count][1] = ctx->Current.IntColor[1] << shift; VB->Fcolor[count][2] = ctx->Current.IntColor[2] << shift; VB->Fcolor[count][3] = ctx->Current.IntColor[3] << shift; VB->Edgeflag[count] = ctx->Current.EdgeFlag; count++; VB->Count = count; if (count==VB_MAX) { gl_transform_vb_part1( ctx, GL_FALSE ); } } /* CI, unlit vertex */ static void vertex_index( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { struct vertex_buffer *VB = ctx->VB; GLuint count = VB->Count; ASSIGN_4V( VB->Obj[count], x, y, z, w ); VB->Findex[count] = ctx->Current.Index; VB->Edgeflag[count] = ctx->Current.EdgeFlag; count++; VB->Count = count; if (count==VB_MAX) { gl_transform_vb_part1( ctx, GL_FALSE ); } } /* * Called when outside glBegin/glEnd, raises an error. */ void gl_nop_vertex( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { gl_error( ctx, GL_INVALID_OPERATION, "glVertex" ); } /* * This function examines the current GL state and sets the * ctx->Exec.Vertex4f pointer to point at the appropriate vertex function. */ void gl_set_vertex_function( GLcontext* ctx ) { ASSERT( !INSIDE_BEGIN_END(ctx) ); if (ctx->Visual->RGBAflag) { if (ctx->Light.Enabled) { if (ctx->Texture.Enabled) { ctx->Exec.Vertex4f = vertex_normal_texture; } else { ctx->Exec.Vertex4f = vertex_normal; } } else { /* not lighting, need vertex color */ if (ctx->Texture.Enabled) { ctx->Exec.Vertex4f = vertex_texture; } else { ctx->Exec.Vertex4f = vertex_color; } } } else { if (ctx->Light.Enabled) { ctx->Exec.Vertex4f = vertex_normal; } else { ctx->Exec.Vertex4f = vertex_index; } } if (!ctx->CompileFlag) { ctx->API.Vertex4f = ctx->Exec.Vertex4f; } } /* * Process a vertex produced by an evaluator. * Input: vertex - the X,Y,Z,W vertex * normal - normal vector * color - 4 integer color components * index - color index * texcoord - texture coordinate */ void gl_eval_vertex( GLcontext* ctx, const GLfloat vertex[4], const GLfloat normal[3], const GLint color[4], GLuint index, const GLfloat texcoord[4] ) { struct vertex_buffer *VB = ctx->VB; GLuint count = VB->Count; /* copy to local var to encourage optimization */ GLint shift = ctx->ColorShift; COPY_4V( VB->Obj[count], vertex ); COPY_3V( VB->Normal[count], normal ); VB->Fcolor[count][0] = color[0] << shift; VB->Fcolor[count][1] = color[1] << shift; VB->Fcolor[count][2] = color[2] << shift; VB->Fcolor[count][3] = color[3] << shift; #ifdef GL_VERSION_1_1 if (ctx->Light.ColorMaterialEnabled && (ctx->Eval.Map1Color4 || ctx->Eval.Map1Color4)) { GLfloat fcolor[4]; fcolor[0] = color[0] * ctx->Visual->InvRedScale; fcolor[1] = color[1] * ctx->Visual->InvGreenScale; fcolor[2] = color[2] * ctx->Visual->InvBlueScale; fcolor[3] = color[3] * ctx->Visual->InvAlphaScale; gl_Materialfv( ctx, ctx->Light.ColorMaterialFace, ctx->Light.ColorMaterialMode, fcolor ); } #endif VB->Findex[count] = index; COPY_4V( VB->TexCoord[count], texcoord ); VB->Edgeflag[count] = ctx->Current.EdgeFlag; count++; VB->Count = count; if (count==VB_MAX) { gl_transform_vb_part1( ctx, GL_FALSE ); } } void gl_RasterPos4f( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { GLfloat v[4], eye[4], clip[4], ndc[3], d; v[0] = x; v[1] = y; v[2] = z; v[3] = w; /* transform v to eye coords: eye = ModelView * v */ TRANSFORM_POINT( eye, ctx->ModelViewMatrix, v ); /* raster color */ if (ctx->Light.Enabled) { GLfloat eyenorm[3]; if (!ctx->ModelViewInvValid) { gl_compute_modelview_inverse(ctx); } TRANSFORM_NORMAL( eyenorm[0], eyenorm[1], eyenorm[2], ctx->Current.Normal, ctx->ModelViewInv ); ctx->ColorShift = 0; /* Colors only shifted when smooth shading */ if (ctx->Visual->RGBAflag) { GLfixed color[4]; /* not really fixed point but integers */ GLfixed bcolor[4]; /* not used, dummy arg */ gl_color_shade_vertices( ctx, 1, &eye, &eyenorm, 0, &color, &bcolor ); ctx->Current.RasterColor[0] = color[0] * ctx->Visual->InvRedScale; ctx->Current.RasterColor[1] = color[1] * ctx->Visual->InvGreenScale; ctx->Current.RasterColor[2] = color[2] * ctx->Visual->InvBlueScale; ctx->Current.RasterColor[3] = color[3] * ctx->Visual->InvAlphaScale; } else { GLuint dummy; gl_index_shade_vertices( ctx, 1, &eye, &eyenorm, 0, &ctx->Current.RasterIndex, &dummy ); } } else { /* use current color or index */ if (ctx->Visual->RGBAflag) { ctx->Current.RasterColor[0] = ctx->Current.IntColor[0] * ctx->Visual->InvRedScale; ctx->Current.RasterColor[1] = ctx->Current.IntColor[1] * ctx->Visual->InvGreenScale; ctx->Current.RasterColor[2] = ctx->Current.IntColor[2] * ctx->Visual->InvBlueScale; ctx->Current.RasterColor[3] = ctx->Current.IntColor[3] * ctx->Visual->InvAlphaScale; } else { ctx->Current.RasterIndex = ctx->Current.Index; } } /* clip to user clipping planes */ if (gl_userclip_point(ctx, eye)==0) { ctx->Current.RasterPosValid = GL_FALSE; return; } /* compute raster distance */ ctx->Current.RasterDistance = (GLfloat) sqrt( eye[0]*eye[0] + eye[1]*eye[1] + eye[2]*eye[2] ); /* apply projection matrix: clip = Proj * eye */ TRANSFORM_POINT( clip, ctx->ProjectionMatrix, eye ); /* clip to view volume */ if (gl_viewclip_point( clip )==0) { ctx->Current.RasterPosValid = GL_FALSE; return; } /* ndc = clip / W */ ASSERT( clip[3]!=0.0 ); d = 1.0F / clip[3]; ndc[0] = clip[0] * d; ndc[1] = clip[1] * d; ndc[2] = clip[2] * d; ctx->Current.RasterPos[0] = ndc[0] * ctx->Viewport.Sx + ctx->Viewport.Tx; ctx->Current.RasterPos[1] = ndc[1] * ctx->Viewport.Sy + ctx->Viewport.Ty; ctx->Current.RasterPos[2] = ndc[2] * ctx->Viewport.Sz + ctx->Viewport.Tz; ctx->Current.RasterPos[3] = clip[3]; ctx->Current.RasterPosValid = GL_TRUE; /* FOG??? */ if (ctx->Texture.Enabled) { COPY_4V( ctx->Current.RasterTexCoord, ctx->Current.TexCoord ); } if (ctx->RenderMode==GL_SELECT) { gl_update_hitflag( ctx, ctx->Current.RasterPos[2] ); } } void gl_windowpos( GLcontext* ctx, GLfloat x, GLfloat y, GLfloat z, GLfloat w ) { /* set raster position */ ctx->Current.RasterPos[0] = x; ctx->Current.RasterPos[1] = y; ctx->Current.RasterPos[2] = CLAMP( z, 0.0F, 1.0F ); ctx->Current.RasterPos[3] = w; ctx->Current.RasterPosValid = GL_TRUE; /* raster color */ if (ctx->Light.Enabled) { GLfloat eye[4]; GLfloat eyenorm[3]; COPY_4V( eye, ctx->Current.RasterPos ); if (!ctx->ModelViewInvValid) { gl_compute_modelview_inverse(ctx); } TRANSFORM_NORMAL( eyenorm[0], eyenorm[1], eyenorm[2], ctx->Current.Normal, ctx->ModelViewInv ); ctx->ColorShift = 0; /* Colors only shifted when smooth shading */ if (ctx->Visual->RGBAflag) { GLfixed color[4]; /* not really fixed point but integers */ GLfixed bcolor[4]; /* not used, dummy arg */ gl_color_shade_vertices( ctx, 1, &eye, &eyenorm, 0, &color, &bcolor ); ctx->Current.RasterColor[0] = (GLfloat) color[0] * ctx->Visual->InvRedScale; ctx->Current.RasterColor[1] = (GLfloat) color[1] * ctx->Visual->InvGreenScale; ctx->Current.RasterColor[2] = (GLfloat) color[2] * ctx->Visual->InvBlueScale; ctx->Current.RasterColor[3] = (GLfloat) color[3] * ctx->Visual->InvAlphaScale; } else { GLuint dummy; gl_index_shade_vertices( ctx, 1, &eye, &eyenorm, 0, &ctx->Current.RasterIndex, &dummy ); } } else { /* use current color or index */ if (ctx->Visual->RGBAflag) { ctx->Current.RasterColor[0] = ctx->Current.IntColor[0] * ctx->Visual->InvRedScale; ctx->Current.RasterColor[1] = ctx->Current.IntColor[1] * ctx->Visual->InvGreenScale; ctx->Current.RasterColor[2] = ctx->Current.IntColor[2] * ctx->Visual->InvBlueScale; ctx->Current.RasterColor[3] = ctx->Current.IntColor[3] * ctx->Visual->InvAlphaScale; } else { ctx->Current.RasterIndex = ctx->Current.Index; } } ctx->Current.RasterDistance = 0.0; if (ctx->Texture.Enabled) { COPY_4V( ctx->Current.RasterTexCoord, ctx->Current.TexCoord ); } if (ctx->RenderMode==GL_SELECT) { gl_update_hitflag( ctx, ctx->Current.RasterPos[2] ); } } #ifdef PROFILE static GLdouble begin_time; #endif void gl_Begin( GLcontext* ctx, GLenum p ) { struct vertex_buffer *VB = ctx->VB; struct pixel_buffer *PB = ctx->PB; #ifdef PROFILE begin_time = gl_time(); #endif if (!ctx->ModelViewInvValid) { gl_compute_modelview_inverse(ctx); } if (ctx->NewState) { gl_update_state(ctx); } else if (ctx->Exec.Vertex4f==gl_nop_vertex) { gl_set_vertex_function(ctx); } if (ctx->Driver.Begin) { (*ctx->Driver.Begin)( ctx, p ); } ctx->Primitive = p; VB->Start = VB->Count = 0; VB->AnyClipped = GL_FALSE; VB->MonoColor = ctx->MonoPixels; if (VB->MonoColor) { /* All pixels generated are likely to be the same color so have * the device driver set the "monocolor" now. */ if (ctx->Visual->RGBAflag) { GLubyte r = ctx->Current.IntColor[0]; GLubyte g = ctx->Current.IntColor[1]; GLubyte b = ctx->Current.IntColor[2]; GLubyte a = ctx->Current.IntColor[3]; (*ctx->Driver.Color)( ctx, r, g, b, a ); } else { (*ctx->Driver.Index)( ctx, ctx->Current.Index ); } } /* * If flat shading, save integer vertex colors * else, save fixed-point (scaled) vertex colors */ ctx->ColorShift = (ctx->Light.ShadeModel==GL_FLAT) ? 0 : FIXED_SHIFT; /* By default use front color/index. Two-sided lighting may override. */ VB->Color = VB->Fcolor; VB->Index = VB->Findex; switch (ctx->Primitive) { case GL_POINTS: ctx->LightTwoSide = 0; PB_INIT( PB, GL_POINT ); break; case GL_LINES: case GL_LINE_STRIP: case GL_LINE_LOOP: ctx->LightTwoSide = 0; ctx->StippleCounter = 0; PB_INIT( PB, GL_LINE ); break; case GL_TRIANGLES: case GL_TRIANGLE_STRIP: case GL_TRIANGLE_FAN: case GL_QUADS: case GL_QUAD_STRIP: case GL_POLYGON: ctx->LightTwoSide = (GLuint) ctx->Light.Model.TwoSide; PB_INIT( PB, GL_POLYGON ); break; default: gl_error( ctx, GL_INVALID_ENUM, "glBegin" ); ctx->Primitive = GL_BITMAP; } } void gl_End( GLcontext* ctx ) { struct pixel_buffer *PB = ctx->PB; struct vertex_buffer *VB = ctx->VB; if (ctx->Primitive==GL_BITMAP) { /* glEnd without glBegin */ gl_error( ctx, GL_INVALID_OPERATION, "glEnd" ); return; } if (VB->Count>VB->Start) { gl_transform_vb_part1( ctx, GL_TRUE ); } if (PB->count>0) { gl_flush_pb(ctx); } PB->primitive = ctx->Primitive = GL_BITMAP; /* Default mode */ VB->MaterialChanges = GL_FALSE; if (ctx->Driver.End) { (*ctx->Driver.End)(ctx); } #ifdef PROFILE ctx->BeginEndTime += gl_time() - begin_time; ctx->BeginEndCount++; #endif }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.