0

I've been trying to draw a circle in c++ using openGL. So far i have a compresses circle and it just has a random line going across the screen. This is the function I'm using to get this shape.

void Sprite::init(int x, int y, int width, int height, Type mode, float scale) {
    _x = x;
    _y = y;
    _width = width;
    _height = height;
    //generate buffer if it hasn't been generated
    if (_vboID == 0) {
        glGenBuffers(1, &_vboID);
    }
    Vertex vertexData[360];
    if (mode == Type::CIRCLE) {
        float rad = 3.14159;
        for (int i = 0; i < 359; i++) {
            vertexData[i].setPosition((rad * scale) * cos(i), (rad * scale) * sin(i));
        }
    }

    //Tell opengl to bind our vertex buffer object
    glBindBuffer(GL_ARRAY_BUFFER, _vboID);
    //Upload the data to the GPU
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);

    //Unbind the buffer
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

What is causing the line? Why is my circle being compressed?

Sorry if this is a dumb question or if this question doesn't belong on this website I'm very new to both c++ as well as this website.

zee
  • 2,933
  • 2
  • 16
  • 28

2 Answers2

2

It is difficult to be sure without testing the code myself, but I'll guess anyway.

Your weird line is probably caused by the buffer not being fully initialized. This is wrong:

Vertex vertexData[360];
for (int i = 0; i < 359; i++) {

It should be:

for (int i = 0; i < 360; i++) {

or else the position at vertexData[359] is left uninitialized and contains some far away point.

About the ellipse instead of a circle, that is probably caused by your viewport not having the same scale horizontally and vertically. If you configure the viewport plus transformation matrices to have a viewing frustum of X=-10..10, Y=-10..10, but the actual viewport is X=0..800 and the Y=0..600, for example, then the scale would be different and you'll get your image distorted.

The solution would be one of:

  1. Create a square viewport instead of rectangular. Check your arguments to glViewport().
  2. Define a view matrix to consider the same ratio your viewport has. You don't show how you set the view/world matrix, maybe you are not even using matrices... If that is the case, you should probably use one.
rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • Thank you so much! just a question though, if the vertexData array stores the coordinates for 360 vertices and it starts at 0 and ends at 359 shouldn't i do the same? or am i missing something here? – zee May 08 '16 at 17:33
  • Yes. But you are using `<` to stop the loop, not `<=`. so with `i < 360` the last iteration is when `i == 359`. In C and C++ it is idiomatic to do loops like that: `int x[N]; for (int i = 0; i < N; ++i) x[i] = ...;`. – rodrigo May 08 '16 at 17:39
0

I don't understand, exactly, what you want obtain but... cos() and sin() receive a radiant argument; so, instead of cos(i) and sin(i), I suppose you need cos((2*rad*i)/360.0)) and sin((2*rad*i)/360.0)) or, semplified, cos((rad*i)/180.0)) and cos((rad*i)/180.0))

And what about the center and the radious of the circle?

(x, y) should be the center of the circle?

scale is the radious?

In this case, I suppose you should write something like (caution: not tested)

Vertex vertexData[360];
float  rad = 3.14159;
if (mode == Type::CIRCLE) {
    for (int i = 0; i < 359; ++i) {
        float  angle = (rad / 180) * i; // (thanks Rodrigo)
        vertexData[i].setPosition(x + scale * cos(angle), y + scale * sin(angle));
    }
}

or, loosing precision but avoidind some moltiplication,

Vertex vertexData[360];
float  rad = 3.14159;
float  angIncr = rad / 180.0;
if (mode == Type::CIRCLE) {
    for (int i = 0, float angle = 0.0; i < 359; ++i, angle += angIncr) {
        vertexData[i].setPosition(x + scale * cos(angle), y + scale * sin(angle));
    }
}

But what about width and heigth?

p.s.: sorry for my bad English.

--- modified with suggestion from Rodrigo --

max66
  • 65,235
  • 10
  • 71
  • 111
  • 1
    Personally I prefer the first version. The second one suffers from an accumulated loss of precision in the `angle` variable. If you are worried about the performance, you could change to `float angle = (rad/180) * i;` so that the compiler is able to reduce the calculation to just one multiplication. – rodrigo May 08 '16 at 17:38
  • @ rodrigo: good point; I'll steal... ehm... take inspiration from your comment and I'll do an edit in my answer. – max66 May 08 '16 at 17:42
  • sorry for the lack of comments in my code. `width` `height` `x` and `y` are being used in the case of not wanting to do a circle that's why i have the `Type mode` parameter. for example if a square or rectangle is needed to be drawn then i would use those parameters, sorry for the confusion. also the scale is not the radius i specified `rad` to be the radius and `scale` is well, just to scale the circle, make it bigger or larger. Also thank you for the info i didn't realize `sin` and `cos` only took radians, but for some reason they still work when I'm using angles. Hope this cleared it up! – zee May 08 '16 at 17:45
  • @ zee: so `rad` was for "radius" and not for "radiant"? And your base radius value is PI? Well... yes... now I'm really confused :) And, yes: still works with angles instead of radiants but your points are doing 57 loops around the center. – max66 May 08 '16 at 17:51
  • Just tested the first version of the code you gave me, and it works flawlessly, gives me the same results as mine expect the scaling is much easier to do! but its suffers from the line going across issue, however like @rodrigo said it's easily fixed by using `for (int i = 0; i < 360; i++) {` instead of `for (int i = 0; i < 359; i++) {` – zee May 08 '16 at 17:51
  • @max66 yeah now that people are pointing out the silly mistakes i made i can see the problems with it. Thanks for the help though I really appreciate it! – zee May 08 '16 at 17:55
  • @zee: yes, the answer of Rodrigo is correct (I didn't see the lack of the last point) and the last, uninitialized, point can explaint (and your test verify that is the correct explanation) the strange line. – max66 May 08 '16 at 17:57
  • @Rodrigo If you care about performance, you wouldn't use a `cos()` and `sin()` call for each point... – Reto Koradi May 08 '16 at 18:00
  • @RetoKoradi how would you suggest for it to be done then? – zee May 08 '16 at 20:46
  • @zee You rotate the point by the angle increment to get the next point. See for example my answer here: http://stackoverflow.com/questions/25279009/how-to-draw-a-circle-using-vbo-in-es2-0. – Reto Koradi May 08 '16 at 22:33