From 5df82c82bd53db90eb72c5aad4dd20cf6f1116b1 Mon Sep 17 00:00:00 2001 From: Brian Paul Date: Fri, 22 Aug 2003 20:11:43 +0000 Subject: patch to import Jon Smirl's work from Bitkeeper --- src/mesa/drivers/dri/radeon/radeon_subset_select.c | 998 +++++++++++++++++++++ 1 file changed, 998 insertions(+) create mode 100644 src/mesa/drivers/dri/radeon/radeon_subset_select.c (limited to 'src/mesa/drivers/dri/radeon/radeon_subset_select.c') diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_select.c b/src/mesa/drivers/dri/radeon/radeon_subset_select.c new file mode 100644 index 0000000000..bd5003ffe5 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_subset_select.c @@ -0,0 +1,998 @@ +/** + * \file radeon_subset_select.c + * \brief Selection. + */ + +/* + * Mesa 3-D graphics library + * Version: 4.1 + * + * Copyright (C) 1999-2002 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* $Id: radeon_subset_select.c,v 1.2 2003/08/22 20:11:45 brianp Exp $ */ + + +#include "glheader.h" +#include "imports.h" +#include "context.h" +/*#include "mmath.h"*/ +#include "mtypes.h" +#include "enums.h" +#include "glapi.h" +#include "feedback.h" + +#include "radeon_context.h" +#include "radeon_subset.h" + +/** + * \brief Vertex. + */ +typedef struct { + struct { GLfloat x, y, z, w; } pos; /**< \brief position */ + struct { GLfloat x, y, z, w; } eyePos; /**< \brief position, eye coordinates */ + struct { GLfloat x, y, z, w; } clipPos; /**< \brief clipped coordinates */ + struct { GLfloat x, y, z, w; } winPos; /**< \brief position, windows coordinates */ + struct { GLfloat s, t; } texCoord; /**< \brief texture coordinates */ + struct { GLfloat r, g, b, a; } color; /**< \brief color */ +} vertex; + + +/** + * \brief Vertex buffer. + */ +static struct select_vb_t { + GLuint vCount; /**< \brief vertex count */ + vertex vBuffer[4]; /**< \brief vertex buffer */ + GLboolean lineReset; + GLboolean partialLineLoop; /**< \brief whether we are in a middle of a line loop */ +} vb; + + + + +/**********************************************************************/ +/** \name Vertex Transformation and Clipping */ +/**********************************************************************/ +/*@{*/ + +/** + * \brief Transform a point (column vector) by a matrix: Q = M * P. + * + * \param Q destination point. + * \param P source point. + * \param M transformation matrix. + */ +#define TRANSFORM_POINT( Q, M, P ) \ + Q.x = M[0] * P.x + M[4] * P.y + M[8] * P.z + M[12] * P.w; \ + Q.y = M[1] * P.x + M[5] * P.y + M[9] * P.z + M[13] * P.w; \ + Q.z = M[2] * P.x + M[6] * P.y + M[10] * P.z + M[14] * P.w; \ + Q.w = M[3] * P.x + M[7] * P.y + M[11] * P.z + M[15] * P.w; + +/** + * \brief Clip coord to window coord mapping. + * + * \param Q destination point. + * \param P source point. + * \param VP view port. + */ +#define MAP_POINT( Q, P, VP ) \ + Q.x = (GLfloat) (((P.x / P.w) + 1.0) * VP.Width / 2.0 + VP.X); \ + Q.y = (GLfloat) (((P.y / P.w) + 1.0) * VP.Height / 2.0 + VP.Y); \ + Q.z = (GLfloat) (((P.z / P.w) + 1.0) * (VP.Far - VP.Near) / 2.0 + VP.Near);\ + Q.w = (GLfloat) P.w; + + +/** + * \brief Linear interpolation: (1 - T) * A + T * B. + * + * \param T interpolation factor. + * \param A first value. + * \param B second value. + * \result interpolated value. + */ +#define INTERPOLATE(T, A, B) ((A) + ((B) - (A)) * (T)) + + + +/** + * \brief Interpolate vertex position, color, texcoords, etc. + * + * \param t interpolation factor. + * \param v0 first vertex. + * \param v1 second vertex. + * \param vOut output vertex. + * + * Uses the #INTERPOLATE macro for all the interpolation of all elements. + */ +static void +interpolate_vertex(GLfloat t, const vertex *v0, const vertex *v1, + vertex *vOut) +{ + vOut->eyePos.x = INTERPOLATE(t, v0->eyePos.x, v1->eyePos.x); + vOut->eyePos.y = INTERPOLATE(t, v0->eyePos.y, v1->eyePos.y); + vOut->eyePos.z = INTERPOLATE(t, v0->eyePos.z, v1->eyePos.z); + vOut->eyePos.w = INTERPOLATE(t, v0->eyePos.w, v1->eyePos.w); + + vOut->clipPos.x = INTERPOLATE(t, v0->clipPos.x, v1->clipPos.x); + vOut->clipPos.y = INTERPOLATE(t, v0->clipPos.y, v1->clipPos.y); + vOut->clipPos.z = INTERPOLATE(t, v0->clipPos.z, v1->clipPos.z); + vOut->clipPos.w = INTERPOLATE(t, v0->clipPos.w, v1->clipPos.w); + + vOut->color.r = INTERPOLATE(t, v0->color.r, v1->color.r); + vOut->color.g = INTERPOLATE(t, v0->color.g, v1->color.g); + vOut->color.b = INTERPOLATE(t, v0->color.b, v1->color.b); + vOut->color.a = INTERPOLATE(t, v0->color.a, v1->color.a); + + vOut->texCoord.s = INTERPOLATE(t, v0->texCoord.s, v1->texCoord.s); + vOut->texCoord.t = INTERPOLATE(t, v0->texCoord.t, v1->texCoord.t); +} + + + + +/* + * Clip bit codes + */ +#define CLIP_LEFT 1 +#define CLIP_RIGHT 2 +#define CLIP_BOTTOM 4 +#define CLIP_TOP 8 +#define CLIP_NEAR 16 +#define CLIP_FAR 32 + + +/** + * \brief Apply view volume clip testing to a point. + * + * \param v point to test. + * \return zero if visible, or the clip code mask, i.e., binary OR of a + * combination of the #CLIP_LEFT, #CLIP_RIGHT, #CLIP_BOTTOM, #CLIP_TOP, #CLIP_NEAR, + * #CLIP_FAR clip bit codes. + */ +static GLuint +clip_point(const vertex *v) +{ + GLuint mask = 0; + if (v->clipPos.x > v->clipPos.w) mask |= CLIP_RIGHT; + if (v->clipPos.x < -v->clipPos.w) mask |= CLIP_LEFT; + if (v->clipPos.y > v->clipPos.w) mask |= CLIP_TOP; + if (v->clipPos.y < -v->clipPos.w) mask |= CLIP_BOTTOM; + if (v->clipPos.z > v->clipPos.w) mask |= CLIP_FAR; + if (v->clipPos.z < -v->clipPos.w) mask |= CLIP_NEAR; + return mask; +} + + +/** + * \def GENERAL_CLIP + * \brief Clipping utility macro. + * + * We use 6 instances of this code in each of the clip_line() and + * clip_polygon() to clip against the 6 planes. For each plane, we define the + * #OUTSIDE and #COMPUTE_INTERSECTION macros appropriately. + */ + + +/** + * \brief Apply clipping to a line segment. + * + * \param v0in input start vertex + * \param v1in input end vertesx + * \param v0new output start vertex + * \param v1new output end vertex + * + * \return GL_TRUE if the line segment is visible, or GL_FALSE if it is totally + * clipped. + * + * \sa #GENERAL_CLIP. + */ +static GLboolean +clip_line(const vertex *v0in, const vertex *v1in, + vertex *v0new, vertex *v1new) +{ + vertex v0, v1, vNew; + GLfloat dx, dy, dz, dw, t; + GLuint code0, code1; + + code0 = clip_point(v0in); + code1 = clip_point(v1in); + if (code0 & code1) + return GL_FALSE; /* totally clipped */ + + *v0new = *v0in; + *v1new = *v1in; + if (code0 == 0 && code1 == 0) + return GL_TRUE; /* no clipping needed */ + + v0 = *v0in; + v1 = *v1in; + + +#define GENERAL_CLIP \ + if (OUTSIDE(v0)) { \ + if (OUTSIDE(v1)) { \ + /* both verts are outside ==> return 0 */ \ + return 0; \ + } \ + else { \ + /* v0 is outside, v1 is inside ==> clip */ \ + COMPUTE_INTERSECTION( v1, v0, vNew ) \ + interpolate_vertex(t, &v1, &v0, &vNew); \ + v0 = vNew; \ + } \ + } \ + else { \ + if (OUTSIDE(v1)) { \ + /* v0 is inside, v1 is outside ==> clip */ \ + COMPUTE_INTERSECTION( v0, v1, vNew ) \ + interpolate_vertex(t, &v0, &v1, &vNew); \ + v1 = vNew; \ + } \ + /* else both verts are inside ==> do nothing */ \ + } + + /* Clip against +X side */ +#define OUTSIDE(V) (V.clipPos.x > V.clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dx = OUT.clipPos.x - IN.clipPos.x; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = (IN.clipPos.x - IN.clipPos.w) / (dw-dx); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against -X side */ +#define OUTSIDE(V) (V.clipPos.x < -(V.clipPos.w)) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dx = OUT.clipPos.x - IN.clipPos.x; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = -(IN.clipPos.x + IN.clipPos.w) / (dw+dx); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against +Y side */ +#define OUTSIDE(V) (V.clipPos.y > V.clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dy = OUT.clipPos.y - IN.clipPos.y; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = (IN.clipPos.y - IN.clipPos.w) / (dw-dy); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against -Y side */ +#define OUTSIDE(V) (V.clipPos.y < -(V.clipPos.w)) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dy = OUT.clipPos.y - IN.clipPos.y; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = -(IN.clipPos.y + IN.clipPos.w) / (dw+dy); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against +Z side */ +#define OUTSIDE(V) (V.clipPos.z > V.clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dz = OUT.clipPos.z - IN.clipPos.z; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = (IN.clipPos.z - IN.clipPos.w) / (dw-dz); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against -Z side */ +#define OUTSIDE(V) (V.clipPos.z < -(V.clipPos.w)) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dz = OUT.clipPos.z - IN.clipPos.z; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = -(IN.clipPos.z + IN.clipPos.w) / (dw+dz); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + +#undef GENERAL_CLIP + + *v0new = v0; + *v1new = v1; + return GL_TRUE; +} + + + +/** + * \brief Apply clipping to a polygon. + * + * \param vIn array of input vertices. + * \param inCount number of input vertices + * \param vOut array of output vertices. + * + * \return number of vertices in \p vOut. + * + * \sa #GENERAL_CLIP. + */ +static GLuint +clip_polygon(const vertex *vIn, unsigned int inCount, vertex *vOut) +{ + vertex inlist[20], outlist[20]; + GLfloat dx, dy, dz, dw, t; + GLuint incount, outcount, previ, curri, result; + const vertex *currVert, *prevVert; + vertex *newVert; + + +#define GENERAL_CLIP(INCOUNT, INLIST, OUTCOUNT, OUTLIST) \ + if (INCOUNT < 3) \ + return GL_FALSE; \ + previ = INCOUNT - 1; /* let previous = last vertex */ \ + prevVert = INLIST + previ; \ + OUTCOUNT = 0; \ + for (curri = 0; curri < INCOUNT; curri++) { \ + currVert = INLIST + curri; \ + if (INSIDE(currVert)) { \ + if (INSIDE(prevVert)) { \ + /* both verts are inside ==> copy current to outlist */ \ + OUTLIST[OUTCOUNT] = *currVert; \ + OUTCOUNT++; \ + } \ + else { \ + newVert = OUTLIST + OUTCOUNT; \ + /* current is inside and previous is outside ==> clip */ \ + COMPUTE_INTERSECTION( currVert, prevVert, newVert ) \ + OUTCOUNT++; \ + /* Output current */ \ + OUTLIST[OUTCOUNT] = *currVert; \ + OUTCOUNT++; \ + } \ + } \ + else { \ + if (INSIDE(prevVert)) { \ + newVert = OUTLIST + OUTCOUNT; \ + /* current is outside and previous is inside ==> clip */ \ + COMPUTE_INTERSECTION( prevVert, currVert, newVert ); \ + OUTLIST[OUTCOUNT] = *newVert; \ + OUTCOUNT++; \ + } \ + /* else both verts are outside ==> do nothing */ \ + } \ + /* let previous = current */ \ + previ = curri; \ + prevVert = currVert; \ + } + +/* + * Clip against +X + */ +#define INSIDE(V) (V->clipPos.x <= V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dx = OUT->clipPos.x - IN->clipPos.x; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = (IN->clipPos.x - IN->clipPos.w) / (dw - dx); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(inCount, vIn, outcount, outlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against -X + */ +#define INSIDE(V) (V->clipPos.x >= -V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dx = OUT->clipPos.x - IN->clipPos.x; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = -(IN->clipPos.x + IN->clipPos.w) / (dw + dx); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(outcount, outlist, incount, inlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against +Y + */ +#define INSIDE(V) (V->clipPos.y <= V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dy = OUT->clipPos.y - IN->clipPos.y; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = (IN->clipPos.y - IN->clipPos.w) / (dw - dy); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(incount, inlist, outcount, outlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against -Y + */ +#define INSIDE(V) (V->clipPos.y >= -V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dy = OUT->clipPos.y - IN->clipPos.y; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = -(IN->clipPos.y + IN->clipPos.w) / (dw + dy); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(outcount, outlist, incount, inlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against +Z + */ +#define INSIDE(V) (V->clipPos.z <= V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dz = OUT->clipPos.z - IN->clipPos.z; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = (IN->clipPos.z - IN->clipPos.w) / (dw - dz); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(incount, inlist, outcount, outlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against -Z + */ +#define INSIDE(V) (V->clipPos.z >= -V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dz = OUT->clipPos.z - IN->clipPos.z; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = -(IN->clipPos.z + IN->clipPos.w) / (dw + dz); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(outcount, outlist, result, vOut) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +#undef GENERAL_CLIP + + return result; +} + +/*@}*/ + + + +/**********************************************************************/ +/** \name Selection */ +/**********************************************************************/ +/*@{*/ + +/** + * \brief Select point. + * + * \param v vertex. + * + * If the clipped point is visible then maps the vertex into window coordinates + * and calls _mesa_update_hitflag(). + */ +static void +select_point(const vertex *v) +{ + GET_CURRENT_CONTEXT(ctx); + if (clip_point(v) == 0) + { + vertex c = *v; + MAP_POINT(c.winPos, c.clipPos, ctx->Viewport); + _mesa_update_hitflag(ctx, c.winPos.z); + } +} + +/** + * \brief Select line. + * + * \param v0 first vertex. + * \param v1 second vertex. + * + * If the clipped line is visible then maps the vertices into window coordinates + * and calls _mesa_update_hitflag(). + */ +static void +select_line(const vertex *v0, const vertex *v1) +{ + GET_CURRENT_CONTEXT(ctx); + vertex c0, c1; + if (clip_line(v0, v1, &c0, &c1)) + { + MAP_POINT(c0.winPos, c0.clipPos, ctx->Viewport); + MAP_POINT(c1.winPos, c1.clipPos, ctx->Viewport); + _mesa_update_hitflag(ctx, c0.winPos.z); + _mesa_update_hitflag(ctx, c1.winPos.z); + } +} + +/** + * \brief Select line. + * + * \param v0 first vertex. + * \param v1 second vertex. + * \param v2 third vertex. + * + * If the clipped polygon is visible then maps the vertices into window + * coordinates and calls _mesa_update_hitflag(). + */ +static void +select_triangle(const vertex *v0, + const vertex *v1, + const vertex *v2) +{ + GET_CURRENT_CONTEXT(ctx); + vertex vlist[3], vclipped[8]; + GLuint i, n; + + vlist[0] = *v0; + vlist[1] = *v1; + vlist[2] = *v2; + n = clip_polygon(vlist, 3, vclipped); + for (i = 0; i < n; i++) { + MAP_POINT(vclipped[i].winPos, vclipped[i].clipPos, ctx->Viewport); + _mesa_update_hitflag(ctx, vclipped[i].winPos.z); + } +} + +/** + * \brief Set current vertex coordinates. + * + * \param x x vertex coordinate. + * \param y y vertex coordinate. + * \param z z vertex coordinate. + * \param w homogeneous coordinate. + * + * Stores the vertex and current attributes in ::vb, transforms it into eye space and then clip space. + * + * If a sufficient number of vertices is stored calls one of select_point(), + * select_line() or select_triangle(), according to the current primitive. + */ +static void +radeon_select_Vertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_polygon_attrib *p = &(ctx->Polygon); + vertex *v = vb.vBuffer + vb.vCount; + + /* store the vertex */ + v->pos.x = x; + v->pos.y = y; + v->pos.z = z; + v->pos.w = w; + v->color.r = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0]; + v->color.g = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1]; + v->color.b = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2]; + v->color.a = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]; + v->texCoord.s = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0]; + v->texCoord.t = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1]; + + /* transform to eye space, then clip space */ + TRANSFORM_POINT(v->eyePos, ctx->ModelviewMatrixStack.Top->m, v->pos); + TRANSFORM_POINT(v->clipPos, ctx->ProjectionMatrixStack.Top->m, v->eyePos); + + switch (ctx->Driver.CurrentExecPrimitive) { + case GL_POINTS: + assert(vb.vCount == 0); + select_point(v); + break; + case GL_LINES: + if (vb.vCount == 0) + { + vb.vCount = 1; + } + else + { + assert(vb.vCount == 1); + select_line(vb.vBuffer + 0, vb.vBuffer + 1); + vb.vCount = 0; + } + break; + case GL_LINE_STRIP: + if (vb.vCount == 0) + { + vb.vCount = 1; + } + else + { + assert(vb.vCount == 1); + select_line(vb.vBuffer + 0, vb.vBuffer + 1); + vb.vBuffer[0] = vb.vBuffer[1]; + /* leave vb.vCount at 1 */ + } + break; + case GL_LINE_LOOP: + if (vb.vCount == 0) + { + vb.vCount = 1; + vb.partialLineLoop = GL_FALSE; + } + else if (vb.vCount == 1) + { + select_line(vb.vBuffer + 0, vb.vBuffer + 1); + vb.partialLineLoop = GL_TRUE; + vb.vCount = 2; + } + else + { + assert(vb.vCount == 2); + vb.partialLineLoop = GL_FALSE; + select_line(vb.vBuffer + 1, vb.vBuffer + 2); + vb.vBuffer[1] = vb.vBuffer[2]; + /* leave vb.vCount at 2 */ + } + break; + case GL_TRIANGLES: + if (vb.vCount == 0 || vb.vCount == 1) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 2); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + vb.vCount = 0; + } + break; + case GL_TRIANGLE_STRIP: + if (vb.vCount == 0 || vb.vCount == 1) + { + vb.vCount++; + } + else if (vb.vCount == 2) + { + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + vb.vCount = 3; + } + else + { + assert(vb.vCount == 3); + select_triangle(vb.vBuffer + 1, vb.vBuffer + 3, vb.vBuffer + 2); + vb.vBuffer[0] = vb.vBuffer[2]; + vb.vBuffer[1] = vb.vBuffer[3]; + vb.vCount = 2; + } + break; + case GL_TRIANGLE_FAN: + if (vb.vCount == 0 || vb.vCount == 1) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 2); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + vb.vBuffer[1] = vb.vBuffer[2]; + /* leave vb.vCount = 2 */ + } + break; + case GL_QUADS: + if (vb.vCount < 3) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 3); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 2, vb.vBuffer + 3); + vb.vCount = 0; + } + break; + case GL_QUAD_STRIP: + if (vb.vCount < 3) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 3); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + select_triangle(vb.vBuffer + 1, vb.vBuffer + 3, vb.vBuffer + 2); + vb.vBuffer[0] = vb.vBuffer[2]; + vb.vBuffer[1] = vb.vBuffer[3]; + vb.vCount = 2; + } + break; + case GL_POLYGON: + switch (p->FrontMode) { + case GL_POINT: + assert(vb.vCount == 0); + select_point(v); + break; + case GL_LINE: + if (vb.vCount == 0) + { + vb.vCount = 1; + vb.partialLineLoop = GL_FALSE; + } + else if (vb.vCount == 1) + { + select_line(vb.vBuffer + 0, vb.vBuffer + 1); + vb.partialLineLoop = GL_TRUE; + vb.vCount = 2; + } + else + { + assert(vb.vCount == 2); + vb.partialLineLoop = GL_FALSE; + select_line(vb.vBuffer + 1, vb.vBuffer + 2); + vb.vBuffer[1] = vb.vBuffer[2]; + /* leave vb.vCount at 2 */ + } + break; + case GL_FILL: + /* draw as a tri-fan */ + if (vb.vCount == 0 || vb.vCount == 1) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 2); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + vb.vBuffer[1] = vb.vBuffer[2]; + /* leave vb.vCount = 2 */ + } + break; + default: + ; /* impossible */ + } + break; + default: + ; /* outside begin/end -- no action required */ + } +} + +/** + * \brief Calls radeon_select_Vertex4f(). + */ +static void radeon_select_Vertex2f(GLfloat x, GLfloat y) +{ + radeon_select_Vertex4f(x, y, 0.0, 1.0); +} + +/** + * \brief Calls radeon_select_Vertex4f(). + */ +static void radeon_select_Vertex2fv(const GLfloat * v) +{ + radeon_select_Vertex4f(v[0], v[1], 0.0, 1.0); +} + +/** + * \brief Calls radeon_select_Vertex4f(). + */ +static void radeon_select_Vertex3f(GLfloat x, GLfloat y, GLfloat z) +{ + radeon_select_Vertex4f(x, y, z, 1.0); +} + +/** + * \brief Calls radeon_select_Vertex4f(). + */ +static void radeon_select_Vertex3fv(const GLfloat * v) +{ + radeon_select_Vertex4f(v[0], v[1], v[2], 1.0); +} + + +/** + * \brief Set current vertex color. + * + * \param r red color component. + * \param g gree color component. + * \param b blue color component. + * \param a alpha color component. + * + * Updates the GL context's current vertex color. + */ +static void radeon_select_Color4f( GLfloat r, GLfloat g, + GLfloat b, GLfloat a ) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; +} + +/** + * \brief Calls radeon_select_Color4f(). + */ +static void radeon_select_Color4fv( const GLfloat *v ) +{ + radeon_select_Color4f( v[0], v[1], v[2], v[3] ); +} + +/** + * \brief Calls radeon_select_Color4f(). + */ +static void radeon_select_Color3f( GLfloat r, GLfloat g, GLfloat b ) +{ + radeon_select_Color4f( r, g, b, 1.0 ); +} + +/** + * \brief Calls radeon_select_Color4f(). + */ +static void radeon_select_Color3fv( const GLfloat *v ) +{ + radeon_select_Color4f( v[0], v[1], v[2], 1.0 ); +} + +/** + * \brief Set current vertex texture coordinates. + * + * \param s texture coordinate. + * \param t texture coordinate. + * + * Updates the GL context's current vertex texture coordinates. + */ +static __inline__ void radeon_select_TexCoord2f( GLfloat s, GLfloat t ) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; + dest[0] = s; + dest[1] = t; +} + +/** + * \brief Calls radeon_select_TexCoord2f(). + */ +static void radeon_select_TexCoord2fv( const GLfloat *v ) +{ + radeon_select_TexCoord2f( v[0], v[1] ); +} + + +/** + * \brief Process glBegin(). + * + * \param mode primitive. + */ +static void radeon_select_Begin(GLenum mode) +{ + GET_CURRENT_CONTEXT(ctx); + + if (mode > GL_POLYGON) { + _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" ); + return; + } + + if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); + return; + } + + ctx->Driver.CurrentExecPrimitive = mode; + + vb.vCount = 0; + vb.lineReset = GL_TRUE; + vb.partialLineLoop = GL_FALSE; +} + +/** + * \brief Process glEnd(). + */ +static void radeon_select_End(void) +{ + GET_CURRENT_CONTEXT(ctx); + + if ( (ctx->Driver.CurrentExecPrimitive == GL_LINE_LOOP || + (ctx->Driver.CurrentExecPrimitive == GL_POLYGON && + ctx->Polygon.FrontMode == GL_LINE)) + && vb.vCount == 2 ) + { + /* draw the last line segment */ + if (vb.partialLineLoop) + select_line(vb.vBuffer + 1, vb.vBuffer + 0); + else + select_line(vb.vBuffer + 2, vb.vBuffer + 0); + } + + ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; +} + + +/** + * \brief Flush vertices. + * + * \param ctx GL context. + * \param flags not used. + * + * Nothing much to do here, besides marking the vertices as flushed, as we + * don't buffer anything. + */ +static void radeonSelectFlushVertices( GLcontext *ctx, GLuint flags ) +{ + ctx->Driver.NeedFlush = 0; +} + +/** + * \brief Install the select callbacks. + * + * \param ctx GL context. + * + * Installs the glBegin()/glEnd() associated select callbacks into the glapi + * table. + */ +void radeon_select_Install( GLcontext *ctx ) +{ + struct _glapi_table *exec = ctx->Exec; + + exec->Color3f = radeon_select_Color3f; + exec->Color3fv = radeon_select_Color3fv; + exec->Color4f = radeon_select_Color4f; + exec->Color4fv = radeon_select_Color4fv; + exec->TexCoord2f = radeon_select_TexCoord2f; + exec->TexCoord2fv = radeon_select_TexCoord2fv; + exec->Vertex2f = radeon_select_Vertex2f; + exec->Vertex2fv = radeon_select_Vertex2fv; + exec->Vertex3f = radeon_select_Vertex3f; + exec->Vertex3fv = radeon_select_Vertex3fv; + exec->Begin = radeon_select_Begin; + exec->End = radeon_select_End; + + ctx->Driver.FlushVertices = radeonSelectFlushVertices; +} +/*@}*/ + + + +/** + * \brief Set rasterization mode. + * + * \param ctx GL context. + * \param mode rasterization mode. Supports GL_RENDER or + * + * If mode is GL_RENDER, calls either radeonVtxfmtInit() or + * radeon_noop_Install depending on whether the application has focus + * (i.e., a fullscreen-cliprect) or not. If mode is GL_SELECT, calls + * radeon_select_Install(). + */ +static void radeonRenderMode( GLcontext *ctx, GLenum mode ) +{ + switch (mode) { + case GL_RENDER: + radeonVtxfmtInit( ctx ); + break; + case GL_SELECT: + radeon_select_Install( ctx ); + break; + default: + break; + } +} + +/** + * \brief Setup the GL context driver callbacks. + * + * \param ctx GL context. + * + * \sa Called by radeonCreateContext(). + */ +void radeonInitSelect( GLcontext *ctx ) +{ + ctx->Driver.RenderMode = radeonRenderMode; +} -- cgit v1.2.3