patch to import Jon Smirl's work from Bitkeeper
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_subset_select.c
1 /**
2 * \file radeon_subset_select.c
3 * \brief Selection.
4 */
5
6 /*
7 * Mesa 3-D graphics library
8 * Version: 4.1
9 *
10 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 */
29
30 /* $Id: radeon_subset_select.c,v 1.2 2003/08/22 20:11:45 brianp Exp $ */
31
32
33 #include "glheader.h"
34 #include "imports.h"
35 #include "context.h"
36 /*#include "mmath.h"*/
37 #include "mtypes.h"
38 #include "enums.h"
39 #include "glapi.h"
40 #include "feedback.h"
41
42 #include "radeon_context.h"
43 #include "radeon_subset.h"
44
45 /**
46 * \brief Vertex.
47 */
48 typedef struct {
49 struct { GLfloat x, y, z, w; } pos; /**< \brief position */
50 struct { GLfloat x, y, z, w; } eyePos; /**< \brief position, eye coordinates */
51 struct { GLfloat x, y, z, w; } clipPos; /**< \brief clipped coordinates */
52 struct { GLfloat x, y, z, w; } winPos; /**< \brief position, windows coordinates */
53 struct { GLfloat s, t; } texCoord; /**< \brief texture coordinates */
54 struct { GLfloat r, g, b, a; } color; /**< \brief color */
55 } vertex;
56
57
58 /**
59 * \brief Vertex buffer.
60 */
61 static struct select_vb_t {
62 GLuint vCount; /**< \brief vertex count */
63 vertex vBuffer[4]; /**< \brief vertex buffer */
64 GLboolean lineReset;
65 GLboolean partialLineLoop; /**< \brief whether we are in a middle of a line loop */
66 } vb;
67
68
69
70
71 /**********************************************************************/
72 /** \name Vertex Transformation and Clipping */
73 /**********************************************************************/
74 /*@{*/
75
76 /**
77 * \brief Transform a point (column vector) by a matrix: Q = M * P.
78 *
79 * \param Q destination point.
80 * \param P source point.
81 * \param M transformation matrix.
82 */
83 #define TRANSFORM_POINT( Q, M, P ) \
84 Q.x = M[0] * P.x + M[4] * P.y + M[8] * P.z + M[12] * P.w; \
85 Q.y = M[1] * P.x + M[5] * P.y + M[9] * P.z + M[13] * P.w; \
86 Q.z = M[2] * P.x + M[6] * P.y + M[10] * P.z + M[14] * P.w; \
87 Q.w = M[3] * P.x + M[7] * P.y + M[11] * P.z + M[15] * P.w;
88
89 /**
90 * \brief Clip coord to window coord mapping.
91 *
92 * \param Q destination point.
93 * \param P source point.
94 * \param VP view port.
95 */
96 #define MAP_POINT( Q, P, VP ) \
97 Q.x = (GLfloat) (((P.x / P.w) + 1.0) * VP.Width / 2.0 + VP.X); \
98 Q.y = (GLfloat) (((P.y / P.w) + 1.0) * VP.Height / 2.0 + VP.Y); \
99 Q.z = (GLfloat) (((P.z / P.w) + 1.0) * (VP.Far - VP.Near) / 2.0 + VP.Near);\
100 Q.w = (GLfloat) P.w;
101
102
103 /**
104 * \brief Linear interpolation: (1 - T) * A + T * B.
105 *
106 * \param T interpolation factor.
107 * \param A first value.
108 * \param B second value.
109 * \result interpolated value.
110 */
111 #define INTERPOLATE(T, A, B) ((A) + ((B) - (A)) * (T))
112
113
114
115 /**
116 * \brief Interpolate vertex position, color, texcoords, etc.
117 *
118 * \param t interpolation factor.
119 * \param v0 first vertex.
120 * \param v1 second vertex.
121 * \param vOut output vertex.
122 *
123 * Uses the #INTERPOLATE macro for all the interpolation of all elements.
124 */
125 static void
126 interpolate_vertex(GLfloat t, const vertex *v0, const vertex *v1,
127 vertex *vOut)
128 {
129 vOut->eyePos.x = INTERPOLATE(t, v0->eyePos.x, v1->eyePos.x);
130 vOut->eyePos.y = INTERPOLATE(t, v0->eyePos.y, v1->eyePos.y);
131 vOut->eyePos.z = INTERPOLATE(t, v0->eyePos.z, v1->eyePos.z);
132 vOut->eyePos.w = INTERPOLATE(t, v0->eyePos.w, v1->eyePos.w);
133
134 vOut->clipPos.x = INTERPOLATE(t, v0->clipPos.x, v1->clipPos.x);
135 vOut->clipPos.y = INTERPOLATE(t, v0->clipPos.y, v1->clipPos.y);
136 vOut->clipPos.z = INTERPOLATE(t, v0->clipPos.z, v1->clipPos.z);
137 vOut->clipPos.w = INTERPOLATE(t, v0->clipPos.w, v1->clipPos.w);
138
139 vOut->color.r = INTERPOLATE(t, v0->color.r, v1->color.r);
140 vOut->color.g = INTERPOLATE(t, v0->color.g, v1->color.g);
141 vOut->color.b = INTERPOLATE(t, v0->color.b, v1->color.b);
142 vOut->color.a = INTERPOLATE(t, v0->color.a, v1->color.a);
143
144 vOut->texCoord.s = INTERPOLATE(t, v0->texCoord.s, v1->texCoord.s);
145 vOut->texCoord.t = INTERPOLATE(t, v0->texCoord.t, v1->texCoord.t);
146 }
147
148
149
150
151 /*
152 * Clip bit codes
153 */
154 #define CLIP_LEFT 1
155 #define CLIP_RIGHT 2
156 #define CLIP_BOTTOM 4
157 #define CLIP_TOP 8
158 #define CLIP_NEAR 16
159 #define CLIP_FAR 32
160
161
162 /**
163 * \brief Apply view volume clip testing to a point.
164 *
165 * \param v point to test.
166 * \return zero if visible, or the clip code mask, i.e., binary OR of a
167 * combination of the #CLIP_LEFT, #CLIP_RIGHT, #CLIP_BOTTOM, #CLIP_TOP, #CLIP_NEAR,
168 * #CLIP_FAR clip bit codes.
169 */
170 static GLuint
171 clip_point(const vertex *v)
172 {
173 GLuint mask = 0;
174 if (v->clipPos.x > v->clipPos.w) mask |= CLIP_RIGHT;
175 if (v->clipPos.x < -v->clipPos.w) mask |= CLIP_LEFT;
176 if (v->clipPos.y > v->clipPos.w) mask |= CLIP_TOP;
177 if (v->clipPos.y < -v->clipPos.w) mask |= CLIP_BOTTOM;
178 if (v->clipPos.z > v->clipPos.w) mask |= CLIP_FAR;
179 if (v->clipPos.z < -v->clipPos.w) mask |= CLIP_NEAR;
180 return mask;
181 }
182
183
184 /**
185 * \def GENERAL_CLIP
186 * \brief Clipping utility macro.
187 *
188 * We use 6 instances of this code in each of the clip_line() and
189 * clip_polygon() to clip against the 6 planes. For each plane, we define the
190 * #OUTSIDE and #COMPUTE_INTERSECTION macros appropriately.
191 */
192
193
194 /**
195 * \brief Apply clipping to a line segment.
196 *
197 * \param v0in input start vertex
198 * \param v1in input end vertesx
199 * \param v0new output start vertex
200 * \param v1new output end vertex
201 *
202 * \return GL_TRUE if the line segment is visible, or GL_FALSE if it is totally
203 * clipped.
204 *
205 * \sa #GENERAL_CLIP.
206 */
207 static GLboolean
208 clip_line(const vertex *v0in, const vertex *v1in,
209 vertex *v0new, vertex *v1new)
210 {
211 vertex v0, v1, vNew;
212 GLfloat dx, dy, dz, dw, t;
213 GLuint code0, code1;
214
215 code0 = clip_point(v0in);
216 code1 = clip_point(v1in);
217 if (code0 & code1)
218 return GL_FALSE; /* totally clipped */
219
220 *v0new = *v0in;
221 *v1new = *v1in;
222 if (code0 == 0 && code1 == 0)
223 return GL_TRUE; /* no clipping needed */
224
225 v0 = *v0in;
226 v1 = *v1in;
227
228
229 #define GENERAL_CLIP \
230 if (OUTSIDE(v0)) { \
231 if (OUTSIDE(v1)) { \
232 /* both verts are outside ==> return 0 */ \
233 return 0; \
234 } \
235 else { \
236 /* v0 is outside, v1 is inside ==> clip */ \
237 COMPUTE_INTERSECTION( v1, v0, vNew ) \
238 interpolate_vertex(t, &v1, &v0, &vNew); \
239 v0 = vNew; \
240 } \
241 } \
242 else { \
243 if (OUTSIDE(v1)) { \
244 /* v0 is inside, v1 is outside ==> clip */ \
245 COMPUTE_INTERSECTION( v0, v1, vNew ) \
246 interpolate_vertex(t, &v0, &v1, &vNew); \
247 v1 = vNew; \
248 } \
249 /* else both verts are inside ==> do nothing */ \
250 }
251
252 /* Clip against +X side */
253 #define OUTSIDE(V) (V.clipPos.x > V.clipPos.w)
254 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
255 dx = OUT.clipPos.x - IN.clipPos.x; \
256 dw = OUT.clipPos.w - IN.clipPos.w; \
257 t = (IN.clipPos.x - IN.clipPos.w) / (dw-dx);
258 GENERAL_CLIP
259 #undef OUTSIDE
260 #undef COMPUTE_INTERSECTION
261
262 /* Clip against -X side */
263 #define OUTSIDE(V) (V.clipPos.x < -(V.clipPos.w))
264 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
265 dx = OUT.clipPos.x - IN.clipPos.x; \
266 dw = OUT.clipPos.w - IN.clipPos.w; \
267 t = -(IN.clipPos.x + IN.clipPos.w) / (dw+dx);
268 GENERAL_CLIP
269 #undef OUTSIDE
270 #undef COMPUTE_INTERSECTION
271
272 /* Clip against +Y side */
273 #define OUTSIDE(V) (V.clipPos.y > V.clipPos.w)
274 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
275 dy = OUT.clipPos.y - IN.clipPos.y; \
276 dw = OUT.clipPos.w - IN.clipPos.w; \
277 t = (IN.clipPos.y - IN.clipPos.w) / (dw-dy);
278 GENERAL_CLIP
279 #undef OUTSIDE
280 #undef COMPUTE_INTERSECTION
281
282 /* Clip against -Y side */
283 #define OUTSIDE(V) (V.clipPos.y < -(V.clipPos.w))
284 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
285 dy = OUT.clipPos.y - IN.clipPos.y; \
286 dw = OUT.clipPos.w - IN.clipPos.w; \
287 t = -(IN.clipPos.y + IN.clipPos.w) / (dw+dy);
288 GENERAL_CLIP
289 #undef OUTSIDE
290 #undef COMPUTE_INTERSECTION
291
292 /* Clip against +Z side */
293 #define OUTSIDE(V) (V.clipPos.z > V.clipPos.w)
294 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
295 dz = OUT.clipPos.z - IN.clipPos.z; \
296 dw = OUT.clipPos.w - IN.clipPos.w; \
297 t = (IN.clipPos.z - IN.clipPos.w) / (dw-dz);
298 GENERAL_CLIP
299 #undef OUTSIDE
300 #undef COMPUTE_INTERSECTION
301
302 /* Clip against -Z side */
303 #define OUTSIDE(V) (V.clipPos.z < -(V.clipPos.w))
304 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
305 dz = OUT.clipPos.z - IN.clipPos.z; \
306 dw = OUT.clipPos.w - IN.clipPos.w; \
307 t = -(IN.clipPos.z + IN.clipPos.w) / (dw+dz);
308 GENERAL_CLIP
309 #undef OUTSIDE
310 #undef COMPUTE_INTERSECTION
311
312 #undef GENERAL_CLIP
313
314 *v0new = v0;
315 *v1new = v1;
316 return GL_TRUE;
317 }
318
319
320
321 /**
322 * \brief Apply clipping to a polygon.
323 *
324 * \param vIn array of input vertices.
325 * \param inCount number of input vertices
326 * \param vOut array of output vertices.
327 *
328 * \return number of vertices in \p vOut.
329 *
330 * \sa #GENERAL_CLIP.
331 */
332 static GLuint
333 clip_polygon(const vertex *vIn, unsigned int inCount, vertex *vOut)
334 {
335 vertex inlist[20], outlist[20];
336 GLfloat dx, dy, dz, dw, t;
337 GLuint incount, outcount, previ, curri, result;
338 const vertex *currVert, *prevVert;
339 vertex *newVert;
340
341
342 #define GENERAL_CLIP(INCOUNT, INLIST, OUTCOUNT, OUTLIST) \
343 if (INCOUNT < 3) \
344 return GL_FALSE; \
345 previ = INCOUNT - 1; /* let previous = last vertex */ \
346 prevVert = INLIST + previ; \
347 OUTCOUNT = 0; \
348 for (curri = 0; curri < INCOUNT; curri++) { \
349 currVert = INLIST + curri; \
350 if (INSIDE(currVert)) { \
351 if (INSIDE(prevVert)) { \
352 /* both verts are inside ==> copy current to outlist */ \
353 OUTLIST[OUTCOUNT] = *currVert; \
354 OUTCOUNT++; \
355 } \
356 else { \
357 newVert = OUTLIST + OUTCOUNT; \
358 /* current is inside and previous is outside ==> clip */ \
359 COMPUTE_INTERSECTION( currVert, prevVert, newVert ) \
360 OUTCOUNT++; \
361 /* Output current */ \
362 OUTLIST[OUTCOUNT] = *currVert; \
363 OUTCOUNT++; \
364 } \
365 } \
366 else { \
367 if (INSIDE(prevVert)) { \
368 newVert = OUTLIST + OUTCOUNT; \
369 /* current is outside and previous is inside ==> clip */ \
370 COMPUTE_INTERSECTION( prevVert, currVert, newVert ); \
371 OUTLIST[OUTCOUNT] = *newVert; \
372 OUTCOUNT++; \
373 } \
374 /* else both verts are outside ==> do nothing */ \
375 } \
376 /* let previous = current */ \
377 previ = curri; \
378 prevVert = currVert; \
379 }
380
381 /*
382 * Clip against +X
383 */
384 #define INSIDE(V) (V->clipPos.x <= V->clipPos.w)
385 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
386 dx = OUT->clipPos.x - IN->clipPos.x; \
387 dw = OUT->clipPos.w - IN->clipPos.w; \
388 t = (IN->clipPos.x - IN->clipPos.w) / (dw - dx); \
389 interpolate_vertex(t, IN, OUT, NEW );
390
391 GENERAL_CLIP(inCount, vIn, outcount, outlist)
392
393 #undef INSIDE
394 #undef COMPUTE_INTERSECTION
395
396 /*
397 * Clip against -X
398 */
399 #define INSIDE(V) (V->clipPos.x >= -V->clipPos.w)
400 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
401 dx = OUT->clipPos.x - IN->clipPos.x; \
402 dw = OUT->clipPos.w - IN->clipPos.w; \
403 t = -(IN->clipPos.x + IN->clipPos.w) / (dw + dx); \
404 interpolate_vertex(t, IN, OUT, NEW );
405
406 GENERAL_CLIP(outcount, outlist, incount, inlist)
407
408 #undef INSIDE
409 #undef COMPUTE_INTERSECTION
410
411 /*
412 * Clip against +Y
413 */
414 #define INSIDE(V) (V->clipPos.y <= V->clipPos.w)
415 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
416 dy = OUT->clipPos.y - IN->clipPos.y; \
417 dw = OUT->clipPos.w - IN->clipPos.w; \
418 t = (IN->clipPos.y - IN->clipPos.w) / (dw - dy); \
419 interpolate_vertex(t, IN, OUT, NEW );
420
421 GENERAL_CLIP(incount, inlist, outcount, outlist)
422
423 #undef INSIDE
424 #undef COMPUTE_INTERSECTION
425
426 /*
427 * Clip against -Y
428 */
429 #define INSIDE(V) (V->clipPos.y >= -V->clipPos.w)
430 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
431 dy = OUT->clipPos.y - IN->clipPos.y; \
432 dw = OUT->clipPos.w - IN->clipPos.w; \
433 t = -(IN->clipPos.y + IN->clipPos.w) / (dw + dy); \
434 interpolate_vertex(t, IN, OUT, NEW );
435
436 GENERAL_CLIP(outcount, outlist, incount, inlist)
437
438 #undef INSIDE
439 #undef COMPUTE_INTERSECTION
440
441 /*
442 * Clip against +Z
443 */
444 #define INSIDE(V) (V->clipPos.z <= V->clipPos.w)
445 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
446 dz = OUT->clipPos.z - IN->clipPos.z; \
447 dw = OUT->clipPos.w - IN->clipPos.w; \
448 t = (IN->clipPos.z - IN->clipPos.w) / (dw - dz); \
449 interpolate_vertex(t, IN, OUT, NEW );
450
451 GENERAL_CLIP(incount, inlist, outcount, outlist)
452
453 #undef INSIDE
454 #undef COMPUTE_INTERSECTION
455
456 /*
457 * Clip against -Z
458 */
459 #define INSIDE(V) (V->clipPos.z >= -V->clipPos.w)
460 #define COMPUTE_INTERSECTION( IN, OUT, NEW ) \
461 dz = OUT->clipPos.z - IN->clipPos.z; \
462 dw = OUT->clipPos.w - IN->clipPos.w; \
463 t = -(IN->clipPos.z + IN->clipPos.w) / (dw + dz); \
464 interpolate_vertex(t, IN, OUT, NEW );
465
466 GENERAL_CLIP(outcount, outlist, result, vOut)
467
468 #undef INSIDE
469 #undef COMPUTE_INTERSECTION
470
471 #undef GENERAL_CLIP
472
473 return result;
474 }
475
476 /*@}*/
477
478
479
480 /**********************************************************************/
481 /** \name Selection */
482 /**********************************************************************/
483 /*@{*/
484
485 /**
486 * \brief Select point.
487 *
488 * \param v vertex.
489 *
490 * If the clipped point is visible then maps the vertex into window coordinates
491 * and calls _mesa_update_hitflag().
492 */
493 static void
494 select_point(const vertex *v)
495 {
496 GET_CURRENT_CONTEXT(ctx);
497 if (clip_point(v) == 0)
498 {
499 vertex c = *v;
500 MAP_POINT(c.winPos, c.clipPos, ctx->Viewport);
501 _mesa_update_hitflag(ctx, c.winPos.z);
502 }
503 }
504
505 /**
506 * \brief Select line.
507 *
508 * \param v0 first vertex.
509 * \param v1 second vertex.
510 *
511 * If the clipped line is visible then maps the vertices into window coordinates
512 * and calls _mesa_update_hitflag().
513 */
514 static void
515 select_line(const vertex *v0, const vertex *v1)
516 {
517 GET_CURRENT_CONTEXT(ctx);
518 vertex c0, c1;
519 if (clip_line(v0, v1, &c0, &c1))
520 {
521 MAP_POINT(c0.winPos, c0.clipPos, ctx->Viewport);
522 MAP_POINT(c1.winPos, c1.clipPos, ctx->Viewport);
523 _mesa_update_hitflag(ctx, c0.winPos.z);
524 _mesa_update_hitflag(ctx, c1.winPos.z);
525 }
526 }
527
528 /**
529 * \brief Select line.
530 *
531 * \param v0 first vertex.
532 * \param v1 second vertex.
533 * \param v2 third vertex.
534 *
535 * If the clipped polygon is visible then maps the vertices into window
536 * coordinates and calls _mesa_update_hitflag().
537 */
538 static void
539 select_triangle(const vertex *v0,
540 const vertex *v1,
541 const vertex *v2)
542 {
543 GET_CURRENT_CONTEXT(ctx);
544 vertex vlist[3], vclipped[8];
545 GLuint i, n;
546
547 vlist[0] = *v0;
548 vlist[1] = *v1;
549 vlist[2] = *v2;
550 n = clip_polygon(vlist, 3, vclipped);
551 for (i = 0; i < n; i++) {
552 MAP_POINT(vclipped[i].winPos, vclipped[i].clipPos, ctx->Viewport);
553 _mesa_update_hitflag(ctx, vclipped[i].winPos.z);
554 }
555 }
556
557 /**
558 * \brief Set current vertex coordinates.
559 *
560 * \param x x vertex coordinate.
561 * \param y y vertex coordinate.
562 * \param z z vertex coordinate.
563 * \param w homogeneous coordinate.
564 *
565 * Stores the vertex and current attributes in ::vb, transforms it into eye space and then clip space.
566 *
567 * If a sufficient number of vertices is stored calls one of select_point(),
568 * select_line() or select_triangle(), according to the current primitive.
569 */
570 static void
571 radeon_select_Vertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w)
572 {
573 GET_CURRENT_CONTEXT(ctx);
574 struct gl_polygon_attrib *p = &(ctx->Polygon);
575 vertex *v = vb.vBuffer + vb.vCount;
576
577 /* store the vertex */
578 v->pos.x = x;
579 v->pos.y = y;
580 v->pos.z = z;
581 v->pos.w = w;
582 v->color.r = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0];
583 v->color.g = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1];
584 v->color.b = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2];
585 v->color.a = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3];
586 v->texCoord.s = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0];
587 v->texCoord.t = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1];
588
589 /* transform to eye space, then clip space */
590 TRANSFORM_POINT(v->eyePos, ctx->ModelviewMatrixStack.Top->m, v->pos);
591 TRANSFORM_POINT(v->clipPos, ctx->ProjectionMatrixStack.Top->m, v->eyePos);
592
593 switch (ctx->Driver.CurrentExecPrimitive) {
594 case GL_POINTS:
595 assert(vb.vCount == 0);
596 select_point(v);
597 break;
598 case GL_LINES:
599 if (vb.vCount == 0)
600 {
601 vb.vCount = 1;
602 }
603 else
604 {
605 assert(vb.vCount == 1);
606 select_line(vb.vBuffer + 0, vb.vBuffer + 1);
607 vb.vCount = 0;
608 }
609 break;
610 case GL_LINE_STRIP:
611 if (vb.vCount == 0)
612 {
613 vb.vCount = 1;
614 }
615 else
616 {
617 assert(vb.vCount == 1);
618 select_line(vb.vBuffer + 0, vb.vBuffer + 1);
619 vb.vBuffer[0] = vb.vBuffer[1];
620 /* leave vb.vCount at 1 */
621 }
622 break;
623 case GL_LINE_LOOP:
624 if (vb.vCount == 0)
625 {
626 vb.vCount = 1;
627 vb.partialLineLoop = GL_FALSE;
628 }
629 else if (vb.vCount == 1)
630 {
631 select_line(vb.vBuffer + 0, vb.vBuffer + 1);
632 vb.partialLineLoop = GL_TRUE;
633 vb.vCount = 2;
634 }
635 else
636 {
637 assert(vb.vCount == 2);
638 vb.partialLineLoop = GL_FALSE;
639 select_line(vb.vBuffer + 1, vb.vBuffer + 2);
640 vb.vBuffer[1] = vb.vBuffer[2];
641 /* leave vb.vCount at 2 */
642 }
643 break;
644 case GL_TRIANGLES:
645 if (vb.vCount == 0 || vb.vCount == 1)
646 {
647 vb.vCount++;
648 }
649 else
650 {
651 assert(vb.vCount == 2);
652 select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
653 vb.vCount = 0;
654 }
655 break;
656 case GL_TRIANGLE_STRIP:
657 if (vb.vCount == 0 || vb.vCount == 1)
658 {
659 vb.vCount++;
660 }
661 else if (vb.vCount == 2)
662 {
663 select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
664 vb.vCount = 3;
665 }
666 else
667 {
668 assert(vb.vCount == 3);
669 select_triangle(vb.vBuffer + 1, vb.vBuffer + 3, vb.vBuffer + 2);
670 vb.vBuffer[0] = vb.vBuffer[2];
671 vb.vBuffer[1] = vb.vBuffer[3];
672 vb.vCount = 2;
673 }
674 break;
675 case GL_TRIANGLE_FAN:
676 if (vb.vCount == 0 || vb.vCount == 1)
677 {
678 vb.vCount++;
679 }
680 else
681 {
682 assert(vb.vCount == 2);
683 select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
684 vb.vBuffer[1] = vb.vBuffer[2];
685 /* leave vb.vCount = 2 */
686 }
687 break;
688 case GL_QUADS:
689 if (vb.vCount < 3)
690 {
691 vb.vCount++;
692 }
693 else
694 {
695 assert(vb.vCount == 3);
696 select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
697 select_triangle(vb.vBuffer + 0, vb.vBuffer + 2, vb.vBuffer + 3);
698 vb.vCount = 0;
699 }
700 break;
701 case GL_QUAD_STRIP:
702 if (vb.vCount < 3)
703 {
704 vb.vCount++;
705 }
706 else
707 {
708 assert(vb.vCount == 3);
709 select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
710 select_triangle(vb.vBuffer + 1, vb.vBuffer + 3, vb.vBuffer + 2);
711 vb.vBuffer[0] = vb.vBuffer[2];
712 vb.vBuffer[1] = vb.vBuffer[3];
713 vb.vCount = 2;
714 }
715 break;
716 case GL_POLYGON:
717 switch (p->FrontMode) {
718 case GL_POINT:
719 assert(vb.vCount == 0);
720 select_point(v);
721 break;
722 case GL_LINE:
723 if (vb.vCount == 0)
724 {
725 vb.vCount = 1;
726 vb.partialLineLoop = GL_FALSE;
727 }
728 else if (vb.vCount == 1)
729 {
730 select_line(vb.vBuffer + 0, vb.vBuffer + 1);
731 vb.partialLineLoop = GL_TRUE;
732 vb.vCount = 2;
733 }
734 else
735 {
736 assert(vb.vCount == 2);
737 vb.partialLineLoop = GL_FALSE;
738 select_line(vb.vBuffer + 1, vb.vBuffer + 2);
739 vb.vBuffer[1] = vb.vBuffer[2];
740 /* leave vb.vCount at 2 */
741 }
742 break;
743 case GL_FILL:
744 /* draw as a tri-fan */
745 if (vb.vCount == 0 || vb.vCount == 1)
746 {
747 vb.vCount++;
748 }
749 else
750 {
751 assert(vb.vCount == 2);
752 select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2);
753 vb.vBuffer[1] = vb.vBuffer[2];
754 /* leave vb.vCount = 2 */
755 }
756 break;
757 default:
758 ; /* impossible */
759 }
760 break;
761 default:
762 ; /* outside begin/end -- no action required */
763 }
764 }
765
766 /**
767 * \brief Calls radeon_select_Vertex4f().
768 */
769 static void radeon_select_Vertex2f(GLfloat x, GLfloat y)
770 {
771 radeon_select_Vertex4f(x, y, 0.0, 1.0);
772 }
773
774 /**
775 * \brief Calls radeon_select_Vertex4f().
776 */
777 static void radeon_select_Vertex2fv(const GLfloat * v)
778 {
779 radeon_select_Vertex4f(v[0], v[1], 0.0, 1.0);
780 }
781
782 /**
783 * \brief Calls radeon_select_Vertex4f().
784 */
785 static void radeon_select_Vertex3f(GLfloat x, GLfloat y, GLfloat z)
786 {
787 radeon_select_Vertex4f(x, y, z, 1.0);
788 }
789
790 /**
791 * \brief Calls radeon_select_Vertex4f().
792 */
793 static void radeon_select_Vertex3fv(const GLfloat * v)
794 {
795 radeon_select_Vertex4f(v[0], v[1], v[2], 1.0);
796 }
797
798
799 /**
800 * \brief Set current vertex color.
801 *
802 * \param r red color component.
803 * \param g gree color component.
804 * \param b blue color component.
805 * \param a alpha color component.
806 *
807 * Updates the GL context's current vertex color.
808 */
809 static void radeon_select_Color4f( GLfloat r, GLfloat g,
810 GLfloat b, GLfloat a )
811 {
812 GET_CURRENT_CONTEXT(ctx);
813 GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
814 dest[0] = r;
815 dest[1] = g;
816 dest[2] = b;
817 dest[3] = a;
818 }
819
820 /**
821 * \brief Calls radeon_select_Color4f().
822 */
823 static void radeon_select_Color4fv( const GLfloat *v )
824 {
825 radeon_select_Color4f( v[0], v[1], v[2], v[3] );
826 }
827
828 /**
829 * \brief Calls radeon_select_Color4f().
830 */
831 static void radeon_select_Color3f( GLfloat r, GLfloat g, GLfloat b )
832 {
833 radeon_select_Color4f( r, g, b, 1.0 );
834 }
835
836 /**
837 * \brief Calls radeon_select_Color4f().
838 */
839 static void radeon_select_Color3fv( const GLfloat *v )
840 {
841 radeon_select_Color4f( v[0], v[1], v[2], 1.0 );
842 }
843
844 /**
845 * \brief Set current vertex texture coordinates.
846 *
847 * \param s texture coordinate.
848 * \param t texture coordinate.
849 *
850 * Updates the GL context's current vertex texture coordinates.
851 */
852 static __inline__ void radeon_select_TexCoord2f( GLfloat s, GLfloat t )
853 {
854 GET_CURRENT_CONTEXT(ctx);
855 GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
856 dest[0] = s;
857 dest[1] = t;
858 }
859
860 /**
861 * \brief Calls radeon_select_TexCoord2f().
862 */
863 static void radeon_select_TexCoord2fv( const GLfloat *v )
864 {
865 radeon_select_TexCoord2f( v[0], v[1] );
866 }
867
868
869 /**
870 * \brief Process glBegin().
871 *
872 * \param mode primitive.
873 */
874 static void radeon_select_Begin(GLenum mode)
875 {
876 GET_CURRENT_CONTEXT(ctx);
877
878 if (mode > GL_POLYGON) {
879 _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" );
880 return;
881 }
882
883 if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
884 _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
885 return;
886 }
887
888 ctx->Driver.CurrentExecPrimitive = mode;
889
890 vb.vCount = 0;
891 vb.lineReset = GL_TRUE;
892 vb.partialLineLoop = GL_FALSE;
893 }
894
895 /**
896 * \brief Process glEnd().
897 */
898 static void radeon_select_End(void)
899 {
900 GET_CURRENT_CONTEXT(ctx);
901
902 if ( (ctx->Driver.CurrentExecPrimitive == GL_LINE_LOOP ||
903 (ctx->Driver.CurrentExecPrimitive == GL_POLYGON &&
904 ctx->Polygon.FrontMode == GL_LINE))
905 && vb.vCount == 2 )
906 {
907 /* draw the last line segment */
908 if (vb.partialLineLoop)
909 select_line(vb.vBuffer + 1, vb.vBuffer + 0);
910 else
911 select_line(vb.vBuffer + 2, vb.vBuffer + 0);
912 }
913
914 ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
915 }
916
917
918 /**
919 * \brief Flush vertices.
920 *
921 * \param ctx GL context.
922 * \param flags not used.
923 *
924 * Nothing much to do here, besides marking the vertices as flushed, as we
925 * don't buffer anything.
926 */
927 static void radeonSelectFlushVertices( GLcontext *ctx, GLuint flags )
928 {
929 ctx->Driver.NeedFlush = 0;
930 }
931
932 /**
933 * \brief Install the select callbacks.
934 *
935 * \param ctx GL context.
936 *
937 * Installs the glBegin()/glEnd() associated select callbacks into the glapi
938 * table.
939 */
940 void radeon_select_Install( GLcontext *ctx )
941 {
942 struct _glapi_table *exec = ctx->Exec;
943
944 exec->Color3f = radeon_select_Color3f;
945 exec->Color3fv = radeon_select_Color3fv;
946 exec->Color4f = radeon_select_Color4f;
947 exec->Color4fv = radeon_select_Color4fv;
948 exec->TexCoord2f = radeon_select_TexCoord2f;
949 exec->TexCoord2fv = radeon_select_TexCoord2fv;
950 exec->Vertex2f = radeon_select_Vertex2f;
951 exec->Vertex2fv = radeon_select_Vertex2fv;
952 exec->Vertex3f = radeon_select_Vertex3f;
953 exec->Vertex3fv = radeon_select_Vertex3fv;
954 exec->Begin = radeon_select_Begin;
955 exec->End = radeon_select_End;
956
957 ctx->Driver.FlushVertices = radeonSelectFlushVertices;
958 }
959 /*@}*/
960
961
962
963 /**
964 * \brief Set rasterization mode.
965 *
966 * \param ctx GL context.
967 * \param mode rasterization mode. Supports GL_RENDER or
968 *
969 * If mode is GL_RENDER, calls either radeonVtxfmtInit() or
970 * radeon_noop_Install depending on whether the application has focus
971 * (i.e., a fullscreen-cliprect) or not. If mode is GL_SELECT, calls
972 * radeon_select_Install().
973 */
974 static void radeonRenderMode( GLcontext *ctx, GLenum mode )
975 {
976 switch (mode) {
977 case GL_RENDER:
978 radeonVtxfmtInit( ctx );
979 break;
980 case GL_SELECT:
981 radeon_select_Install( ctx );
982 break;
983 default:
984 break;
985 }
986 }
987
988 /**
989 * \brief Setup the GL context driver callbacks.
990 *
991 * \param ctx GL context.
992 *
993 * \sa Called by radeonCreateContext().
994 */
995 void radeonInitSelect( GLcontext *ctx )
996 {
997 ctx->Driver.RenderMode = radeonRenderMode;
998 }