Drawing an OpenGL overlay using SwapBuffers interception - c++

I'm trying to make a library that would allow me to draw my overlay on top of the content of a game window that uses OpenGL by intercepting the call to the SwapBuffers function. For interception i use Microsoft Detours.
BOOL WINAPI __SwapBuffers(HDC hDC)
{
HGLRC oldContext = wglGetCurrentContext();
if (!context) // Global variable
{
context = wglCreateContext(hDC);
}
wglMakeCurrent(hDC, context);
// Drawing
glRectf(0.1F, 0.5F, 0.2F, 0.6F);
wglMakeCurrent(hDC, oldContext);
return _SwapBuffers(hDC); // Call the original SwapBuffers
}
This code works, but occasionally, when I move my mouse, my overlay blinks. Why? Some forums have said that such an implementation can significantly reduce FPS. Is there any better alternative? How do I correctly translate a normal position to an OpenGL position? For example, width = 1366. It turns out 1366 = 1, and 0 = -1. How to get the value for example for 738? What about height?

To translate a screen coordinate to normal coordinate you need to know the screen width and screen height, linear mapping from [0, screenwidth] to [-1, 1] / [0, screenheight] to [-1, 1]. It is as simple as follows:
int screenwidth, screenheight;
//...
screenwidth = 1366;
screenheight = 738;
//...
float screenx, screeny;
float x = (screenx/(float)screenwidth)*2-1;
float y = (screeny/(float)screenheight)*2-1;
Problem z=0:
glRect renders to z=0, it is a problem because the plane would be infinitely near. Because opengl considers rendering to world space still. Screen space lies at (x, y, 1) in non transformed world space. OpenGL almost always works with 3D coordinates.
There are two ways to tackle this problem:
You should prefer using functions with a z component, because opengl does not render correctly at z=0. z=1 corresponds to the normalized screen space
or you add a glTranslatef(0,0,1); to get to the normalized screen space
Remember to disable depth testing when rendering 2D on the screen space and resetting the modelview matrix.

Related

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

How to draw on just a portion of the screen with SpriteBatch in libgdx?

When I do this:
SpriteBatch spriteBatch = new SpriteBatch();
spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, 320, 0, 240, -1, 1));
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0);
spriteBatch.end();
SpriteBatch will draw the textureRegion onto the coordinate system 320-240 that I have specified to the whole screen. Say I want to draw with the same coordinate system 320 240 but only on the left half of the screen (which means everything will be scaled down horizontally in the left side, leaving the right half of the screen black), how can I do?
You're going to want to use the ScissorStack. Effectively, you define a rectangle that you want to draw in. All drawing will be in the rectangle that you defined.
Rectangle scissors = new Rectangle();
Rectangle clipBounds = new Rectangle(x,y,w,h);
ScissorStack.calculateScissors(camera, spriteBatch.getTransformMatrix(), clipBounds, scissors);
ScissorStack.pushScissors(scissors);
spriteBatch.draw(...);
spriteBatch.flush();
ScissorStack.popScissors();
This will limit rendering to within the bounds of the rectangle "clipBounds".
It is also possible push multiple rectangles. Only the pixels of the sprites that are within all of the rectangles will be rendered.
From http://code.google.com/p/libgdx/wiki/GraphicsScissors
Before rendering the batch, you can set the viewport to draw on a specific screen area. The important line is:
Gdx.gl.glViewport(x, y, w, h);
The viewport usually starts at x = 0 and y = 0 and extends to the full width and height of the screen. If we want to see only a part of that original viewport, we need to change both the size and the starting position. To draw only on the left half of the screen, use:
x = 0;
y = 0;
w = Gdx.graphics.getWidth()/2;
h = Gdx.graphics.getWidth();
I found the solution here and originally answered this question to a slightly more complicated problem, but the technique is the same.
To focus on any different portion of the viewport, simply choose x, y, w, and h accordingly. If you're going to do any more rendering in the normal fashion, make sure to reset the viewport with the original x, y, w, and h values.
Perhaps I am misunderstanding the question, but could you not just double the viewport width, setting it to 640 instead of 320?
SpriteBatch spriteBatch = new SpriteBatch;
spriteBatch.setProjectionMatrix(new Matrix4().setToOrtho(0, 640, 0, 240, -1, 1));
spriteBatch.begin();
spriteBatch.draw(textureRegion, 0, 0);
spriteBatch.end();
You could either
double the viewport width of the SpriteBatch
use a Sprite and set its width scale to 0.5f (be careful about the origin) and use its draw(SpriteBatch) method to draw it.

LWJGL 3D picking

So I have been trying to understand the concept of 3D picking but as I can't find any video guides nor any concrete guides that actually speak English, it is proving to be very difficult. If anyone is well experienced with 3D picking in LWJGL, could you give me an example with line by line explanation of what everything means. I should mention that all I am trying to do it shoot the ray out of the center of the screen (not where the mouse is) and have it detect just a normal cube (rendered in 6 QUADS).
Though I am not an expert with 3D picking, I have done it before, so I will try to explain.
You mentioned that you want to shoot a ray, rather than go by mouse position; as long as this ray is parallel to the screen, this method will still work, just the same as it will for a random screen coordinate. If not, and you actually wish to shoot a ray out, angled in some direction, things get a little more complicated, but I will not go in to it (yet).
Now how about some code?
Object* picking3D(int screenX, int screenY){
//Disable any lighting or textures
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE);
//Render Scene
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
orientateCamera();
for(int i = 0; i < objectListSize; i++){
GLubyte blue = i%256;
GLubyte green = min((int)((float)i/256), 255);
GLubyte red = min((int)((float)i/256/256), 255);
glColor3ub(red, green, blue);
orientateObject(i);
renderObject(i);
}
//Get the pixel
GLubyte pixelColors[3];
glReadPixels(screenX, screenY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixelColors);
//Calculate index
int index = pixelsColors[0]*256*256 + pixelsColors[1]*256 + pixelColors[2];
//Return the object
return getObject(index);
}
Code Notes:
screenX is the x location of the pixel, and screenY is the y location of the pixel (in screen coordinates)
orientateCamera() simply calls any glTranslate, glRotate, glMultMatrix, etc. needed to position (and rotate) the camera in your scene
orientateObject(i) does the same as orientateCamera, except for object 'i' in your scene
when I 'calculate the index', I am really just undoing the math I performed during the rendering to get the index back
The idea behind this method is that each object will be rendered exactly how the user sees it, except that all of a model is a solid colour. Then, you check the colour of the pixel for the screen coordinate requested, and which ever model the colour is indexed to: that's your object!
I do recommend, however, adding a check for the background color (or your glClearColor), just in case you don't actually hit any objects.
Please ask for further explanation if necessary.

How to tell the size of font in pixels when rendered with openGL

I'm working on the editor for Bitfighter, where we use the default OpenGL stroked font. We generally render the text with a linewidth of 2, but this makes smaller fonts less readable. What I'd like to do is detect when the fontsize will fall below some threshold, and drop the linewidth to 1. The problem is, after all the transforms and such are applied, I don't know how to tell how tall (in pixels) a font of size <fontsize> will be rendered.
This is the actual inner rendering function:
if(---something--- < thresholdSizeInPixels)
glLineWidth(1);
float scalefactor = fontsize / 120;
glPushMatrix();
glTranslatef(x, y + (fix ? 0 : size), 0);
glRotatef(angle * radiansToDegreesConversion, 0, 0, 1);
glScalef(scaleFactor, -scaleFactor, 1);
for(S32 i = 0; string[i]; i++)
OpenglUtils::drawCharacter(string[i]);
glPopMatrix();
Just before calling this, I want to check the height of the font, then drop the linewidth if necessary. What goes in the ---something--- spot?
Bitfighter is a pure old-school 2D game, so there are no fancy 3D transforms going on. All code is in C++.
My solution was to combine the first part Christian Rau's solution with a fragment of the second. Basically, I can get the current scaling factor with this:
static float modelview[16];
glGetFloatv(GL_MODELVIEW_MATRIX, modelview); // Fills modelview[]
float scalefact = modelview[0];
Then, I multiply scalefact by the fontsize in pixels, and multiply that by the ratio of windowHeight / canvasHeight to get the height in pixels that my text will be rendered.
That is...
textheight = scalefact * fontsize * widndowHeight / canvasHeight
And I liked also the idea of scaling the line thickness rather than stepping from 2 to 1 when a threshold is crossed. It all works very nicely now.
where we use the default OpenGL stroked font
OpenGL doesn't do fonts. There is no default OpenGL stroked font.
Maybe you are referring to GLUT and its glutStrokeCharacter function. Then please take note that GLUT is not part of OpenGL. It's an independent library, focused on providing a simplicistic framework for small OpenGL demos and tutorials.
To answer your question: GLUT Stroke Fonts are defined in terms of vertices, so the usual transformations apply. Since usually all transformations are linear, you can simply transform the vector (0, base_height, 0) through modelview and projection finally doing the perspective divide (gluProject does all this for you – GLU is not part OpenGL, too), the resulting vector is what you're looking for; take the vector length for scaling the width.
This should be determinable rather easily. The font's size in pixels just depends on the modelview transformation (actually only the scaling part), the projection transformation (which is a simple orthographic projection, I suppose) and the viewport settings, and of course on the size of an individual character of the font in untransformed form (what goes into the glVertex calls).
So you just take the font's basic size (lets consider the height only and call it height) and first do the modelview transformation (assuming the scaling shown in the code is the only one):
height *= scaleFactor;
Next we do the projection transformation:
height /= (top-bottom);
with top and bottom being the values you used when specifying the orthographic transformation (e.g. using glOrtho). And last but not least we do the viewport transformation:
height *= viewportHeight;
with viewportHeight being, you guessed it, the height of the viewport specified in the glViewport call. The resulting height should be the height of your font in pixels. You can use this to somehow scale the line width (without an if), as the line width parameter is in floats anyway, let OpenGL do the discretization.
If your transformation pipeline is more complicated, you could use a more general approach using the complete transformation matrices, perhaps with the help of gluProject to transform an object-space point to a screen-space point:
double x0, x1, y0, y1, z;
double modelview[16], projection[16];
int viewport[4];
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
gluProject(0.0, 0.0, 0.0, modelview, projection, viewport, &x0, &y0, &z);
gluProject(fontWidth, fontHeight, 0.0, modelview, projection, viewport, &x1, &y1, &z);
x1 -= x0;
y1 -= y0;
fontScreenSize = sqrt(x1*x1 + y1*y1);
Here I took the diagonal of the character and not only the height, to better ignore rotations and we used the origin as reference value to ignore translations.
You might also find the answers to this question interesting, which give some more insight into OpenGL's transformation pipeline.

OpenGL Orthographic Projection Clipping

Assuming I use Orhographic Projection, and have a reshape function like this:
void reshape(f32 width, f32 height){
aspect = width/height;
glViewport(0, 0, width, height);
// guaranted 960x640 HUD canvas
if(640*aspect>=960){
ortho.x = 640*aspect;
ortho.y = 640;
}else{
ortho.x = 960;
ortho.y = 960/aspect;
}
glOrtho(0, ortho.x, ortho.y, 0, -1.0f, 1.0f);
}
How can I make sure, that all vertices >ortho.x or >ortho.y (normally offscreen) are didn't drawn?
Because if I scale the windows to something with a bigger aspect ratio than 1.5f (960/640) I see the objects, that schouldn't be full visible (because the viewport is so big like the window).
Is there something like a clipping pane in orthographic projection?
What you want is to use [glScissor][1] to ensure that the rendered area never goes beyond a certain size. glScissor takes a rectangle in window coordinates (remember: window coordinates have the origin at the bottom-left). The scissor test prevents the generation of fragments outside of this area.
To activate the scissor test, you must use glEnable(GL_SCISSOR). Unless you do that, the above call won't actually do anything.
Use constant values for the limit parameters of glOrtho, but use glViewport and glScissor (enable with glEnable(GL_SCISSOR_TEST)) to limit rendering to a sub-portion of your window.
BTW: You should set the projection and viewport in the rendering function. Doing it in the reshape handler makes not much sense. In any serious OpenGL application you'll switch projection modes several times during a full render, so just do it that way from the very beginning.