I am fairly new to using GLUT, and I have been attempting to compile a program (which I found here, first response) that uses the mouse to draw a rectangle by recording the starting and ending points of a click-and-drag.
As a clean copy/paste, it will compile but not draw anything. It just displays a white screen, even after changing the background color to black (in the setup() function). I've read several sources to verify that this program doesn't miss anything in its draw and reshape functions, and it's all there.
I create a window, set the viewport to the window dimensions, and then use the gluOrtho2D function to set the mapping (since the window and viewport are the same dimensions, I set the mapping to the window dimensions). The mouse callback records where I left-click, and where I release left-click, then calls the glutPostRedisplay() function to redraw the window with the new coordinates. After a bit of debugging, I discovered the coordinates are recorded and saved appropriately, and are measured in pixels (x and y are integers between 0 and window dimension), so I should be able to draw a rectangle from one vertex to the other vertex using the coordinates. But, like I said, it only displays a white screen.
So, is there something wrong with the way I am drawing the rectangle? Am I mapping the window incorrectly? I am seriously lost, and any feedback would be greatly appreciated.
EDIT2: I changed the glutInitDisplayMode from GLUT_SINGLE to GLUT_DOUBLE, and that fixed the whole non-interactive white screen thing. Now it will draw a rectangle with the mouse with a flipped y-coordinate (which I fixed), and it works great now. Thank you very much for the suggestion.
Here is my program (EDIT1: added comments):
#include <cstdlib>
#include <GL/glut.h>
using namespace std;
GLsizei width, height;
struct Position
{
Position() : x(0), y(0) {}
float x;
float y;
};
Position start; // Records left-click location
Position finish; // Records left-click release location
void display()
{
glClear(GL_COLOR_BUFFER_BIT); // clear window
glColor3ub(rand()%256, rand()%256, rand()%256); // generates random color
glBegin(GL_QUADS);
glVertex2f(start.x,start.y);
glVertex2f(finish.x,start.y);
glVertex2f(finish.x,finish.y);
glVertex2f(start.x,finish.y);
glEnd();
glutSwapBuffers(); // display newly drawn image in window
}
void reshape( int w, int h )
{
glViewport( 0, 0, (GLsizei)w, (GLsizei)h ); // set to size of window
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0.0, (float)w, 0.0, (float)h );
width = w; // records width globally
height = h; // records height globally
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
switch(button)
{
case GLUT_LEFT_BUTTON:
if(state==GLUT_DOWN)
{
start.x = x; //x1
start.y = y; //y1
}
if(state==GLUT_UP)
{
finish.x = x; //x2
finish.y = y; //y2
}
break;
glutPostRedisplay();
}
}
void motion( int x, int y )
{
finish.x = x;
finish.y = y;
glutPostRedisplay();
}
void setup()
{
glClearColor(0.0, 0.0, 0.0, 1.0); // *should* display black background
}
int main(int argc, char** argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(640,480);
glutInitWindowPosition(100,100);
glutCreateWindow("");
setup();
// initializing callbacks
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutMainLoop();
return 0;
}
As my comment suggested:
change:
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
to:
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
Related
i've a problem with drawing firework effect in animated scene when i clicked on mouse button. Why it don't drawing?
My Code:
#include<GL/glut.h>
struct Point {
GLint x;
GLint y;
};
Point p1, p2;
int ww=600,wh=400;
int xi,yi,xf,yf,y1b,x1b,y2b,x2b;
float px, py, t;
float x=0.,y=0.,x1=5.;
void update()
{
x+=0.01;
x1 -= 0.02;
if (x>6)
{
x -= 6;
x1 = 4;
}
}
There I create a function that draw firework effect on the basis of bezier curves. It will Okey if I draw on the static window.
// Bezier curve firework
void bezier(int xi, int yi, int xf, int yf)
{
// Coordinates for additional points of bezier curve
x1b = xi + rand()%15;
y1b = yi + rand()%5;
x2b = xf + rand()%15;
y2b = xf + rand()%5;
calculate and draw the curves
for (t=0.;t<=1.;t+=0.001)
{
px=(1-t)*(1-t)*(1-t)*xi+3*t*(1-t)*(1-t)*x1b+3*t*t*(1-t)*x2b+t*t*t*xf;
py=(1-t)*(1-t)*(1-t)*yi+3*t*(1-t)*(1-t)*y1b+3*t*t*(1-t)*y2b+t*t*t*yf;
glPointSize(2);
glBegin(GL_POINTS);
//glColor3f(1,0,0);
glVertex2d(px,py);
glEnd();
glFlush();
}
}
void initRendering()
{
glEnable(GL_DEPTH_TEST);
}
void reshaped(int w , int h)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, (double)w/(double)h,1,200);
}
// If pressed ESC -> exit
void keyPressed(unsigned char k, int x, int y)
{
if(k==27)
{
exit(0);
}
}
Then, if I pressed mouse button it should call the function above and draw what I need. But nothing(
// If pressed mouse button -> draw firework effect
void mousePressed(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP)
{
xi=x;
yi=wh-y;
xf=x + 5.;
p1.x = xi; p1.y = yi;
p2.x = xf; p2.y = yi;
//drawLine(xi,yi,xf,yi);
bezier(xi, yi,xf, yi);
}
glutPostRedisplay();
}
There I create animated window. Two clouds move in gorizontal waves.
// Display a two moving clouds and the earth
void display()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix();
glTranslatef(x1,y,-5.0);
glBegin(GL_POLYGON);
glColor3f(1.,0.,0.5);
glVertex3f(-1.,1.,-5.);
glVertex3f(0.,2.,-5.);
glVertex3f(-2.,2.,-5.);
glVertex3f(1.,1.,-5.);
glEnd();
glPopMatrix();
glPushMatrix();
glTranslatef(x,y,-5.);
glBegin(GL_POLYGON);
glColor3f(0.,0.5,0.5);
glVertex3f(1.,0.7,-5.);
glVertex3f(1.5,1.0,-5.0);
glVertex3f(0.7,1.5,-5.0);
glVertex3f(0.0,2.0,-5.0);
glVertex3f(-0.7,1.5,-5.0);
glVertex3f(-1.4,1.6,-5.0);
glVertex3f(-1.7,1.0,-5.0);
glVertex3f(-1.5,0.7,-5.0);
glVertex3f(-1.0,0.5,-5.0);
glEnd();
glPopMatrix();
glBegin(GL_POLYGON);
glColor3f(1.,1.,1.5);
glVertex3f(-2.,-2.,-5.);
glVertex3f(-2.0,-2.0,-5.0);
glVertex3f(-1.0,-1.5,-5.0);
//glVertex3f(0.0,0.0,-5.0);
glVertex3f(2.0,-2.0,-5.0);
glVertex3f(1.2,-1.5,-5.0);
glEnd();
update();
glutSwapBuffers();
glFlush();
}
void myinit()
{
glViewport(0,0,ww,wh);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)ww,0.0,(GLdouble)wh);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc,char **argv)
{
// Initialization
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
glutInitWindowPosition(100,100);
glutInitWindowSize(400,400);
glutCreateWindow("Salute | Clouds");
initRendering();
// Registration
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshaped);
// Handler of
myinit();
glutKeyboardFunc(keyPressed);
glutMouseFunc(mousePressed);
// Main Loop
glutMainLoop();
return(0);
}
I think the problem is as follows:
I'm trying to draw my firework in an updated animated window. And every time I clicked on the screen, it is updated. And in the end, nothing is visible.
Actually the question:
How to make so that function glutMoseFunk would draw my salute in updated window?
While your scene is draw in perspective projection, the function bezier works with orthographic projection. This means you have to change the projection matrix befor you call bezier.
Further, do all the rendering in the main loop (display function). The event mousePressed should only be used to change parameters (set xi, yi, ...).
The display function may look like this:
int ww=400, wh=400;
void display()
{
// clear the frame buffer
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
// setup perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, (double)ww/(double)wh,1,200);
// set model view matrix (identity matrix)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// draw scene
.....
// setup ortihgraphic projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)ww,0.0,(GLdouble)wh);
bezier(xi, yi,xf, yi);
update();
glutSwapBuffers();
glutPostRedisplay();
}
The reshaped function should set the viewport and notice the window size only:
void reshaped(int w , int h)
{
ww = w;
wh = h;
glViewport(0, 0, ww, wh);
}
For the sake of learning, I'm accessing individual pixel data using GLUT and manually setting pixel color by going through all pixels in the window, like this (some non-related code omitted):
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0, WIDTH, 0.0, HEIGHT);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT);
for (int i = 0; i < WIDTH; i++) {
for (int j = 0; j < HEIGHT; j++) {
glPointSize(1.0f);
glColor3f(255, 0, 0);
glBegin(GL_POINTS);
glVertex2i(i, j);
glEnd();
}
}
glutSwapBuffers();
}
void timer(int obsolete) {
glutPostRedisplay();
glutTimerFunc(16, timer, 0);
}
int main(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("GLUT Test");
init();
glutDisplayFunc(display);
timer(0);
glutMainLoop();
return 0;
}
I'm expecting to get a fully red pixels window, but I'm getting something different - a window with black vertical stripes, as if horizontal for loop suddenly skipped some lines.
Any ideas what am I doing wrong here? I have a suspicion it might be related to float to int conversion somewhere "inside", but I'm not sure what to search for.
Edit: I've found out that if I resize the window in runtime to be one pixel less in width, then these black stripe tears disappear.
You set up the projection such that the left edge is at 0, and the right one at WIDTH. Note that your pixels are small squares with an area, and this means that 0.0 maps to the left edge ot the left-most pixel, and WIDTH maps to the right edge of the right-most pixel. Integer coordinates will lie exactly in the middle between two pixels. And with some numerical precision loss during transformation, you might end up with two neighboring points beeing rounded to the same pixel.
You can either add 0.5 to x and y when drawing your points, or just shift your orth projection by half a pixel so that integers are mapped to pixel centers:
Ortho(-0.5f, WIDTH-0.5f, -0.5f, HEIGHT-0.5f, ...);
I want to make a space invader game in opengl. So I thought of creating the enemies using triangles. Before making the game, I want to try out my hand in animation. I have triangle. i want to translate it left upto some point with animation(i.e, triangle is translated after some interval of time. It should look as if it is moving).After reaching some point in the left, I want to translate it back to the same position or some distances right. The process should go on till the screen is open. I used sleep function. But it is not working. No animation is shown. Only the translated triangle is drawn at different translated position. Help me.
Here is my code-
#include "windows.h"
#include <gl/glut.h>
#include<stdio.h>
void init( void )
{
printf( "OpenGL version: %s\n", (char*)glGetString(GL_VERSION));
printf( "OpenGL renderer: %s\n", (char*)glGetString(GL_RENDERER));
//Configure basic OpenGL settings
glClearColor(1.0, 1.0, 0.0, 0.0);
glMatrixMode(GL_PROJECTION);
gluOrtho2D(0.0,640.0,0.0,480.0);
glColor3f(1.0,0.0,0.0);
glPointSize(3);
}
void house(int x, int y,int z)
{
glPushMatrix();
glTranslatef(x, y,z);
glBegin (GL_LINES);
glVertex2i (0,30);
glVertex2i (15,60);
glVertex2i (15,60);
glVertex2i (30,30);
glVertex2i (30,30);
glVertex2i (0,30);
glEnd();
//Sleep(200);
glPopMatrix();
//glutSwapBuffers();
}
// Main drawing routine. Called repeatedly by GLUT's main loop
void display( void )
{
//Clear the screen and set our initial view matrix
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
int i;
for(i = 10; i < 350; i = i + 50)
{
house(i,20,0);
Sleep(200);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFlush();
}
// Entry point - GLUT setup and initialization
int main( int argc, char** argv )
{
glutInit( &argc, argv );
glutInitDisplayMode (GLUT_DEPTH | GLUT_SINGLE| GLUT_RGB);
glutInitWindowSize (800, 600);
glutInitWindowPosition (100, 100);
glutCreateWindow( "OpenGL Test" );
glutDisplayFunc( display );
init();
glutMainLoop();
return 0;
}
In main() you have declared your display() as display callback function. GLUT will call this function either when it determines that the window need to be redrawn or when it is told to redraw it for example by the function glutPostRedisplay().
The display function is expected to call redraw the windows at a specific point in time. The glFlush() will force the execution of the GL commands.
The problem is that your animation loop is inside the redraw function and glFlush() is called at the end, showing the result at once. And you don't tell GLUT to redraw the windows. This is why you don't seee the animation.
For the purpose of the tutorial, I propose you to define a global variable for the initial position of the house drawing. Of course, you'll have to improve this as soon as you understood how all this works.
static int pos = 10; // temporary work around, just for the demo
Then define a timer function, that gets called after a time interval. This will be the core of your animation, organizing the moving, and the redrawing of the window by calling glutPostRedisplay() :
void timerfunc(int value) // handle animation
{
pos += 50; // update the postion
if (pos<350) // as in your originial loop
glutTimerFunc(200, timerfunc, 0); // plan next occurence
glutPostRedisplay(); // redraw the window
}
Activate your timer function, in main() just before launching glutMainLoop():
glutTimerFunc(200, timerfunc, 0); // call a timer function
glutMainLoop(); // this call is already in your code
Your display function can then be changed into:
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
house(pos, 20, 0); // draw the house at its last calculated position
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glFlush();
}
Then it works in animated modus !
I have a problem, i'm using glut (the openGL utility toolkit). I'm making a subwindow in a mainwindow. The mainwindow displays a simple figure and the subwindow displays the figure from another view. The figure rotates so the mainwindow and the subwindow should always be redisplayed.
But only one of the two displays the rotating figure. So when I start the program the figure in the mainwindow rotates but in the subwindow it don't rotate, it just stands still.
When I move my mouse in the subwindow and press any key the roles changes so the figure rotates in the subwindow and stands still in the mainwindow.
How can I let them both display simultaneous. I followed the tutorial from Lighthouse, but it didn't give me an answer.
Do I have to do something with my viewport?
* GLUT Shapes Demo
*
* Written by Nigel Stewart November 2003
*
* This program is test harness for the sphere, cone
* and torus shapes in GLUT.
*
* Spinning wireframe and smooth shaded shapes are
* displayed until the ESC or q key is pressed. The
* number of geometry stacks and slices can be adjusted
* using the + and - keys.
*/
#include <windows.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <math.h>
#include <stdlib.h>
static int slices = 16;
static int stacks = 16;
int m=0;
int mainWindow,SubWindow, SubWindow2;
/* GLUT callback Handlers */
static void resize(int width, int height)
{
const float ar = (float) width / (float) height;
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-10,10,-10,10,-10,10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity() ;
}
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
case 'q':
exit(0);
break;
case '+':
slices++;
stacks++;
break;
case '-':
if (slices>3 && stacks>3)
{
slices--;
stacks--;
}
break;
}
//glutPostRedisplay();
}
void keyp(int key, int xx, int yy) {
glutSetWindow(mainWindow);
glutPostRedisplay();
}
void displaysub()
{const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
const double a = t*90.0;
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearColor(20,1,1,1);
glLoadIdentity();
glOrtho(-5,5,-5,5,-5,5);
glColor3f(0,0,0);
glRotated(a,0,0,10);
glPushMatrix();
glTranslated(0,0,0);
glutSolidSphere(2,10,10);
glPopMatrix();
glutSwapBuffers();
}
void display()
{const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
const double a = t*90.0;
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearColor(3,0,0,1);
glLoadIdentity();
glOrtho(-10,10,-10,10,-10,10);
glRotated(a,10,10,0);
displaysub();
}
static void idle(void)
{
glutPostRedisplay();
}
/* Program entry point */
void init()
{
glClearColor(3,0,0,1);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
// register callbacks
glutIgnoreKeyRepeat(1);
glutKeyboardFunc(key);
glutSpecialFunc(keyp);
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
mainWindow = glutCreateWindow("GLUT Shapes");
glutSetWindow(mainWindow);
glClearColor(3,0,0,1);
glutDisplayFunc(display);
init();
SubWindow = glutCreateSubWindow(mainWindow,0,0,50,50);
glutSetWindow(SubWindow);
glClearColor(3,0,0,1);
glutDisplayFunc(displaysub);
init();
glutIdleFunc(idle);
glutMainLoop();
return 1;
}
The documentation on glutPostRedisplay specifies that only the display func of the current window will be called. In this case there are two windows. I am not an expert using glut but I would suggest two changes
Remove displaysub() from the display() function and rewrite idle()
static void idle()
{
int currentWindow = glutGetWindow();
glutSetWindw(mainWindow);
glutPostRedisplay();
glutSetWindw(subWindow);
glutPostRedisplay();
glutSetWindow(currentWindow);
}
glutPostRedisplay just marks the window for update in the main loop, which I guess is the one with mouse focus. By doing a post for each window independent of the current window all windows will receive their respective display calls
Maybe I set up GLUT wrong. I want verticies to be relative to their size in pixels. Right now if I create a hexagon, it takes up the whole screen even though the units are 6.
#include <iostream>
#include <stdlib.h> //Needed for "exit" function
#include <cmath>
//Include OpenGL header files, so that we can use OpenGL
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
using namespace std;
//Called when a key is pressed
void handleKeypress(unsigned char key, //The key that was pressed
int x, int y) { //The current mouse coordinates
switch (key) {
case 27: //Escape key
exit(0); //Exit the program
}
}
//Initializes 3D rendering
void initRendering() {
//Makes 3D drawing work when something is in front of something else
glEnable(GL_DEPTH_TEST);
}
//Called when the window is resized
void handleResize(int w, int h) {
//Tell OpenGL how to convert from coordinates to pixel values
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION); //Switch to setting the camera perspective
//Set the camera perspective
glLoadIdentity(); //Reset the camera
gluPerspective(45.0, //The camera angle
(double)w / (double)h, //The width-to-height ratio
1.0, //The near z clipping coordinate
200.0); //The far z clipping coordinate
}
//Draws the 3D scene
void drawScene() {
//Clear information from last draw
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //Reset the drawing perspective
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glBegin(GL_POLYGON); //Begin quadrilateral coordinates
//Trapezoid
glColor3f(255,0,0);
for(int i = 0; i < 6; ++i) {
glVertex2d(sin(i/6.0*2* 3.1415),
cos(i/6.0*2* 3.1415));
}
glEnd(); //End quadrilateral coordinates
glutSwapBuffers(); //Send the 3D scene to the screen
}
int main(int argc, char** argv) {
//Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(400, 400); //Set the window size
//Create the window
glutCreateWindow("Basic Shapes - videotutorialsrock.com");
initRendering(); //Initialize rendering
//Set handler functions for drawing, keypresses, and window resizes
glutDisplayFunc(drawScene);
glutKeyboardFunc(handleKeypress);
glutReshapeFunc(handleResize);
glutMainLoop(); //Start the main loop. glutMainLoop doesn't return.
return 0; //This line is never reached
}
How can I make it so that the coordinates:
(0,0),
(10,0),
(10,10),
and (0,10) define a polygon starting at the top left of the screen and is a width and height of 10 pixels?
If you want the objects to be scaled that sort of way, you should use an orthographic projection.
Right now, with perspective, things are scaled not only by their size, but by their Z-axis position. So use this function instead of gluPerspective:
gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);
That function basically defines the space you can see, which is like a big rectangular prism. That makes far things appear the same size as near things.
As for the exact scaling, it will also change relative to the viewport size. To get the pixels exactly right, you would have to constantly change the projection, or keep the viewport size fixed.
For it to work out as 1:1, if your viewport is x pixels wide, the orthographic projection should be x pixels wide as well.
If you're drawing in 2D, you don't want to use perspective projection. If you set up your camera with gluOrtho2D(0, window_width, window_height, 0); then you should get what you're looking for.