How to display shape and text on OpenGL screen simultaneously? - c++

The below code works perfectly fine with no fatal error but, when i use arguments "w","h" in "gluortho2d" as gluortho2d(0,w,h,0) in reshape function I get text on screen whereas if I put these arguments "0,0" as gluortho2d(0,0,0,0) I get shape of box.
How can I get both of them(box and text) simultaneously on screen?
#include"glut.h"
void drawBitmapText(char *string, float x, float y, float z);
void reshape(int w, int h);
void display(void);
void drawBitmapText(char *string, float x, float y, float z)
{
char *c;
glRasterPos3f(x, y, z);//define position on the screen where to draw text.
for (c = string; *c != '\0'; c++)
{
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *c);
}
}
void reshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();//Resets to identity Matrix.
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void display(void)
{
glBegin(GL_POLYGON);//1
glVertex2f(-0.2, 0.6 - 0.3);
glVertex2f(-0.1, 0.6 - 0.3);
glVertex2f(-0.1, 0.5 - 0.3);
glVertex2f(-0.2, 0.5 - 0.3);
glEnd();
glColor3f(0, 1, 0);
drawBitmapText("Usama Ishfaq", 200, 400, 0);//drawBitmapText("Usama Ishfaq", x(how much right), y(how much down), z);
glutSwapBuffers();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("Usama OGL Window");
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}

By not following bad tutorials and placing calls to glViewport and projection matrix setup at the only place valid: The display function. Setting the viewport and projection matrix in the reshape handler is an anti-pattern. Don't do it.
Do this
void display(void)
{
int const w = glutGet(GLUT_WINDOW_WIDTH);
int const h = glutGet(GLUT_WINDOW_HEIGHT);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();//Resets to identity Matrix.
gluOrtho2D(-1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBegin(GL_POLYGON);//1
glVertex2f(-0.2, 0.6 - 0.3);
glVertex2f(-0.1, 0.6 - 0.3);
glVertex2f(-0.1, 0.5 - 0.3);
glVertex2f(-0.2, 0.5 - 0.3);
glEnd();
/* viewport doesn't change in this
* application, but it's perfectly
* valid to set a different
* glViewport(...) here */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();//Resets to identity Matrix.
gluOrtho2D(0, w, h, 0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(0, 1, 0);
drawBitmapText("Usama Ishfaq", 200, 400, 0);//drawBitmapText("Usama Ishfaq", x(how much right), y(how much down), z);
glutSwapBuffers();
}
Update (due to request in coments):
Why is it wrong to set the viewport and projection parameters in the reshape handler? Well, you just experienced the reason yourself: They are not "one size fits all" state and throughout rendering slightly more complex frames that go beyond just a mesh drawn, you're going to want to mix and match different viewports and projections throughout rendering. Here's a (incomplete) list of things that require to have different viewports and projections while rendering a single frame:
render-to-texture (FBO) – needs viewport withing the bounds of the texture, and usually also a different projection (important for shadow mapping, dynamic cubemaps and lots of other advanced, multipass rendering techniques)
minimaps / overview frames or similar in the corner (viewport covering just the corner)
text annotation overlays (different projection; usually a plain identity transform so to draw text rectangles directly in NDC space)
"magnifying glass" overlay
Since changing viewport and projection state happens multiple times in only slightly more complex OpenGL drawing, it makes
a) zero sense to set it in the reshape handler: whatever the handler sets will be set only at the beginning of the drawing of the first frame and thereafter the frame drawing code itself would have to reset to what the reshape handler sets. So why even bother doing it in the reshape handler at all?
b) placing viewport and projection setup code in the reshape handler a burden in the long run, because it might cause other parts of the program getting dependent on that. And if that happens, once you realize your mistake and try to move that viewport and projection setup code to where it belongs other parts of the program that relied on it being called from the reshape handler break and you have to fix those, too.
All in all, there are no reasons to place any drawing related calls (and glViewport and projection setup definitely are drawing related) in the reshape handler. Of course "one time" initialization is perfectly fine there, i.e. if you want to adjust the size of FBO render targets to match the window, or if you want to prepare an overlay image that later on gets applied repeatedly.

You can make this much simpler. For what you're doing, there's no need to bother with setting transformations at all.
It looks like, for the box, you're trying to use coordinates in the range [-1.0, 1.0] for both coordinate directions. This corresponds to the OpenGL NDC (Normalized Device Coordinates) coordinate system, which is the coordinate space vertices are in after both the modelview and projection transformations are applied. If you keep these at their default identity matrix, you can specify coordinates directly in NDC space. In other words, to use coordinates in the range [-1.0, 1.0], do... nothing at all, and just keep everything at its default.
The reason the box rendering works for you when you call:
gluOrtho2D(0.0, 0.0, 0.0, 0.0);
is that this call will result in an error, as documented on the man page:
GL_INVALID_VALUE is generated if left = right, or bottom = top, or near = far.
and will therefore keep the defaults untouched, which is exactly what you need.
Now, for the text, it looks like you want to specify the position in units of pixels. The problem you're having is that glRasterPos*() runs the specified coordinates through the transformation pipeline, meaning that, with the default identity modelview and projection transformations, it expects the input coordinates to be in the range [-1.0, 1.0] just like the coordinates you pass to glVertex2f().
Fortunately, there's a very easy way to avoid that. There's a very similar glWindowPos*() call, with the only difference that the coordinates passed to it are in window coordinates, which are in units of pixels.
So in summary:
Remove all glMatrixMode() calls.
Remove all glLoadIdentity() calls.
Remove all gluOrtho2D() calls.
In drawBitmapText(), replace the glRasterPos3f() call by:
glWindowPos2f(x, y);
The only thing to watch out for is that the origin of window coordinates is in the bottom left corner. So if your text position is given relative to the top left corner, you'll need something like:
glWindowPos2f(x, windowHeight - y);
To address some misleading information in another answer: It's perfectly fine to call glViewport() in the reshape() function, as long as you use the same viewport for all your rendering. In more complex applications, you will often need different viewports for different parts of the rendering (e.g. when you render to FBOs, or to only part of the window), so you will need to call glViewport() at the proper places during rendering. But for a simple example, where you do all your rendering to the entire window, there's nothing wrong with calling it in reshape().

Related

OpenGL showing more/less of the world through resize

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);

Text wont output on screen C++ / OpenGL

I am currently trying to output a string onto screen in OpenGL my relevant code is as follows:
void drawBitmapText(char *string,float x,float y)
{
char *c;
glRasterPos2f(x, y);
for (c=string; *c != '\0'; c++)
{
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_10, *c);
}
}
Where my display function looks like so:
void display(void)
{
int speed=frame/20;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
frame++;
if((frame>=0) && (frame<1000)) // Scene 1.
{
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
drawBitmapText("Hello World",200,200);
glutSwapBuffers();
}
}
I believe I have implemented it correctly but apparently not. Any ideas?
If the xy position passed to glRasterPos2f(x, y); lies outside the viewport after transformation, the following raster drawing operations will be omitted until a new raster position that transforms to within the viewport is specified.
If you don't know what "transformation" and "viewport" mean you should educate yourself on this. Only so much: The coordinates given to glRasterPos are not pixel coordinates.
The position passed to glRasterPos2f() is processed just like vertices you pass to draw calls. This means that the current transformations (modelview and projection) are applied to the position.
If you don't specify any transformations, the default for both of these is the identity transformation. This means that the resulting coordinates are the same as the input coordinates.
Once all transformations are applied, OpenGL expects that the resulting coordinates are in a coordinate system called Normalized Device Coordinates (NDC). In this coordinate system, the range [-1.0, 1.0] for each coordinate direction maps to the window size. Which means that if no transformations are applied, your input coordinates should already be within that range.
I can think of at least 3 options to get this working for you:
Specify coordinates in the range [-1.0, 1.0]. For example:
glRasterPos2f(-1.0f, -1.0f);
would place text at the bottom left corner, and:
glRasterPos2f(0.0f, 0.0f);
places it at the center of the window.
If you want to specify the position in pixels, set up a corresponding projection transformation:
glMatrixMode(GL_PROJECTION);
glLoadIndentity();
glOrtho(0.0, width, 0.0, height, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
Use glWindowPos2f() instead of glRasterPos2f(). This function also sets the raster position, but takes input in window coordinates (which are in pixel units), and does not apply the current transformations.

Draw oval with sphere in Opengl

I want to draw an oval by projection the sphere on the screen (like rasterize). Here is my code but it doesn't show anything on the screen. Should I use more functions to initialize the projection? Is this way possible to draw oval on screen by using sphere?
GLfloat xRotated, yRotated, zRotated;
GLdouble radius=1;
void display(void);
void reshape(int x, int y);
int main (int argc, char **argv)
{
glutInit(&argc, argv);
glutInitWindowSize(800,800);
glutCreateWindow("OVAL");
zRotated = 30.0;
xRotated=43;
yRotated=50;
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
void display(void)
{
glMatrixMode(GL_PROJECTION);
glOrtho(0.1, 1.0, 0.1, 1.0, -1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0,0.0,-5.0);
glColor3f(0.9, 0.3, 0.2);
glRotatef(xRotated,1.0,0.0,0.0);
glRotatef(yRotated,0.0,1.0,0.0);
glRotatef(zRotated,0.0,0.0,1.0);
glScalef(1.0,1.0,1.0);glutSolidSphere(radius,20,20);
glFlush();
}
void reshape(int x, int y)
{
if (y == 0 || x == 0) return;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(39.0,(GLdouble)x/(GLdouble)y,0.6,21.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,x,y);
}
You are drawing a sphere compltely outside of the viewing volume, so it should be no surprise that it can't be seen.
There are a couple of issues with your code:
All OpenGL matrix functions besides glLoadIndentity and glLoadMatrix always post-multiply a matrix to the current top element of the current matrix stack. In your display function, you call glOrtho without resetting the projection matrix to identity before. This will result in totally weird - and different - results if the display callback is called more than once.
You should add a call to glLoadIdentity() right before calling glOrtho.
You set up the model view transformations so that the sphere's center will always end up at (0,0,-5) in eye space. However, you set a projectiom matrix which defines a viewing volume which goes from z=1 (near plane) to z=-1 (far plane) in eye space, so your spehre is actually behind the far plane.
There are several ways this could be fixed. Changing the viewing frustum by modifying the parameters of glOrtho might be the easisest. You could for example try (-2, 2, -2, 2, 1, 10) to be able to see the sphere.
It is not really clear what
I want to draw an oval by projection the sphere on the screen (like rasterize).
exactly means. If you just want the sphere to be distorted to an ellipsoid, you could just apply some non-uniform scaling. This in principle could be done in the projection matrix (if no other objects are to be shown), but this would make much more sense to apply it to the model matrix of the sphere - you already have the glScale call there, you could try something like glScalef(1.0f, 0.5f, 1.0f);.
Also note that the ortho parameters I suggested previously will result in some distortion if your viewport is not exactly square. In a real world, one wants to incorporate the aspect ratio of the viewport into the projection matrix.
If you want to see the sphere deformed as by a perspective projection, you would have to skip the glOrtho altogheter and switch to a perspective projection matrix.
The code you are using is totally outdated. The OpenGL matrix stack has been deprecated in OpenGL 3.0 (2008) and is not available in core profiles of modern OpenGL. The same applies for builtin vertex attributes like glColor or immediate mode drawing and client-side vertex arrays. As a result, GLUT's drawing functions can also not be used with modern GL any more.
If you really intend learning OpenGL nowadays, I stronly advise you to ignore this old cruft and star learning the modern way.

Object without deformations - OpenGL

Anybody knows how to keep a triangle without deformations and always at the middle of the windows whatever is his size?
I know I have to do one callback with reshape function and then define it, but I'm not sure what is going inside resize function:
void resize(int width, int height) {
viewport(0,0,width,height);
...?
}
I have this main help. glutInitWindowSize(600, 600);
Since the GL calls use normalised vertex coordinates ranging from -1 to +1, it is possible to keep any object in the center of the screen by using the right coordinates independent of the screen pixel sizes.
However, the same independency also brings in the behaviour that, depending on the screen aspect ratio (or window aspect ratio, as the case may be) the object will also change, unless explicitly accounted for. See the discussions in How can i convert an oval to circle openGL ES2.0 Android
Here's a important hint: Don't use the resize callback to do anything with OpenGL.
I know I have to do one callback with reshape function and then define it, but I'm not sure what is going inside resize function:
Then you knew wrong.
It leads to a lot of confusion. OpenGL is a state based drawing API and like all state machines it should be reset into a well known state before you use it. That includes projection and viewport. With that in mind your problem becomes trivial
void display()
{
/* draw some stuff */
glViewport(...);
setup_projection();
setup_modelview();
draw_stuff();
/* draw some other stuff with different projection and modelview */
glViewport(...);
setup_other_projection();
setup_other_modelview();
draw_other_stuff();
/* ... */
swapBuffers();
}
If you're using GLUT you can use glutGet(GLUT_WINDOW_WIDTH) and glutGet(GLUT_WINDOW_HEIGHT) to retrieve the window's size for the viewport calls.
So in your case you'd use a glViewport that covers your whole window and a projection that always maps a certain view space into that viewport. For example
void display()
{
int const win_width = glutGet(GLUT_WINDOW_WIDTH);
int const win_height = glutGet(GLUT_WINDOW_HEIGHT);
float const win_aspect = (float)win_width / (float) win_height;
glViewport(0, 0, win_width, win_height);
/* Using fixed function pipeline for brevity */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/* map the vertical range -1…1 to the window height and
a symmetric range -aspect … 0 … +aspect to the viewport */
glOrtho(-win_aspect, win_aspect, -1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
draw_triangle();
/* ... */
glutSwapBuffers();
}

Cord system and units?

How do I change default cord system and units in OpenGL?
Right now it's using the default, meaning it goes from -1.0 (left) to 1.0 (right) with 0 being the origin (same with Y, -1.0 being top, 1.0 being bottom).
Optimally I would 1) want to change units to roughly same number of pixels. For example, on an 800x600 display have it go from -400 to 400 (on x) and -300 to 300 (on y). Seems like it would be easier to work with than -1.0 to 1.0
2) Bonus points: how do I change the x/y? One game engine had I seen had it go from 0 to maxWidth and 0 to maxHeight.
That is, 0,0 was top left and 800,600 was bottom right. (0, 600 would be left bottom and 800,0 would be top right)
I think these both have to do with the viewpoint command, but don't know if I fully understand it.
First answering your last point: There is no "viewpo i nt" commant. There is glViewport which defines the mapping from so called clip space [-1,1]×[-1,1]×[-1,1] into window/screen space — important: glViewport doesn't set some clipping, so if your viewport only covers some smaller, middle part of your window, things that exceed the viewport in rendering may/will cause artifacts outside the viewport. Scissor testing (enabled and set with *glEnable(GL_SCISSOR_TEST)* and glScissor) does this kind of clipping, which also works within the viewport (nice for implementing selection rubber bands!).
Now to cover your first question: OpenGL's coordinate system is whatever you want it to be; in OpenGL-3.1 and OpenGL-4 there's no default coordinate system at all! In OpenGL-2 and below there are a number of so called transformation matrices, most importantly modelview and projection.
You can think projection to be some kind of a camera's lens (although it works entirely differently). What is does is, it transforms the world (or modelview) space into the aforementioned clip space. It is this projection matrix, that allows you map any affine coordinate system into clip space. OpenGL before version 3 provides you helper functions glFrustum and glOrtho for the most oftenly used projections: Perspective and Ortho.
Let's construct some projection ourself (it's an ortho, but I'd like to show how things work on the math side). Say you'd like to map x in [0; 200], y in [0; 100] to [-1; 1] (left to right), [-1,1] (top to bottom), and leave z as it is. Then
x_clip = -1 + x*(1-(-1))*(200-0) = -1 + x*2/200
y_clip = 1 + y*(-1 1 )*(100-0) = 1 + x*(-2)/100
z_clip = z
This translates into the following matrix:
2/200 0 0 -1
0 -2/100 0 1
0 0 1 0
0 0 0 1
You could now put this into the projection matrix using glLoadMatrix.
The modelview matrix is used for moving stuff around in the world space. It's also used to define the viewpoint: OpenGL has no camera. Instead we just move the whole world in an opposite way to how we'd moved a camera within the world to the desired viewpoint (this time …point, not …port!)
glOrtho():
#include <GL/glut.h>
unsigned int win_w = 0;
unsigned int win_h = 0;
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, win_w, win_h, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3ub(255,0,0);
glPushMatrix();
glScalef(50,50,50);
glBegin(GL_QUADS);
glVertex2f(0,0);
glVertex2f(1,0);
glVertex2f(1,1);
glVertex2f(0,1);
glEnd();
glPopMatrix();
glFlush();
glutSwapBuffers();
}
void reshape(int w, int h)
{
win_w = w;
win_h = h;
glViewport(0, 0, w, h);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);
glutInitWindowSize(800,600);
glutCreateWindow("Ortho);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}