OpenGL - drawing 2D polygons shapes with texture - c

I am trying to make a few effects in a C+GL game. So far I draw all my sprites as a quad, and it works.
However, I am trying to make a large ring appear at times, with a texture following that ring, as it takes less memory than a quad with the ring texture inside.
The type of ring I want to make is not a round-shaped GL mesh ring (the "tube" type) but a "paper" 2D ring. That way I can modify the "width" of the ring, getting more of the effect than a simple quad+ring texture.
So far all my attempts have been...kind of ridiculous, as I don't understand GL's coordinates too well (and I can't really understand the available documentation...I am just a designer with no coder help or background. A n00b, basically).
glBegin(GL_POLYGON);
for(i = 0;i < 360; i += 10){
glTexCoord2f(0, 0);
glVertex2f(Cos(i)*(H-10),Sin(i)*H);
glTexCoord2f(0, HP);
glVertex2f(Sin(i)*(H-10),Cos(i)*(H-10));
glTexCoord2f(WP, HP);
glVertex2f(Cos(i)*H,Sin(i)*(H-10));
glTexCoord2f(WP, 0);
glVertex2f(Sin(i)*H,Cos(i)*H);
}
glEnd();
This is my last attempt, and it seems to generate a "sunburst" from the right edge of the circle instead of a ring. It's an amusing effect but definitely not what I want. Other results included the circle looking exactly the same as the quad textured (aka drawing a sprite literally) or something that looked like a pop-art filter, by working on this train of thought.
Seems like my logic here is entirely flawed, so, what would be the easiest way to obtain such a ring? No need to reply in code, just some guidance for a non-math-skilled user...
Edit: A different way to word what I want, would be a sequence of rotated rectangles connected to each other, forming a low-resolution ring.

So you want an annulus? That is, the area between two circles with the same center but different radii? I'd try a quad strip like this:
glBegin(GL_QUAD_STRIP);
for(i = 0; i <= 360; i += 10){
glTexCoord2f(WP*i/360, 0);
glVertex2f(Cos(i)*(H-10),Sin(i)*(H-10));
glTexCoord2f(WP*i/360, HP);
glVertex2f(Cos(i)*H,Sin(i)*H);
}
glEnd();
Each quad is a 10-degree sector of the ring. Note that if you want to draw N quads in a strip, it takes 2*(N+1) points, so we draw a total of 2*(36+1) = 74 points.

The post here on the OpenGL forums seems to do what you want. An overview of the approach:
If you want a circle filed with a
texture, you can use triangle fan.
First, draw the vertex at the center
of the circle. Then draw the vertex on
the contour of the circle, use
cos(angle)*radius for x and
sin(angle)*radius for y. Since texture
coordinates s and t are in the range
[0 1] => s = (cos(angle)+1.0)*0.5 and
t = (sin(angle)+1.0)*0.5 . The texture
coordinate for the vertex at the
center of the circle is (0.5,0.5).
GLvoid draw_circle(const GLfloat radius,const GLuint num_vertex)
{
GLfloat vertex[4];
GLfloat texcoord[2];
const GLfloat delta_angle = 2.0*M_PI/num_vertex;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,texID);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
glBegin(GL_TRIANGLE_FAN);
//draw the vertex at the center of the circle
texcoord[0] = 0.5;
texcoord[1] = 0.5;
glTexCoord2fv(texcoord);
vertex[0] = vertex[1] = vertex[2] = 0.0;
vertex[3] = 1.0;
glVertex4fv(vertex);
for(int i = 0; i < num_vertex ; i++)
{
texcoord[0] = (std::cos(delta_angle*i) + 1.0)*0.5;
texcoord[1] = (std::sin(delta_angle*i) + 1.0)*0.5;
glTexCoord2fv(texcoord);
vertex[0] = std::cos(delta_angle*i) * radius;
vertex[1] = std::sin(delta_angle*i) * radius;
vertex[2] = 0.0;
vertex[3] = 1.0;
glVertex4fv(vertex);
}
texcoord[0] = (1.0 + 1.0)*0.5;
texcoord[1] = (0.0 + 1.0)*0.5;
glTexCoord2fv(texcoord);
vertex[0] = 1.0 * radius;
vertex[1] = 0.0 * radius;
vertex[2] = 0.0;
vertex[3] = 1.0;
glVertex4fv(vertex);
glEnd();
glDisable(GL_TEXTURE_2D);
}

Related

openGL(c) draw square

i need to draw a square using c (openGL),
i only have 1 coordinate which is the center of the square (lets say 0.5,0.5) and i need to draw a square ABCD with each side 0.2 length (AB,BC,CD,DA),
I tried using the next function but it does not draw anything for some reson,
void drawSquare(double x1,double y1,double radius)
{
glColor3d(0,0,0);
glBegin(GL_POLYGON);
double locationX = x1;
double locationY = x2;
double r = radius;
for(double i=0; i <= 360 ; i+=0.1)
{
glVertex2d(locationX + radius*i, locationY + radius*i);
}
glEnd();
}
can someone please tell me why its not working\point me to the right direction (i do not want to draw polygon with 4 coordinated normally, but with only 1 coordinate with a givven radius,
thanks!
Your code will not even draw a circle. If anything, it will draw a diagonal line extending out of the view area very quickly. A circle plot would need to use sine and cosine, based on the radius and angle.
I have not tried this code, but it needs to be more like this to draw a square.
void drawSquare(double x1, double y1, double sidelength)
{
double halfside = sidelength / 2;
glColor3d(0,0,0);
glBegin(GL_POLYGON);
glVertex2d(x1 + halfside, y1 + halfside);
glVertex2d(x1 + halfside, y1 - halfside);
glVertex2d(x1 - halfside, y1 - halfside);
glVertex2d(x1 - halfside, y1 + halfside);
glEnd();
}
There are no normals defined: perhaps I should have travelled counter-clockwise.
Simple way to draw a square is to use GL_QUADS and the four vertices for the four corners of the square. Sample code is below-
glBegin(GL_QUADS);
glVertex2f(-1.0f, 1.0f); // top left
glVertex2f(1.0f, 1.0f); // top right
glVertex2f(1.0f, -1.0f); // bottom right
glVertex2f(-1.0f, -1.0f); // bottom left
glEnd();
Since in the case you have to draw square from the mid point which is interaction of two diagonals of square. You use the following facts and draw the same.
length of diagonal = x*square root of 2 (x=side of square)
diagonals of a square are perpendicular
diagonals of a square are the same length
If your point is at 0.5,0.5 which coordinate of interaction point, and side is 0.2. So you can easily determine the point coordinate of four corners as in the figure given below and code it accordingly.

OpenGL: Wrapping texture around cylinder

I am trying to add textures to a cylinder to draw a stone well. I'm starting with a cylinder and then mapping a stone texture I found here but am getting some weird results. Here is the function I am using:
void draw_well(double x, double y, double z,
double dx, double dy, double dz,
double th)
{
// Set specular color to white
float white[] = {1,1,1,1};
float black[] = {0,0,0,1};
glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,shinyvec);
glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,white);
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,black);
glPushMatrix();
// Offset
glTranslated(x,y,z);
glRotated(th,0,1,0);
glScaled(dx,dy,dz);
// Enable textures
glEnable(GL_TEXTURE_2D);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
glBindTexture(GL_TEXTURE_2D,texture[0]); // Stone texture
glBegin(GL_QUAD_STRIP);
for (int i = 0; i <= 359; i++)
{
glNormal3d(Cos(i), 1, Sin(i));
glTexCoord2f(0,0); glVertex3f(Cos(i), -1, Sin(i));
glTexCoord2f(0,1); glVertex3f(Cos(i), 1, Sin(i));
glTexCoord2f(1,1); glVertex3f(Cos(i + 1), 1, Sin(i + 1));
glTexCoord2f(1,0); glVertex3f(Cos(i + 1), -1, Sin(i + 1));
}
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
// Later down in the display function
draw_well(0, 0, 0, 1, 1, 1, 0);
and the output I receive is
I'm still pretty new to OpenGL and more specifically textures so my understanding is pretty limited. My thought process here is that I would map the texture to each QUAD used to make the cylinder, but clearly I am doing something wrong. Any explanation on what is causing this weird output and how to fix it would be greatly appreciated.
There are possibly three main issues with your draw routine. quad-strip indexing, texture coordinates repeating too often and possible incorrect usage of the trig functions;
Trigonometric functions usually accept values which represent angles expressed in radians and not degrees. Double check what the parameters of the Sin and Cos functions you are using.
Quadstrip indexing is incorrect. Indexing should go like this...
Notice how the quad is defined in a clock-wise fashion, however the diagonal vertices are defined sequentially. You are defining the quad as v0, v1, v3, v2 instead of v0, v1, v2, v3 so swap the last two vertices of the four. This also leads to another error in not sharing the vertices correctly. You are duplicating them along each vertical edge since you draw the same set of vertices (i+1) in one loop, as you do in the next (i.e since i has now been incremented by 1).
Texture coordinates are in the range from 0, 1 for each quad which means you are defining a cylinder which is segmented 360 times and this texture is repeated 360 times around the cylinder. I'm assuming the texture should be mapped 1:1 to the Cylinder and not repeated?
Here is some example code using what you provided. I have reduced the number of segments down to 64, if you wish to still have 360 then ammend numberOfSegments accordingly.
float pi = 3.141592654f;
unsigned int numberOfSegments = 64;
float angleIncrement = (2.0f * pi) / static_cast<float>(numberOfSegments);
float textureCoordinateIncrement = 1.0f / static_cast<float>(numberOfSegments);
glBegin(GL_QUAD_STRIP);
for (unsigned int i = 0; i <= numberOfSegments; ++i)
{
float c = cos(angleIncrement * i);
float s = sin(angleIncrement * i);
glTexCoord2f( textureCoordinateIncrement * i, 0); glVertex3f( c, -1.0f, s);
glTexCoord2f( textureCoordinateIncrement * i, 1.0f); glVertex3f( c, 1.0f, s);
}
glEnd();
N.BYou are using an old version of OpenGL (the use of glBegin/glVertex etc).

OpenGL - circle not being drawn smooth

I am drawing a circle using OpenGL, with the set of calls being:
float delta_theta = 0.001;
glBegin(GL_POLYGON); // OR GL_LINE_LOOP
glEnable( GL_LINE_SMOOTH );
glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
for (angle = 0; angle < 2*3.1415; angle += delta_theta)
glVertex3f( radius*cos(angle), radius*sin(angle), 0 );
glEnd();
The problem is that the circle is not smooth. I am moving (translating) the circle along axes; at some points it becomes smooth, but mostly, it's like a blot, please see the attached screenshot.
Any suggestions as to what I could do to smoothen the circle?
I would suggest you not try to implement this with lines or a filled polygon for one thing.
Use a single GL_POINT and enable GL_POINT_SMOOTH. That will rasterize the point as a filled circle instead of the normal square. It will be much more efficient, provided you use a point size your implementation supports for anti-aliased points (often up to ~ 63.5 on NV implementations, more on others).

GluProject Not showing Accurate coordinate in C

I am trying to find the screen coordinates from the opengl coordinates(projected in 3D space) I have used glproject call for this purpose,i have used rotation and translation to in my code
At certain point after performing some transformation, i called glproject api to get the screen coordinate of a particular projected point P(x,y,z)
glproject(x,y,z,modelMatrix,projectionmatrix,viewport,*x_s,*y_s,*z_s);
I am able to get x screen coordinate correctly in x_s , but y coordinates are different
The only change in y which is not in x is when initially i called the glperspective to set fovy(The field of view angle, in degrees, in the y-direction). gluPerspective(60.0f, Width/Height,0.0001f,1000.0f);
Let me Rephrase the question I have created a 3D point on screen and now i am getting the 2d(x,y) coordinates of that point through GLproject they come different from the mouse coordinates What could be the possible solution to get correct coordinates.
Here is the code snippet
#include<GL/glut.h> /* Header File For The GLUT Library */
GLint Window; /* The number of our GLUT window */
float tmp_x,tmp_y,tmp_z;
GLfloat w = 1200; /* Window size. Global for use in rotation routine */
GLfloat h = 1200;
GLint prevx, prevy; /* Remember previous x and y positions */
GLfloat xt=1.0,yt=1.0,zt=1.0; /* translate */
int width = 1600;
int height = 1200;
//This function will set windowing transformation
void transform(GLfloat Width , GLfloat Height )
{
glViewport(0,0, (GLfloat)Width, (GLfloat)Height);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0f, Width/Height,0.0001f,1000.0f);
glTranslatef(0.0, 0.0, -15.0f); /* Centre and away the viewer */
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
GLvoid draw_room()
{
int i;
glPushMatrix();
glShadeModel(GL_SMOOTH);
glLineWidth(1.0);
glPointSize(4.0); /* Add point size, to make it clear */
glBegin(GL_POINTS); /* start drawing the cube.*/
glColor3f(0.0f,0.0f,1.0f); /* Set The Color To Orange*/
glColor3f(1.0f,0.0f,0.0f); /* Set The Color To Orange*/
glVertex3f(3.1f,2.1f,2.1f);
glEnd(); /* Done Drawing The Cube*/
glEnable(GL_DEPTH_TEST);
}
//OpenGl Display callback Function It call init room
void DrawGLScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
printf("%f %f %f\n",xt,yt,zt);
glPushMatrix();
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(xt,yt, zt);
draw_room();
glPopMatrix();
glutSwapBuffers(); /* Swap buffers */
glFlush();
}
GLvoid Mouse( int b , int s, int xx, int yy)
{
double a1,a2,a3;
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
//gluProject(xt+3.1f,yt+2.1f,zt+2.1f, modelview, projection, viewport, &a1, &a2, &a3);
gluProject(3.1f,2.1f,2.1f, modelview, projection, viewport, &a1, &a2, &a3);
printf("Mouse: %d %d\n",xx,yy); // Both Print are giving different coordinaes.
printf("Unproject %f %f %f\n",a1,a2,a3);
switch (b) {
case GLUT_LEFT_BUTTON: /* only stash away for left mouse */
prevx = xx - w/2;
prevy = h/2 - yy;
break;
case GLUT_MIDDLE_BUTTON:
break;
case GLUT_RIGHT_BUTTON:
break;
}
}
What could be the possible solution for this?
OpenGL uses lower left corner of screen as coordinate system orign. Window system usually uses upper left corner as coordinate system orign. You need to handle this difference. Example:
printf("Mouse: %d %d\n",xx,yy);
printf("Unproject %f %f %f\n",a1,viewport[1]-a2,a3);
A side issue:
gluPerspective(60.0f, Width/Height,0.0001f,1000.0f);
You have a very large ratio between your near and far plane distance. This is very bad for depth resolution. As a general rule you should set the near clip plane distance as far as possible, as the scene allows. The far clip plane for a projection as created by gluPerspective should be set as near as possible (it's also possible to set the far clipping plane to infinity if the projection matrix is built slightly different).
Anyway, your low depth resolution will have a negative impact on your mouse pointer screen position back projection.
Let me Rephrase the question I have created a 3D point on screen and now i am getting the 2d(x,y) coordinates of that point through GLproject they come different from the mouse coordinates What could be the possible solution to get correct coordinates.
Most window systems put the pointer coordinate system origin to the upper left. OpenGL sets the viewport coordinate system origin into the lower left. So you'll have to invert the mouse position in the window along the Y=Up axis.

Simple form with pixel manipulation with opengl in linux

i want to create a 800X600 window that just show some circle and be able to manipulate pixels of the form every milisecond and show the result to the user. there is no interaction between user and form(no click, no dblclick,…) it just shows some circles with one color and lines with different pixel colors(each line may have different pixel colors)
also i want to be able to change the coordination system, i mean change it from top-left to the center of the window. could anyone help me do that with some sample code? links? tutorial?
OpenGL doesn't have a built-in circle function, but it does have line functions, and you can simulate a circle using polygons. To draw lines, you can do something like this:
glBegin (GL_LINES);
// First line segment
glVertex2f (x0, y0);
glVertex2f (x1, y1);
// Second line segment
glVertex2f (x2, y2);
glVertex2f (x3, y3);
glEnd ();
To draw a circle, you can write a loop to draw a triangle fan. Something like:
glBegin (GL_TRIANGLE_FAN);
// Center point
glVertex2f (cx, cy);
for (segment = 0; segment < maxSegments; segment++)
{
double angle = delta * segment;
double x = cx + cos (angle) * radius;
double y = cy + sin (angle) * radius;
glVertex2f (x, y);
}
glEnd ();
In this case, delta is 2 * pi / maxSegments, and maxSegments is the number of segments you want in your circle approximation.

Resources