How to fill in a color an internal area of a polygon?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

How to fill in a color an internal area of a polygon?

Post by Andrey01 »

I`ve drawed a round by method

Code: Select all

draw2DPolygon()
. However, it allows to set a color only for bounds of any polygon (in given case, for the circle): http://irrlicht.sourceforge.net/docu/cl ... 853b944ad4 How to fill in any color an internal area of the figure me?
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to fill in a color an internal area of a polygon?

Post by CuteAlien »

You have to create polygons then yourself and draw with draw2DVertexPrimitiveList. That takes vertices which have screen coordinates in X,Y and does the corresponding transformations for you when drawing.

Example for circle (note, I just copy-pasted it with a few modifications from code I wrote, so if there are tiny errors in there which I missed doing that, don't be surprised):

Code: Select all

 
struct CircleSettings
{
    vector2di center;       // in screen coordinates
    f32 radius;             // in pixels
    video::SColor color;
    u32 numVertices = 21;   // including center
};
 
void makeCircle(irr::core::array<irr::video::S3DVertex>& vertices, irr::core::array<irr::u16>& indices, const CircleSettings& settings)
{
    const f64 stepSize = 360.0 / (f64)(settings.numVertices-1); // degree angles between vertex points on circle
    indices.set_used(settings.numVertices+1);   // one more as first and last vertex in circle is identical
    for ( u32 i=0; i<settings.numVertices; ++i)
        indices[i] = i;
    indices[settings.numVertices] = 1;
 
    const vector2df centerf((f32)settings.center.X, (f32)settings.center.Y);
    vertices.set_used(settings.numVertices);
    vertices[0] = video::S3DVertex(centerf.X, centerf.Y, 0.f, 0.f, 1.f, 0.f, settings.color, 0.5f, 0.5f);
    for ( u32 i=0; i < settings.numVertices-1; ++i )
    {
        vector2df offset(0.f, settings.radius;);
        offset.rotateBy(i*stepSize);
        vertices[i+1] = video::S3DVertex(centerf.X+offset.X, centerf.Y+offset.Y, 0.f, 0.f, 1.f, 0.f, settings.color, 0.5f, 0.5f);
    }
}
 
// create the circle
irr::core::array<irr::video::S3DVertex> verticesCircle;
irr::core::array<irr::u16> indicesCircle;
CircleSettings circle;
// circle.center = some value;
// circle.radius = same value;
circle.color = video::SColor(255, 135, 206, 235);   // any value
makeCircle(verticesCircle, indicesCircle, circle);
 
// draw it 
driver->draw2DVertexPrimitiveList(verticesCircle.pointer(), verticesCircle.size(),
        indicesCircle.pointer(), indicesCircle.size()-2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN,
        video::EIT_16BIT);
 
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

Re: How to fill in a color an internal area of a polygon?

Post by Andrey01 »

Thanks for a reply and help.

However, when I see your example, I can not understand what 'draw2DVertexPrimitiveList' actually does and by what principle it works. Does this draw a circle filled by a color? Also, what are indices? Shortly before your reply I made up an other way: I can just draw each circle in a while loop and decrement its radius until it is not a zero value. So the round will get filled. However, it doesn`t fill the round fully, it leaves a transparent gap in the center.
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to fill in a color an internal area of a polygon?

Post by CuteAlien »

draw2DVertexPrimitiveList draws whatever 2d polygons I pass to it. I approximate a circle here with triangles (as we always do in 3d, just doing the same here in 2d). The type of polygons is one of the parameters - in this case EPT_TRIANGLE_FAN. Which draws triangles around one center point (like middle point of a circle). Like this: https://en.wikipedia.org/wiki/Triangle_fan (all points connect to A in that page). If you use enough points like that you can get a nice circle (made out of triangles).

Just try my code - you can copy the function and the struct. Then call the create the circle stuff to create the circle. And in your drawing loop (after drawAll() etc) call the draw2DVertexPrimitiveList part.

Indices are same as in math. Index 0 is the first element, 1 is the second and so on. Index just means - use the x-th element. So if you use the same number of vertices and indices and set the indices just to 0,1,2,3,... then it simply uses the vertices in their original order. But if you want to use vertices in another order then you can use different indices. For example in my code I use one vertex twice to start and close the circle with the same vertex. It's that line:
indices[settings.numVertices] = 1;
There I say basically - use that vertex[1] once more. Which is why in my example my index array is one element larger than the vertex array. I could have added another vertex at the same position instead in this specific case, but in other situations it's simpler to separate vertices from the order in which those vertices are used.

Or think about drawing 2 triangles. Each triangle needs 3 vertices. But - if you draw 2 triangles you really only need 4 vertices and not 6 if they share two vertices. So with this function you can pass 4 vertices and then 6 indices. Where the indices would be 0,1,2 for first triangle and maybe 2,3,0 for the second triangle. And vertices would be the 4 corners.

Also check documentation to draw2DVertexPrimitiveList. It's a bit complicated looking function at first, but it's really just about drawing lots of polygons (usually triangles) in a single call.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

Re: How to fill in a color an internal area of a polygon?

Post by Andrey01 »

Hmm, but how do you get each triangle colored? I suppose the color is determined by summing the colors of its vertices? And also I don`t quite understand why you need one more a vertice, although really is the only starting vertice not sufficient to close the circle?
Andrey01
Posts: 57
Joined: Mon Jul 27, 2020 9:08 pm

Re: How to fill in a color an internal area of a polygon?

Post by Andrey01 »

It seems your code doesn`t colorize an internal area of a triangle fan (maybe I am doing something wrong). In any case, my code below:

Code: Select all

 
//! based on draw2DPolygon, however unlike that, this fills also with the given color the internal area of the polygon
void GUISkin::drawColored2DPolygon(const v2s32 center, u32 radius, 
            u32 vertex_count,           // count of vertices, not counting a center one
            u32 border_thickness, 
            const video::SColor* colors)
{
    if (!colors)
        colors = Colors;
    
    if (border_thickness >= radius)
        return;
    
    // This code in the loop is necessary for drawing border
    for (u32 i = 0; i < border_thickness; i++)
    {
        Driver->draw2DPolygon(center, (f32)radius, colors[EGDC_3D_DARK_SHADOW], vertex_count);
        radius--;
    }
    
    const f64 step_size = 360.0f / vertex_count;
    
    core::array<video::S3DVertex> vertices{vertex_count+1};     // + 1 for the center vertex
    core::array<u32> indices{vertex_count+2};                   // one more index for the same starting vertex
    
    for (u32 i = 0; i < vertex_count + 1; i++)
        indices[i] = i;
    
    indices[vertex_count + 1] = 1;
    
    vertices[0] = video::S3DVertex{(f32)center.X, (f32)center.Y, 0.f, 0.f, 1.f, 0.f, colors[EGDC_3D_DARK_SHADOW], 0.5f, 0.5f};
    v2f32 offset{0.f, (f32)radius};
    
    for (u32 i = 1; i <= vertex_count; i++)
    {
        offset.rotateBy(step_size*i, v2f32{(f32)center.X, (f32)center.Y});
        vertices[i] = video::S3DVertex{(f32)center.X + offset.X, (f32)center.Y + offset.Y, 0.f, 0.f, 1.f, 0.f, colors[EGDC_3D_DARK_SHADOW], 0.5f, 0.5f};
    }
       
    Driver->draw2DVertexPrimitiveList(vertices.pointer(), vertices.size(), indices.pointer(), 
                indices.size()-2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, video::EIT_16BIT);
}
 
CuteAlien
Admin
Posts: 9646
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: How to fill in a color an internal area of a polygon?

Post by CuteAlien »

Andrey01 wrote:Hmm, but how do you get each triangle colored? I suppose the color is determined by summing the colors of its vertices? And also I don`t quite understand why you need one more a vertice, although really is the only starting vertice not sufficient to close the circle?
Yes, color is defined by vertex colors. Which are set with the CircleSettings::color parameter in my case.
I don't need one more vertex, but one more index. So I can index the start vertex twice - and use it to also close the circle. index 0 is the circle center. index 1 is the first and last point on the circle - that's why I set the last index to it: indices[settings.numVertices] = 1;

But looking at your code you seem to have figured it out already :-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Post Reply