RE: [AD] Bug in clip3d_f() / polygon3d_f()

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


> I wrote this stuff :-) Well, in fact the function checks the order the
> vertices are given in, in order to fill the double-linked list of points
> in clockwise order in every case (so it handles both cases : clockwise
> and anticlockwise). IMHO to fix the bug you mentionned we should just
> change the way the function checks the vertices order. So far, it
> computes the cross product of two vectors made with the first three
> vertices, so if two points among the first three ones are close or
> coincident the check will fail and the poly won't be drawn. I think a
> better way to test the points order would be to check the sign of the
> polygon area : such a test would rely on every vertex coordinates
> instead of using the first three vertices and would therefore be more
> robust.

Nice idea, but I've already solved the problem :-) Rather than ensuring the
edges are stored in clockwise order, the routine is now adapted to handle
both scenarios.

Here are patches for poly3d.c and aintern.h. The functions now handle
coincident vertices properly. I believe the patches can be applied safely to
CVS, but just so everyone knows exactly what I did, here goes:

1. The polygon_z_normal() calls and equivalents, used to ensure that the
list of edges is created in a clockwise fashion, have been removed. The
edges could go in either direction, depending on the input vertices.

2. _fill_3d_edge_structure() and -_f() now take it upon themselves to fail
if an edge is horizontal or gets clipped out of existence. This avoids a
possible floating-point divide-by-zero in one of them (albeit one with no
consequence). It also means these checks do not have to be done by the main
code, so the fceil() calls only occur once - within
_fill_3d_edge_structure(). The functions now return an int. I had to change
the prototypes in aintern.h - but seriously, do those prototypes need to be
there?

3. In do_polygon3d(), left_edge and right_edge don't necessarily correspond
to the left and right edges of the polygon. They could be reversed. As a
result of this ambiguity, I was able to simplify the code to check that
left_edge and right_edge would properly traverse one side of the polygon
each. However...

4. draw_polygon_segment() now swaps the two edges if they are the wrong way
round. It compares the x-coordinates of the tops of the edges. If they are
equal, it compares the values of dx.

5. I have made equivalent changes to the triangle3d() and triangle3d_f()
functions.

I've tested the floating point functions, and they now work perfectly. I
haven't tested the fixed point equivalents.

Finally, comments on what I said before:

> However, I can say for sure that this problem was introduced
> since the last WIP, and exists in the CVS version. I suspect it was
> introduced when the polygon3d functions were given proper sub-pixel
accuracy
> (or did I imagine that? :-)

I can't explain this. If I had the motivation to look at the old file from
the WIP, I probably could explain it, but since it works now, there's
probably no point.

> At the same time, I'd like to point out that the polygons often miss the
> left and top edges of the screen by 1 pixel. This never used to happen.

I think this must just have been 1-pixel-thick polygons not appearing at the
edges, because the gaps are filled with 1-pixel-thick polygons now, using
the new patches. Weird :-)

> I could spend ages puzzling over the inner
> workings of these functions, but I thought it would be better if
> the problem was fixed by someone who already knows what's going on.

Well I guess I spent ages :-) I just couldn't wait!

Ben Davis

PS Apologies to Laurence for consistently spelling his name wrong!

Attachment: aintern.h.diff
Description: Binary data

Attachment: poly3d.c.diff
Description: Binary data



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/