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);
}
Related
I've checked every other related question on this site but none of the solutions have worked for me. I'm simply trying to follow my rectangle, which moves left and right with key presses in OpenGL. Here's my very simple program:
/*Begin useful backend functions/vars*/
/*************************************/
//Window size and refresh rate (60 fps)
int width = 500;
int height = 500;
int interval = 1000 / 60;
//Used to draw rectangles
void drawRect(float x, float y, float width, float height) {
glBegin(GL_QUADS);
glVertex2f(x, y);
glVertex2f(x + width, y);
glVertex2f(x + width, y + height);
glVertex2f(x, y + height);
glEnd();
}
/***********************************/
/*End useful backend functions/vars*/
/*Game vars*/
/***********/
//keycodes
#define keyA 0x41
#define keyD 0x44
//player
int playerWidth = 30;
int playerHeight = 50;
int playerSpeed = 3;
//player starting position
float playerX = width / 2;
float playerY = 25.0f;
/***************/
/*End game vars*/
/*Game specific functions*/
/*************************/
void keyboard() {
//Move player (and camera) on key presses
if (GetAsyncKeyState(keyA)) {
playerX -= playerSpeed;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-playerSpeed,0,0);
}
if (GetAsyncKeyState(keyD)) {
playerX += playerSpeed;
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(playerSpeed, 0, 0);
}
}
/********************/
/*End game functions*/
/*Draw and update for window*/
/****************************/
void draw() {
//Initialliy clear
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//Draw player
drawRect(playerX, playerY, playerWidth, playerHeight);
//Swap buffers to end
glutSwapBuffers();
}
void update(int value) {
// input handling
keyboard();
// Call update() again in 'interval' milliseconds
glutTimerFunc(interval, update, 0);
// Redisplay frame
glutPostRedisplay();
}
/*****************/
/*End draw/update*/
/*Main function*/
/***************/
int main(int argc, char** argv) {
// initialize opengl (via glut)
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(width, height);
glutCreateWindow("My Game");
// Register callback functions
glutDisplayFunc(draw);
glutTimerFunc(interval, update, 0);
// setup scene to be 2d
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, width, 0, height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//set draw color to white
glColor3f(1.0f, 1.0f, 1.0f);
//start the whole thing
glutMainLoop();
return 0;
}
/*************/
/*End of main*/
The keyboard movement works perfectly, however:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(-playerSpeed,0,0);
inside my keyboard() function, does nothing. And if I try it with GL_PROJECTION, it turns my screen black.
First of all note, that drawing by glBegin/glEnd sequences and the fixed function matrix stack is deprecated since decades. See Fixed Function Pipeline and Legacy OpenGL.
Simplify things.
Add a the keyboard events for key up and down (glutKeyboardFunc / glutKeyboardUpFunc). This functions only modifies the speed of the player. The speed is set when a button is pressed and is set 0, when a button is release:
int playerSpeed = 0;
void keyboardDown(unsigned char key, int x, int y)
{
if (key == 'a')
playerSpeed -= 3;
else if (key == 'd')
playerSpeed = 3;
}
void keyboardUp( unsigned char key, int x, int y )
{
playerSpeed = 0;
}
The timer event just modifies the position of the player:
void update(int value)
{
playerX += playerSpeed;
glutTimerFunc(interval, update, 0);
glutPostRedisplay();
}
In draw the model matrix is set and the rectangle is drawn:
void draw()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(playerX, playerY, 0);
//Draw player
drawRect(0, 0, playerWidth, playerHeight);
//Swap buffers to end
glutSwapBuffers();
}
Set the callback functions in main:
int main(int argc, char** argv)
{
// ...
glutDisplayFunc(draw);
glutTimerFunc(interval, update, 0);
glutKeyboardFunc( keyboardDown );
glutKeyboardUpFunc( keyboardUp );
// ...
}
I have a square and I'm trying to make it stay a square when the window is resized, instead of stretching with the window. I have some code which I thought would work but when I resize the window the square shrinks and disappears. It doesn't come back when I return the window to it's original size. Can someone tell me what I've done wrong and how to fix it?
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
glFlush();
return;
}
void reshape(int w, int h) {
const float aspectRatio = ((float)w) / h;
float xSpan = 1;
float ySpan = 1;
if (aspectRatio > 1) {
xSpan *= aspectRatio;
}
else {
ySpan *= aspectRatio;
}
gluOrtho2D(-1*xSpan, xSpan, -1*ySpan, ySpan);
glViewport(0, 0, w, h);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutCreateWindow("simple");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
}
The functions gluOrtho2D and glOrtho multiply the current matrix by the new orthographic projection matrix.
This causes that if the reshape is called a 2nd time, the matrix which was set by gluOrtho2D before, is multiplied by the new one and you get consecutive changes.
You have to "reset" the matrix (init the identiy matrix) on the matrix stack by glLoadIdentity. Further you should choose the projection matrix stack by glMatrixMode:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-1*xSpan, xSpan, -1*ySpan, ySpan);
The setup of the viewport glViewport is correct and you also consider the aspect ratio correctly (in gluOrtho2D). But there is an issue if the aspect ratio is less than 1.0. It should be ySpan /= aspectRatio;
I recommend to do the setting of the viewport and the projection matrix in the display function and just to set a notification flag in the reshape function. Note, the viewport and the projection matrix should be changed as rare as possible.
bool vp_valid = true;
int width, height;
void reshape(int w, int h) {
vp_valid = false;
width = w;
height = h;
}
void display(void)
{
if (!vp_valid)
{
const float aspectRatio = (float)width / height;
float sx = aspectRatio > 1.0f ? aspectRatio : 1.0f;
float sy = aspectRatio > 1.0f ? 1.0f : 1.0f/aspectRatio;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-sx, sx, -sy, sy);
glViewport(0, 0, width, height);
}
.....
}
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);
this is my cube. Once created, it has a random x position on either -2, -1, 0, 1, or 2.
void cube(void)
{
srand (time(0));
int cube_posX;
int lowv = -2;
int highv = 2;
cube_posX = rand() % (highv - lowv + 1) + lowv;
glTranslatef(cube_posX, 0.0, cube_angle);
glRotatef(cube_angle, 90.0, 0.0, 1.0);
glutSolidCube(0.25);
}
and this is how I move the cube slowly forward
void MOVE_CUBE(int value)
{
cube_posZ = cube_posZ - 0.01;
glutPostRedisplay();
glutTimerFunc(25, MOVE_CUBE, 0);
}
and finally putting them in display:
void init(void)
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}
float cam_eyeX = 0.0, cam_eyeY = 1.5, cam_eyeZ = 5.0;
float cam_centerX = 0.0, cam_centerY = 0.0, cam_centerZ = 0.0;
void display(void)
{
glClearColor(1.0,1.0,1.0,1.0); //to add background color (white)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(cam_eyeX, cam_eyeY, cam_eyeZ, cam_centerX, cam_centerY, cam_centerZ, 0.0, 1.0, 0.0); //camera! (cam position X, cam position Y, cam position Z, cam target X, cam target Y, cam target Z, up position X, up position Y, up position Z)
cube();
glutSwapBuffers();
angle += 0.05; //to affect the glRotate function
glFlush();
}
void reshape(int w, int h)
{
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
glMatrixMode (GL_MODELVIEW);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); // Set up display buffer
glutInitWindowSize(750, 500); //window's size
glutInitWindowPosition(100, 100); //window's position
glutCreateWindow("Hendra Ganteng!"); //window's title
init();
glutDisplayFunc(display);
glutIdleFunc (display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard_Handler);
MOVE_CUBE(0);
glutMainLoop();
return 0;
}
But when I see it in action, the cube moves forward flawlessly, but keeps changing x position onto those 5 possibilities (-2,-1,0,1,2) every 0.5 to 1 second. If I disable the srand(time(0)), the cube changes its x position rapidly. I just want to make it stay in 1 x position so then I can call more cubes in different x position. Could someone please kindly what's wrong in my code?
How is that behaviour not expected? You are generating a random X position every time you display your cube. If you re-seed the random number generator using the time, then it will be start a different sequence whenever the time changes (once per second).
Instead, you should pre-generate your cube(s). How about this:
// Global cube data
struct Cube {
int x;
double angle;
};
vector<Cube> cubes;
const int num_cubes = 1;
// Example initialisation...
void InitCubes()
{
cubes.reserve(num_cubes);
for( int i = 0; i < num_cubes; i++ )
{
Cube cube;
cube.x = rand() % (highv - lowv + 1) + lowv;
cube.angle = 0.0;
cubes.push_back(cube);
}
}
Now the update/display cycles simply need to modify the angle, but not the x-position.
void UpdateCube( Cube & cube )
{
cube.angle += 0.05;
}
void DisplayCube( Cube & cube )
{
glTranslatef((double)cube.x, 0.0, cube.angle);
glRotatef(cube.angle, 90.0, 0.0, 1.0);
glutSolidCube(0.25);
}
In your main function, call InitCubes() during startup.
In your display function, do this:
void display(void)
{
glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(cam_eyeX, cam_eyeY, cam_eyeZ, cam_centerX, cam_centerY, cam_centerZ, 0.0, 1.0, 0.0);
// Display cubes
for( int i = 0; i < cubes.size(); i++ ) DisplayCube( cubes[i] );
glutSwapBuffers();
glFlush();
// Update cubes for next render cycle.
for( int i = 0; i < cubes.size(); i++ ) UpdateCube( cubes[i] );
}
I am trying to learn the scan-line fill algorithm implemented in OpenGL/GLUT. I cannot wrap my mind around the concept. Could anybody explain to me the algorithm in a reasonably simple fashion? The algo is below:
#include<GL/glut.h>
float x1,x2,x3,x4,y1,y2,y3,y4;
void draw_pixel(int x,int y)
{
glColor3f(0.0,1.0,1.0);
glPointSize(1.0);
glBegin(GL_POINTS);
glVertex2i(x,y);
glEnd();
}
void edgedetect(float x1,float y1,float x2,float y2,int *le,int *re)
{
float temp,x,mx;
int i;
if(y1>y2)
{
temp=x1,x1=x2,x2=temp;
temp=y1,y1=y2,y2=temp;
}
if(y1==y2)
mx=x2-x1;
else
mx=(x2-x1)/(y2-y1);
x=x1;
for(i=int(y1);i<=(int)y2;i++)
{
if(x<(float)le[i]) le[i]=(int)x;
if(x>(float)re[i]) re[i]=(int)x;
x+=mx;
}
}
void scanfill(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4)
{
int le[500],re[500],i,j;
for(i=0;i<500;i++)
le[i]=500,re[i]=0;
edgedetect(x1,y1,x2,y2,le,re);
edgedetect(x2,y2,x3,y3,le,re);
edgedetect(x3,y3,x4,y4,le,re);
edgedetect(x4,y4,x1,y1,le,re);
for(j=0;j<500;j++)
{
if(le[j]<=re[j])
for(i=le[j];i<re[j];i++)
draw_pixel(i,j);
}
}
void display()
{
x1=250.0;y1=200.0;x2=150.0;y2=300.0;x3=250.0;
y3=400.0;x4=350.0;y4=300.0;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(0.0,0.0,1.0);
glBegin(GL_LINE_LOOP);
glVertex2f(x1,y1);
glVertex2f(x2,y2);
glVertex2f(x3,y3);
glVertex2f(x4,y4);
glEnd();
scanfill(x1,y1,x2,y2,x3,y3,x4,y4);
glFlush();
}
void init()
{
glClearColor(1.0,1.0,1.0,1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,499.0,0.0,499.0);
}
void main(int argc,char **argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutCreateWindow("scanline");
glutDisplayFunc(display);
init();
glutMainLoop();
}
The scanfill function is filling the the pixels coverted by the 4-sided polygon described by the four x-y coordinates. To do this, it uses the edgedetect function, which simulates drawing the edges of the polygon and remembers the minimum and maximum x coordinate for each y coordinate. The scanfill function then goes through each y coordinate and draws a horizontal line of pixels across the remembered range.