summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/radeon/radeon_subset_select.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/radeon/radeon_subset_select.c')
-rw-r--r--src/mesa/drivers/dri/radeon/radeon_subset_select.c998
1 files changed, 998 insertions, 0 deletions
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;
+}