I've been trying to add some basic HUD-like Text to my OpenGL/C++ project.
Therefore i decided
glutBitmapCharacter( type, character)
to be my weapon of choice.
I realized that, for the easiest use, i should append a 2D Matrix to my previous Rendering area.
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 10, 0, 10);
This should give me a sweet 10*10 2D cube to play around in.
Now a problem arised when glutBitmapCharacter remembers his last character position to append the next one. Pretty smart while it's writing a string, it obviously remembers this position and makes my Text fly all the way across screen once :) Naughty.
glRasterPos2f(x,y);
should be - as i heard - the normal thing to reset this thingy - (altough i don't perfectly understand why a gl function controls a glu Function, but thats just a sidenote).
Now the weird thing that happens, is once i run the code:
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, 10, 0, 10);
string message ="mmh... Pie...";
float poss[3];
glRasterPos3f(0.0, 0.0, 0.0);
glGetFloatv(GL_CURRENT_RASTER_POSITION, poss);
std::cout<< "X" <<(GLfloat) poss[0] << " Y"<<poss[1] << " Z"<<poss[2] << std::endl;
for( size_t i = 0; i < message.size(); ++i ) {
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, message[i]);
}
glPopMatrix();
My Text doesnt get shown. In fact the resulting X, Y and Z
(not even sure Z is necessary.. should be 0 anyway) are all inf (infinite).
If i don't set my own glRasterPos, things just work out fine, apart from leaving the screen. My returning positions are an upcounting X and 0 , 0 - as expected.
So whats the deal on this, what exactly am i doing wrong?
you produced a grand Segmentation Error: glGetFloatv(GL_CURRENT_RASTER_POSITION, poss) returns 4 values, so you must use:
float poss[4];
Apart from this, your code runs fine on my machine and returns:
X0 Y0 Z0.5
So the fault seems not to be in the code you posted here. You should try© it to a basic "HelloWorld"-GL program and see if it works there. Be careful that some OpenGL commands only work after a valid drawing surface is initialized - I guess you did that?
Related
Alright, so I have never created a game before, and I am trying to make a 2d tile based game.
So I am really confused about something that should be pretty simple, coordinates.
I have tile coordinates, like
{0,0,0,0,0,1}
{0,0,1,0,0,1}
{0,0,0,0,0,1}
{0,0,1,1,1,1}
{0,0,0,0,0,1}
lets say this is my world and i am trying to render it, well i cant render it, each tile needs a width,
this is where i get confused, so you can do, im not new to coding
twidth = 100, theight = 100;
for(y = each row) {
for(x = each tile in each row) {
draw rect (
X1 = x*twidth,
Y1 = y*theight,
X2 = x*twidth+twidth,
X2 = y*theight+theight
)
}
}
I might be wrong about this, but: now literally everything else needs to multiplied by the twidth/height, it will be even harder if you want different sized tiles, at least its confusing to me, how do other games handle things like this? im not sure if i explained very well what my problem is, any help would be appreciated
im using opengl[legacy] and i think the solution might be a function to setup screenspace differently, so rendering
glVertex2d(0,1) is actually 100px, this would make collisions, and such, much easier
im using opengl[legacy] and i think the solution might be a function to setup screenspace differently, so rendering glVertex2d(0,1) is actually 100px, this would make collisions, and such, much easier
You can achieve that in legacy OpenGL by setting up the projection matrix properly:
glMatrixMode(GL_PROJECTION);
glOrtho(0, 16, 0, 9, -1, 1);
This will set it up so that glVertex2d(0, 0) maps to the bottom left corner and glVertex2d(16, 9) will map to the top right corner, giving you 16x9 tiles in the viewport. To fix the size of the tile in pixels we calculate the fractional number of tiles instead:
glOrtho(0, (double)viewportWidth / twidth, 0, (double)viewportHeight / theight, -1, 1);
After that you can 'scroll' the world by translating it through the GL_MODELVIEW matrix.
I am using OpenGL library in my Visual C++ application where I want to draw say, 100 points in random locations and I would like to check if these points random co-ordinates or random locations that generated are within the screen or window boundaries. I tired using a (x,y,z) vertex option and I get the points vertical running along a line. If I try generating only (x,y) and drawing them then I do get a lot more points scattered but definitely not all 100 within the window dimensions.
my code looks something like this:
GLfloat dots_vert[99];
for (int i = 0; i < 99; i++){
if (i % 2 == 0)
dots_vert[i] = 0.0f;
else
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*100.0f - (100.0f / 2);
}
glEnable(GL_POINT_SMOOTH);
glPointSize(3.0f);
glEnableClientState(GL_VERTEX_ARRAY);
GLuint vbo_ID;
glGenBuffers(1, &vbo_ID);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glBufferData(GL_ARRAY_BUFFER, sizeof(dots_vert), dots_vert, GL_DYNAMIC_DRAW);
while (!GetAsyncKeyState(VK_DOWN)){
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_ID);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glDrawArrays(GL_POINTS, 0, 100);
SwapBuffers(g_pOpenGLWindow->hDC);
Let me guide you through the glaring mistakes I can immediately see in that code.
First of all the obvious first mistake: you claim to be drawing 100 points but your dots_vert array is only 99 elements long. This is repeated in the following loop, where you go from 0 to 98 for a total of 99 times.
So first of all:
GLfloat dots_vert[100];
for (int i = 0; i < 100; ++i)
{
[...]
}
There is another huge mistake in there but we'll keep that for later, let's move on for now.
The second mistake is about the knowledge of the OpenGL API and computer graphics. First of all, your goal is to pass points to the GPU, so you need the glVertexAttribPointer function, that much you figured out. The absolute first thing you wanna do is to look at the glVertexAttribPointer reference documentation, so you have an idea of what you need. You need an index, a size, a type, a normalized flag, a stride and an offset.
Let's look at what the reference documentation says about the size parameter:
size
Specifies the number of components per generic vertex attribute. Must be 1, 2, 3, 4. Additionally, the symbolic constant GL_BGRA is accepted by glVertexAttribPointer. The initial value is 4.
This is immediately obvious to be crucial in determining what kind of data you're trying to pass to the GPU. You set the parameter to 3, which means that you have an x, a y and a z. But the previous code contradicts this. For starters, your dots_vert array is 100 elements long, and you want to draw 100 points, so you have enough for 100/100 = 1 component per point, not 3. But even worse, the inside of the for loop contradicts this even further, so let's go back and check the mistake I mentioned previously.
Mistake number three: your for loop consists of an if {} else {} statement, where you set the current element of the dots_vert array to a value of 0.0f if the index of the loop is even (if (i % 2 == 0)), and a random value between -50.0f and 50.0f otherwise. Assuming 1 component per point, this means that you're only generating the x coordinates, so you're working in a single dimension.
Clearly this is not what you intended to do, also because half of your points will be 0.0f and therefore they'll all overlap. So I assume you were trying to generate a random value for x and y, and set z to 0.0f, which would make much more sense. First of all, you have 3 components per point and therefore you'll need an array with 100*3 = 300 elements. So first of all, let's fix the previous code:
GLfloat dots_vert[300];
for (int i = 0; i < 300; ++i)
{
[...]
}
Much better. Now we need to generate a random x and y valye for each point, and set z to 0.0f since we don't need it. You wanna do all of the components at once in a single loop, so you want your loop to step by 3, not 1, so once again let's fix the previous code:
GLfloat dots_vert[300];
for (int i = 0; i < 300; i += 3)
{
[...]
}
Now we can generate x, y and z together in a single loop. This is the crucial part where understanding how computer graphics work, specifically in the context of the OpenGL API. OpenGL uses a coordinate system where the origin is in the middle of the screen, the x axis moves horizontally (positive x points to your right), the y axis moves vertically (positive y points up), and the z axis goes straight through the screen (positive z points out of the screen, towards you). Now this is the very important part: x, y and z are clipped to a specific range of values; anything outside of this range is ignored. For all coordinates, the range goes from -1.0f to 1.0f. Anything below of above that is not drawn at all.
So if you want to have 100 points to be inside the screen, ignoring projection which is outside of the scope of this exercise, you want to generate x and y in the -1.0f to 1.0f range, not -50.0f to 50.0f like you're doing there. You can keep z to 0.0f, doesn't really matter in this case. This is why most of your points fall outside of the screen: with that range, statistically speaking, around 98% of your points will fall outside of the clip space and will be ignored.
So ultimately this is what you want:
GLfloat dots_vert[300];
for (int i = 0; i < 300; i += 3)
{
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x
dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y
dots_vert[i+2] = 0.0f; // this is z
}
Finally a reminder: when you do glDrawArrays(GL_POINTS, 0, 100); you're telling the GPU to draw 100 points. Each point is made of however many components you specified in the size parameter of the glVertexAttribPointer function. In this case you wanna draw 100 points, each point is made of 3 components, so the GPU expects an array of 100*3 = 300 floats. numbers. Anything less could result in either a segmentation fault or even worse an undefined behavior (which means anything can happen), so pay close attention to what you're doing and make sure you know exactly what kind of data you're passing to the GPU because you might end up with a nonsense result and you'll be stuck trying to figure out what went wrong. In this case, you have basically no code at all to check so it's easy to fix, but when you'll end up with a decent amount of code (and you will eventually), an error like this could mean hours or even days wasted trying to find the error.
As a bonus, feel free to ignore this one: technically a point is made of 4 components. This component is called w and its use is outside of the scope of this exercise so don't worry about it, just remember that it should always be set to 1.0f, unless you are doing projection.
So technically you could do this too:
GLfloat dots_vert[400];
for (int i = 0; i < 400; i += 4)
{
dots_vert[i] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is x
dots_vert[i+1] = ((GLfloat)rand() / (GLfloat)RAND_MAX)*2.0f - 1.0f; // this is y
dots_vert[i+2] = 0.0f; // this is z
dots_vert[i+3] = 1.0f; // this is w
}
Then you set the size parameter of glVertexAttribPointer to 4 instead of 3, the result should be exactly the same.
I'm trying to apply transformation to a specific part of my drawing that will only come in effect when a key is pressed.
I'm using glPushMatrix() then I do my transformation, then glPopMatrix().
What happens when I press my key is that the transformation is done only once, then no matter how many times I press the key again nothing happens.
Here's a snippet from my code:
void drawShapes(){
glClear(GL_COLOR_BUFFER_BIT);
//setting my variables
glPushMatrix();
if (translateFlag) //this is set to true in the keyboard function
{
x += 10;
glTranslated(x, 0, 0);
translateFlag = false;
}
drawCircle();
glPopMatrix();
//more drawings
}
when I remove the pushMatrix and popMatrix it works but it applies the transformation to all of my shapes, which is not what I want.
Any help would be appreciated..
[Update]
I've tried to run my code on 4 other computers (one macbook Air, one macbook Pro -an exact copy of mine- and 2 iMacs and) and it doesn't even run on any of them, could this mean the problem lies in my own macbook?!
Also I copied code that runs perfectly fine on the macbook air, rotating parts and everything and when I run it on mine I got the same disappointing result as my own code.
Here's the heypasteit code for my code 31JL
possible problems:
void drawShapes(){
glClear(GL_COLOR_BUFFER_BIT);
//setting my variables
// maybe you have forgot to set matrix mode correctly. make the projection and modelview
matrices correct.
glPushMatrix();
if (translateFlag) //this is set to true in the keyboard function
//probably your key hit function is not working properly (I can't say without looking at full code)
{
x += 10;
glTranslated(x, 0, 0);
translateFlag = false;
}
drawCircle();
glPopMatrix();
//more drawings
// you are using glFlush() ????? try swapbuffers. exact function depends
on the API you are using (GLUT \ GLFW etc.)
}
I have a bitmap map that created from a dted file. I want to use that bitmap and create a 3d terrain render. I am trying to do it with vertex vectors but I couldn't reach my goal at all. Here is my paintGL code:
void render::paintGL(){
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0,0,-100);
for(int z=0;z<dted.width()-1;z++){
glBegin(GL_TRIANGLE_STRIP);
for(int x = 0; x<dted.height()-1; x++){
glColor3f(matrix[x][z], matrix[x][z], matrix[x][z]);
glVertex3f(x, matrix[x][z], -z);
//vertex0 ends here
glColor3f(matrix[x+1][z], matrix[x+1][z], matrix[x+1][z]);
glVertex3f(x+1, matrix[x+1][z], -z);
//vertex1 ends here
glColor3f(matrix[x][z+1], matrix[x][z+1], matrix[x][z+1]);
glVertex3f(x, matrix[x][z+1], -z-1);
//vertex2 ends here
glColor3f(matrix[x+1][z+1], matrix[x+1][z+1], matrix[x+1][z+1]);
glVertex3f(x+1, matrix[x+1][z+1], -z-1);
//vertex3 ends here
}
glEnd();
}}
I had to write the code instead of copy-paste because of internet issues. So there may be things that I forgot but I did my best. Let me explain the variables and other things above:
dted is the dted image I created and I set boundaries from that images width and height values. matrix is a 2d matrix that holds the elevation values I get from the pre-created dted image pixels.
After all the code above I couldn't manage to render the terrain. I don't know if it renders the terrain but it just doesn't show me or it's not rendering at all. If you explain where is my mistake and suggest a solution for it, it would be great.
Sorry for the grammar mistakes if I did any, and I hope I did explain my problem well. If the code I provided is not sufficient, feel free to mention that and I can write the other parts down too.
Have a nice day.
Edit: Ok I got a fresh news over here. I have managed to draw a plain after getting over some control with mouse issues. However, when I try to get amplitude, it shows nothing. That because of the too much amplitude I guess, but when I divide it by a constant like 15 the same plain shows up again. Is this because of I used GL_TRIANGLE_STRIP ?
Your rendering code seems strange: You build your tri strip with degenerated triangles and might access data which isn't there. I guessed the rest of your approach and tried to fix your method. Try this:
void render::paintGL(){
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glTranslatef(0,0,-100);
for(int z = 0; z < dted.width() - 2; z++) {
glBegin(GL_TRIANGLE_STRIP);
for(int x = 0; x < dted.height() - 1; x++){
glColor3f(matrix[x][z], matrix[x][z], matrix[x][z]);
glVertex3f(x, matrix[x][z], -z);
//vertex0 ends here
glColor3f(matrix[x][z + 1], matrix[x][z + 1], matrix[x][z + 1]);
glVertex3f(x, matrix[x][z + 1], -z - 1);
//vertex1 ends here
}
glEnd();
}}
Other than this, triangle strips are fine. If you still don't see anything, follow the suggestion by Sga and use GL_POINTS. Then fix you camera/other rendering code until you see them.
For the other guys who are looking for solution at this: Make sure that your glFrustum's zNear parameter is far enough to see things. Mine were to close and when I increased it, the problem was solved.
I had already coded the display list.. and when i opened it again the next day -> gone..
niiice i thought.. i've wasted hours for nothing
and the next problem is.. i can't get it to work anymore
the display list actually works but not how it should.. textures are stretched somehow
i get my world from a text file.. each platform defined by start amount of x.. end amount of x
the y amount of the platform's bottom.. u and v (which i don't use) and filter for choosing texture.
setupworld is the function that reads from the text file and writes my variables into a structure.
Oh and numblocks is the number of platforms to display
void setupworld(){
float xstart,xend,ystart,u,v;
unsigned int filter;
FILE *filein;
char oneline[255];
filein=fopen("data/world.txt","rt");
readstr(filein,oneline);
sscanf(oneline, "Anzahl %d\n",&numblocks);
for (int loop=0;loop<numblocks; loop++)
{
readstr(filein,oneline);
sscanf(oneline,"%f %f %f %f %f %d",&xstart,&xend,&ystart,&u,&v,&filter);
block.data[loop].xstart=xstart;
block.data[loop].xend=xend;
block.data[loop].ystart=ystart;
block.data[loop].u=u;
block.data[loop].v=v;
block.data[loop].filter=filter;
}
fclose(filein);
return;}
BuildLists() creates my Display List, but first loads the png files and the world, cause they influence my display list... i had to rewrite this part of code and i just dont know where i made the mistake..
first loop is for creating the platforms and the 2nd one for blocks.. each platform consists of a number of 2x2 blocks simply next to eachother
GLvoid BuildLists(){
texture[0]=LoadPNG("data/rock_gnd.png");
texture[1]=LoadPNG("data/rock_wall2.png");
texture[2]=LoadPNG("data/pilz_test.png");
setupworld();
quad[0]=glGenLists(numblocks);
for(int loop=0;loop<numblocks;loop++)
{
GLfloat xstart,xend,ystart,u,v;
xstart=block.data[loop].xstart;
xend=block.data[loop].xend;
ystart=block.data[loop].ystart;
u=block.data[loop].u;
v=block.data[loop].v;
GLuint filter=block.data[loop].filter;
GLfloat blocks=(xend-xstart)/2.0f;
glNewList(quad[loop],GL_COMPILE);
glBindTexture(GL_TEXTURE_2D, texture[filter]);
for(int y=0;y<blocks;y++)
{
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f);
glVertex3f(xstart,ystart,-1.0f);
glTexCoord2f(1.0f,0.0f);
glVertex3f(xstart+((y+1)*2.0f),ystart,-1.0f);
glTexCoord2f(1.0f,1.0f);
glVertex3f(xstart+((y+1)*2.0f),ystart+2.0f,-1.0f);
glTexCoord2f(0.0f,1.0f);
glVertex3f(xstart,ystart+2.0f,-1.0f);
glEnd();
}
glEndList();
quad[loop+1]=quad[loop]+1;
}
}
the display list is compiled during initialisation just before enabling the 2d textures
this is how i call it during my actual code
int DrawWorld(GLvoid){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLfloat camtrans=-xpos;
glTranslatef(camtrans,0,0);
glPushMatrix();
for(int i=0;i<numblocks;i++)
{
glCallList(quad[i]);
}
glPopMatrix();
return TRUE; }
so this is it.. i think the mistake is in the BuildLists() function but i'm not sure anymore..
Here is the link to my screenshot.. as u see the textures look weird for some reason
http://www.grenzlandzocker.de/test.png
In your code:
quad[0]=glGenLists(numblocks);
creates numblocks display lists, but you only get the first display list id, and it is stored in quad[0]. Later, you use:
glNewList(quad[loop],GL_COMPILE);
where quad[loop] is undefined for loop != 0. You can instead use:
glNewList(quad[0] + loop,GL_COMPILE);
Because the ids for display lists are contiguous, starting with the value of quad[0]. You also need to modify your rendering code to:
glCallList(quad[0] + i);
For the same reason ...