Why doesn't this code draw a triangle? - c

I'm very new to OpenGL and I just wrote up a section of code using SDL 2 that to my knowledge should have drawn a triangle, but this code doesn't seem to work and so I am not done learning. I've got all the initialization code SDL 2 documentation says I need already written in, and the functions returned by dynamic loading ARE callable. When I execute this code instead of a triangle I get a black (but cleared) window. Why does this code not draw the triangle I want, and why is the window cleared to black by this code? I want to know the technical details behind mainly the first question so I can depend on it later.
(*main_context.glViewport)(0, 0, 100, 100);
(*main_context.glBegin)(GL_TRIANGLES);
(*main_context.glColor4d)(255, 255, 255, 255);
(*main_context.glVertex3d)(1, 1, -50);
(*main_context.glVertex3d)(1, 30, 1);
(*main_context.glVertex3d)(30, 1, 1);
(*main_context.glEnd)();
(*main_context.glFinish)();
(*main_context.glFlush)();
SDL_GL_SwapWindow(window);
Update:
I've revised my code to include different coordinates and I got the triangle to draw, but I cannot get it to draw when farther away. Why is that?
(*main_context.glVertex3d)(2, -1, 1); /* Works. */
(*main_context.glVertex3d)(2, -1, 3); /* Doesn't work. */

Unless you are setting up a projection and/or modelview matrix elsewhere in your code, it's using the default (identity matrix) transform, which is an orthographic projection with (-1, -1) at the bottom left and (1, 1) at the top right. glViewport only changes the portion of the default framebuffer being rendered to, it has no bearing on the projection whatsoever.
With an orthographic projection, the Z coordinate does not affect the screen-space position of a point, except that points outside the Z clipping planes will not be rendered. In this case, that's everything outside of -1 <= z <= 1. Given that one of your points is (1, 1, -50), this seems to be your problem.

Related

Processing doesn't draw complete curves using while loop

I'm investigating possibilities that Processing gives regarding generative art, and I stumbled upon a problem:
I'd like to generate multiple Bezier curves using a while loop. However, the program skips parts of some curves, while others are drawn properly.
Here's a working example:
void setup() {
size(1000,500);
background(#ffffff);
}
float[] i_x = {1,1};
float[] i_y = {1,1};
void draw() {
while (i_y[0] < height)
{
bezier(0,i_y[0],100,height-100,width - 100,height-100,width, i_y[0]);
i_y[0] = i_y[0] * 1.1;
}
save("bezier.jpg");
}
And here is the output. As you can see, only few of the curves are drawn in their full shape.
Also, when I draw one of the 'broken' curves out of the loop, it works fine.
I'd appreciate any help. I'm having good time learning coding concepts with visual output that Processing provides.
It works as intended. Look what happens when you change the background color (great post btw, the working example made it good enough for me to want to debug it!):
If you're clever, you'll notice that the "inside" of the curve has a color. Except that for now it's white. That's why only the topmost are "invisible": you're drawing them one after the other, starting topmost, so every new curve eats the last one by painting over it, but only "inside the curve". See what happens when I apply some color to differentiate the fill and the background better:
Now that the problem is obvious, here's the answer: transparency.
while (y < height)
{
fill(0, 0, 0, 0); // this is the important line, you can keep your algo for the rest
bezier(0, y, offset, height-offset, width - offset, height-offset, width, y);
y *= 1.1;
}
Which gives us this result:
Have fun!

Get texture coordinates of mouse position in SDL2?

I have the strict requirement to have a texture with resolution (let's say) of 512x512, always (even if the window is bigger, and SDL basically scales the texture for me, on rendering). This is because it's an emulator of a classic old computer assuming a fixed texture, I can't rewrite the code to adopt multiple texture sizes and/or texture ratios dynamically.
I use SDL_RenderSetLogicalSize() for the purpose I've described above.
Surely, when this is rendered into a window, I can get the mouse coordinates (window relative), and I can "scale" back to the texture position with getting the real window size (since the window can be resized).
However, there is a big problem here. As soon as window width:height ratio is not the same as the texture's ratio (for example in full screen mode, since the ratio of modern displays would not match of the ratio I want to use), there are "black bars" at the sides or top/bottom. Which is nice, since I want always the same texture ratio, fixed, and SDL does it for me, etc. However I cannot find a way to ask SDL where is my texture rendered exactly inside the window based on the fixed ratio I forced. Since I need the position within the texture only, and the exact texture origin is placed by SDL itself, not by me.
Surely, I can write some code to figure out how those "black bars" would change the origin of the texture, but I can hope there is a more simple and elegant way to "ask" SDL about this, since surely it has the code to position my texture somewhere, so I can re-use that information.
My very ugly (can be optimized, and floating point math can be avoided I think, but as the first try ...) solution:
static void get_mouse_texture_coords ( int x, int y )
{
int win_x_size, win_y_size;
SDL_GetWindowSize(sdl_win, &win_x_size, &win_y_size);
// I don't know if there is more sane way for this ...
// But we must figure out where is the texture within the window,
// which can be changed since the fixed ratio versus the window ratio (especially in full screen mode)
double aspect_tex = (double)SCREEN_W / (double)SCREEN_H;
double aspect_win = (double)win_x_size / (double)win_y_size;
if (aspect_win >= aspect_tex) {
// side ratio correction bars must be taken account
double zoom_factor = (double)win_y_size / (double)SCREEN_H;
int bar_size = win_x_size - (int)((double)SCREEN_W * zoom_factor);
mouse_x = (x - bar_size / 2) / zoom_factor;
mouse_y = y / zoom_factor;
} else {
// top-bottom ratio correction bars must be taken account
double zoom_factor = (double)win_x_size / (double)SCREEN_W;
int bar_size = win_y_size - (int)((double)SCREEN_H * zoom_factor);
mouse_x = x / zoom_factor;
mouse_y = (y - bar_size / 2) / zoom_factor;
}
}
Where SCREEN_W and SCREEN_H are the dimensions of the my texture, quite misleading by names, but anyway. Input parameters x and y are the window-relative mouse position (reported by SDL). mouse_x and mouse_y are the result, the texture based coordinates. This seems to work nicely. However, is there any sane solution or a better one?
The code which calls the function above is in my event handler loop (which I call regularly, of course), something like this:
void handle_sdl_events ( void ) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_MOUSEMOTION:
get_mouse_texture_coords(event.motion.x, event.motion.y);
break;
[...]

Drawing a 2D texture in OpenGL [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I had a drawing function called DrawImage but it's really confusing and is only working with a specific form of the reshape function so I have 2 questions:
How do I draw a texture in OpenGL ? I just want to create a function that gets a texture, x, y, width, height and maybe angle and paint it and draws it according to the arguments. I want to draw it as a GL_QUAD regularly but I'm not sure how to do that anymore .-. People say I should use SDL or SFML to do so, is it recommended ? If it is, can you give me a simple function that loads a texture and one that draws it ? I'm currently using SOIL to load textures.
the function is as here:
void DrawImage(char filename, int xx, int yy, int ww, int hh, int angle)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, filename);
glLoadIdentity();
glTranslatef(xx,yy,0.0);
glRotatef(angle,0.0,0.0,1.0);
glTranslatef(-xx,-yy,0.0);
// Draw a textured quad
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(xx,yy);
glTexCoord2f(0, 1); glVertex2f(xx,yy + hh);
glTexCoord2f(1, 1); glVertex2f(xx + ww,yy + hh);
glTexCoord2f(1, 0); glVertex2f(xx + ww,yy);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glEnd();
}
Someone said to me that you can't call glDisable, glPopMatrix or glMatrixMode between glBegin and glEnd. The problem is - the code won't work without it. Any idea how to make it work without it ?
2. About the glutReshapeFunc, the documentation says it gets a pointer to a functions with 2 args, width and height - I created (up to now) a function that gets void - any idea how to write a reshape function that gets a width and height and actually does what reshape needs to do.
and one minor question: How better is C++ than C when it comes to GUIs like OpenGL ? As all as I can see, only OOP is the matter and I didn't went to any problem that OOP could solve and C couldn't (in OpenGL I mean).
No need to answer all of the question - question number 1 is basically the most important to me :P
Your DrawImage function looks pretty much just fine. Although, yes, you shouldn't be calling glMatrixMode etc. befor glEnd so remove them. I believe the issue is simply to do with setting up your projection matrix and the added calls just happen to fix an issue that shouldn't be there in the first place. glutReshapeFunc is used to capture window resize events so until you need it you don't have to use it.
SDL gives you a lot more control over events and glut, but takes a little longer to set up. GLFW is also a good alternative. I guess its not that important to change unless you see a feature you need. These are libs to create a GL context and do some event handling. SOIL can be used for them all.
OpenGL is a graphics API and gives a common interface for doing hardware accelerated 3D graphics, not a GUI lib. There are GUI libs written for OpenGL though.
Yes I believe many take OOP to the extreme. I like the term C++ as a better C, rather than completely restructuring the way you code. Maybe just keep using C, but with a C++ compiler. Then when you see a feature you like, use it. Eventually you may find you're using lots and then have a better appreciation for the reason for their existence and when to use them rather than blindly following coding practices. Just imo, this is all very subjective.
So, the projection matrix...
To draw stuff in 3D on a 2D screen you "project" the 3D points onto a plane. I'm sure you've seen images like this:
This allows you to define your arbitrary 3D coordinate system. Except for drawing stuff in 2D its natural to want to use pixel coordinates directly. After all that's what you monitor displays. Thus, you want to use kind of a bypass projection which doesn't do any perspective scaling and matches pixels in scale and aspect ratio.
The default projection (or "viewing volume") is an orthographic -1 to one cube. To change it,
glMatrixMode(GL_PROJECTION); //from now on all glOrtho, glTranslate etc affect projection
glOrtho(0, widthInPixels, 0, heightInPixels, -1, 1);
glMatrixMode(GL_MODELVIEW); //good to leave in edit-modelview mode
Call this anywhere really, but since the only affecting variables are window width/height it's normal to put it in some initialization code or, if you plan on resizing your window, a resize event handler such as:
void reshape(int x, int y) {... do stuff with x/y ...}
...
glutReshapeFunc(reshape); //give glut the callback
This will make the lower left corner of the screen the origin and values passed to glVertex can now be in pixels.
A couple more things: instead of glTranslatef(-xx,-yy,0.0); you could just use glVertex2f(0,0) after. Push/pop matrix should always be paired within a function so the caller isn't expected to match it.
I'll finish with a full example:
#include <GL/glut.h>
#include <GL/gl.h>
#include <stdio.h>
int main(int argc, char** argv)
{
//create GL context
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA);
glutInitWindowSize(800, 600);
glutCreateWindow("windowname");
//create test checker image
unsigned char texDat[64];
for (int i = 0; i < 64; ++i)
texDat[i] = ((i + (i / 8)) % 2) * 128 + 127;
//upload to GPU texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 8, 8, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, texDat);
glBindTexture(GL_TEXTURE_2D, 0);
//match projection to window resolution (could be in reshape callback)
glMatrixMode(GL_PROJECTION);
glOrtho(0, 800, 0, 600, -1, 1);
glMatrixMode(GL_MODELVIEW);
//clear and draw quad with texture (could be in display callback)
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, tex);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
glTexCoord2i(0, 0); glVertex2i(100, 100);
glTexCoord2i(0, 1); glVertex2i(100, 500);
glTexCoord2i(1, 1); glVertex2i(500, 500);
glTexCoord2i(1, 0); glVertex2i(500, 100);
glEnd();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glFlush(); //don't need this with GLUT_DOUBLE and glutSwapBuffers
getchar(); //pause so you can see what just happened
//System("pause"); //I think this works on windows
return 0;
}
If you're ok with using OpenGL 3.0 or higher, an easier way to draw a texture is glBlitFramebuffer(). It won't support rotation, but only copying the texture to a rectangle within your framebuffer, including scaling if necessary.
I haven't tested this code, but it would look something like this, with tex being your texture id:
GLuint readFboId = 0;
glGenFramebuffers(1, &readFboId);
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFboId);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex, 0);
glBlitFramebuffer(0, 0, texWidth, texHeight,
0, 0, winWidth, winHeight,
GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &readFboId);
You can of course reuse the same FBO if you want to draw textures repeatedly. I only create/destroy it here to make the code self-contained.

OpenGL - maintaining aspect ratio upon window resize

I am drawing a polygon in a square window. When I resize the window, for instance by fullscreening, the aspect ratio is disturbed. From a reference I found one way of preserving the aspect ratio. Here is the code:
void reshape (int width, int height) {
float cx, halfWidth = width*0.5f;
float aspect = (float)width/(float)height;
glViewport (0, 0, (GLsizei) width, (GLsizei) height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(cx-halfWidth*aspect, cx+halfWidth*aspect, bottom, top, zNear, zFar);
glMatrixMode (GL_MODELVIEW);
}
Here, cx is the eye space center of the zNear plane in X. I request if someone could please explain how could I calculate this. I believe this should be the average of the initial first two arguments to glFrustum(). Am I right? Any help will be greatly appreciated.
It looks like what you want to do is maintain the field of view or angle of view when the aspect ratio changes. See the section titled 9.085 How can I make a call to glFrustum() that matches my call to gluPerspective()? of the OpenGL FAQ for details on how to do that. Here's the short version:
fov*0.5 = arctan ((top-bottom)*0.5 / near)
top = tan(fov*0.5) * near
bottom = -top
left = aspect * bottom
right = aspect * top
See the link for details.
The first two arguments are the X coordinates of the left and right clipping planes in eye space. Unless you are doing off-axis tricks (for example, to display uncentered projections across multiple monitors), left and right should have the same magnitude and opposite sign. Which would make your cx variable zero.
If you are having trouble understanding glFrustrum, you can always use gluPerspective instead, which has a somewhat simplified interface.

Should I translate first or rotate first?

I'm trying to create a simple scene where I can walk around, with the criteria of being able to pan around and walk around with the keys. However, in my draw scene function, when I translate my scene than rotate, the panning around doesn't work properly as the entire scene just rotates around me, causing objects to go through me. When I rotate than translate my scene, I can pan around properly, however, I can move only in a certain direction, so if I pan around to my right 90 degrees, I'll move left instead of going forward. Is there anyway where I can put these 2 effects together?
This is the code that I use to draw my view:
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
glTranslated(xposition, 0, zposition); //This is where I translate my views
glRotated(yrot, 0, 1, 0); //
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER_ARB, quadVBO);
glNormalPointer(GL_FLOAT, 0, (void*)sizeof(sideArray));
glColorPointer(3, GL_FLOAT, 0, (void*)sizeof(sideArray)+sizeof(normals));
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawArrays(GL_QUADS, 0, sizeof(sideArray)/sizeof(GLfloat)/3);
glPopMatrix();
glFlush();
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
Here are some pictures that illustrate my problem right now:
Rotate then translate:
Pic1
http://dl.dropbox.com/u/2747708/Screen%20Shot%202012-04-03%20at%2010.17.39%20PM.PNG
Pic2
I can imitate the turn of the camera
http://dl.dropbox.com/u/2747708/Screen%20Shot%202012-04-03%20at%2010.17.48%20PM.PNG
Pic3
However, when I walk forward, it only walks in one direction, and not the direction I'm looking at.
http://dl.dropbox.com/u/2747708/Screen%20Shot%202012-04-03%20at%2010.18.30%20PM.PNG
http://dl.dropbox.com/u/2747708/Screen%20Shot%202012-04-03%20at%2010.18.39%20PM.PNG
Translate then Rotate:
Pic1
http://dl.dropbox.com/u/2747708/Screen%20Shot%202012-04-03%20at%2010.19.44%20PM.PNG
Pic2
I can move around freely, walking straight to any direction I'm looking at.
http://dl.dropbox.com/u/2747708/Screen%20Shot%202012-04-03%20at%2010.19.52%20PM.PNG
Pic3
However, when I rotate the scene, the entire thing rotates, which causes objects to clip through me and doesn't "pan" through the view anymore like when I rotate then translate my view.
http://dl.dropbox.com/u/2747708/Screen%20Shot%202012-04-03%20at%2010.20.01%20PM.PNG
Your problem isn't with the order of transformations. You should be rotating then translating.
The problem is that you aren't taking rotation into account when moving. The formula for movement:
movementX = sin(direction);
movementY = cos(direction);
where direction is the number of radians turned clockwise from north, and positive X is east, and positive Y is north.
I'm not sure how to comment on or add to Kendall's answer so I'll just add this as a new answer.
I think you may be using Y for up, so you would use this if direction is in radians:
movementX = sin(direction);
movementZ = cos(direction);
if direction is in degrees you will have to convert it to radians:
radians = degrees*(PI/180);
Just multiply the movement by 1 or -1 based on whether you are moving forwards or backwards:
movementX = sin(direction)*forwardsBackwards;
movementZ = cos(direction)*forwardsBackwards;
If you need strafing as well you can do:
movementX = sin(direction)*forwardsBackwards+sin(direction+1.5707)*sideToSide;
movementZ = cos(direction)*forwardsBackwards+cos(direction+1.5707)*sideToSide;
Where sideToSide is 1 or -1 based on if you are strafing left or right. The 1.5707 is 90 degrees in radians(PI/2), which means no matter what direction you are facing it takes the 90 degree angle to the right of it. You can also add 90 degrees to the degree rotation before converting if you want to.
Multiply the entire thing by your desired movement speed:
movementX = (sin...eToSide)*speed;
movementZ = (cos...eToSide)*speed;
This will however create a straferunning effect where you will move faster if you move in 2 directions at once. If you want to make it so that doesn't happen add this before calculating movement:
if (!forwardsBackwards && !sideToSide )
{
forwardsBackwards *= 0.7071;
sideToSide *= 0.7071;
}
You could also replace .7071 with cos(45) if you need it to be extremely accurate.
Alternatively you could:
float diagonalMod = 1;
if (!forwardsBackwards && !sideToSide)
diagonalMod = 0.7071; // or cos(45)
movementX = (sin...eToSide)*speed*diagonalMod;
movementZ = (cos...eToSide)*speed*diagonalMod;
You will want to rotate first and then translate. The other way, if I am thinking about it right, is basically like moving the point at which your camera will rotate around, the pivot point. This is why you would clip through objects when rotating.
Also, you should perform "camera" rotation and translation immediately following a glLoadIdentity(); as you want everything else in your scene to move and rotate, as that is how an OpenGL "camera" functions. This is how it would be setup:
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotated(yrot, 0, 1, 0);
glTranslated(xposition, 0, zposition);
glPushMatrix();
And for future reference in case you expand on it:
glRotatef(Pitch, 1, 0, 0); // Up and down look
glRotatef(Yaw, 0, 1, 0); // Left and right look
glRotatef(Roll, 0, 0, 1); // Like a barrel roll in a jet
glTranslatef(X,Y,Z);

Resources