Function for drawing polygons

I have 2 functions to draw polygons I don't know what is more efficient.

Here's the code.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
internal void DrawPolygon(app_offscreen_buffer *Buffer,int points, ...)
{
    v2 start = {};
    v2 tempPoint1 = {};
    v2 tempPoint2 = {};
    va_list args;
    if(points>=3) {
        va_start(args, points);
        start = va_arg(args, v2);
        tempPoint1 = start;
        points--;
        for (int i=0; i< points-1; i++ ) {
            tempPoint2 = va_arg(args, v2);
            DrawBresenhamLine(Buffer,tempPoint1.x,tempPoint1.y, tempPoint2.x,tempPoint2.y);
            tempPoint1 = tempPoint2;
        }
        DrawBresenhamLine(Buffer,start.x,start.y, tempPoint2.x,tempPoint2.y);
        va_end(args);
    }
}

internal void DrawPolygonEx(app_offscreen_buffer *Buffer,int num_vertices,v2 *points){

  for(int i=0;i<num_vertices-1;i++)
  {
      DrawBresenhamLine(Buffer,points[i].x,
         points[i].y,
         points[i+1].x,
         points[i+1].y);
  }
  DrawBresenhamLine(Buffer,points[0].x,
       points[0].y,
       points[(num_vertices)-1].x,
       points[(num_vertices)-1].y);    
}


And do you no any good free tool to check difference between 2 function calls or maybe a code profiler ....
the real difference between the two is that the vararg version requires that all points are copied onto the stack before the call whereas the other function can simply pass the pointer to where they are stored.
^ what ratchetfreak said.

Also these functions do two different things - first one won't draw anything if there are only two points. Second one will draw one line.

Edited by Mārtiņš Možeiko on
Yeah, vararg funcs doesn't seem to be very good at doing copy elision optimizations (where copies of the params don't have to be pushed on the stack), and also seems to do poorly at being inlined.

On the other hand, if you wanted a similar syntax, but instead did it by creating overloaded functions for different point counts, like this
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void DrawPolygon( void* Buffer, v2 a, v2 b, v2 c )
{
    DrawBresenhamLine( Buffer, a.x, a.y, b.x, b.y );
    DrawBresenhamLine( Buffer, b.x, b.y, c.x, c.y );
    DrawBresenhamLine( Buffer, c.x, c.y, a.x, a.y );
}

void DrawPolygon( void* Buffer, v2 a, v2 b, v2 c, v2 d )
{
    DrawBresenhamLine( Buffer, a.x, a.y, b.x, b.y );
    DrawBresenhamLine( Buffer, b.x, b.y, c.x, c.y );
    DrawBresenhamLine( Buffer, c.x, c.y, d.x, d.y );
    DrawBresenhamLine( Buffer, d.x, d.y, a.x, a.y );
}

// ..etc


You would get the copy elision optimization, and also eliminate the call due to inlining.

Of course, the version with the pointer will also eliminate the copying (and in a more clear way, IMO), and also likely to be inlined, so I would go with something like that one, personally.
i don't like to brag, and it's not on point, but i stole a trick from Sean Barret on how to iterate through a list like you have in the second function, where the last case is the start and end vertex, and i wanted to share it.

insted of
1
2
3
4
5
for(int i=0;i<N-1;i++)
{
 do_thing(a[i],a[i+1]);
}
do_thing[a[N-1],a[0]);


just make the special case the first case, for example
1
2
3
4
5
int i=N-1, j=0;
for(;j<N;i=j,j++)
{
 do_thing(a[i],a[j]);
}


or another example with the same thing:
1
2
3
4
5
6
7
vertex v=a[N-1];
for(int i=0;i<N;i++)
{
 vertex w=a[i];
 do_thing(v,w);
 v=w;
}


with that new way, you can only change the way you call the function in one place, and i like it more. also, you can now make an init and proceed functions and then you can iterate on the edges without knowing about what the do_thing you want to do.

Edited by The_8th_mage on Reason: forgot a reason in the end,2. miswrote Sean's name.