Handmade Hero » Forums » Code » Function for drawing polygons
msmshazan
Shazan Shums
169 posts

Some day I will make quality software.
Programming FTW.

#9684 Function for drawing polygons
1 year, 9 months ago

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 ....

Just being curious on programming....
ratchetfreak
396 posts
#9685 Function for drawing polygons
1 year, 9 months ago

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.
mmozeiko
Mārtiņš Možeiko
1789 posts / 1 project
#9690 Function for drawing polygons
1 year, 9 months ago Edited by Mārtiņš Možeiko on Dec. 8, 2016, 6:50 p.m.

^ 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.
Mattias Gustavsson
@Mattias_G
36 posts

Amateur (ex-pro) game dev, making retro styled games and small public domain C/C++ libs.

#9710 Function for drawing polygons
1 year, 9 months ago

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.
e1211
The_8th_mage
71 posts / 1 project
#9730 Function for drawing polygons
1 year, 9 months ago Edited by The_8th_mage on Dec. 9, 2016, 11:44 p.m. Reason: forgot a reason in the end,2. miswrote Sean's name.

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.