OpenGL: Limiting changes to object only - opengl

I'm making a basic game in openGL with GLUT, and I've come across a small hitch.
When I attempt to draw an object from a class into my world, it gives everything a tint of colour which was last created with the function makeMaterial (see below).
Does anyone know how I could restrict these changes to being applied to the object only?
I've tried push/pop, but it doesn't seem to limit anything.
Additionally, if the last colour drawn is black, I see nothing at all, except for my snowman.
Here are the relevant code:
makeMaterial :-
makeMaterial( float r,float g,float b,float a,float s )
{
float color[4];
float white[4];
GLfloat surfshine[1] ;
surfshine[0]=s*128.0 ;
color[0]=r;color[1]=g;color[2]=b;color[3]=a;
white[0]=0.5;white[1]=0.5;white[2]=0.5;white[3]=1.0;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,color);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,color);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,white);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS,surfshine);
}
makeMaterial in use :-
makeMaterial(0.05f,0.05f,0.05f,1.00f, 0.4f);
glPushMatrix();
glutSolidCube(10.0);
glPopMatrix();
my draw function :-
void drawToScene(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
uniformFPS.setStartTime(glutGet(GLUT_ELAPSED_TIME));
camera.updateCamera();
lvl1.drawLevel();
enemy.drawSnowman(350.0f,6.0f, 200.0f);
crosshair.show();
glutSwapBuffers();
uniformFPS.enforceChecks();
}

If you really want to ensure you are restricting changes to a specific section, you should be able to use glPushAttrib(GL_LIGHTING_BIT) before you do your makeMaterial call, and glPopAttrib after your drawing of the object is done. The reference for glPushAttrib here shows what properties are push'd by each of the possible bits you can supply. I don't know that this is a particularly well regarded way to handle your state however.
A more general solution would be to make a call to makeMaterial with appropriate values before each set of drawing commands, i.e. assuming you have just one material for your snowman and one material for your world:
//...
makeMaterial(1.0f,1.0f,1.0f,1.0f,1.0f);
lvl1.drawLevel();
makeMaterial(0.5f,0.5f,0.5f,0.5f,0.5f);
enemy.drawSnowman(350.0f,6.0f,200.0f);
//...

OpenGL behaves like a state machine when it comes to properties like current color, current material properties, current line width, etc. The values provided are preserved unless they are changed with calls to setter methods explicity.
A proper way to handle your problem would be to have all such properties, be properties of the object being drawn and call appropriate methods before rendering the objects.

Related

openGL - understanding colors changes due to lightning

I am writing some software in C, to render a yellow and a brown cube. However once I programmed light, all the colors changes to light blue. Could someone explain me why the colors changed? And how I can prevent such an extreme change?
This is the code I used for the light:
GLfloat color1 = {0.633, 0.237, 0.170}; \\ changed to blue
void initLight()
{
GLfloat red[] = {1.0,0.0,0.0,1.0};
GLfloat white[] = {1.0,1.0,1.0,1.0};
GLfloat blueGreen[] = {0.0,0.4,1.0,1.0};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, white);
glLightfv(GL_LIGHT0,GL_AMBIENT,white);
glLightfv(GL_LIGHT0,GL_DIFFUSE,blueGreen);
glMaterialf(GL_FRONT,GL_SHININESS,127.0);
glEnable(GL_LIGHT0);
}
Based on the fact that you're using immediate mode, I assume you wrote something that looks like this setting up the vertices?
glBegin(GL_TRIANGLES);
glVertex3f(/*...*/);
glColor3f(/*...*/);
/*...*/
glEnd();
When you add lighting to the scene, the renderer no longer considers the color values you proposed for the individual vertices, and instead substitutes in white or grey (causing the light to turn those faces blueish-green). To fix that, you need to tell the renderer to treat the vertex colors as material colors. This code should be sufficient:
glEnable(GL_COLOR_MATERIAL);
This is, of course, also a reason why you really, really should not be using OpenGL's immediate mode or Fixed Function Pipeline rendering, as it causes problems like this. I recommend the tutorial found here for learning Modern OpenGL.
Edit: Fixed a Typo
DOUBLE EDIT COMBO:
Alright, so there's a few other things you'll need to take into account.
GLfloat lp0[] = {4.0,4.0,3.0,0.0};
Generally speaking, position vectors should have their w component (the last one) set to 1, not 0. You may want to change it to
GLfloat lp0[] = {4.0,4.0,3.0,1.0};
Beyond that, you'll want to try playing around with the position, particularly using things like matrix adjustments. Again; this is yet another reason not to use FFP, and in this case, it's because it's difficult to tell where the light is being positioned relative to the objects. Putting it at <4,4,3> in worldspace only makes sense if you know for certain that its position is being translated by the modelview and projection matrices correctly, and at least in the code that I'm seeing, that doesn't appear to be the case.
Immediately after:
glEnable(GL_COLOR_MATERIAL);
You probably should also call:
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
Also, your ambient light is very bright. You may need to bring the intensity of your ambient light down somewhat to get the proper effect from the tinted diffuse light.

dll injection: drawing simple game overlay with opengl

I'm trying to draw a custom opengl overlay (steam does that for example) in a 3d desktop game.
This overlay should basically be able to show the status of some variables which the user
can affect by pressing some keys. Think about it like a game trainer.
The goal is in the first place to draw a few primitives at a specific point on the screen. Later I want to have a little nice looking "gui" component in the game window.
The game uses the "SwapBuffers" method from the GDI32.dll.
Currently I'm able to inject a custom DLL file into the game and hook the "SwapBuffers" method.
My first idea was to insert the drawing of the overlay into that function. This could be done by switching the 3d drawing mode from the game into 2d, then draw the 2d overlay on the screen and switch it back again, like this:
//SwapBuffers_HOOK (HDC)
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glOrtho(0.0, 640, 480, 0.0, 1.0, -1.0);
//"OVERLAY"
glBegin(GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glVertex2f(0, 0);
glVertex2f(0.5f, 0);
glVertex2f(0.5f, 0.5f);
glVertex2f(0.0f, 0.5f);
glEnd();
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
SwapBuffers_OLD(HDC);
However, this does not have any effect on the game at all.
Is my approach correct and reasonable (also considering my 3d to 2d switching code)?
I would like to know what the best way is to design and display a custom overlay in the hooked function. (should I use something like windows forms or should I assemble my component with opengl functions - lines, quads
...?)
Is the SwapBuffers method the best place to draw my overlay?
Any hint, source code or tutorial to something similiar is appreciated too.
The game by the way is counterstrike 1.6 and I don't intend to cheat online.
Thanks.
EDIT:
I could manage to draw a simple rectangle into the game's window by using a new opengl context as proposed by 'derHass'. Here is what I did:
//1. At the beginning of the hooked gdiSwapBuffers(HDC hdc) method save the old context
GLboolean gdiSwapBuffersHOOKED(HDC hdc) {
HGLRC oldContext = wglGetCurrentContext();
//2. If the new context has not been already created - create it
//(we need the "hdc" parameter for the current window, so the initialition
//process is happening in this method - anyone has a better solution?)
//Then set the new context to the current one.
if (!contextCreated) {
thisContext = wglCreateContext(hdc);
wglMakeCurrent(hdc, thisContext);
initContext();
}
else {
wglMakeCurrent(hdc, thisContext);
}
//Draw the quad in the new context and switch back to the old one.
drawContext();
wglMakeCurrent(hdc, oldContext);
return gdiSwapBuffersOLD(hdc);
}
GLvoid drawContext() {
glColor3f(1.0f, 0, 0);
glBegin(GL_QUADS);
glVertex2f(0,190.0f);
glVertex2f(100.0f, 190.0f);
glVertex2f(100.0f,290.0f);
glVertex2f(0, 290.0f);
glEnd();
}
GLvoid initContext() {
contextCreated = true;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, 640, 480, 0.0, 1.0, -1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClearColor(0, 0, 0, 1.0);
}
Here is the result:
cs overlay example
It is still very simple but I will try to add some more details, text etc. to it.
Thanks.
If the game is using OpenGL, then hooking into SwapBuffers is the way to go, in principle. In theory, there might be sevaral different drawables, and you might have to decide in your swap buffer function which one(s) are the right ones to modify.
There are a couple of issues with such kind of OpenGL interceptions, though:
OpenGL is a state machine. The application might have modified any GL state variable there is. The code you provided is far from complete to guarantee that something is draw. For example, if the application happens to have shaders enabled, all your matrix setup might be without effect, and what really would appear on the screen depends on the shaders.
If depth testing is on, your fragments might lie behind what already was drawn. If polygon culling is on, your primitive might be incorrectly winded for the currect culling mode. If the color masks are set to GL_FALSE or the draw buffer is not set to where you expect it, nothing will appear.
Also note that your attempt to "reset" the matrices is also wrong. You seem to assume that the current matrix mode is GL_MODELVIEW. But this doesn't have to be the case. It could as well be GL_PROJECTION or GL_TEXTURE. You also apply glOrtho to the current projection matrix without loading identity first, so this alone is a good reason for nothing to appear on the screen.
As OpenGL is a state machine, you also must restore all the state you touched. You already try this with the matrix stack push/pop. But you for example failed to restore the exact matrix mode. As you have seen in 1, a lot more state changes will be required, so restoring it will be more comples. Since you use legacy OpenGL, glPushAttrib() might come handy here.
SwapBuffers is not a GL function, but one of the operating system's API. It gets a drawable as parameter, and does only indirectly refer to any GL context. It might be called while another GL context is bound to the thread, or with none at all. If you want to play it safe, you'll also have to intercept the GL context creation function as well as MakeCurrent. In the worst (though very unlikely) case, the application has the GL context bound to another thread while it is calling the SwapBuffers, so there is no change for you in the hooked function to get to the context.
Putting this all together opens up another alternative: You can create your own GL context, bind it temporarily during the hooked SwapBuffers call and restore the original binding again. That way, you don't interfere with the GL state of the application at all. You still can augment the image content the application has rendered, since the framebuffer is part of the drawable, not the GL context. Doing so might have a negative impact on performance, but it might be so small that you never would even notice it.
Since you want to do this only for a single specific application, another approach would be to find out the minimal state changes which are necessary by observing what GL state the application actually set during the SwapBuffers call. A tool like apitrace can help you with that.

Glusphere giving strange lighting

When working with glut, i used glutsolidsphere to draw my spheres, but having moved to glfw, i had to use glusphere. I basically copied the entire function "glutsolidsphere" to my own code, but am getting a strange lighting problem where before i wasn't. Heres the code for the sphere :
void drawSolidSphere(GLdouble radius, GLint slices, GLint stacks)
{
GLUquadric *shape = gluNewQuadric();
gluQuadricDrawStyle(shape, GLU_FILL);
gluQuadricNormals(shape, GLU_SMOOTH);
gluSphere(shape, radius, slices, stacks);
}
Whats the problem here?
Edit : For some reason, i cant upload images from college, so i'll try describe it : The sphere outline looks fine, however you can see the segments on the inside, like the outside of the sphere is transparent, and it causes there to be clear divides in the sphere.
Looks like there's a problem with depth testing.
Assuming you have a depth buffer from glfw, does this fix it?
glEnable(GL_DEPTH_TEST);
I haven't used glfw, but to request a depth buffer it looks like you just need to pass 24 for example to the depthbits argument of glfwOpenWindow.
You will also need to add GL_DEPTH_BUFFER_BIT to your glClear call if you haven't already.
I've experienced inconsistencies with the default GL state, specifically GL_DEPTH_TEST, across windows and linux using glut/freeglut before.
Also, see gluNewQuadric leaking memory

Render text in foreground

I am trying to render some strings in the foreground in a OpenGL/GLUT application under MacOSX 10.7.2.
At the moment I am using this code to draw a few lines in the foreground and it works fine.
void drawForeground() {
int width = 10;
int height = 10;
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(-1, width, -1, height, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDepthMask(GL_FALSE);
glBegin(GL_LINES);
//Draw the lines
glEnd();
/*********************/
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glDepthMask(GL_TRUE);
}
Now I would like to draw also some text. In the previous function I added this piece of code in the line where I put the asterisks:
glRasterPos2d(2,2);
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, 'c');
but it didn't work. If I use the same two lines outside the drawForeground method the 'c' appears.
I already called glDisable(GL_TEXTURE_2D) and nothing changed.
May someone help me understanding my error?
Solution:
It turned out the solution to be disabling lighting using glDisable(GL_LIGHTING), reenabling it after rendering the text.
I would like to underline that the text is rendered always at the same dimension, independently from the parameters of the glOrtho call.
Nothing certain, but a couple of things to try if you haven't already:
What is the color set to before you call glutBitmapCharacter()? If the drawing color is set to something that doesn't show up against the background, it could simply look like nothing is being drawn.
Have you tried calling glDisable(GL_TEXTURE) in addition to glDisable(GL_TEXTURE_2D)?
Are there other things like lighting that you enable anywhere else in your code, and then don't disable before rendering the text that might affect things? When I've run into bugs like this in the past, it seems like they are often related to something in the OpenGL state being in a state I didn't expect, often because I made some change to the state elsewhere and forgot to undo it. I would recommend that you try systematically commenting out various OpenGL calls in your code, even if they don't seem directly related, and see if the characters ever show up. If they do, then you'll know which state change you need to make/undo.

How to use gluPerspective only once?

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//set viewpoint
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(VIEW_ANGLE,Screen_Ratio,NEAR_CLIP,FAR_CLIP);
gluLookAt(0,5,5, 0,0,0, 0,1,0);
//transform model 1
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotatef(Theta, 0,1,0);
//draw model 1
glBegin(GL_QUADS);
...
glEnd();
The code above works fine, but is there any way to remove the call to gluPerspective?
What I mean is, I would like to call it only once in initialization, instead of repeatedly during each rendering.
You call gluPerspective there, because it belongs there. OpenGL is not a scene graph where you initialize things. It's a state driven drawing API. The projection matrix is a state and every serious graphics application changes this state multiple times throughout a single frame rendering.
OpenGL does not know geometrical objects, positions and cameras. It just pushes points, lines and triangles through a processing pipeline, and draws the result to the screen. After something has been drawn, OpenGL has no recollection of it, whatsoever.
I mean calling it only once in initialization.
OpenGL is not initialized (except creation of the rendering context, but actually this is part of the operating system's graphics stack, not OpenGL). Sure, you upload textures and buffer object data to it, but that can happen anytime.
Do not use gluLookAt on the projection matrix, as it defines the camera/view and therefore belongs to the modelview matrix, usually as the left-most transformation (the first after glLoadIdentity), where it makes up the view part of the word modelview. Although it also works your way, it's conceptually wrong. This would also solve your issue, as then you just don't have to touch the projection matrix every frame.
But actually datenwolf's approach is more conceptually clean regarding OpenGL's state machine architecture.
If you don't call glLoadIdentity() (which resets the current matrix to be the identity matrix, i.e. undoes what gluPerspective() has done) every frame and instead carefully push/pop the transform matrices you can get away with calling it only in initialization quite happily. Usually it's far easier just to call load identity each time your start drawing and then reset it. e.g.:
// Initalisation
glLoadIdentity();
gluPerspective(...);
Then later on:
// Drawing each frame
glClear(...);
glPushMatrix();
gluLookAt(...);
//draw stuff
glPopMatrix();