Infinite Loop Drawing in OpenGL and Broken Lines issue - c

Infinite Loop Question
I want to achieve the effect as shown the picture:
I am generating this by including an infinite loop inside the glutDisplayFunct callback function, and which is not good as i cannot then process any input from the keyboard. The other method of which i can think is to probably use the glut's explicit window refresh functions.
I want to know how can i insert an infinite loop and also check for keyboard input. Here is the sample code i have made. It simply implements the DDA algorithm and attempts to draw infinite lines by generating random coordinates and colours.
#include <stdio.h>
#include <GL/glut.h>
int width;
int height;
void dda (int x1, int y1, int x2, int y2)
{
int del_x, del_y, sample_steps, i = 1;
double x_incr, y_incr, x, y;
del_x = x2 - x1;
del_y = y2 - y1;
sample_steps = (abs (del_x) > abs (del_y)) ? abs (del_x) : abs (del_y);
x_incr = del_x / (double) sample_steps;
y_incr = del_y / (double) sample_steps;
x = x1;
y = y1;
glBegin (GL_POINTS);
while (i<=sample_steps)
{
glVertex2f ((2.0 * x)/width, (2.0 * y)/height);
x += x_incr;
y += y_incr;
i++;
}
glEnd ();
glFlush ();
}
void keypress_handler (unsigned char key, int x, int y)
{
if (key == 'q' || key == 'Q')
{
glutLeaveMainLoop ();
}
}
void init_screen (void)
{
glMatrixMode (GL_PROJECTION);
glClearColor (0, 0, 0, 1);
glClear (GL_COLOR_BUFFER_BIT);
glLoadIdentity ();
glMatrixMode (GL_MODELVIEW);
}
void test_dda (void)
{
int x1, y1, x2, y2;
float r, g, b;
int i=1;
glClear (GL_COLOR_BUFFER_BIT);
srand (time(NULL));
width = glutGet (GLUT_WINDOW_WIDTH);
height = glutGet (GLUT_WINDOW_HEIGHT);
while (i)
{
x1 = rand () % width - (width /2); /* Global */
y1 = rand () % height - (height /2); /* Global */
x2 = rand () % width - (width /2); /* Global */
y2 = rand () % height - (height /2); /* Global */
r = rand () / (float) RAND_MAX;
g = rand () / (float) RAND_MAX;
b = rand () / (float) RAND_MAX;
glColor3f (r, g, b);
dda (x1, y1, x2, y2);
printf ("\r%d", i);
i++;
}
}
void reshape (int w, int h)
{
glViewport (0, 0, w, h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluOrtho2D (-1, 1, -1, 1);
glMatrixMode (GL_MODELVIEW);
}
int main (int argc, char *argv[])
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
init_screen ();
glutCreateWindow ("DDA");
glutDisplayFunc (test_dda);
glutReshapeFunc (reshape);
glutKeyboardFunc (keypress_handler);
glutMainLoop ();
printf ("\n");
return 0;
}
Broken lines when first drawn
Also i have an additional question, which is like this:
When i uncomment the infinite loop (the while (i)) inside the test_dda function and run the executable with 1280x960 screen size every line drawn shows as broken lines, they seems look something like dashed lines. But, if i do not infinitely loop in this function and draw the lines with some other way, like forcing OpenGL to redraw, the lines shows as they should be displayed. I have noticed that when drawing the first time, the lines show broken. The broke lines of which i am talking is shown below:
To understand what i am saying do the following to get the effect. Change the while (i) to while (i<1000) . This will draw 1000 lines on the screen. When i run with this change with 1280x960 window size, the window is drawn 2 times. The first time the lines are drawn shows as broken as the above image. The moment 1000 lines are drawn, the window is cleared again the it is drawn again, but this time the lines shows as they should be. Why this is happening.

You don't have to. The infinite loop already happens inside glutMainLoop(). It will call your display function over and over again till the program is closed. To keep the output of previous frames (i.e. drawing over them), don't clear the color buffer with glClear().
As for the broken lines: Don't draw lines pixel by pixel. While I didn't have a closer look, you most likely have some discrepancy caused by your view/projection matrix (i.e. you're drawing the dots with too much spacing). Instead, use OpenGL calls to draw lines.
What you're trying to do here is essentially trying to do software rendering on top of hardware accelerated rendering, which is just weird and not really recommended.

The "display" function (test_dda in your case) is called every time the window needs to be redrawn. The event handling code in GLUT get no change of running if you are in an infinite loop inside the display function.
Instead use a timer, and draw one line in the timer function and then call a function to force GLUT to redraw the window, where you "flush" the GL pipe.

I think that the starting solution you are adopting is conceptually wrong.
Don't take me bad :)
If the point is to draw constantly lines over and over, one possible solution would be to segment the process in this way:
FRAME 1 STEP1: You draw the lines on a framebuffer mapped to a texture over a quad containing the working texture
FRAME 1 STEP2: You draw a quad with the working texture
GLUT INPUT CALLBACK
FRAME 2 STEP1: You draw the lines on a framebuffer mapped to a texture over a quad containing the working texture
FRAME 1 STEP2: You draw a quad with the output working texture
GLUT INPUT CALLBACK
And so on.....

Related

What causes the stackoverflow? And how can I resolve it?

I was doing the homework for computer graphics.
We need to use floodfill to paint an area, but no matter how I changed the reserve stack of Visual Studio, it would always jump out stackoverflow.
void Polygon_FloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) {
int interiorColor;
interiorColor = GetPixel(hdc, x0, y0);
if ((interiorColor != borderColor) && (interiorColor != fillColor)) {
SetPixel(hdc, x0, y0, fillColor);
Polygon_FloodFill(hdc, x0 + 1, y0, fillColor, borderColor);
Polygon_FloodFill(hdc, x0, y0 + 1, fillColor, borderColor);
Polygon_FloodFill(hdc, x0 - 1 ,y0, fillColor, borderColor);
Polygon_FloodFill(hdc, x0, y0 - 1, fillColor, borderColor);
}
You may have too large an area to fill, which causes recursive calls to consume all of the execution stack in your program.
Your options:
grow the execution stack even further, if you can
reduce the area (how about just 100x100 or 20x20?)
stop using the execution stack and use a data structure that works similarly but can contain more elements (by being more efficient and/or being able to grow/be larger)
use a different algorithm (e.g. consider going from individual pixels to horizontal spans of pixels, there will be many fewer of the latter than the former)
What causes the stackoverflow?
What is the range of x0? +/- 2,000,000,000? That is your stack depth potential.
Code does not obviously prevent going out of range unless GetPixel(out-of-range) returns a no-match value.
And how can I resolve it?
Code needs to be more selective on recursive calls.
When a row of pixels can be set, do so without recursion.
Then examine that row's neighbors and only recurse when the neighbors were not continuously in need of setting.
A promising approach would handle the middle and then look at the 4 cardinal directions.
// Pseudo code
Polygon_FloodFill(x,y,c)
if (pixel(x,y) needs filling) {
set pixel(x,y,c);
for each of the 4 directions
// example: east
i = 1;
// fill the east line first
while (pixel(x+i,y) needs filling) {
i++;
set pixel(x,y,c);
}
// now examine the line above the "east" line
recursed = false;
for (j=1; j<i; j++) {
if (pixel(x+j, y+j) needs filling) {
if (!recursed) {
recursed = true;
Polygon_FloodFill(x+j,y+j,c)
} else {
// no need to call Polygon_FloodFill as will be caught with previous call
}
} else {
recursed = false;
}
}
// Same for line below the "east" line
// do same for south, west, north.
}
how many pixels to fill? each pixel is one level deep of recursion and you got a lot of variables all local ones and operands of the recursive function + return value and address so for reach pixel you store this:
void Polygon_FloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) {
int interiorColor;
in 32 bit environment I estimate this in [Bytes]:
4 Polygon_FloodFill return address
4 HDC hdc ?
4 int x0
4 int y0
4 int fillColor
4 int borderColor
4 int interiorColor
-------------------
~ 7*4 = 28 Bytes
There might be even more depending on the C engine and calling sequence.
Now if your filled area has for example 256x256 pixel then you need:
7*4*256*256 = 1.75 MByte
of memory on the stack/heap. How much memory you got depends on the settings you compile/link with so go to project option and look for memory stack/heap limits...
How to deal with this?
lower the stack/heap trashing
simply do not use operands for your flood_fill instead move them to global variables:
HDC floodfill_hdc;
int floodfill_x0,floodfill_y0,floodfill_fillColor,floodfill_borderColor;
void _Polygon_FloodFill()
{
// here your original filling code
int interiorColor;
...
}
void PolygonFloodFill(HDC hdc, int x0, int y0, int fillColor, int borderColor) // this is what you call when want to fill something
{
floodfill_hdc=hdc;
floodfill_x0=x0;
floodfill_y0=y0;
floodfill_fillColor=fillColor;
floodfill_borderColor=borderColor;
_Polygon_FloodFill();
}
this will allow to fill ~14 times bigger area.
limit recursion depth
This is also sometimes called priority que ... You just add one gobal counter that is counting actual depth of recursion and if hit limit value then do not allow recursion. Instead add pixel position to some list that will be processed after actual recursion stops.
change filling from pixels to lines
this simply eliminates a lot of recursive calls in wildly rough estimate to sqrt(n) recursions from n... You simply fill whole line from a start point to predetermined direction until you hit the border ... So you would have just recursion call per each line instead of per pixel. Here example (see [edit2]):
Paint algorithm leaving white pixels at the edges when I color
However the function name Polygon_FloodFill implies you got the border polygon in vector form. If the case than filling it will be much faster using polygon rasterization techniques like:
how to rasterize rotated rectangle (in 2d by setpixel)
but for that the polygon must be convex one so if not the case you need to triangulate or break down to convex polygons first (for example with Ear clipping).

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

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.

Looking for a fast outlined line rendering algorithm

I'm looking for a fast algorithm to draw an outlined line. For this application, the outline only needs to be 1 pixel wide. It should be possible, whether by default or through an option, to make two lines connect together seamlessly, if they share a common point.
Excuse the ASCII art but this is probably the best way to demonstrate it.
Normal line:
##
##
##
##
##
##
"Outlined" line:
**
*##**
**##**
**##**
**##**
**##**
**##*
**
I'm working on a dsPIC33FJ128GP802. It's a small microcontroller/digital signal processor, capable of 40 MIPS (million instructions per second.) It is only capable of integer math (add, subtract and multiply: it can do division, but it takes ~19 cycles.) It's being used to process an OSD layer at the same time and only 3-4 MIPS of the processing time is available for calculations, so speed is critical. The pixels occupy three states: black, white and transparent; and the video field is 192x128 pixels. This is for Super OSD, an open source project: http://code.google.com/p/super-osd/
The first solution I thought of was to draw 3x3 rectangles with outlined pixels on the first pass and normal pixels on the second pass, but this could be slow, as for every pixel at least 3 pixels are overwritten and the time spent drawing them is wasted. So I'm looking for a faster way. Each pixel costs around 30 cycles. The target is <50, 000 cycles to draw a line of 100 pixels length.
I suggest this (C/pseudocode mix) :
void draw_outline(int x1, int y1, int x2, int y2)
{
int x, y;
double slope;
if (abs(x2-x1) >= abs(y2-y1)) {
// line closer to horizontal than vertical
if (x2 < x1) swap_points(1, 2);
// now x1 <= x2
slope = 1.0*(y2-y1)/(x2-x1);
draw_pixel(x1-1, y1, '*');
for (x = x1; x <= x2; x++) {
y = y1 + round(slope*(x-x1));
draw_pixel(x, y-1, '*');
draw_pixel(x, y+1, '*');
// here draw_line() does draw_pixel(x, y, '#');
}
draw_pixel(x2+1, y2, '*');
}
else {
// same as above, but swap x and y
}
}
Edit: If you want to have successive lines connect seamlessly, I
think you really have to draw all the outlines in the first pass, and
then the lines. I edited the code above to draw only the outlines. The
draw_line() function would be exactly the same but with one single
draw_pixel(x, y, '#'); instead of four draw_pixel(..., ..., '*');.
And then you just:
void draw_polyline(point p[], int n)
{
int i;
for (i = 0; i < n-1; i++)
draw_outline(p[i].x, p[i].y, p[i+1].x, p[i+1].y);
for (i = 0; i < n-1; i++)
draw_line(p[i].x, p[i].y, p[i+1].x, p[i+1].y);
}
My approach would be to use the Bresenham to draw multiple lines. Looking at your ASCII art, you'll note that the outline lines are just the same as the Bresenham line, just shifted 1 pixel up and down -- plus a single pixel to the left of the first point and to the right of the last.
For a generic version, you'll need to determine whether your line is flat or steep -- i.e., whether abs(y1 - y0) <= abs(x1 - x0). For steep lines, the outlines are shifted by 1 pixel to the left and right, and the closing pixels are above the starting and below the ending point.
It could be worth optimizing this by drawing the line and two outline pixels in one go for each line pixel. However, if you need seamless outlines, the simplest solution would be to first draw all outlines, then the lines themselves -- which wouldn't work with the "three-pixel-Bresenham" optimization.

Resources