For the entire night, I've been looking around the internet, both stackoverflow and elsewhere, to find something to say how to print text on GLUT. While I've found places that say how, none have explained it well, saying which parts of the function is neccessary, which parts aren't. I've also tried to copy in some of the code with the closest to a success is something that made my entire screen white except for some blue pixels. So I've given up, and I'm hoping this will clear up confusion for me and the many people who are confused, like me.
So, I have found this code:
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(1280, 720);
int len = menu.length();
for (int i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
and I have placed it in my code:
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(-_cameraAngle, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, -9.0f + zoom);
glTranslatef(0.0f, -1.0f, 0.0f);
string menu = "Hello!";
glColor3f(1.0f, 0.0f, 0.0f);
glRasterPos2f(1280, 720);
int len = menu.length();
for (int i = 0; i < len; i++) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
} /*if I need to post the rest of drawScene(), which is the function delegated
as the Display Func, tell me. I don't want to because it's long
What I want to know is what am I doing wrong, and what do future readers in my position need to do in order to get good results.
You don't say what's specifically wrong, but I'm suspecting that your text is not showing up. The reason is likely that the raster position is being clipped, and this is causing your text to not be rendered.
The raster position is the "anchor point" of where a bitmap will be drawn. Usually, this is the lower-left corner of the bitmap (the glBitmap can change that with by setting the x and y parameters to something other than zero, but assume you're not doing that). The raster position is transformed by the model-view matrix, just like a vertex in a geometric primitive. And just like a vertex, if the transformed raster position lies outside of the viewport, it's clipped, and nothing is rendered. What's important to know here is that any rendering of a bitmap - regardless of its size - is predicated on the raster position being inside of the viewport.
In your example, you don't show the viewport you're using, nor the projection transformation (the matrix on the GL_PROJECTION stack), but you set the raster position to (1280, 720), which may well be outside of the viewport.
Let's say you want to render your text in the lower-left corner of your window (and for the sake of argument, let's say your window is 1280 x 1024). When it's time to render your text, drop the following into your rendering routine:
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
gluOrtho2D( 0, 1280, 0, 1024 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glRasterPos2i( 10, 1014 ); // move in 10 pixels from the left and bottom edges
for ( int i = 0; i < len; ++i ) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
glPopMatrix();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glMatrixMode( GL_MODELVIEW );
Depending on which version of OpenGL you're using, you may be able to use a simpler routine glWindowPos2i() (the 2i can be replaced with other dimension-type pairs like other OpenGL functions), which bypasses transforming the raster position by the model-view and projection matrices, and works directly in window coordinates. In that case, you'd write the above code as:
glWindowPos2i( 10, 1014 ); // move in 10 pixels from the left and bottom edges
for ( int i = 0; i < len; ++i ) {
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, menu[i]);
}
Related
I want to draw points with openGL, I have a 32x32 screen size and I want to fill it with the color red, however I don't understand how the parameters of glVertex2f(-1, 0.5) are working
My first instinct was to do something like this:
glutInit(&argc, argv); // Initialize GLUT
glutCreateWindow("OpenGL Setup Test"); // Create a window with the given title
glutInitWindowSize(32, 32); // Set the window's initial width & height
glutDisplayFunc(displaySpectrogram); // Register display callback handler for window re-paint
glutMainLoop(); // Enter the event-processing loop
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer (background)
glBegin(GL_POINTS);
glColor3f(1.0f, 0.0f, 0.0f); // Red
for (int i = 0; i < 32; i++)
{
for (int j = 0; j < 32; j++)
{
glVertex2f(i,j);
}
}
glEnd();
glFlush(); // Render now
But glVertex2f() parameters range is -1 to 1 I think so I'm not sure how to achieve that.
There is another way with texture but I have no idea on how to use them and there are no tutorials for that online
I recommend to use an Orthographic projection. In Orthographic Projection, the view space coordinates are linearly mapped to the clip space coordinates and normalized device coordinates. The viewing volume is defined by 6 distances (left, right, bottom, top, near, far). The values for left, right, bottom, top, near and far define a cuboid (box).
With legacy OpenGL matrices you can use glOrtho to set an orthographic projection matrix:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 32, 0, 32, -1, 1);
So a lot of questions online about resizing have been about maintaining the right ratios and avoid stretching etc. From what I understand, this would be done by setting the new ratio with gluOrtho2D.
However, I wasn't sure exactly how to go about showing MORE and LESS of the world upon resize. E.g. you have a plane that could travel from 0 to 100 along the x axis. Upon resizing, it should now (still same size) travel from 0 to 200.
EDIT: so what I mean is, I want everything in my game to stay the same size as before, but the "sky" if you will, should be bigger upon the resize, and my plane should be able to fly into that sky (since currently I have code that limits it to within the screen).
Similarly, if my screen is smaller, then the plane should no longer be able to fly to the section of the 'sky' that no longer exists
Initially, I'm setting up my program using the following lines, where everything about the game is stored in 'game', and XSize, YSize returns the size of the screen.
void init(void) {
glClearColor(0.0, 0.0, 0.3, 0.0); /* set background color to a dark blue */
glColor3f(1.0, 1.0, 1.0); /* set drawing color to white */
glMatrixMode(GL_PROJECTION);
glEnable (GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLoadIdentity();
gluOrtho2D(0, game.getXSize()*game.getAspect(), 0, game.getYSize() / game.getAspect()); /* defines world window */
}
int main(int argc, char *argv[]) {
game = GameManager(GAMENAME, 1000, 750, 60);
/*SETUP*/
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(game.getXSize(), game.getYSize());
glutCreateWindow(GAMENAME);
/*Other GLUT main function lines here */
glutReshapeFunc(resize);
}
When I try to set up the gluOrtho2D in resize, however, the program sets up the background and stops drawing anything at all.
void resize(int w, int h){
game.setScreenSize(w,h);
glViewport(0,0,width,height)
const GLfloat aspectRatio = (GLfloat)game.getXSize() / (GLfloat)game.getYSize();
gluOrtho2D(0, game.getXSize()*game.getAspect(), 0, game.getYSize() / game.getAspect());
}
I have, of course, managed to just use glViewport(0,0,w,h) by itself, but that's pretty much the same as not doing anything at all (the graphics just stretch, and functions I'm using to move objects to the mouse position no longer work properly), since glViewport is called by default if I don't create a Reshape function.
The general way world coordinates get mapped to screen in OpenGL is:
world coordinates --> clip space coordinates --> device coordinates
The "world coordinates" are just whatever you feed to OpenGL as vertex data. They can be whatever you want, there are no rules.
The vertex shader (or matrix stack, if you are time traveling to the 1990s) is what transforms world coordinates to clip space coordinates.
The clip space coordinates go from –1…+1. So (–1,–1) is the lower-left corner of the window, (–1,+1) is the top left, (+1,+1) is the top right, etc. This is the same no matter what size your window is. So if your window gets larger, the picture will also get larger, unless you scale down the clip space coordinates at the same time.
So if you want to keep the same world coordinates and keep the same size in pixels, you have to change the way world coordinates are transformed to clip space. In general, this means that if your window gets twice as big, your clip space coordinates should get half as big, in order to keep everything the same size.
Typically, to achieve this, you'll end up multiplying in a matrix that looks something like this:
int windowWidth = ..., windowHeight = ...;
double matrix[2][2] = {
{ 1.0 / windowWidth, 0.0 },
{ 0.0, 1.0 / windowHeight },
};
That's if you're using a 2D matrix. Change this appropriately if you are using glOrtho or for your particular vertex shader. Or just read the manual for glOrtho.
By using:
gluOrtho2D(-1.0f, 1.0f, -1.0f, 1.0f);
Which would be the same as:
glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
Then I'm assuming your problem is that when you scale a scene like this, then it ends up looking like this:
As you say this can be fixed by taking the aspect ratio into account. Given the width and height of your screen. Then you can calculate the aspect ratio and set the proper orthographic projection:
const GLfloat aspectRatio = (GLfloat)width / (GLfloat)height;
gluOrtho2D(-aspectRatio, aspectRatio, -1.0f, 1.0f);
This now results in everything scaling in relation to the aspect ratio, and subsequently allowing you to see more.
Since the above is actually a sphere in 3D, setting the near and far values is also needed:
glOrtho(-aspectRatio, aspectRatio, -1.0f, 1.0f, 1.0f, 100.0f);
I followed a guide to draw a Lorenz system in 2D.
I want now to extend my project and switch from 2D to 3D. As far as I know I have to substitute the gluOrtho2D call with either gluPerspective or glFrustum. Unfortunately whatever I try is useless.
This is my initialization code:
// set the background color
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
/// set the foreground (pen) color
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);*/
// set the foreground (pen) color
glColor4f(1.0f, 1.0f, 1.0f, 0.02f);
// enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// enable point smoothing
glEnable(GL_POINT_SMOOTH);
glPointSize(1.0f);
// set up the viewport
glViewport(0, 0, 400, 400);
// set up the projection matrix (the camera)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//gluOrtho2D(-2.0f, 2.0f, -2.0f, 2.0f);
gluPerspective(45.0f, 1.0f, 0.1f, 100.0f); //Sets the frustum to perspective mode
// set up the modelview matrix (the objects)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
while to draw I do this:
glClear(GL_COLOR_BUFFER_BIT);
// draw some points
glBegin(GL_POINTS);
// go through the equations many times, drawing a point for each iteration
for (int i = 0; i < iterations; i++) {
// compute a new point using the strange attractor equations
float xnew=z*sin(a*x)+cos(b*y);
float ynew=x*sin(c*y)+cos(d*z);
float znew=y*sin(e*z)+cos(f*x);
// save the new point
x = xnew;
y = ynew;
z = znew;
// draw the new point
glVertex3f(x, y, z);
}
glEnd();
// swap the buffers
glutSwapBuffers();
the problem is that I don't visualize anything in my window. It's all black. What am I doing wrong?
The name "gluOrtho2D" is a bit misleading. In fact gluOrtho2D is probably the most useless function ever. The definition of gluOrtho2D is
void gluOrtho2D(
GLdouble left,
GLdouble right,
GLdouble bottom,
GLdouble top )
{
glOrtho(left, right, bottom, top, -1, 1);
}
i.e. the only thing it does it calling glOrtho with default values for near and far. Wow, how complicated and ingenious </sarcasm>.
Anyway, even if it's called ...2D, there's nothing 2-dimensional about it. The projection volume still has a depth range of [-1 ; 1] which is perfectly 3-dimensional.
Most likely the points generated lie outside the projection volume, which has a Z value range of [0.1 ; 100] in your case, but your points are confined to the range [-1 ; 1] in either axis (and IIRC the Z range of the strange attractor is entirely positive). So you have to apply some translation to see something. I suggest you choose
near = 1
far = 10
and apply a translation of Z: -5.5 to move things into the center of the viewing volume.
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 trying to draw a simple string (overlay) on the screen.
From what I've found over the internet, I'm using it this way:
void write(string text, int x, int y){
glRasterPos2i(x,y);
for(int i = 0; i < text.length(); i++){
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, text.data()[i]);
}
}
But it draws the string according to the world coordinates. Say, if x and y are set to 10, they are drawn at (10,10,0) coordinates in the world. But I simple need this string at window's (10,10) coordinates in 2D.
This is part of a small project, and the draw method is given as below. I don't want to change it much as it may break something else in the project.
void disp(){
// set viewing translation and object rotations
glMatrixMode( GL_MODELVIEW );
glLoadIdentity ();
glTranslatef( INIT_VIEW_X, INIT_VIEW_Y, INIT_VIEW_Z );
glRotatef( xRot, 1.0, 0.0, 0.0 );
glRotatef( zRot, 0.0, 0.0, 1.0 );
glScalef( scaleFactor, scaleFactor, scaleFactor );
glClear(GL_COLOR_BUFFER_BIT);
draw();
glFlush();
}
I also don't exactly know what they do, and I think drawing the text to world coordinates have to do with something in this code. I've also tried Using GLUT bitmap fonts but it doesn't work either.
How can I simple draw onto the screen. OpenGL is over complicating things; I try to simply write to the window, but it takes the whole thing and translates into 3D world. I just don't want this.
From twall, yes you need to clear BOTH the modelview and projection matrices
//TEXT
glMatrixMode( GL_PROJECTION ) ;
glPushMatrix() ; // save
glLoadIdentity();// and clear
glMatrixMode( GL_MODELVIEW ) ;
glPushMatrix() ;
glLoadIdentity() ;
glDisable( GL_DEPTH_TEST ) ; // also disable the depth test so renders on top
glRasterPos2f( 0,0 ) ; // center of screen. (-1,0) is center left.
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
char buf[300];
sprintf( buf, "Oh hello" ) ;
const char * p = buf ;
do glutBitmapCharacter( GLUT_BITMAP_HELVETICA_18, *p ); while( *(++p) ) ;
glEnable( GL_DEPTH_TEST ) ; // Turn depth testing back on
glMatrixMode( GL_PROJECTION ) ;
glPopMatrix() ; // revert back to the matrix I had before.
glMatrixMode( GL_MODELVIEW ) ;
glPopMatrix() ;
From what I can gather, it seems what you're after is orthographic projection.
I'm not sure about OpenGL specifically (I'm used to higher-level graphics libraries), but here's a couple of links that could be a starting point:
Setting a orthographic projection matrix?
http://www.cprogramming.com/tutorial/opengl_projections.html
you can step back to "2D" coordinates like so:
//save your current matrix on the stack, so you don't lose it
glPushMatrix();
//load identity matrix, so you don't have any 3d transformations
glLoadIdentity ();
//now you also can transform the text
//to the position just as you like
//glTransformf( ... )
//make sure the text is draw, even though it might be outside the viewing area
glDisable( GL_DEPTH_TEST )
drawMyFunkyText();
glEnable( GL_DEPTH_TEST )
//restore the matrix as it was before,
//so you can draw all your shapes as before
glPopMatrix();