My problem
I am still learning opengl and I was working on a game similar to chicken invaders. What I am trying to do is to have a background similar to that of chicken invaders with some stars and galaxy. I did that using a quad with the size of the screen that I added texture to. Up until now all is good but I am now trying to translate this galaxy background downward so that the spaceship and the chicken seem as if they are moving forward through space. My idea is to used glutIdleFunc() function and on every iteration, I should sleep first for 30 milliseconds then update the galaxy background so that every row of pixels is moved downward by 1 row and the last row is copied to the first row. The problem is that this approach works fine for the about 15 seconds then the program stops completely and my computer hangs and freezes to the extent that I need to restart my pc. I think my approach requires ridiculously many operations every time glutIdleFunc() is called. I searched for people who faced similar situations online but I found no similar post.
code:
main function
int main(int argc, char** argr) {
glutInit(&argc, argr);
glutInitWindowSize(SCREEN_WIDTH, SCREEN_WIDTH);
// background is a global variable that contains the bitmap array
int err = load_image("Art/background.bmp", &background);
if(err)
{
fprintf(stderr, "%d\n", err);
exit(1);
}
glutCreateWindow("OpenGL - 2D Template");
glutDisplayFunc(Display);
glutMotionFunc(mo);
glutMouseFunc(mou);
glutIdleFunc(Animate);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
gluOrtho2D(0.0, 1000, 0.0, 600);
glutMainLoop();
}
Animation
void Animate(void)
{
msleep(300);
translate_image(&background, 30);
glutPostRedisplay();
}
void translate_image(image_t* img, const int c)
{
uint32_t copy[img->height][img->width];
for(int i = 0; i < img->height; i++)
{
for(int j = 0; j < img->width; j++)
{
copy[i][j] = img->data[i * img->width + j];
}
}
for(int i = 0; i < img->height; i++)
{
for(int j = 0; j < img->width; j++)
{
int index = (i + c) % img->height;
img->data[index * img->width + j] = copy[i][j];
}
}
}
Display Function
void Display() {
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
texture = glInitTexture(background);
drawImage(texture, 0.0f, 0.0f, background.width, background.height);
glDisable(GL_TEXTURE_2D);
drawSpaceShip();
glFlush();
}
Main question
is There a more efficient way to do the same thing I am trying to do with freezing my computer every time I run it ?
You don't have to copy around the picture contents. It suffices to animate the texture coordinates, which you use to map the picture to the quad.
Also you must call glutInitDisplayMode before glutCreateWindow for it to have an effect. Also you don't want a single buffered framebuffer, but a double buffered one GLUT_DOUBLE instead of GLUT_SINGLE and call glutSwapBuffers instead of glFinish.
Related
So, I have a matrix of pairs of x and y coordinates, each line in the matrix represents a route, which I would like to represent as a GL_LINE_STRIP in OpenGL. The thing is I would like to draw the lines with different colors each time. I thought my code would work, but somehow OpenGL keeps drawing the line_strips with the same color.
I thought this would do the work, xy is the matrix of pairs of coordinates:
static void Redraw(void)
{
...
glClear(GL_COLOR_BUFFER_BIT);
//drawing routes
srand(time(NULL));
for(int i = 0; i < xy.size(); i++)
{
vector<pair<int, int>> route = xy[i];
double r = ((double) rand() / (RAND_MAX));
double g = ((double) rand() / (RAND_MAX));
double b = ((double) rand() / (RAND_MAX));
glColor3f(r,g,b);
glLineWidth(2);
glBegin(GL_LINE_STRIP);
for(int j = 0; j < route.size();j++)
glVertex2d(route[j].first, route[j].second);
glEnd();
}
glFlush();
}
and my main:
int main(int argc,char *argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(1080,720);
glutInitWindowPosition(0,0);
glutCreateWindow("h_constante");
gluOrtho2D(0,1000,0,1000);
glutDisplayFunc(Redraw);
glutMainLoop();
return 0;
}
I was pushing all my nodes inside the first line in the matrix so I was actually drawing one big GL_LINE_STRIP. Thanks a lot for all the help!
It is a CUDA Code which performs ray tracing. The OpenGL window is used to display the output of the ray tracing performed. Since, the RayTrace is quite slow, I am not particularly concerned about OpenGL performace etc.
But when the ray-tracing (startRayTrace()) is called, the OpenGL window just goes to "Not Responding" State, and displays the output once the ray tracing is finished.
I can't figure out how to prevent it going into the not-respond state. When it goes in not respond state, I cannot minimize the window etc. but the rendered image is still shown as it is.
void display(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glLoadIdentity();
float image[768][1024][3] = { 0 };
for (int i = 0; i < 768; ++i) {
for (int j = 0; j < 1024; ++j) {
int idx = (767 - i) * 1024 + j;
image[i][j][0] = host_c[idx].x;
image[i][j][1] = host_c[idx].y;
image[i][j][2] = host_c[idx].z;
}
}
glRasterPos2i(-1, -1);
glDrawPixels(1024, 768, GL_RGB, GL_FLOAT, image);
glEnd();
glutSwapBuffers();
}
void winResize(int w, int h) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport( (w>1024)?((w-1024)/2):(0), (h>768)?((h-768)/2):(0), w, h);
glMatrixMode(GL_MODELVIEW);
}
void startRayTrace() {
cudaMemcpyToSymbol(cam_offset, &cam_offset_global, sizeof(double), 0, cudaMemcpyHostToDevice);
init <<< 1, 1 >>> ();
cudaDeviceSynchronize();
char title[35];
//rayTrace <<<48, 16 >>> ();
//cudaDeviceSynchronize();
for (int i = 0; i < 24; ++i) {
rayTrace <<< 1, 32 >>> (); //Overcome Watchdog timer on Windows without disabling TDR
cudaDeviceSynchronize();
sprintf(title, "Ray Tracing | Rendering %.2f%%...", ((i + 1) / 24.f) * 100);
glutSetWindowTitle(title);
}
copyToHost <<< 1, 1 >>> (dev_c);
cudaMemcpy(host_c, dev_c, WIDTH * HEIGHT * sizeof(vector), cudaMemcpyDeviceToHost);
}
void keyPress(unsigned char key, int x, int y) {
if (key == 'd') {
cam_offset_global += 10;
}
if (key == 'a') {
cam_offset_global -= 10;
}
}
void keyUp(unsigned char key, int x, int y) {
if (key == 'd' || key == 'a') {
startRayTrace();
}
//cudaDeviceSynchronize();
glutPostRedisplay();
}
int main(int argc, char * argv[]) {
cudaMalloc(&dev_c, WIDTH * HEIGHT * sizeof(vector));
//OpenGL Window
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition(100, 100);
glutInitWindowSize(1024, 768);
glutCreateWindow("Ray Tracing | Rendering 0%...");
//Ray Tracing
startRayTrace();
cudaDeviceSynchronize();
const GLubyte* ren = glGetString(GL_RENDERER);
printf("\n\n\n OpenGL Renderer : %s \n\n", ren);
//Register Callbacks
glutDisplayFunc(display);
glutReshapeFunc(winResize);
glutKeyboardFunc(keyPress);
glutKeyboardUpFunc(keyUp);
glutMainLoop();
delete[] host_c;
cudaFree(dev_c);
return 0;
}
Once the ray-trace is done, the host_c[] stores the image data, which I use to display the output on glWindow. The glutPostRedisplay() is supposed to re-render the output once ray trace finishes and host_c[] is updated, but the glWindow hangs until the ray-tracing finishes.
GLUT is not going to read further events, while it's being right inside an event hand.er You're calling startRayTrace right from the keyboard callback. However startRayTrace doesn't just start the raytrace, it also waits for completion. And because of that, GLUT will be stuck until the raytrace finishes.
CUDA kernels are executed asynchronously. To get note of when the kernel finishes, add a cudaEvent right after the kernel in the CUDA stream. Then register a GLUT idle callback function. In that function, poll if the event did complete, and when the event did complete, issue a glutPostRedisplay.
Do not cudaSync… inside the keyboard function, because that will stall.
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 have to make a 2d Chess Board of 8 * 8 blocks in OpenGL with VisualC++. I have the following code that i tried .
But I have a problem in this code .
I can't reduce the board size. e.g. 5*5.
When i click on the window it redraws the board.
I want to make this code to just work with loops. Except If , Else.
#include<GL\glut.h>
int black=0,white=1,color=0;
GLint a1=10,b1=10,a2=30,b2=30;
void init (void)
{
glClearColor (0.0, 0.0,1.0,0.0);
glMatrixMode (GL_PROJECTION);
glClear (GL_COLOR_BUFFER_BIT);
gluOrtho2D (0.0,120.0,0.0,140.0);
}
void lineSegment ()
{
for(int i=0;i<3;i++)
{
if(b2<120)
{
a1=10;b1=b2;
a2=30;b2=b2+20;
}
for(int j=0;j<5;j++)
{
if(a2<120)
{
if(color==black)
{
glColor3f(0,0,0);
glRecti(a1,b1,a2,b2);
color=1;
a1=a2;
a2=a2+20;
}
else
{
glColor3f(1,1,1);
glRecti(a1,b1,a2,b2);
color=0;
a1=a2;
a2=a2+20;
}
}
}
//GLint a1=10,b1=10,a2=30,b2=30;
}
glFlush();
}
void main (int argc, char** argv)
{
glutInit(&argc,argv); //Initialize GLUT.
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // Set display mode.
glutInitWindowPosition (50,100); //Set top-left display-window position.
glutInitWindowSize (400,300); //Set display-window width and height.
glutCreateWindow ("An Example OpenGL Program"); //Create display window.
init(); // Execute initialization procedure.
glutDisplayFunc(lineSegment); //send graphics to display window.
glutMainLoop(); //display everything and wait.
}
Im going to suggest you significantly reduce the code you are working with. Define a width and height for the board and the number of divisions per side of the board.
Lets define width and height as w and h respectively and the number of divisions n and m respectively. w.l.o.g. assume n and m divide w and h evenly.
void DrawBoard(int w, int h, int n, int m) {
bool color = true;
int sw = w/n, sh = h/m; //square width and height respectively
//for each width and height draw a rectangle with a specific color
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
//oscillate the color per square of the board
if(color)
glColor3f(1, 1, 1);
else
glColor3f(0, 0, 0);
color = !color;
//draw a rectangle in the ith row and jth column
glRecti(i*sw, j*sh, (i+1)*sw, (j+1)*sh);
}
if(m % 2 == 0) color = !color; //switch color order at end of row if necessary
}
}
This should give the basic idea, though I might have hessed up an index or two. But essentially, iterate over the grid cells and draw a rectangle per board square.
This code will also draw the board starting at coordinate (0, 0) and finishing at (w, h). However if you would like it in an arbitrary position you can either add an (x, y) to eaxh corresponding coordinate in the glRecti call, or learn about transforms in openGL and use glTranslatef.
I'm currently working on a program, that will be able to visualize the evolution of point on the plane that are flowing along a vectorfield. I've finished the first version which I've pasted below. When running the program with a large number of points it seems that only the last say 30000 points gets drawn into the window. I'd like to be able to draw about 1000000 points, so I'm way off.
I've tried lovering the number if iterations (the Iteration variable - controlling the number of points), and here it acts just fine. However when increasing it substantially the first part is no longer drawn.
#include <iostream>
#include <stdio.h>
#include <math.h>
//#include <gsl/gsl_math.h>
//#include <gsl/gsl_sf.h>
#include <GL/freeglut.h>
#include <GL/gl.h>
using namespace std;
//Initial iterations to make the system settle:
int initIter=0;
//Iterations once system has settled:
int Iterations = 100000;
/**Starting point in time-phase-space (t,x,y,vx,vy).
For mathematical reasons the last two components should
always be 0**/
float TPS[5]={0,0.00,0.100,0.00,0.000};
//Timestep:
float dt=0.001;
/**The Step function make one Picard
iteration **/
float * Step(float * Arr){
static float NewTPS[5];
NewTPS[0] = Arr[0]+dt;
NewTPS[1] = Arr[1]+Arr[3]*dt;
NewTPS[2] = Arr[2]+Arr[4]*dt;
//This is the dynamical functions:
NewTPS[3] = -Arr[2];
NewTPS[4] = Arr[1];
return NewTPS;
}
/** This function sets up GLUT plotting
window: **/
void myInit(){
// set the background color
glClearColor(0.0f, 0.0f, 0.0f, 1.00f);
// set the foreground (pen) color
glColor4f(1.0f, 1.0f, 1.0f, 0.04f);
// set up the viewport
glViewport(0, 0, 800, 800);
// set up the projection matrix (the camera)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0f, 2.0f, -2.0f, 2.0f);
// set up the modelview matrix (the objects)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Computing initial iterations:
for (int i=0;i<initIter;i++){
//cout << TPS[1]<<" " << TPS[2] << endl;
float * newTPS2;
newTPS2 = Step(TPS);
//Assigning the values of newTPS2 to TPS:
for (int j=0; j<5;j++){
TPS[j]=*(newTPS2+j);
}
}
// enable blending
//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// enable point smoothing
//glEnable(GL_POINT_SMOOTH);
//glPointSize(1.0f);
}
/** This function draws a the point that
is passed to it: **/
void Draw(){
// clear the screen
glClear(GL_COLOR_BUFFER_BIT);
// draw some points
glBegin(GL_POINTS);
for (int i = 0; i <Iterations ; i++) {
float * newTPS2;
//cout << TPS[0]<< " " << TPS[1] << " " << TPS[2]<< endl;
newTPS2 = Step(TPS);
//Assigning the values of newTPS to TPS:
for (int j=0; j<5;j++){
TPS[j]=*(newTPS2+j);
}
// draw the new point
glVertex2f(TPS[1], TPS[2]);
}
glEnd();
// swap the buffers
glutSwapBuffers();
//glFlush();
}
int main(int argc, char** argv){
// initialize GLUT
glutInit(&argc, argv);
// set up our display mode for color with alpha and double buffering
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(800, 800);
glutCreateWindow("Trace of 2D-dynamics");
myInit();
// register our callback functions
glutDisplayFunc(Draw);
// glutKeyboardFunc(mykey);
// start the program
glutMainLoop();
return 0;
}
If you want to just color specific pixels on the screen, you should't be using glVertex at all. Put them all in a contiguos memory block, create a texture from it and render a quad covering the whole screen. That might be faster than calculating their positions inside OpenGL.
Probably in your implementation the size of a primitive is limited to a signed short, that is 32768 points. If that is the case you have to do glEnd/glBegin for each group of 32768 points or so:
for (int i = 0, x = 0; i <Iterations ; i++, x++) {
//...
if (x >= 32768)
{
x = 0;
glEnd();
glBegin(GL_POINTS);
}
//...
}
BTW, you may consider using vertex buffer objects (VBO). This limitation is likely the same, but are quite faster to draw.