I'm trying to make a simple game of pong using SDL and OpenGL in C++ and I'm having trouble displaying any sort of OpenGL image onto the screen and was wondering if anybody could help:
Initialization:
void init_everything()
{
SDL_Init( SDL_INIT_EVERYTHING );
SDL_SetVideoMode( width_of_screen, height_of_screen, bpp_of_screen, SDL_OPENGL );
glClearColor( 0, 0, 0, 0 );
// Sets the projection
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, width_of_screen, height_of_screen, 0, 1, -1 );
// initalises the modelview matrix
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
SDL_WM_SetCaption( "Pong - By Michael Clover", NULL );
}
After this I call the class function:
void paddle::show()
{
//Move to offset
glTranslatef( x, y, 0 );
//Start quad
glBegin( GL_QUADS );
//Set color to white
glColor4f( 1.0, 1.0, 1.0, 1.0 );
//Draw square
glVertex3f( 0, 0, 0 );
glVertex3f( paddle_width, 0, 0 );
glVertex3f( paddle_width, paddle_height, 0 );
glVertex3f( 0, paddle_height, 0 );
//End quad
glEnd();
//Reset
glLoadIdentity();
}
I then put this in my main function:
int main( int argc, char **argv )
{
bool quit = false;
init_everything();
paddle playerpaddle;
while (quit == false )
{
while( SDL_PollEvent( &event ) )
{
playerpaddle.handle_input();
if (event.type == SDL_QUIT)
{
quit = true;
}
}
playerpaddle.move();
glClear( GL_COLOR_BUFFER_BIT );
playerpaddle.show();
SDL_GL_SwapBuffers();
}
clean_up();
return 0;
}
All I get is a constant black background screen that I set within a 640 by 480px SDL screen.
Sorry for the huge amount of text and I would be extremely grateful for any insight on what the problem could be here, I'm guessing I'm making a silly mistake somewhere.
I think glOrtho might be set up wrong. The last 2 parameters are near and far clipping planes. Your near plane should be less than zero if you don't want to clip your paddle. And your far plane should be greater than zero. So try this:
glOrtho( 0, width_of_screen, height_of_screen, 0, -1, 1 );
Just 2 things to check now that you've ruled out errors:
Try removing the glTranslatef call. It may be too far off for you to see the scene.
Are you creating your vertices in a clockwise order? I can't tell by the variables you used, but if paddle_height is > 0 or paddle_width < 0, it's not going to be clockwise (which it needs to be).
Try this for your projection instead (if you want 0,0,0 at your center).
double range = 4.0; // Set this to whatever you want for the range of the display.
double ratio = double(displayWidth) / double(displayHeight);
glOrtho(-range* ratio, range* ratio, -range, range, -1.0, 1.0);
Temporarily try to render a square from -1.0,-1.0 to 1.0,1.0 to see if your display is working.
Related
I'm trying to draw a selection box over an image drawn using glDrawPixels, but I cannot get it to show. In order to represent the coordinates of the box, I have 4 global integers that I update on mouse actions (the first 2 on click, the others when the mouse is dragged), which I then use in the drawing function. I'm sure that the drawing function is called when the mouse gets dragged, and that the four values at least get updated, since I tried printing them every time the drawing function gets called.
The OpenGL calls I have in the main are:
glutInit(&argc, argv);
glutInitWindowSize(WINDOW_DIM, WINDOW_DIM);
glutInitWindowPosition(0, 0);
glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
glutCreateWindow("Window");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glClearColor(0.0, 0.0, 0.0, 1.0);
glDisable(GL_DEPTH_TEST);
glutMainLoop();
and my display function:
void display()
{
printf("calling display\n");
for(unsigned int i=0; i<WINDOW_DIM*WINDOW_DIM; ++i)
{
pixels[i]=colors[img[i]];
}
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(WINDOW_DIM, WINDOW_DIM, GL_RGB, GL_FLOAT, (float*)pixels);
glutSwapBuffers();
if(upd_xmin!=0 || upd_ymin!=0 || upd_xmax!=0 || upd_ymax!=0)
{
glDrawBuffer(GL_FRONT);
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
printf("drawing selection\n");
printf("coords %d %d %d %d\n", upd_xmin, upd_ymin, upd_xmax, upd_ymax);
glColor3f(1.0, 1.0, 1.0);
glLineWidth(3.0);
glBegin(GL_LINE_LOOP);
glVertex2i(upd_xmin, upd_ymin);
glVertex2i(upd_xmin, upd_ymax);
glVertex2i(upd_xmax, upd_ymax);
glVertex2i(upd_xmax, upd_ymin);
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
glDrawBuffer(GL_BACK);
}
}
As I said, I don't think the problem is with the mouse and motion function, seeing how the coordinates of the box (the upd_x and upd_y variables in the code above) get updated when there's a mouse event, but if needed I can post those as well.
Don't swap the buffers in the middle. Just draw the selection box on the back-buffer like everything else:
#include <GL/glut.h>
int StartX = -1;
int StartY = -1;
int EndX = -1;
int EndY = -1;
void mouse( int button, int state, int x, int y )
{
if( button == GLUT_LEFT && state == GLUT_DOWN )
{
StartX = x;
StartY = y;
}
if( button == GLUT_LEFT && state == GLUT_UP )
{
StartX = -1;
StartY = -1;
EndX = -1;
EndY = -1;
}
}
void motion( int x, int y )
{
EndX = x;
EndY = y;
glutPostRedisplay();
}
void display()
{
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double ar = w / h;
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glBegin( GL_TRIANGLES );
glColor3ub( 255, 0, 0 );
glVertex2i( -1, -1 );
glColor3ub( 0, 255, 0 );
glVertex2i( 1, -1 );
glColor3ub( 0, 0, 255 );
glVertex2i( 0, 1 );
glEnd();
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
if( StartX > 0 && StartY > 0 && EndX > 0 && EndY > 0 )
{
glLogicOp(GL_XOR);
glEnable(GL_COLOR_LOGIC_OP);
glColor3f(1.0, 1.0, 1.0);
glLineWidth(3.0);
glBegin(GL_LINE_LOOP);
glVertex2i(StartX, StartY);
glVertex2i(EndX, StartY);
glVertex2i(EndX, EndY);
glVertex2i(StartX, EndY);
glEnd();
glDisable(GL_COLOR_LOGIC_OP);
}
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMouseFunc( mouse );
glutMotionFunc( motion );
glutMainLoop();
return 0;
}
Since you weren't specifying them I added projection and modelview matrices.
I believe the problem lies here:
glClear(GL_COLOR_BUFFER_BIT);
glDrawPixels(WINDOW_DIM, WINDOW_DIM, GL_RGB, GL_FLOAT, (float*)pixels);
glutSwapBuffers();
rest of drawing
Your render call should look like:
clear
render
swap buffers
Where render is all of your draw calls (including glDrawPixels).
Also, glDrawPixels was removed in OpenGL 3.2. Unless you absolutely need to use that particular method, why not use an orthographic projection to draw GUI elements (which the selection box can be though of as)?
Edit: Also, be aware that if you make draw calls after glDrawPixels, those may overwrite what you drew with glDrawPixels.
In OpenGL/JOGL, when using more than one clipping plane, the union of all clipping planes appears to be applied. What I want is instead the intersection of all clipping planes to be applied. Is this possible? See the below simplified 2-D example.
Edit: An example of clipping by vertex shader (see comments below).
Multi-pass:
#include <GL/glut.h>
void scene()
{
glColor3ub( 255, 0, 0 );
glBegin( GL_QUADS );
glVertex2i( -1, -1 );
glVertex2i( 1, -1 );
glVertex2i( 1, 1 );
glVertex2i( -1, 1 );
glEnd();
}
void display()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -2 * ar, 2 * ar, -2, 2, -1, 1);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnable( GL_CLIP_PLANE0 );
// -y plane
GLdouble plane0[] = { -1, 0, 0, 0 };
glClipPlane( GL_CLIP_PLANE0, plane0 );
scene();
// -x plane
GLdouble plane1[] = { 0, -1, 0, 0 };
glClipPlane( GL_CLIP_PLANE0, plane1 );
scene();
glutSwapBuffers();
}
int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "Clipping" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
Using glClipPlane, no. Vertices are clipped if they are outside the positive halfspace of at least one plane. Once that happens, it doesn't matter what any other plane may be.
However, you can get this effect (or almost any other effect) by writing appropriate values to gl_ClipDistance in a vertex shader.
Any portion where the interpolated value that you write out is less than 0.0 ("negative halfspace") will be clipped, and you can write any value you like, e.g. the squared distance to a point, or the sum of distances to two planes, or anything else you calculate.
I'm going to show FPS on the screen with the freeglut function glutBitmapString,but it shows nothing. Here is my code. Is there anyone can figure where the problem is?
void PrintFPS()
{
frame++;
time=glutGet(GLUT_ELAPSED_TIME);
if (time - timebase > 100) {
cout << "FPS:\t"<<frame*1000.0/(time-timebase)<<endl;
char* out = new char[30];
sprintf(out,"FPS:%4.2f",frame*1000.0f/(time-timebase));
glColor3f(1.0f,1.0f,1.0f);
glRasterPos2f(20,20);
glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24,(unsigned char* )out);
timebase = time;
frame = 0;
}
}
void RenderScene(void)
{
// Clear the window with current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 0.5f };
GLfloat vYellow[] = {1.0f,1.0f,0.0f,1.0f};
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vYellow);
//triangleBatch.Draw();
squareBatch.Draw();
PrintFPS();
glutSwapBuffers();
}
it supposed to show the FPS on the top left of the screen
The position that's provided by glRasterPos is treated just like a vertex, and transformed by the current model-view and projection matrices. In you example, you specify the text to be position at (20,20), which I'm guessing is supposed to be screen (viewport, really) coordinates.
If it's the case that you're rendering 3D geometry, particularly with a perspective projection, your text may be clipped out. However, there are (at least) two simple solutions (presented in order of code simplicity):
use one of the glWindowPos functions instead of glRasterPos. This function bypasses the model-view and projection transformations.
use glMatrixMode, glPushMatrix, and glPopMatrix to temporarily switch to window coordinates for rendering:
// Switch to window coordinates to render
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0, windowWidth, 0, windowHeight );
glRasterPos2i( 20, 20 ); // or wherever in window coordinates
glutBitmapString( ... );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
I'm having the following problem. While glPolygonOffset works perfectly for meshes, for example when I'm trying to draw a wireframe outline on top of the object, it doesn't work for simple lines.
Here is how it works for meshes:
// draw object
mTexture.enableAndBind();
gl::color( Colorf( 1, 1, 1 ) );
gl::draw( mVboMesh );
mTexture.unbind();
// overlay wireframe
gl::enableWireframe();
glLineWidth(1);
glEnable( GL_POLYGON_OFFSET_LINE );
glPolygonOffset( -1, -1 );
glColor3f( 0, 0, 1 );
gl::draw( mVboMesh );
glDisable( GL_POLYGON_OFFSET_LINE );
gl::disableWireframe();
For some reason it doesn't work for lines. What I'm trying to achieve is to draw a coordinate frame's arrows over a grid. I'm using the very same GL_POLYGON_OFFSET_LINE mode as when I was drawing lines, just like I was doing for the wireframe over the object. However in this case glPolygonOffset( -1, -1 ); makes absolutely no difference. I've tried it with huge values like 100 and it's the same. Absolutely no effect. Here is what I'm doing:
// enable 3D rendering
gl::enable( GL_CULL_FACE );
gl::enableDepthRead();
gl::enableDepthWrite();
// drawing the grid
int size = 2000;
int step = 25;
gl::color( Colorf( 0.2f, 0.2f, 0.2f ) );
for( float i = -size; i <= size; i += step )
{
glBegin( GL_LINES );
glVertex3f( i, 0, -size );
glVertex3f( i, 0, size );
glVertex3f( -size, 0, i );
glVertex3f( size, 0, i );
glEnd( );
}
// drawing the arrows
glEnable( GL_POLYGON_OFFSET_LINE );
glPolygonOffset( -1, -1 );
glBegin( GL_LINES );
gl::color( Colorf( 1, 0, 0 ) );
glVertex3f( 0, 0, 0 );
glVertex3f( 100, 0, 0 );
gl::color( Colorf( 0, 1, 0 ) );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, 100, 0 );
gl::color( Colorf( 0, 0, 1 ) );
glVertex3f( 0, 0, 0 );
glVertex3f( 0, 0, 100 );
glEnd( );
glDisable( GL_POLYGON_OFFSET_LINE );
// disable 3D rendering
gl::disableDepthWrite();
gl::disableDepthRead();
gl::disable( GL_CULL_FACE );
and an example of the Z-fighting I get:
One hack I've tried and what worked perfectly is:
disable depth read, enable depth write
draw grid
draw arrows
enable depth read
draw other objects
However this is a very special case and while it works for a flat grid and arrows, it wouldn't work for pretty much anything else with a complex shape.
My questions are:
Why does glPolygonOffset not work for lines-on-lines while it works for lines-on-polygon?
How can I fix it, without resorting to the above hack, what only works in very specific cases?
// I'm using Cinder as a framework, but it shouldn't matter since I'm using raw OpenGL commands
Update
I've checked the answer in the first comment, and tried that method as well, however that one doesn't work either, since the result depends on the distance from the camera.
//// draw coordinate frame and grid
glDepthRange (0.01, 1.0);
drawGrid( 2000.0f, 25.0f );
glDepthRange (0.0, 0.99);
gl::drawCoordinateFrame( 100.0f, 5.0f, 2.0f );
glDepthRange (0.0, 1.0);
// draw object
I guess one hack could be to draw the line just a bit closer to the view point (let's say 0.1 closer). This should avoid z-fighting.
In order to do so, you calculate the normalized directional vector from your point to the POV position. Then you scale it with a small factor, and add it to your line point coordinates
I have a simple program to use depth test. It is not working as expected. The program draws X, Y axis and a sphere near the origin.
If I don't turn on the GL_DEPTH_TEST, the sphere is drawn over the axis. If I turn on the GL_DEPTH_TEST, the axis are drawn over the sphere which I was not expecting. Can someone tell me what I did
wrong ?
void
glwid::initializeGL()
{
glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
}
void
glwid::resizeGL(int width, int height)
{
glViewport( 0, 0, (GLint)width, (GLint)height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective ( 90, (GLint)width/ (GLint)height, 0.0, 200.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glEnable (GL_DEPTH_TEST);
}
void
glwid::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
gluLookAt (0, 0, 100, 0, 0, 0, 0, 1, 0);
//
// X axis
//
glBegin( GL_LINES );
qglColor( green );
glVertex3f (-100.0, 0, 0. );
glVertex3f (100.0, 0, 0. );
glEnd();
//
// Y axis
//
glBegin( GL_LINES );
qglColor( red );
glVertex3f (0.0, 100.0, 0. );
glVertex3f (0.0, -100, 0. );
glEnd();
//
// sun
//
glTranslated (5, 0, 20);
GLUquadricObj *sphere_quadric = gluNewQuadric();
glColor3ub (255, 255, 0);
gluQuadricDrawStyle(sphere_quadric, (GLenum)GLU_SMOOTH);
gluSphere(sphere_quadric, 10, 36, 36);
}
I've tried your code. The problem is in resizeGL() function.
The problem was your putting to
gluPerspective ( 90, (GLint)width/ (GLint)height, 0.0, 200.0 );
0.0 value as a third argument. Put 0.01 for example - and everything will be ok. that's because this parameter should always be positive:
http://www.opengl.org/sdk/docs/man/xhtml/gluPerspective.xml
Also change (GLint)width/ (GLint)height to (GLfloat)width/ (GLfloat)height otherwise the result will be strange.
And it's better to put glEnable(GL_DEPTH_TEST) into initializeGL() function
Your axis starts at Z location 0. The Sphere is at Z location 20 (farther away from the "camera") therefore the axis is in-front of the sphere and is being shown.
As you currently have it setup, as Z values go up they move away from the screen. As they go down, they are going closer to the screen.
You have two options: Disable depth testing while drawing your axis (therefore it will always be behind everything). Or move your axis to Z position 100 or so and scale it up to make it look the same size. Option one is probably better.
Simply wrapping your axis drawing routines in glDisable(GL_DEPTH_TEST); and glEnable (GL_DEPTH_TEST); should do the trick