I am using gl and glut on Windows platform
my problem is that glReadPixels returns all 0s. I guess it has something to do with the way I initialize the window so it cannot get the correct pixel value.
This is how I initialize the window:
glutInit(&argc, argv);
glutInitWindowSize(800,600);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 800, 600, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.375, 0.375, 0);
glClearColor(0, 0, 0, 1.0);
And with this, I get all 0s:
Edit:
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x-20, y-20);
glVertex2i(x-20, y+20);
glVertex2i(x+20, y+20);
glVertex2i(x+20, y-20);
glEnd();
unsigned char pixel[4];
glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
After I glClear, I did render some shapes, at (x, y) then I used glReadPixels to get the color at (x, y) but it returns 0s. I tried to glReadPixels the whole screen and it returns 0s too.
Edit 2:
So, to be more clear about my problem, here is the code:
I just don't know where the source of the problem could be so I pasted all of the code here. This is the tanks program from the book "Game Programming All in One" by Jonathan S. Habour. The book uses Allegro library, I try to convert to openGL. At the "look for a hit" in the updatebullet procedure, I printed out the coordinates of the enemy tank and the color at that pixel but all I get is 0s.
#include <GL/glut.h>
#include <stdlib.h>
#include <iostream.h>
#include <windows.h>
//define tank structure
struct tagTank
{
int x,y;
int dir,speed;
} tanks[2];
struct tagBullet
{
int x,y;
int alive;
int xspd,yspd;
} bullets[2];
void setuptanks()
{
tanks[0].x = 30;
tanks[0].y = 40;
tanks[0].dir = 1;
tanks[0].speed = 5;
tanks[1].x = 800 - 30;
tanks[1].y = 600 - 30;
tanks[1].dir = 3;
tanks[1].speed = 5;
}
void drawtank(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
int dir = tanks[num].dir;
//draw tank body
glColor3f(1.0, 0.0, 0.0);
if (num) glColor3f(0.0, 0.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x-20, y-20);
glVertex2i(x-20, y+20);
glVertex2i(x+20, y+20);
glVertex2i(x+20, y-20);
glEnd();
glColor3f(0.5, 0.0, 0.0);
if (num) glColor3f(0.0, 0.0, 0.5);
glBegin(GL_QUADS);
glVertex2i(x-10, y-10);
glVertex2i(x-10, y+10);
glVertex2i(x+10, y+10);
glVertex2i(x+10, y-10);
glEnd();
//draw the turret based on direction
glColor3f(1.0, 1.0, 1.0);
switch (dir)
{
case 0:
glBegin(GL_QUADS);
glVertex2i(x-2, y-30);
glVertex2i(x-2, y);
glVertex2i(x+2, y);
glVertex2i(x+2, y-30);
glEnd();
break;
case 1:
glBegin(GL_QUADS);
glVertex2i(x, y-2);
glVertex2i(x, y+2);
glVertex2i(x+30, y+2);
glVertex2i(x+30, y-2);
glEnd();
break;
case 2:
glBegin(GL_QUADS);
glVertex2i(x-2, y);
glVertex2i(x-2, y+30);
glVertex2i(x+2, y+30);
glVertex2i(x+2, y);
glEnd();
break;
case 3:
glBegin(GL_QUADS);
glVertex2i(x-30, y-2);
glVertex2i(x-30, y+2);
glVertex2i(x, y+2);
glVertex2i(x, y-2);
glEnd();
break;
}
}
void erasetank(int num)
{
//calculate box to encompass the tank
int left = tanks[num].x - 30;
int top = tanks[num].y - 30;
int right = tanks[num].x + 30;
int bottom = tanks[num].y + 30;
//erase the tank
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(left, top);
glVertex2i(left, bottom);
glVertex2i(right, bottom);
glVertex2i(right, top);
glEnd();
}
void movetank(int num)
{
int dir = tanks[num].dir;
int speed = tanks[num].speed;
//update tank position based on direction
switch(dir)
{
case 0:
tanks[num].y -= speed;
break;
case 1:
tanks[num].x += speed;
break;
case 2:
tanks[num].y += speed;
break;
case 3:
tanks[num].x -= speed;
break;
}
//keep tank inside the screen
if (tanks[num].x > 800-30)
{
tanks[num].x = 800-30;
tanks[num].speed = 0;
}
else if (tanks[num].x < 30)
{
tanks[num].x = 30;
tanks[num].speed = 0;
}
else if (tanks[num].y > 600-30)
{
tanks[num].y = 600-30;
tanks[num].speed = 0;
}
else if (tanks[num].y < 30)
{
tanks[num].y = 30;
tanks[num].speed = 0;
}
else tanks[num].speed = 5;
}
void explode(int num, int x, int y)
{
int n;
//retrieve location of enemy tank
int tx = tanks[!num].x;
int ty = tanks[!num].y;
//is bullet inside the boundary of the enemy tank?
if (x > tx-30 && x < tx+30 && y > ty-30 && y < ty+30)
setuptanks();
//draw some random circles for the "explosion"
for (n = 0; n < 10; n++)
{
glColor3f((rand() % 101)/100.0, (rand() % 101)/100.0, (rand() % 101)/100.0);
glBegin(GL_QUADS);
glVertex2i(x-16, y-16);
glVertex2i(x-16, y+16);
glVertex2i(x+16, y+16);
glVertex2i(x+16, y-16);
glEnd();
//Sleep(10);
}
//clear the area of debris
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x-16, y-16);
glVertex2i(x-16, y+16);
glVertex2i(x+16, y+16);
glVertex2i(x+16, y-16);
glEnd();
}
void updatebullet(int num)
{
int x = bullets[num].x;
int y = bullets[num].y;
if (bullets[num].alive)
{
//erase bullet
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_QUADS);
glVertex2i(x-2, y-2);
glVertex2i(x-2, y+2);
glVertex2i(x+2, y+2);
glVertex2i(x+2, y-2);
glEnd();
//move bullet
bullets[num].x += bullets[num].xspd;
bullets[num].y += bullets[num].yspd;
x = bullets[num].x;
y = bullets[num].y;
//stay within the screen
if (x < 5 || x > 800 || y < 20 || y > 600)
{
bullets[num].alive = 0;
return;
}
//look for a hit
unsigned char pixel[4];
glReadPixels(tanks[!num].x, tanks[!num].y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
cout << tanks[!num].x << ", " << tanks[!num].y << " | " << (int)pixel[0] << ", " << (int)pixel[1] << ", " << (int)pixel[2] << endl;
if ((int)pixel[0] || (int)pixel[1] || (int)pixel[2])
{
bullets[num].alive = 0;
explode(num, x, y);
return;
}
//draw bullet
x = bullets[num].x;
y = bullets[num].y;
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x-2, y-2);
glVertex2i(x-2, y+2);
glVertex2i(x+2, y+2);
glVertex2i(x+2, y-2);
glEnd();
}
}
void fireweapon(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
//ready to fire again?
if (!bullets[num].alive)
{
bullets[num].alive = 1;
//fire bullet in direction tank is facing
switch (tanks[num].dir)
{
//north
case 0:
bullets[num].x = x;
bullets[num].y = y-30;
bullets[num].xspd = 0;
bullets[num].yspd = -20;
break;
//east
case 1:
bullets[num].x = x+30;
bullets[num].y = y;
bullets[num].xspd = 20;
bullets[num].yspd = 0;
break;
//south
case 2:
bullets[num].x = x;
bullets[num].y = y+30;
bullets[num].xspd = 0;
bullets[num].yspd = 20;
break;
//west
case 3:
bullets[num].x = x-30;
bullets[num].y = y;
bullets[num].xspd = -20;
bullets[num].yspd = 0;
break;
}
}
}
void up(int num)
{
tanks[num].dir = 0;
}
void down(int num)
{
tanks[num].dir = 2;
}
void left(int num)
{
tanks[num].dir = 3;
}
void right(int num)
{
tanks[num].dir = 1;
}
static void display(void)
{
erasetank(0);
erasetank(1);
movetank(0);
movetank(1);
drawtank(0);
drawtank(1);
updatebullet(0);
updatebullet(1);
glFlush();
Sleep(50);
}
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
exit(0);
break;
case 'a':
left(1);
break;
case 'd':
right(1);
break;
case 'w':
up(1);
break;
case 's':
down(1);
break;
case 32:
fireweapon(1);
break;
case 13:
fireweapon(0);
break;
}
glutPostRedisplay();
}
static void specialkey(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_LEFT:
left(0);
break;
case GLUT_KEY_RIGHT:
right(0);
break;
case GLUT_KEY_UP:
up(0);
break;
case GLUT_KEY_DOWN:
down(0);
break;
}
glutPostRedisplay();
}
static void idle(void)
{
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(800,600);
glutInitWindowPosition(10,10);
glutCreateWindow("Tanks");
glClear(GL_COLOR_BUFFER_BIT);
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutSpecialFunc(specialkey);
glutIdleFunc(idle);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 800, 600, 0, 0, 1);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0.375, 0.375, 0);
glClearColor(0, 0, 0, 1.0);
setuptanks();
glutMainLoop();
return EXIT_SUCCESS;
}
As Roger Rowland pointed out you are reading from the wrong part of the screen. You need to flip your y-coordinate before you pass it into glReadPixels()
Other things:
You don't need erasetank() or erasebullet(), just clear the screen each frame
It's a good idea to put glClear() and your matrix stuff in the display callback
An explicit glutInitDisplayMode() is a good idea
There's no real reason not to use GLUT_DOUBLE
Use a glutTimerFunc() instead of sleep()
All together:
#include <GL/glut.h>
#include <iostream>
using namespace std;
//define tank structure
struct tagTank
{
int x,y;
int dir,speed;
} tanks[2];
struct tagBullet
{
int x,y;
int alive;
int xspd,yspd;
} bullets[2];
void setuptanks()
{
tanks[0].x = 30;
tanks[0].y = 40;
tanks[0].dir = 1;
tanks[0].speed = 5;
tanks[1].x = 800 - 30;
tanks[1].y = 600 - 30;
tanks[1].dir = 3;
tanks[1].speed = 5;
}
void drawtank(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
int dir = tanks[num].dir;
//draw tank body
glColor3f(1.0, 0.0, 0.0);
if (num) glColor3f(0.0, 0.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x-20, y-20);
glVertex2i(x-20, y+20);
glVertex2i(x+20, y+20);
glVertex2i(x+20, y-20);
glEnd();
glColor3f(0.5, 0.0, 0.0);
if (num) glColor3f(0.0, 0.0, 0.5);
glBegin(GL_QUADS);
glVertex2i(x-10, y-10);
glVertex2i(x-10, y+10);
glVertex2i(x+10, y+10);
glVertex2i(x+10, y-10);
glEnd();
//draw the turret based on direction
glColor3f(1.0, 1.0, 1.0);
switch (dir)
{
case 0:
glBegin(GL_QUADS);
glVertex2i(x-2, y-30);
glVertex2i(x-2, y);
glVertex2i(x+2, y);
glVertex2i(x+2, y-30);
glEnd();
break;
case 1:
glBegin(GL_QUADS);
glVertex2i(x, y-2);
glVertex2i(x, y+2);
glVertex2i(x+30, y+2);
glVertex2i(x+30, y-2);
glEnd();
break;
case 2:
glBegin(GL_QUADS);
glVertex2i(x-2, y);
glVertex2i(x-2, y+30);
glVertex2i(x+2, y+30);
glVertex2i(x+2, y);
glEnd();
break;
case 3:
glBegin(GL_QUADS);
glVertex2i(x-30, y-2);
glVertex2i(x-30, y+2);
glVertex2i(x, y+2);
glVertex2i(x, y-2);
glEnd();
break;
}
}
void movetank(int num)
{
int dir = tanks[num].dir;
int speed = tanks[num].speed;
//update tank position based on direction
switch(dir)
{
case 0:
tanks[num].y -= speed;
break;
case 1:
tanks[num].x += speed;
break;
case 2:
tanks[num].y += speed;
break;
case 3:
tanks[num].x -= speed;
break;
}
//keep tank inside the screen
if (tanks[num].x > 800-30)
{
tanks[num].x = 800-30;
tanks[num].speed = 0;
}
else if (tanks[num].x < 30)
{
tanks[num].x = 30;
tanks[num].speed = 0;
}
else if (tanks[num].y > 600-30)
{
tanks[num].y = 600-30;
tanks[num].speed = 0;
}
else if (tanks[num].y < 30)
{
tanks[num].y = 30;
tanks[num].speed = 0;
}
else tanks[num].speed = 5;
}
void explode(int num, int x, int y)
{
int n;
//retrieve location of enemy tank
int tx = tanks[!num].x;
int ty = tanks[!num].y;
//is bullet inside the boundary of the enemy tank?
if (x > tx-30 && x < tx+30 && y > ty-30 && y < ty+30)
setuptanks();
//draw some random circles for the "explosion"
for (n = 0; n < 10; n++)
{
glColor3f((rand() % 101)/100.0, (rand() % 101)/100.0, (rand() % 101)/100.0);
glBegin(GL_QUADS);
glVertex2i(x-16, y-16);
glVertex2i(x-16, y+16);
glVertex2i(x+16, y+16);
glVertex2i(x+16, y-16);
glEnd();
}
}
void updatebullet(int num)
{
if (bullets[num].alive)
{
//move bullet
bullets[num].x += bullets[num].xspd;
bullets[num].y += bullets[num].yspd;
int x = bullets[num].x;
int y = bullets[num].y;
//stay within the screen
if (x < 5 || x > 800 || y < 20 || y > 600)
{
bullets[num].alive = 0;
return;
}
//look for a hit
unsigned char pixel[4];
int h = glutGet( GLUT_WINDOW_HEIGHT );
glReadPixels(x, h - y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
cout << x << ", " << y << " | " << (int)pixel[0] << ", " << (int)pixel[1] << ", " << (int)pixel[2] << endl;
if ((int)pixel[0] || (int)pixel[1] || (int)pixel[2])
{
bullets[num].alive = 0;
explode(num, x, y);
return;
}
//draw bullet
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_QUADS);
glVertex2i(x-2, y-2);
glVertex2i(x-2, y+2);
glVertex2i(x+2, y+2);
glVertex2i(x+2, y-2);
glEnd();
}
}
void fireweapon(int num)
{
int x = tanks[num].x;
int y = tanks[num].y;
//ready to fire again?
if (!bullets[num].alive)
{
bullets[num].alive = 1;
//fire bullet in direction tank is facing
switch (tanks[num].dir)
{
//north
case 0:
bullets[num].x = x;
bullets[num].y = y-30;
bullets[num].xspd = 0;
bullets[num].yspd = -20;
break;
//east
case 1:
bullets[num].x = x+30;
bullets[num].y = y;
bullets[num].xspd = 20;
bullets[num].yspd = 0;
break;
//south
case 2:
bullets[num].x = x;
bullets[num].y = y+30;
bullets[num].xspd = 0;
bullets[num].yspd = 20;
break;
//west
case 3:
bullets[num].x = x-30;
bullets[num].y = y;
bullets[num].xspd = -20;
bullets[num].yspd = 0;
break;
}
}
}
void up(int num)
{
tanks[num].dir = 0;
}
void down(int num)
{
tanks[num].dir = 2;
}
void left(int num)
{
tanks[num].dir = 3;
}
void right(int num)
{
tanks[num].dir = 1;
}
static void display(void)
{
glClearColor(0, 0, 0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
int w = glutGet( GLUT_WINDOW_WIDTH );
int h = glutGet( GLUT_WINDOW_HEIGHT );
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.375, 0.375, 0);
movetank(0);
movetank(1);
drawtank(0);
drawtank(1);
glFlush();
updatebullet(0);
updatebullet(1);
glutSwapBuffers();
}
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 : exit(0); break;
case 'a': left(1); break;
case 'd': right(1); break;
case 'w': up(1); break;
case 's': down(1); break;
case 32: fireweapon(1); break;
case 13: fireweapon(0); break;
}
}
static void specialkey(int key, int x, int y)
{
switch (key)
{
case GLUT_KEY_LEFT: left(0); break;
case GLUT_KEY_RIGHT: right(0); break;
case GLUT_KEY_UP: up(0); break;
case GLUT_KEY_DOWN: down(0); break;
}
}
void timer( int value )
{
glutTimerFunc( 50, timer, 0 );
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInitWindowSize(800,600);
glutInit(&argc, argv);
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutCreateWindow("Tanks");
glutDisplayFunc(display);
glutKeyboardFunc(key);
glutSpecialFunc(specialkey);
glutTimerFunc( 0, timer, 0 );
setuptanks();
glutMainLoop();
return EXIT_SUCCESS;
}
Related
After the camera rotation on the Y axis and X and the subsequent move, is a strange camera rotation along the axis Z. For example, here is the normal state but I was randomly moved around the stage, all twisted I do not know what to do and how to fix the problem, I hope for your help. I saw this question, it does not help me, because I do not even use glm, do not mark as a duplicate.
Code:
#include <iostream>
#include <chrono>
#include <GL/glut.h>
#include "Camera.h"
using namespace std;
constexpr auto FPS_RATE = 120;
int windowHeight = 600, windowWidth = 600, windowDepth = 600;
float angle = 0, speedRatio = 0.25;
struct MyPoint3f
{
float x;
float y;
float z;
};
MyPoint3f lastMousePos = { };
bool mouseButtonWasPressed = false;
float mouseSensitivity = 0.1;
float camMoveSpeed = 3;
float camPitchAngle = 0, camYawAngle = 0;
Camera cam;
void init();
void displayFunction();
void idleFunction();
void reshapeFunction(int, int);
void keyboardFunction(unsigned char, int, int);
void specialKeysFunction(int, int, int);
void mouseFunc(int, int, int, int);
void motionFunction(int, int);
double getTime();
double getTime()
{
using Duration = std::chrono::duration<double>;
return std::chrono::duration_cast<Duration>(
std::chrono::high_resolution_clock::now().time_since_epoch()
).count();
}
const double frame_delay = 1.0 / FPS_RATE;
double last_render = 0;
void init()
{
glutDisplayFunc(displayFunction);
glutIdleFunc(idleFunction);
glutReshapeFunc(reshapeFunction);
glutKeyboardFunc(keyboardFunction);
glutMouseFunc(mouseFunc);
glutMotionFunc(motionFunction);
glViewport(0, 0, windowWidth, windowHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-windowWidth / 2, windowWidth / 2, -windowHeight / 2, windowHeight / 2, -windowDepth / 2, windowDepth / 2);
glClearColor(0.0, 0.0, 0.0, 0.0);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
cam.setShape(45, (double)windowWidth / windowHeight, 0.1, 1000);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
cam.set(Point3(0, 0, 350), Point3(0, 0, 349), Vector3(0, 1, 0));
}
void displayFunction()
{
angle += speedRatio;
if (angle >= 360 || angle <= -360) angle = 0;
if (camPitchAngle <= -360) camPitchAngle = 0;
if (camPitchAngle >= 360) camPitchAngle = 0;
if (camYawAngle <= -360) camYawAngle = 0;
if (camYawAngle >= 360) camYawAngle = 0;
cout << camPitchAngle << " " << camYawAngle << endl;
cam.pitch(-(camPitchAngle *= mouseSensitivity));
cam.yaw(-(camYawAngle *= mouseSensitivity));
camPitchAngle = 0; camYawAngle = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glRotatef(angle, 1, 0, 0);
glRotatef(angle, 0, 1, 0);
glColor3f(0, 1, 0);
glutWireCube(150.0);
glBegin(GL_LINES);
glColor3f(1, 0, 0);
for (int i = 0; i <= 75; i += 5)
{
glVertex3i(i, 0, 0);
glVertex3i(-i, 0, 0);
glVertex3i(0, i, 0);
glVertex3i(0, -i, 0);
glVertex3i(0, 0, i);
glVertex3i(0, 0, -i);
}
glEnd();
glPopMatrix();
//RSHIFT and CTRL
if (GetAsyncKeyState(VK_LSHIFT))
{
cam.slide(0, 1.0 * camMoveSpeed, 0);
}
if (GetAsyncKeyState(VK_LCONTROL))
{
cam.slide(0, -1.0 * camMoveSpeed, 0);
}
glutSwapBuffers();
}
void idleFunction()
{
const double current_time = getTime();
if ((current_time - last_render) > frame_delay)
{
last_render = current_time;
glutPostRedisplay();
}
}
void reshapeFunction(int w, int h)
{
}
void keyboardFunction(unsigned char key, int w, int h)
{
switch (key)
{
case '+': case '=':
speedRatio += 0.125;
break;
case '-': case '_':
speedRatio -= 0.125;
break;
case 'A': case 'a':
cam.slide(-1.0 * camMoveSpeed, 0, 0);
break;
case 'D': case 'd':
cam.slide(1.0 * camMoveSpeed, 0, 0);
break;
case 'W': case 'w':
cam.slide(0, 0, -1.0 * camMoveSpeed);
break;
case 'S': case 's':
cam.slide(0, 0, 1.0 * camMoveSpeed);
break;
case 'Z': case 'z':
cam.yaw(-1);
break;
case 'X': case 'x':
cam.yaw(1);
break;
case 27:
angle = 0;
speedRatio = 0;
cam.set(Point3(0, 0, 350), Point3(0, 0, 349), Vector3(0, 1, 0));
break;
default:
cout << key << endl;
break;
}
}
void specialKeysFunction(int key, int x, int y)
{
cout << key << endl;
}
void mouseFunc(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
mouseButtonWasPressed = true;
lastMousePos.x = x;
lastMousePos.y = y;
}
}
void motionFunction(int mousePosX, int mousePosY)
{
if (mousePosX >= 0 && mousePosX < windowWidth && mousePosY >= 0 && mousePosY < windowHeight)
{
if (mouseButtonWasPressed)
{
camPitchAngle += -mousePosY + lastMousePos.y;
camYawAngle += mousePosX - lastMousePos.x;
lastMousePos.x = mousePosX;
lastMousePos.y = mousePosY;
}
}
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(windowWidth, windowHeight);
glutInitWindowPosition((GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2, (GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2);
glutCreateWindow("Window");
init();
glutMainLoop();
return 0;
}
Camera.h
Camera.cpp
When you do
glRotatef(angle, 1, 0, 0);
glRotatef(angle, 0, 1, 0);
Then the model is rotated around the y-axis and then the rotated model is rotated around the x-axis, because glRotatef sets a rotation matrix and multiplies it to the current matrix.
Because the model is rotated around the y-axis before it is rotated around the x-axis, the (view space) y-axis is kept it the yz-plane of the view space.
If you want to keep the x-axis in the xz-plane of the view space, you've to do the rotation around the x-axis first:
glRotatef(angle, 0, 1, 0);
glRotatef(angle, 1, 0, 0);
The same issue occurs when you apply pich() and yaw() to the camera object. If you switch it (first yaw() then pitch()), then that won't solve the issue, because pitch and yaw are applied incrementally by each mouse move (pich(), yaw(), pich(), yaw(), pich(), yaw() ...). So there is always a yaw() after a pitch() and the model gets tilted.
To solve the issue you've to sum up camPitchAngle and camYawAngle. Take into account the mouse intensity:
void motionFunction(int mousePosX, int mousePosY)
{
if (mousePosX >= 0 && mousePosX < windowWidth && mousePosY >= 0 && mousePosY < windowHeight)
{
if (mouseButtonWasPressed)
{
camPitchAngle += (-mousePosY + lastMousePos.y) * mouseSensitivity;
camYawAngle += (mousePosX - lastMousePos.x) * mouseSensitivity;
lastMousePos.x = mousePosX;
lastMousePos.y = mousePosY;
}
}
}
Copy the camera object (cam / curr_cam) in displayFunction and apply camPitchAngle and camYawAngle to the copy. Use the copy to set the view and projection matrix:
void displayFunction()
{
// [...]
// cam.pitch(-(camPitchAngle *= mouseSensitivity)); <--- delete
// cam.yaw(-(camYawAngle *= mouseSensitivity)); <--- delete
// [...]
Camera curr_cam = cam;
curr_cam.yaw( -camYawAngle );
curr_cam.pitch( -camPitchAngle );
// [...]
if (GetAsyncKeyState(VK_LSHIFT))
{
curr_cam.slide(0, 1.0 * camMoveSpeed, 0);
}
if (GetAsyncKeyState(VK_LCONTROL))
{
curr_cam.slide(0, -1.0 * camMoveSpeed, 0);
}
// [...]
}
Of course you've to set camYawAngle = 0 respectively camPitchAngle = 0; when z, x or ESC is pressed.
Firstly thanks for giving your time.This is one of question which has a lot of answers but it does not work, here I am trying to take an example and let's see if we can solve this and maybe someone will get benefited again in future.
So the problem is we have glreadpixel() calling on a point on a circle, which is drawn by bresenham function.
But the thing is its not even giving any value than 0,0,0 for RGB on changing the background colour of the window.
Here is the big code, enjoy experimenting. I have tried everything. By the way, I am developing n macOS (OpenGL is hardware independent )
using namespace std;
#include <GLUT/glut.h>
#include <iostream>
#include <vector>
#include <CoreGraphics/CoreGraphics.h>
int r = 40;
int flag = 0;
int cordinates [50][3]=
{
{50, 50} , //0 station
{400, 450} , //1 station
{750, 250} //2 station
};
int matrix[50][50] = {
{0,1,1},
{1,0,1},
{1,1,0}
};
int trains[50][50] = {
{3,4,0,1,999},
{11,1,1,2,999},
{0,0,0,999}
};
int x,y;
int *x1, *y3, x2, y2;
int xx,yy,xxx,yyy,p,q,vertexcount,counter;
int xinc,xinc3,i,j,system_time,flag1,time_chekcer_cnt,dda =0;
char buf3[12],buf[12];
float tempx0,tempy0,tempx1,tempy1;
int train0 = 999 ;int start0,speed0,next0,nextx0,nexty0,final0 = 999 ;//999 signifies invalid
int train1 ,start1, speed1,next1,nextx1,nexty1,final1 = 999 ;//999 signifies invalid
int train2 ,start2, speed2,next2,final2 = 999 ;//999 signifies invalid
void init2D()
{
glClearColor(0,0,0,0.0);
glMatrixMode (GL_PROJECTION);
glLoadIdentity();
gluOrtho2D (0.0, 900.0, 0.0, 900.0);
}
;
void bresenham_circle(const int h, const int k,const int r)
{
int x=0,y=r,p=(3-(2*r));
do{
//Read pixel
unsigned char pixelub[3];
// glReadPixels(<#GLint x#>, <#GLint y#>, <#GLsizei width#>, <#GLsizei height#>, <#GLenum format#>, <#GLenum type#>, <#GLvoid *pixels#>)
glPointSize(1);
//draw two points
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POINTS);
glVertex2i((h+x),(k+y));
glEnd();
//color detection start
glReadPixels
(
(h+x),(k+y),
1, 1,
GLUT_RGB, GL_UNSIGNED_BYTE, &pixelub
);
//print
cout <<"reading pixel : "<<(h+x)<<" "<<(k+y);
printf("r: %u g: %u b: %u\n", pixelub[0], pixelub[1], pixelub[2]);
cout << endl;
//end
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POINTS);
glVertex2i((h+y),(k+x));
glEnd();
glBegin(GL_POINTS);
glVertex2i((h+y),(k-x));
glEnd();
glBegin(GL_POINTS);
glVertex2i((h+x),(k-y));
glEnd();
glBegin(GL_POINTS);
glVertex2i((h-x),(k-y));
glEnd();
glBegin(GL_POINTS);
glVertex2i((h-y),(k-x));
glEnd();
glBegin(GL_POINTS);
glVertex2i((h-y),(k+x));
glEnd();
glBegin(GL_POINTS);
glVertex2i((h-x),(k+y));
glEnd();
x++;
if(p<0){
p+= ((4*x)+6);
}else {
y--;
p+=(4*(x-y)+10);
}
}
while (x<=y);
}
void drawBitmapText(char *string,float x,float y,float z)
{
char *c;
glRasterPos3f(x, y,z);
for (c=string; *c != NULL; c++)
{
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c);
}
}
void systemtime(){
sprintf(buf, "%d", system_time); // puts string into buffer
printf("%s\n", buf);
sprintf(buf3, "%d", system_time-1); // puts string into buffer
if(system_time >1){
glColor3f(1.0, 1.0, 1.0);
drawBitmapText(buf3,200,200,0);
glColor3f(0.0, 1.0, 0.0);
drawBitmapText(buf,200,200,0);
system_time =system_time+1;
}else {
drawBitmapText(buf,200,200,0);
system_time =system_time+1;
}
};
void draw_pixel(int x, int y){
glPointSize(5);
glColor3f(1.0, 1.0, 0.0);
glBegin(GL_POINTS);
cout << "\n THIS IS PRINTING X and Y :"<<x<<" & "<<y<<endl;
glVertex2i(x, y);
glEnd();
glFlush();
}
//bresenham ..... i vant DDA
void draw_dda( float *x0, float *y0, int x1, int y1,int speed) {
//cout << "\n LOOPING FOR START CORDIANTES : X0 and Y0 "<<*x0<<*y0<<endl;
int dx = x1 - *x0;
int dy = y1 - *y0;
//GLfloat x1 = p1.x; GLfloat y1 = p1.y;
GLfloat step = 0;
if(abs(dx) > abs(dy)) {
step = abs(dx);
} else {
step = abs(dy);
}
GLfloat xInc = dx/step;
GLfloat yInc = dy/step;
for (int speed_count = 0 ; speed_count < speed ; speed_count++){
glPointSize(5);
glColor3f(1.0, 0.0, 0.0);
glBegin(GL_POINTS);
//cout << "\n THIS IS PRINTING X and Y :"<<xInc<<" & "<<yInc<<endl;
glVertex2i(*x0, *y0);
glEnd();
int cy1 = *y0;
int cx1 = *x0;
//cout << "\n calling bresenham";
glColor3f(1.0, 1.0, 1.0);
bresenham_circle(cx1, cy1, r);
//cout << " \n" <<cx1<<" "<<cy1<<" "<<r;
while (flag != 1){
r--;
//cout <<"\n r is "<<r<<endl;
if (r == 0){
flag = 1;
}
}
r =40;flag= 0;
*x0 = *x0+xInc;
*y0 = *y0+yInc;
glColor3f(1.0, 0.0, 0.0);
int cy = *y0;
int cx = *x0;
//cout << "\n calling bresenham";
bresenham_circle(cx, cy, r);
//cout << " \n" <<cx<<" "<<cy<<" "<<r;
while (flag != 1){
r--;
//cout <<"\n r is "<<r<<endl;
if (r == 0){
flag = 1;
}
}
r =40;flag= 0;
//cout << "\n THIS IS PRINTING X and Y :"<<xInc<<" & "<<yInc<<endl;
}
}
void drawline(float *x0, float *y0, int x1, int y1)
{ cout << "\n LOOPING FOR START CORDIANTES : ("<<*x0<<","<<*y0<<") To ("<<x1<<","<<y1<<")"<<endl;
int dx, dy, p, x, y;
dx=x1-*x0;
dy=y1-*y0;
x=*x0;
y=*y0;
p=2*dy-dx;
//cout << "X and X1 "<<x<<x1<<endl;
if (x<x1)
{
if(p>=0)
{
draw_pixel(x,y);
//cout << ">>>>>. Y INCREMENTED >>>>> "<<y<<endl;
y=y+1;
p=p+2*dy-2*dx;
}
else
{ //cout << "\n >>>>>NOT Y INCREMENTED >>>>> "<<y<<endl;
draw_pixel(x,y);
//cout << "X and Y "<<x<<y<<endl;
p=p+2*dy;
}
x=x+1;
}
*x0=x;
*y0=y;
//cout << "\n X "<<x<<" and Y "<<y<<endl;
//cout << "\n X0 "<<*x0<<" and Y0 "<<*y0<<endl;
}
void display_ndots()
{glClear(GL_COLOR_BUFFER_BIT);
glPointSize(5);
glColor3f(1.0, 0.0, 0.0);
//draw two points
glBegin(GL_POINTS);
for(int i = 0; i < 10; i++)
{ xx = cordinates[i][0];
yy = cordinates[i][1];
glVertex2i(xx,yy);
//printf("%i",xx);
}
glEnd();
glColor3f(0.0, 1.0, 0.0);
//draw a line
glLineWidth(3);
glBegin(GL_LINES);
for(counter = 0 ; counter < 3 ; counter ++){
for (p = 0 ; p < 3 ; p ++){
for (q = 0 ; q < 3 ; q ++){
if( matrix[p][q] == 1){
xx = cordinates[p][0];
yy = cordinates[p][1];
xxx = cordinates[q][0];
yyy = cordinates[q][1];
glVertex2i(xx,yy);
glVertex2i(xxx,yyy);
}
}
}
}
glEnd();
systemtime();
time_chekcer_cnt = 0;
for(time_chekcer_cnt = 0 ; time_chekcer_cnt <10 ; time_chekcer_cnt ++){
if (system_time == trains[time_chekcer_cnt][0]){
switch (time_chekcer_cnt)
{
case 0: printf("Trian number %i have been started server time is %i \n",time_chekcer_cnt,system_time);
/*Initializing Train Data*/
train0 = time_chekcer_cnt;
speed0 = trains[time_chekcer_cnt][1];
start0 = trains[time_chekcer_cnt][2];
cout<<"\n >>>>>>>>>>>>>"<<start0<<endl;
tempx0 = cordinates[start0][0];
tempy0 = cordinates[start0][1];
next0 = trains[time_chekcer_cnt][3];
nextx0 = cordinates[next0][0];
nexty0 = cordinates[next0][1];
;
i=0;
while (trains[time_chekcer_cnt][i] != 999) {
i = i+1;
}
final0 = trains[time_chekcer_cnt][i-1];//999 signifies invalid
printf("\nfinal station is %i \n",final0);
//tempx01 = cordinates[start0][0]+10;
//tempy01 = cordinates[start0][1];
break;
case 1:
printf("Trian number %i have been started server time is %i \n",time_chekcer_cnt,system_time);
/*Initializing Train Data*/
train1 = time_chekcer_cnt;
speed1 = trains[time_chekcer_cnt][1];
start1 = trains[time_chekcer_cnt][2];
cout<<"\n >>>>>>>>>>>>>"<<start0<<endl;
tempx1 = cordinates[start0][0];
tempy1 = cordinates[start0][1];
next1 = trains[time_chekcer_cnt][3];
nextx1 = cordinates[next0][0];
nexty1 = cordinates[next0][1];
;
i=0;
while (trains[time_chekcer_cnt][i] != 999) {
i = i+1;
}
final1 = trains[time_chekcer_cnt][i-1];//999 signifies invalid
printf("\nfinal station is %i \n",final0);
break;
//default: // code to be executed if n doesn't match any cases
}
}
}
if (train0 != 999){
glColor3f(1.0, 1.0, 0.0);
draw_dda( &tempx0, &tempy0 ,nextx0, nexty0,speed0);
cout << "Draving from corinates ("<<tempx0<<","<<tempy0<<") To ("<<nextx0<<","<<nexty0<<")"<<endl;
}
if (train1 != 999){
glColor3f(1.0, 1.0, 0.0);
/// cout << "original x and y are "<<nextx0<<" & "<<nexty0;
draw_dda( &tempx1, &tempy1 ,nextx1, nexty1,speed1);
cout << "Draving from corinates ("<<tempx0<<","<<tempy0<<") To ("<<nextx0<<","<<nexty0<<")"<<endl;
// drawline( &tempx0, &tempy0 ,nextx0, nexty0);
//draw_dda( &tempx01, &tempy01 ,nextx0+10, nexty0);
// cout<<"After call by reference it is :"<<nextx0<<" & "<<nexty0;
}
/*bresenham_circle(100, 100, r);
while (flag != 1){
r--;
cout <<"\n r is "<<r<<endl;
if (r == 0){
flag = 1;
}
}*/
glFlush();
glGetError();
}
void timlycall (int unused) {
glutPostRedisplay();
glutTimerFunc(1000, timlycall, 0);
}
int main(int argc,char *argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (900, 900);
glutInitWindowPosition (0, 0);
glutCreateWindow ("points and lines");
init2D();
glutDisplayFunc(display_ndots);
//glutDisplayFunc(init2D);
glutTimerFunc(0, timlycall, 0);
glutMainLoop();
return 0;
}
Please not macos have library GLUT but windows have GL
Update 1.0
OK folks we have made some progress :
Using GLUT_RGB in glreadpixel() gives error code 1280 i.e. detected
by method BDL have provided. Which stands for incorrect enumeration ,
so use GL_RGB inside glreadpixel()
Now one more interesting thing we have to tackle, i.e now GlReadPixel
is giving r:255 g: 255 b: 255 as output , i.e background color
instead of color that must be yellow , because we are calling the
function on point which lies on the circle that too after its
painted.
You are passing a wrong enumeration to glReadPixels. GLUT_RGB is not the same as GL_RGB and may thus not be used for this function.
This would have been reported as a GL_INVALID_ENUM error by glGetError(), but the error code is never checked. You should use something like:
GLenum error = glGetError();
if (error != GL_NO_ERROR)
std::cout << "OpenGL error: " << error << std::endl;
I am fairly new to openGL. One exercise was to rewrite a piece of code using vertex arrays. This is what I come up with. When I compile and then run the .exe all I get is a white window. I think it could be an index variable I have messed up. I think.
#include <cmath>
#include <iostream>
#ifdef __APPLE__
# include <GL/glew.h>
# include <GL/freeglut.h>
# include <OpenGL/glext.h>
#else
# include <GL/glew.h>
# include <GL/freeglut.h>
# include <GL/glext.h>
#pragma comment(lib, "glew32.lib")
#endif
#define PI 3.14159265
using namespace std;
// Globals.
static float R = 5.0; // Radius of hemisphere.
static int p = 6; // Number of longitudinal slices.
static int q = 4; // Number of latitudinal slices.
static float Xangle = 0.0, Yangle = 0.0, Zangle = 0.0; // Angles to rotate hemisphere.
static float *vert;
static int *ind;
// Fill the vertex array with co-ordinates of the sample points.
void fillVerArr(void)
{
int k = 0;
for (int j = 0; j <= q; j++)
{
for (int i = 0; i <= p; i++)
{
vert[k++] = R * sin( (float)j/q * PI/2.0 ) * cos( 2.0 * (float)i/p * PI );
vert[k++] = R * sin( (float)j/q * PI/2.0 ) * sin( 2.0 * (float)i/p * PI );
vert[k++] = R * cos( (float)j/q * PI/2.0 );
}
}
}
// Fill the array of index arrays.
void fillIndArr(int j)
{
for(int i = 0; i <= p; i++)
{
ind[2*i] = (j+1)*p+(i+1);
ind[2*i+1] = j*p + i;
}
}
// Initialization routine.
void setup(void)
{
glClearColor(1.0, 1.0, 1.0, 0.0);
// Enable vertex array.
glEnableClientState(GL_VERTEX_ARRAY);
}
// Drawing routine.
void drawScene(void)
{
int i, j;
glClear (GL_COLOR_BUFFER_BIT);
glLoadIdentity();
// Command to push the hemisphere, which is drawn centered at the origin,
// into the viewing frustum.
glTranslatef(0.0, 0.0, -10.0);
vert = new float[3 * (p+1) * (q+1)];
fillVerArr();
// Commands to turn the hemisphere.
glRotatef(Zangle, 0.0, 0.0, 1.0);
glRotatef(Yangle, 0.0, 1.0, 0.0);
glRotatef(Xangle, 1.0, 0.0, 0.0);
// Hemisphere properties.
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glColor3f(0.0, 0.0, 0.0);
glVertexPointer(3,GL_FLOAT,0,vert);
for(j = 0; j < q; j++)
{
ind = new int[2*p];
fillIndArr(j);
glDrawElements(GL_TRIANGLE_STRIP,2*(p+1) + 1,GL_FLOAT,ind );
}
glFlush();
}
// OpenGL window reshape routine.
void resize(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-5.0, 5.0, -5.0, 5.0, 5.0, 100.0);
glMatrixMode(GL_MODELVIEW);
}
// Keyboard input processing routine.
void keyInput(unsigned char key, int x, int y)
{
switch(key)
{
case 27:
exit(0);
break;
case 'P':
p += 1;
glutPostRedisplay();
break;
case 'p':
if (p > 3) p -= 1;
glutPostRedisplay();
break;
case 'Q':
q += 1;
glutPostRedisplay();
break;
case 'q':
if (q > 3) q -= 1;
glutPostRedisplay();
break;
case 'x':
Xangle += 5.0;
if (Xangle > 360.0) Xangle -= 360.0;
glutPostRedisplay();
break;
case 'X':
Xangle -= 5.0;
if (Xangle < 0.0) Xangle += 360.0;
glutPostRedisplay();
break;
case 'y':
Yangle += 5.0;
if (Yangle > 360.0) Yangle -= 360.0;
glutPostRedisplay();
break;
case 'Y':
Yangle -= 5.0;
if (Yangle < 0.0) Yangle += 360.0;
glutPostRedisplay();
break;
case 'z':
Zangle += 5.0;
if (Zangle > 360.0) Zangle -= 360.0;
glutPostRedisplay();
break;
case 'Z':
Zangle -= 5.0;
if (Zangle < 0.0) Zangle += 360.0;
glutPostRedisplay();
break;
default:
break;
}
}
// Routine to output interaction instructions to the C++ window.
void printInteraction(void)
{
cout << "Interaction:" << endl;
cout << "Press P/p to increase/decrease the number of longitudinal slices." << endl
<< "Press Q/q to increase/decrease the number of latitudinal slices." << endl
<< "Press x, X, y, Y, z, Z to turn the hemisphere." << endl;
}
// Main routine.
int main(int argc, char **argv)
{
printInteraction();
glutInit(&argc, argv);
glutInitContextVersion(2, 1);
glutInitContextProfile(GLUT_COMPATIBILITY_PROFILE);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("hemisphere.cpp");
// registers callback routines
glutDisplayFunc(drawScene);
glutReshapeFunc(resize);
glutKeyboardFunc(keyInput);
glewExperimental = GL_TRUE;
glewInit();
// call setup()
setup();
// run the event processing loop, calling callback routines as needed.
glutMainLoop();
}
Your specify the types of the values in the index array as GL_FLOAT in the call to glDrawElements, while they are in fact of type int.
Values of the index array must be of type GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT.
I am having trouble with this code. I want it to fire fireworks that explode and fall in front of a static background. Right now the fireworks and background work, but together they cause a flickering and the fireworks don't fall at a regular rate. How do I prevent this flickering and achieve a regular rate of firework's fall?
#include <GL/freeglut.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include "Header.h"
using namespace std;
#define M_PI (3.1415926535897932384626433832795)
GLfloat randomNum()
{
return (rand() % 10000) / 10000.0;
}
GLfloat nx = 0;
GLfloat ny = .8;
#define MAX_POINTS 750
GLfloat numPoints;
GLfloat curx, cury;
GLfloat x[MAX_POINTS], y[MAX_POINTS];
GLfloat xacc[MAX_POINTS], yacc[MAX_POINTS];
GLfloat red, green, blue;
int step; int length;
GLfloat newRed = 0;
GLfloat newGreen = 0;
GLfloat newBlue = 0;
GLint totPor = 0;
GLint strontiumPor = 0;
GLfloat bariumPor = 0;
GLfloat copperPor = 0;
GLfloat sodiumPor = 0;
GLfloat phosPor = 0;
GLfloat red2;
GLfloat green2;
GLfloat green3;
GLfloat blue2;
void initialize()
{
int j; double temp, temp2;
numPoints = randomNum()*(MAX_POINTS - 1);
curx = nx;
cury = ny;
//Color Mixing
if (totPor != 0)
{
red = newRed * strontiumPor / (totPor - strontiumPor); //s red
green = newGreen * bariumPor / (totPor - bariumPor); //b green
blue = newBlue * copperPor / (totPor - copperPor); //c blue
red2 = newRed * sodiumPor / (totPor - sodiumPor); //d yellow
green2 = newGreen * sodiumPor / (totPor - sodiumPor);
green3 = newGreen * phosPor / (totPor - phosPor); //p blue green
blue2 = newBlue * phosPor / (totPor - phosPor);
red = red + red2;
green = green + green2 + green3;
blue = blue + blue2;
}
else
{
red = newRed;
green = newGreen;
blue = newBlue;
}
glPointSize(1.7);
step = 0;
length = 500 + 300 * randomNum();
/* initialize the blast */
for (j = 0; j<numPoints; j++) {
x[j] = curx;
y[j] = cury;
temp = randomNum();
temp2 = randomNum()*2.0*M_PI;
xacc[j] = (cos(temp2) * temp) / length;
yacc[j] = (sin(temp2) * temp) / length;
}
}
void draw_fireworks(void)
{
int i;
double glow = (length - (step)) / (double)length;
glColor3f(red*glow, green*glow, blue*glow); //glow
glBegin(GL_POINTS);
for (i = 0; i<numPoints; i++) {
x[i] += xacc[i];
y[i] += yacc[i];
glVertex2f(x[i], y[i]);
}
glEnd();
glFlush();
glutSwapBuffers();
}
void display(void)
{
int i;
glClear(GL_COLOR_BUFFER_BIT);
if (step < 0.9*length) {
for (i = 0; i<numPoints; i++)
yacc[i] -= 0.02 / length; // gravity
draw_fireworks();
}
step++;
if (step > length) initialize();
DrawScene();
glutSwapBuffers();
}
int t = 0;
void idle(void)
{
if (t == 45000)
{
glutPostRedisplay();
t = 0;
}
t++;
}
void SpecialKey(int key, int x, int y)
{
switch (key) {
case GLUT_KEY_LEFT:
/* Move fireworks left or right, up or down */
nx = nx + -.025;
break;
case GLUT_KEY_RIGHT:
nx = nx + .025;
break;
case GLUT_KEY_UP:
ny = ny + .025;
break;
case GLUT_KEY_DOWN:
ny = ny + -.025;
break;
}
glutPostRedisplay();
}
void Keyboard(unsigned char key, int x, int y)
{
//Select Chemicals
switch (key)
{
case 's':
newRed = 1;
strontiumPor = strontiumPor + 1;
totPor = totPor + 1;
break;
case 'b':
newGreen = 1;
bariumPor = bariumPor + 1;
totPor = totPor + 1;
break;
case 'c':
newBlue = 1;
copperPor = copperPor + 1;
totPor = totPor + 1;
break;
case 'd':
newRed = 1;
newGreen = 1;
sodiumPor = sodiumPor + 1;
totPor = totPor + 1;
break;
case 'p':
newBlue = 1;
newGreen = 1;
phosPor = phosPor + 1;
totPor = totPor + 1;
break;
case 'R': newRed = newRed + .1;
break;
case 'G': newGreen = newGreen + .1;
break;
case 'B': newBlue = newBlue + .1;
break;
case ' ': //Space bar is Reset or start
newRed = 1;
newGreen = 1;
newBlue = 1;
totPor = 0;
strontiumPor = 0;
bariumPor = 0;
copperPor = 0;
sodiumPor = 0;
phosPor = 0;
break;
case 'm': nx = 0; ny = 0.8; //M resets target to default
break;
case 'q': exit(0); //Q is quit
}
glutPostRedisplay();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-1.0, 1.0,
-1.0*(GLfloat)h / (GLfloat)w, 1.0*(GLfloat)h / (GLfloat)w,
-1.0, 1.0);
else
glOrtho(-1.0*(GLfloat)w / (GLfloat)h, 1.0*(GLfloat)w / (GLfloat)h,
-1.0, 1.0,
-1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(700, 700);
glutInitWindowPosition(0, 0);
glutCreateWindow("Fireworks Display");
glClearColor(0.0, 0.0, 0.0, 0.0);
initialize();
initText();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutIdleFunc(idle);
glutKeyboardFunc(Keyboard);
glutSpecialFunc(SpecialKey);
glutMainLoop();
return 0;
}
And then also this:
#include <GL/freeglut.h>
#include "Soil.h"
GLuint tex_ID;
void LoadTextureMap()
{
int width, height, channels;
unsigned char* image = SOIL_load_image("washington.png", &width, &height, &channels, SOIL_LOAD_AUTO);
glGenTextures(1, &tex_ID);
glBindTexture(GL_TEXTURE_2D, tex_ID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, channels, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, image);
SOIL_free_image_data(image);
}
void Tree(GLfloat x, GLfloat y, GLfloat z)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex_ID);
glPushMatrix();
glRotatef(180, 0.0f, 0.0f, 1.0f);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex3f(-1.0 + x, -1.0 + y, 1.0 + z);
glTexCoord2f(0.0, 1.0); glVertex3f(-1.0 + x, 1.0 + y, 1.0 + z);
glTexCoord2f(1.0, 1.0); glVertex3f(1 + x, 1.0 + y, 1.0 + z);
glTexCoord2f(1.0, 0.0); glVertex3f(1 + x, -1.0 + y, 1.0 + z);
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
void DrawScene()
{
Tree(0, 0, 0);
}
void initText()
{
LoadTextureMap();
}
You're calling glutSwapBuffers() in draw_fireworks() and also in display(). You should call it only once per frame.
Btw, if you want to learn OpenGL don't waste your time with this legacy fixed function pipeline stuff. Go with shaders instead.
I've just began learning OpenGL and this program is a mixture of stuff I've put together myself and some stuff straight copied from tutorials to speed up the process (like the whole OBJ loader you will see soon).
I'm having an error on
glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
//draw the faces
glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
glVertex3f(vertex[faces[i]->faces[3]-1]->x,vertex[faces[i]->faces[3]-1]->y,vertex[faces[i]->faces[3]-1]->z);
and that error is EXC_BAD_ACCESS code = 1. I'm completely lost for answers to this issue and I've searched around but couldn't find anything unfortunately. I also know for a fact that it is loading the file as well because that was the first issue I faced but resolved. Below is all my code (which is in one file. I'll be making a whole new project from scratch soon).
Main.cpp
#include <GLUT/GLUT.h>
#include <math.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <cmath>
void init();
void keyboard(unsigned char key, int x, int y);
void reshape(int w, int h);
void display();
void camera();
void cubePositions();
void drawCube();
void enable();
void plane();
// Roation angles.
float xPos = 0;
float yPos = 0;
float zPos = 0;
float xRot = 0;
float yRot = 0;
float angle = 0.0;
float lastx, lasty;
// Cubes position arrays.
float cubePosZ[10];
float cubePozX[10];
// Fog variables.
GLfloat fogAngle = 0.0;
GLfloat density = 0.1;
GLfloat fogColor[4] = {0.5, 0.5, 0.5, 1.0};
#define checkImageWidth 64
#define checkImageHeight 64
static GLubyte checkImage[checkImageHeight][checkImageWidth][4];
static GLuint texName;
void makeCheckImage(void)
{
int i, j, c;
for (i = 0; i < checkImageHeight; i++) {
for (j = 0; j < checkImageWidth; j++) {
c = ((((i&0x8)==0)^((j&0x8))==0))*255;
checkImage[i][j][0] = (GLubyte) c;
checkImage[i][j][1] = (GLubyte) c;
checkImage[i][j][2] = (GLubyte) c;
checkImage[i][j][3] = (GLubyte) 255;
}
}
}
struct coordinate{
float x,y,z;
coordinate(float a,float b,float c) : x(a),y(b),z(c) {};
};
//for faces, it can contain triangles and quads as well, the four variable contain which is that
struct face{
int facenum;
bool four;
int faces[4];
face(int facen,int f1,int f2,int f3) : facenum(facen){ //constructor for triangle
faces[0]=f1;
faces[1]=f2;
faces[2]=f3;
four=false;
}
face(int facen,int f1,int f2,int f3,int f4) : facenum(facen){ //overloaded constructor for quad
faces[0]=f1;
faces[1]=f2;
faces[2]=f3;
faces[3]=f4;
four=true;
}
};
//we rotate or object with angle degrees
int loadObject(const char* filename)
{
std::vector<std::string*> coord; //read every single line of the obj file as a string
std::vector<coordinate*> vertex;
std::vector<face*> faces;
std::vector<coordinate*> normals; //normal vectors for every face
std::ifstream in(filename); //open the .obj file
if(!in.is_open()) //if not opened, exit with -1
{
std::cout << "Nor oepened" << std::endl;
return -1;
}
char buf[256];
//read in every line to coord
while(!in.eof())
{
in.getline(buf,256);
coord.push_back(new std::string(buf));
}
//go through all of the elements of coord, and decide what kind of element is that
for(int i=0;i<coord.size();i++)
{
if(coord[i]->c_str()[0]=='#') //if it is a comment (the first character is #)
continue; //we don't care about that
else if(coord[i]->c_str()[0]=='v' && coord[i]->c_str()[1]==' ') //if vector
{
float tmpx,tmpy,tmpz;
sscanf(coord[i]->c_str(),"v %f %f %f",&tmpx,&tmpy,&tmpz); //read in the 3 float coordinate to tmpx,tmpy,tmpz
vertex.push_back(new coordinate(tmpx,tmpy,tmpz)); //and then add it to the end of our vertex list
}else if(coord[i]->c_str()[0]=='v' && coord[i]->c_str()[1]=='n') //if normal vector
{
float tmpx,tmpy,tmpz; //do the same thing
sscanf(coord[i]->c_str(),"vn %f %f %f",&tmpx,&tmpy,&tmpz);
normals.push_back(new coordinate(tmpx,tmpy,tmpz));
}else if(coord[i]->c_str()[0]=='f') //if face
{
int a,b,c,d,e;
if(count(coord[i]->begin(),coord[i]->end(),' ')==3) //if it is a triangle (it has 3 space in it)
{
sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b);
faces.push_back(new face(b,a,c,d)); //read in, and add to the end of the face list
}else{
sscanf(coord[i]->c_str(),"f %d//%d %d//%d %d//%d %d//%d",&a,&b,&c,&b,&d,&b,&e,&b);
faces.push_back(new face(b,a,c,d,e)); //do the same, except we call another constructor, and we use different pattern
}
}
}
//raw
int num; //the id for the list
num=glGenLists(1); //generate a uniqe
glNewList(num,GL_COMPILE); //and create it
for(int i=0;i<faces.size();i++)
{
if(faces[i]->four) //if it's a quad draw a quad
{
glBegin(GL_QUADS);
//basically all I do here, is use the facenum (so the number of the face) as an index for the normal, so the 1st normal owe to the first face
//I subtract 1 because the index start from 0 in C++
glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
//draw the faces
glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
glVertex3f(vertex[faces[i]->faces[3]-1]->x,vertex[faces[i]->faces[3]-1]->y,vertex[faces[i]->faces[3]-1]->z);
glEnd();
}else{
glBegin(GL_TRIANGLES);
glNormal3f(normals[faces[i]->facenum-1]->x,normals[faces[i]->facenum-1]->y,normals[faces[i]->facenum-1]->z);
glVertex3f(vertex[faces[i]->faces[0]-1]->x,vertex[faces[i]->faces[0]-1]->y,vertex[faces[i]->faces[0]-1]->z);
glVertex3f(vertex[faces[i]->faces[1]-1]->x,vertex[faces[i]->faces[1]-1]->y,vertex[faces[i]->faces[1]-1]->z);
glVertex3f(vertex[faces[i]->faces[2]-1]->x,vertex[faces[i]->faces[2]-1]->y,vertex[faces[i]->faces[2]-1]->z);
glEnd();
}
}
glEndList();
//delete everything to avoid memory leaks
for(int i=0;i<coord.size();i++)
delete coord[i];
for(int i=0;i<faces.size();i++)
delete faces[i];
for(int i=0;i<normals.size();i++)
delete normals[i];
for(int i=0;i<vertex.size();i++)
delete vertex[i];
return num; //return with the id
}
// Sets the position of the cubes randomly. Can later be used for more purposeful placements.
void cubePositions()
{
for (int i = 0; i < 10; i++)
{
cubePosZ[i] = rand() % 5 + 5;
cubePozX[i] = rand() % 5 + 5;
}
}
void drawCube()
{
for (int i = 0; i < 10; i++)
{
glPushMatrix();
//glTranslated(-cubePozX[i + 1] * 10, -1, -cubePosZ[i + 1] * 10);
glTranslated((i + 4), 0, (i - 5));
glTranslatef(i, 0, 5 * i);
glScalef(2, 2, 2);
glBegin(GL_QUADS);
glTexCoord2f(1, 0);
glVertex3f(-1, -1, 0);
glNormal3f(1, 1, 1);
glTexCoord2f(1, 1);
glVertex3f(-1, 1, 0);
glTexCoord2f(0, 1);
glVertex3f(1, 1, 0);
glTexCoord2f(0, 0);
glVertex3f(1, -1, 0);
glVertex3f(-1, -1, -1);
glVertex3f(-1, 1, -1);
glEnd();
glPopMatrix();
}
}
void plane()
{
glPushMatrix();
glColor4f(1.0, 0.0, 1.0, 1.0);
glTranslatef(0, -2.5, 0.0);
glScalef(100, 2, 100);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3f(-1, 0, 1);
glTexCoord2f(1.0, 0.0);
glVertex3f(-1, 0, -0.5);
glTexCoord2f(1.0, 1.0);
glVertex3f(1, 0, -0.5);
glTexCoord2f(0.0, 1.0);
glVertex3f(1, 0, 1);
glEnd();
glPopMatrix();
}
int cube;
void init()
{
cubePositions();
cube = loadObject("/Users/Admin/test.obj");
}
void enable()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_TEXTURE_2D);
float col[] = {1.0, 1.0, 1.0, 1.0};
glLightfv(GL_LIGHT0, GL_DIFFUSE, col);
}
void camera()
{
glRotatef(xRot, 1.0, 0.0, 0.0);
glRotatef(yRot, 0.0, 1.0, 0.0);
glTranslated(-xPos, -yPos, -zPos);
}
void display()
{
glClearColor(0.8, 0.8, 0.8, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
camera();
enable();
drawCube();
plane();
glCallList(cube);
glTranslated(-2, 0, 0);
glutSwapBuffers();
angle++;
}
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, 1000.0);
glMatrixMode (GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y)
{
if (key == 27)
{
exit(0);
}
if (key == 'q')
{
xRot += 0.5;
if (xRot > 360)
{
xRot -= 360;
}
}
if (key == 'z')
{
xRot -= 0.5;
if (xRot < - 360)
{
xRot += 360;
}
}
if (key == 'w')
{
float xRotRad;
float yRotRad;
xRotRad = (xRot / 180 * 3.14159f);
yRotRad = (yRot / 180 * 3.14159f);
xPos += float(sin(yRotRad));
zPos -= float(cos(yRotRad));
yPos -= float(sin(xRotRad));
}
if (key == 's')
{
float xRotRad;
float yRotRad;
xRotRad = (xRot / 180 * 3.14159f);
yRotRad = (yRot / 180 * 3.14159f);
xPos -= float(sin(yRotRad));
zPos += float(cos(yRotRad));
yPos += float(sin(xRotRad));
}
if (key == 'd')
{
yRot += 1;
if (yRot > 360)
{
yRot -= 360;
}
}
if (key == 'a')
{
yRot -= 1;
if (yRot < -360)
{
yRot += 360;
}
}
if (key == 'x')
{
yPos -= 1;
}
if (key == 'c')
{
yPos += 1;
}
}
void mouseMovement(int x, int y)
{
int diffX = x - lastx;
int diffY = y - lasty;
lastx = x;
lasty = y;
xRot += (float)diffY;
yRot += (float)diffX;
}
int main(int argc, char * argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(1000, 1000);
glutInitWindowPosition(100, 100);
glutCreateWindow("OpenGL GLUT Computing - Taylor Moore");
init();
glutDisplayFunc(display);
glutIdleFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutPassiveMotionFunc(mouseMovement);
glutMainLoop();
return 0;
}
EXC_BAD_ACCESS usually means you are trying to access a chunk of memory that has been released or dealloc'ed. Here's the first response to a Google search on the term EXC_BAD_ACCESS that explains two strategies for tracking down the cause.