1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
29 * \brief Clipping stage
31 * \author Keith Whitwell <keith@tungstengraphics.com>
35 #include "pipe/p_util.h"
36 #include "pipe/p_shader_tokens.h"
39 #include "draw_pipe.h"
43 #define IS_NEGATIVE(X) ((X) < 0.0)
46 #ifndef DIFFERENT_SIGNS
47 #define DIFFERENT_SIGNS(x, y) ((x) * (y) <= 0.0F && (x) - (y) != 0.0F)
50 #ifndef MAX_CLIPPED_VERTICES
51 #define MAX_CLIPPED_VERTICES ((2 * (6 + PIPE_MAX_CLIP_PLANES))+1)
57 struct draw_stage stage
; /**< base class */
59 /* Basically duplicate some of the flatshading logic here:
62 uint num_color_attribs
;
63 uint color_attribs
[4]; /* front/back primary/secondary colors */
69 /* This is a bit confusing:
71 static INLINE
struct clipper
*clipper_stage( struct draw_stage
*stage
)
73 return (struct clipper
*)stage
;
77 #define LINTERP(T, OUT, IN) ((OUT) + (T) * ((IN) - (OUT)))
80 /* All attributes are float[4], so this is easy:
82 static void interp_attr( float *fdst
,
87 fdst
[0] = LINTERP( t
, fout
[0], fin
[0] );
88 fdst
[1] = LINTERP( t
, fout
[1], fin
[1] );
89 fdst
[2] = LINTERP( t
, fout
[2], fin
[2] );
90 fdst
[3] = LINTERP( t
, fout
[3], fin
[3] );
93 static void copy_colors( struct draw_stage
*stage
,
94 struct vertex_header
*dst
,
95 const struct vertex_header
*src
)
97 const struct clipper
*clipper
= clipper_stage(stage
);
99 for (i
= 0; i
< clipper
->num_color_attribs
; i
++) {
100 const uint attr
= clipper
->color_attribs
[i
];
101 COPY_4FV(dst
->data
[attr
], src
->data
[attr
]);
107 /* Interpolate between two vertices to produce a third.
109 static void interp( const struct clipper
*clip
,
110 struct vertex_header
*dst
,
112 const struct vertex_header
*out
,
113 const struct vertex_header
*in
)
115 const unsigned nr_attrs
= clip
->stage
.draw
->num_vs_outputs
;
124 dst
->vertex_id
= UNDEFINED_VERTEX_ID
;
127 /* Clip coordinates: interpolate normally
130 interp_attr(dst
->clip
, t
, in
->clip
, out
->clip
);
133 /* Do the projective divide and insert window coordinates:
136 const float *pos
= dst
->clip
;
137 const float *scale
= clip
->stage
.draw
->viewport
.scale
;
138 const float *trans
= clip
->stage
.draw
->viewport
.translate
;
139 const float oow
= 1.0f
/ pos
[3];
141 dst
->data
[0][0] = pos
[0] * oow
* scale
[0] + trans
[0];
142 dst
->data
[0][1] = pos
[1] * oow
* scale
[1] + trans
[1];
143 dst
->data
[0][2] = pos
[2] * oow
* scale
[2] + trans
[2];
144 dst
->data
[0][3] = oow
;
148 * Note: start at 1 to skip winpos (data[0]) since we just computed
151 for (j
= 1; j
< nr_attrs
; j
++) {
152 interp_attr(dst
->data
[j
], t
, in
->data
[j
], out
->data
[j
]);
157 static void emit_poly( struct draw_stage
*stage
,
158 struct vertex_header
**inlist
,
160 const struct prim_header
*origPrim
)
162 struct prim_header header
;
165 /* later stages may need the determinant, but only the sign matters */
166 header
.det
= origPrim
->det
;
168 for (i
= 2; i
< n
; i
++) {
169 header
.v
[0] = inlist
[i
-1];
170 header
.v
[1] = inlist
[i
];
171 header
.v
[2] = inlist
[0]; /* keep in v[2] for flatshading */
174 unsigned tmp1
= header
.v
[1]->edgeflag
;
175 unsigned tmp2
= header
.v
[2]->edgeflag
;
177 if (i
!= n
-1) header
.v
[1]->edgeflag
= 0;
178 if (i
!= 2) header
.v
[2]->edgeflag
= 0;
180 header
.edgeflags
= ((header
.v
[0]->edgeflag
<< 0) |
181 (header
.v
[1]->edgeflag
<< 1) |
182 (header
.v
[2]->edgeflag
<< 2));
185 const struct draw_vertex_shader
*vs
= stage
->draw
->vertex_shader
;
187 debug_printf("Clipped tri:\n");
188 for (j
= 0; j
< 3; j
++) {
189 for (k
= 0; k
< vs
->info
.num_outputs
; k
++) {
190 debug_printf(" Vert %d: Attr %d: %f %f %f %f\n", j
, k
,
191 header
.v
[j
]->data
[k
][0],
192 header
.v
[j
]->data
[k
][1],
193 header
.v
[j
]->data
[k
][2],
194 header
.v
[j
]->data
[k
][3]);
199 stage
->next
->tri( stage
->next
, &header
);
201 header
.v
[1]->edgeflag
= tmp1
;
202 header
.v
[2]->edgeflag
= tmp2
;
208 dot4(const float *a
, const float *b
)
217 /* Clip a triangle against the viewport and user clip planes.
220 do_clip_tri( struct draw_stage
*stage
,
221 struct prim_header
*header
,
224 struct clipper
*clipper
= clipper_stage( stage
);
225 struct vertex_header
*a
[MAX_CLIPPED_VERTICES
];
226 struct vertex_header
*b
[MAX_CLIPPED_VERTICES
];
227 struct vertex_header
**inlist
= a
;
228 struct vertex_header
**outlist
= b
;
233 inlist
[0] = header
->v
[0];
234 inlist
[1] = header
->v
[1];
235 inlist
[2] = header
->v
[2];
237 while (clipmask
&& n
>= 3) {
238 const unsigned plane_idx
= ffs(clipmask
)-1;
239 const float *plane
= clipper
->plane
[plane_idx
];
240 struct vertex_header
*vert_prev
= inlist
[0];
241 float dp_prev
= dot4( vert_prev
->clip
, plane
);
242 unsigned outcount
= 0;
244 clipmask
&= ~(1<<plane_idx
);
246 inlist
[n
] = inlist
[0]; /* prevent rotation of vertices */
248 for (i
= 1; i
<= n
; i
++) {
249 struct vertex_header
*vert
= inlist
[i
];
251 float dp
= dot4( vert
->clip
, plane
);
253 if (!IS_NEGATIVE(dp_prev
)) {
254 outlist
[outcount
++] = vert_prev
;
257 if (DIFFERENT_SIGNS(dp
, dp_prev
)) {
258 struct vertex_header
*new_vert
= clipper
->stage
.tmp
[tmpnr
++];
259 outlist
[outcount
++] = new_vert
;
261 if (IS_NEGATIVE(dp
)) {
262 /* Going out of bounds. Avoid division by zero as we
263 * know dp != dp_prev from DIFFERENT_SIGNS, above.
265 float t
= dp
/ (dp
- dp_prev
);
266 interp( clipper
, new_vert
, t
, vert
, vert_prev
);
268 /* Force edgeflag true in this case:
270 new_vert
->edgeflag
= 1;
274 float t
= dp_prev
/ (dp_prev
- dp
);
275 interp( clipper
, new_vert
, t
, vert_prev
, vert
);
277 /* Copy starting vert's edgeflag:
279 new_vert
->edgeflag
= vert_prev
->edgeflag
;
288 struct vertex_header
**tmp
= inlist
;
295 /* If flat-shading, copy color to new provoking vertex.
297 if (clipper
->flat
&& inlist
[0] != header
->v
[2]) {
299 inlist
[0] = dup_vert(stage
, inlist
[0], tmpnr
++);
302 copy_colors(stage
, inlist
[0], header
->v
[2]);
307 /* Emit the polygon as triangles to the setup stage:
310 emit_poly( stage
, inlist
, n
, header
);
314 /* Clip a line against the viewport and user clip planes.
317 do_clip_line( struct draw_stage
*stage
,
318 struct prim_header
*header
,
321 const struct clipper
*clipper
= clipper_stage( stage
);
322 struct vertex_header
*v0
= header
->v
[0];
323 struct vertex_header
*v1
= header
->v
[1];
324 const float *pos0
= v0
->clip
;
325 const float *pos1
= v1
->clip
;
328 struct prim_header newprim
;
331 const unsigned plane_idx
= ffs(clipmask
)-1;
332 const float *plane
= clipper
->plane
[plane_idx
];
333 const float dp0
= dot4( pos0
, plane
);
334 const float dp1
= dot4( pos1
, plane
);
337 float t
= dp1
/ (dp1
- dp0
);
342 float t
= dp0
/ (dp0
- dp1
);
347 return; /* discard */
349 clipmask
&= ~(1 << plane_idx
); /* turn off this plane's bit */
353 interp( clipper
, stage
->tmp
[0], t0
, v0
, v1
);
356 copy_colors(stage
, stage
->tmp
[0], v0
);
358 newprim
.v
[0] = stage
->tmp
[0];
365 interp( clipper
, stage
->tmp
[1], t1
, v1
, v0
);
366 newprim
.v
[1] = stage
->tmp
[1];
372 stage
->next
->line( stage
->next
, &newprim
);
377 clip_point( struct draw_stage
*stage
,
378 struct prim_header
*header
)
380 if (header
->v
[0]->clipmask
== 0)
381 stage
->next
->point( stage
->next
, header
);
386 clip_line( struct draw_stage
*stage
,
387 struct prim_header
*header
)
389 unsigned clipmask
= (header
->v
[0]->clipmask
|
390 header
->v
[1]->clipmask
);
393 /* no clipping needed */
394 stage
->next
->line( stage
->next
, header
);
396 else if ((header
->v
[0]->clipmask
&
397 header
->v
[1]->clipmask
) == 0) {
398 do_clip_line(stage
, header
, clipmask
);
400 /* else, totally clipped */
405 clip_tri( struct draw_stage
*stage
,
406 struct prim_header
*header
)
408 unsigned clipmask
= (header
->v
[0]->clipmask
|
409 header
->v
[1]->clipmask
|
410 header
->v
[2]->clipmask
);
413 /* no clipping needed */
414 stage
->next
->tri( stage
->next
, header
);
416 else if ((header
->v
[0]->clipmask
&
417 header
->v
[1]->clipmask
&
418 header
->v
[2]->clipmask
) == 0) {
419 do_clip_tri(stage
, header
, clipmask
);
423 /* Update state. Could further delay this until we hit the first
424 * primitive that really requires clipping.
427 clip_init_state( struct draw_stage
*stage
)
429 struct clipper
*clipper
= clipper_stage( stage
);
431 clipper
->flat
= stage
->draw
->rasterizer
->flatshade
? TRUE
: FALSE
;
434 const struct draw_vertex_shader
*vs
= stage
->draw
->vertex_shader
;
437 clipper
->num_color_attribs
= 0;
438 for (i
= 0; i
< vs
->info
.num_outputs
; i
++) {
439 if (vs
->info
.output_semantic_name
[i
] == TGSI_SEMANTIC_COLOR
||
440 vs
->info
.output_semantic_name
[i
] == TGSI_SEMANTIC_BCOLOR
) {
441 clipper
->color_attribs
[clipper
->num_color_attribs
++] = i
;
446 stage
->tri
= clip_tri
;
447 stage
->line
= clip_line
;
452 static void clip_first_tri( struct draw_stage
*stage
,
453 struct prim_header
*header
)
455 clip_init_state( stage
);
456 stage
->tri( stage
, header
);
459 static void clip_first_line( struct draw_stage
*stage
,
460 struct prim_header
*header
)
462 clip_init_state( stage
);
463 stage
->line( stage
, header
);
467 static void clip_flush( struct draw_stage
*stage
,
470 stage
->tri
= clip_first_tri
;
471 stage
->line
= clip_first_line
;
472 stage
->next
->flush( stage
->next
, flags
);
476 static void clip_reset_stipple_counter( struct draw_stage
*stage
)
478 stage
->next
->reset_stipple_counter( stage
->next
);
482 static void clip_destroy( struct draw_stage
*stage
)
484 draw_free_temp_verts( stage
);
490 * Allocate a new clipper stage.
491 * \return pointer to new stage object
493 struct draw_stage
*draw_clip_stage( struct draw_context
*draw
)
495 struct clipper
*clipper
= CALLOC_STRUCT(clipper
);
499 if (!draw_alloc_temp_verts( &clipper
->stage
, MAX_CLIPPED_VERTICES
+1 ))
502 clipper
->stage
.draw
= draw
;
503 clipper
->stage
.point
= clip_point
;
504 clipper
->stage
.line
= clip_first_line
;
505 clipper
->stage
.tri
= clip_first_tri
;
506 clipper
->stage
.flush
= clip_flush
;
507 clipper
->stage
.reset_stipple_counter
= clip_reset_stipple_counter
;
508 clipper
->stage
.destroy
= clip_destroy
;
510 clipper
->plane
= draw
->plane
;
512 return &clipper
->stage
;
516 clipper
->stage
.destroy( &clipper
->stage
);