How to convert from GLUT coordinates to window coordinates [duplicate] - c++

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Glut Mouse Coordinates
Let's say that I have a window of 600x600.
When I receive mouse events I don't know what's the real position of the mouse, in OpenGL I use this to draw points:
(-0.5,0.5) | (0.5,0.5)
|
--------(0,0)-------
|
|
(-0.5,-0.5) | (0.5,-0.5)
But when I receive GLUT mouse events depending on the size of the window I get different coordinates.I want a relative (to the window) coordinate system.How do I get this?

I am pretty sure glut gives you the mouse coordinates in window space (i.e. if the window is 800x600 and the mouse position is in the middle, it will give you x: 400, y: 300), so if you want to bring that to the opengl space you posted above, you would do the following:
float x = (400 / 800) - 0.5f; //0.0
float y = (300 / 600) - 0.5f; //0.0
so a generic version would look something like this:
float mouseX = (theGlutMouseXCoordinate / theGlutWindowWidth) - 0.5f;
float mouseY = (theGlutMouseYCoordinate / theGlutWindowHeight) - 0.5f;

Maybe I'm misreading your question, or oversimplifying the answer, but aren't you just looking for something like:
float x = mouse.x / screen.width; //x now in [0,1]
float y = mouse.y / screen.height; //y now in [0,1]
x-=0.5f;
y-=0.5f;
Or reversed:
float wx = (x + 0.5f) * screen.width;
float wy = (Y + 0.5f) * screen.height;

Related

How to zoom in on cursor point in Mandelbrot Set?

I'm currently trying to implement a zoom feature for the Mandelbrot Set code I've been working on. The idea is to zoom in/out where I left/right click. So far whenever I click the screen, the fractal is indeed zoomed in. The issue is that the fractal is rendered not at the origin-- in other words, it's not zoomed in on the point I want. I was hoping through here I can get both a code review and conceptual understanding of how to zoom in on a point in general.
Here's how I transformed the pixel coordinate before I used escape algorithm:
MandelBrot.Frag
vec2 normalizedFragPos = (gl_FragCoord.xy/windowSize); //normalize fragment position
dvec2 scaledFragPos = normalizedFragPos*aspectRatio;
scaledFragPos -= aspectRatio/2; //Render the fractal at center of window
scaledFragPos /= scale; //Factor to zoom in or out coordinates.
scaledFragPos -= translation; //Translate coordinate
//Escape Algorithm Below
On my left-click handle, I thought I should convert the cursor position to the same coordinate range as the Mandelbrot Range. So I basically did the same thing I did in the fragment shader:
Window.cpp
float x_coord{ float(GET_X_LPARAM(informaton_long))/size.x }; // normalized mouse x-coordinate
float y_coord{ float(GET_Y_LPARAM(informaton_long))/size.y }; // normalized mouse y-coordinate
x_coord *= aspectRatio[0]; //move point based of relative position to length of window.
y_coord *= aspectRatio[1]; //move point based of relative position to width of window.
x_coord /= scale; //Scale point to match previous zoom factor
y_coord /= scale; //Scale point to match previous zoom factor
translation[0] = x_coord;
translation[1] = y_coord;
//increment scale
scale += .15f;
Lets apply some algebra. Your shader does the following transformation:
mandelbrotCoord = aspectRatio * (gl_FragCoord / windowSize - 0.5) / scale - translation
When we zoom in on mouseCoord, we want to change the scale and adjust the translation such that the madelbrotCoord under the mouse stays the same. To do that we first calculate the mandelbrotCoord under the mouse using the old scale:
mandelbrotCoord = aspectRatio * (mouseCoord / windowSize - 0.5) / scale - translation
Then change the scale (which should be changed exponentially BTW):
scale *= 1.1;
Then solve for the new translation:
translation = aspectRatio * (mouseCoord / windowSize - 0.5) / scale - mandelbrotCoord
Also notice that your system probably reports the mouse coordinate with the y coordinate increasing downwards, whereas OpenGL has its window y coordinate increasing upwards (unless you override it with glClipControl). Therefore you're likely to need to flip the y coordinate of the mouseCoord too.
mouseCoord[1] = windowSize[1] - mouseCoord[1];
For best result I would also adjust the mouse coordinates to be in the middle of the pixel (+0.5, +0.5).
Putting it all together:
float mouseCoord[] = {
GET_X_LPARAM(informaton_long) + 0.5,
GET_Y_LPARAM(informaton_long) + 0.5
};
mouseCoord[1] = size[1] - mouseCoord[1];
float anchor[] = {
aspectRatio[0] * (mouseCoord[0] / size[0] - 0.5) / scale - translation[0],
aspectRatio[1] * (mouseCoord[1] / size[1] - 0.5) / scale - translation[1]
};
scale *= 1.1;
translation[0] = aspectRatio[0] * (mouseCoord[0] / size[0] - 0.5) / scale - anchor[0];
translation[1] = aspectRatio[1] * (mouseCoord[1] / size[1] - 0.5) / scale - anchor[1];
Note: some of the math above might be canceled away. However, if you want to implement a proper pan&zoom functionality (when you can zoom with the mouse wheel while you are panning) then you'll need to store the initial mandelbrotCoord of where the panning started, and then reuse it on subsequent motion and wheel events till the mouse is released. Surprisingly large amount of image viewers get this part wrong!

Calculating a future position of a ball that can bounce off the walls

I'm trying to do some future prediction where I want to calculate where the ball should be a particular height (y). The ball is fired upwards and can bounce off the sides of the game. Bounces do not affect movement velocity.
My current config is bottom left is (0,0) and bottom right is (10,0) with no upper height limit.
Code:
void getPositionXAtHeight(float height, Vec2 pos, Vec2 vel, float gravityForce = 9.8f, float gameWidth, float& positionX)
{
float a = gravityForce / 2.0f;
float b = vel.y;
float c = pos.y - height;
float t = (sqrtf((b * b) - (4.0f * a * c)) - b) / (2.0f * a);
positionX = pos.x + (vel.x*t);
}
Can anyone advise if my code is correct so far and what I should do to handle wall bounces?
Also I feel I should do some error checking but am unsure where abouts I need to?
It's not clear what's the direction of gravity, but suppose that it's along the y-axis. Then, for symmetry, you can just "wrap around" the x values, if they go above 10. E.g. if your equation results in x=11, for symmetry, after the bounce, x=9 (10 - (11 - 10)).
Similarly, you can treat "double bounces", etc.

mouse press projection (c++ openGL)

I'm making a simple tutorial game with openGL and have a question about touch method. Please checkout my code:
My (0,0) point is in center of a screen:
void Init()
{
glClearColor(0.3,0.3,0.3,0.0);
glMatrixMode(GL_PROJECTION);
glOrtho(-400.0,400.0,-300.0,300.0,0,1.0); //сетка, середина в точке 0
}
Before this i'm call mouse methods:
glutPassiveMotionFunc(Mouse);
glutMouseFunc(MousePress);
And in method MousePress when touch is coming, it's another system coordinate with (0,0) point in top left corner of a screen. Please can you tell me better approach then make something like x-300;y-400 in MousePress method.
Given the simpler orthographic projection, your "x-300;y-400" is the correct approach, although you might want to do some scaling too...
float x = mouseX/(float)windowWidth;
float y = 1.0f - mouseY/(float)windowHeight; //flip since y=0 is at the top
//x and y are now 0 to 1, bottom left to top right
x = left + x * (right - left);
y = bottom + y * (top - bottom);
//x and y are now in 3D coordinates
Here, left/right/bottom/top are from glOrtho, which in your case can be substituted as follows (but of course storing in a variable is better)...
x = -400 + x * (400 - (-400));
y = -300 + y * (300 - (-300));
If you were using a perspective projection it gets a bit more complicated, as I've described here.
[EDIT]
Assuming the window size is 800x600, the above cancels to {x-400,300-y}. For example,
mouseY = 50;
windowHeight = 600;
float y = 1.0f - (50/(float)600); //1.0 - 0.08333 = 0.91667
y = -300 + y * (300 - (-300)); //-300 + 0.91667 * 600 = 250, also 300-50

Converting Window coordinates to Axis coordinates in OpenGL

Im creating a simple program in OpenGL to draw rectangles with the mouse. My goal is to click somewhere, drag the mouse and create a rectangle just like you do in paint or any other design program.
I have a view defined like:
glMatrixMode(GL_PROJECTION);
glOrtho(AXIS_X_MIN, AXIS_X_MAX, AXIS_Y_MIN, AXIS_Y_MAX, AXIS_Z_MIN, AXIS_Z_MAX);
and a window defined this way:
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
How can I convert the window coordinates which go from 0 to WINDOW_WIDTH and from 0 to WINDOW_HEIGHT into axis coordinates and respective quadrants?
Try:
double x = x_mouse / (double) WINDOW_WIDTH
* (AXIS_X_MAX - AXIS_X_MIN) + AXIS_X_MIN;
double y = (1 - y_mouse / (double) WINDOW_HEIGHT)
* (AXIS_Y_MAX - AXIS_Y_MIN) + AXIS_Y_MIN;
If you don't want to make the calculations by "hand", you can always check this small article, that makes use of a function from GLU library that shall do this internally.
http://steinsoft.net/index.php?site=Programming/Code%20Snippets/OpenGL/no8
gluUnProject — transforms map window coordinates to object coordinates.
To be honest, I barely have any idea of how it works. You can check it out here: OpenGL - gluUnProject
Also if you try this it should work:
float coorX = mouseX * width / WINDOW_WIDTH + AXIS_X_MIN;
float coorY = mouseY * heigth/ WINDOW_HEIGHT + AXIS_Y_MIN;

How do you rotate a sprite around its center by calculating a new x and y position?

I'm using Dark GDK and C++ to create a simple 2d game. I'm rotating an object but it rotates from the top left corner of the sprite.
I have the following variables available:
PlayerX
PlayerY
PlayerWidth
PlayerHeight
RotateAngle (360 > x > 0)
Is there an algorithm that will modify the pivot point of the sprite, preferable to the center?
Here is a small code sample:
void Player::Move( void )
{
if ( checkLeft() )
{
PlayerX -= PlayerSpeed;
if ( PlayerX < 0 )
PlayerX = 0;
}
if ( checkRight() )
{
PlayerX += PlayerSpeed ;
if ( PlayerX > 800 - PlayerWidth )
PlayerX = 800 - PlayerWidth;
}
if ( checkUp())
{
PlayerY -= PlayerSpeed;
if ( PlayerY < 0 )
PlayerY = 0;
}
if ( checkDown())
{
PlayerY += PlayerSpeed;
if ( PlayerY > 600 - PlayerHeight)
PlayerY = 600 - PlayerHeight;
}
RotateAngle += 5;
if(RotateAngle > 360)
RotateAngle -=360;
dbRotateSprite(Handle,RotateAngle);
dbSprite ( 1 , PlayerX , PlayerY , Handle );
}
Edit
I'm considering opening up some reputation for this question, I have yet to be provided with an answer that works for me. If someone can provide an actual code sample that does the job, I'd be very happy.
The problem with Blindy's answer is that no matter how much I simply translate it back or forth, the spirte still rotates around the top left hand corner and moving it somewhere rotating around the top left corner, then moving it back to the same position accomplishes nothing. Here is what I believe to be going on:
alt text http://img248.imageshack.us/img248/6717/36512474.png
Just so there is no confusion I have created a an image of what is going on. The left shows what is actually happening and the right shows what I need to happen.
alt text http://img101.imageshack.us/img101/1593/36679446.png
You'd need to do something like:
translate by (-playerx-playerwidth/2, -playery-playerheight/2)
rotate by rotateangle
translate by (playerx+playerwidth/2, playery+playerheight/2)
The idea is to center your sprite on the origin then rotate around the origin (glRotate) and after you get the rotated sprite you translate it back in its place.
NB: If your sprite is initially "centered" around the origin, but with a corner not the actual center of the sprite, you first translate the object to center the sprite's center with the origin. So like if your sprite had the top-left corner in the origin, you'd translate by (-playerwidth/2, -playerheight/2), then rotate then translate by (playerx,playery).
The answers so far are correct in telling you how it should be done but I fear that the Dark GDK API seems to be too primitive to be able to do it that simple way.
Unfortunately dbRotateSprite rotates the sprite about the top left regardless of the sprite's transform which is why you're having no luck with the other suggestions. To simulate rotation about the centre you must manually correct the position of the sprite i.e. you simply have to rotate the sprite and then move it as a two-step process.
I'm not familiar with the API and I don't know if y is measured up or down and which way the angle is measured so I'm going to make some assumptions. If y is measured down like many other 2D graphics systems, and the angle is measured from the x-axis increasing as it goes from the positive x-axis to the positive y-axis, then I believe the correct psuedo-code would look like
// PlayerX and PlayerY denote the sprite centre
// RotateAngle is an absolute rotation i.e. not a relative, incremental rotation
RotateAngle += 5;
RotateAngle %= 360;
RadiansRotate = (RotateAngle * PI) / 180;
dbRotateSprite( Handle, RotateAngle );
HalfSpriteWidth = dbSpriteWidth( Handle ) / 2;
HalfSpriteHeight = dbSpriteHeight( Handle ) / 2;
SpriteX = PlayerX
- HalfSpriteWidth * cos(RadiansRotate)
+ HalfSpriteHeight * sin(RadiansRotate);
SpriteY = PlayerY
- HalfSpriteHeight * cos(RadiansRotate)
- HalfSpriteWidth * sin(RadiansRotate);
// Position the top left of the sprite at ( SpriteX, SpriteY )
dbSprite ( 1 , SpriteX , SpriteY , Handle );
When you rotate the object, you are applying a transformation to the points that compose the object. In this case, the four corners each rotate on their own, and the end result is the quad formed in their new locations. As everyone else has mentioned, the critical part of this is knowing where the origin about which the points rotate.
Imagine if instead of a sprite, you only had one point. If its origin was at the same position as that point, rotating it would have no effect (the position of the point would not move). However, if the origin was anywhere else, the point would rotate in a circle, with the origin as the center of that circle. And how would you get that origin to be somewhere other than at the same position as the point? Move the point within the coordinate system. In other words, translate it.
The order of the various transformations (rotate, translate, scale, etc.) is critical to this. If you rotated the point 180 degrees and then translated it to the right, it would end up to the right of where it started, but if you moved it to the right and then rotated it 180 degrees, it would end up on the left.
I'd recommend reading up on 2D transformations. Understanding how matrices play in all this would also be useful, but not strictly necessary to get the effect you're looking for.
Looking at your image, what you're doing is you're rotating the square in place, you're not translating it at all. This is what you're doing:
^ ^
| |
| |
| ====> |
| |
+--+-----> x---------->
| | / \
+--+ \ /
x
As you can see, your square is with its top-left corner in the origin and all you're doing is rotating it around the origin.
This is what I'm saying you should do:
^ ^ ^
| | |
| | ===> | ==> translate to
| ====> | x ==> where you want
| +-+ /|\ ==> to draw it
+--+-----> |+|---------> +-------->
| | +-+ \ /
+--+ x
You can only rotate around the center, so center the point you want to rotate your primitives around then place them where you want.
OMG ive been tryna do this for a while now to, n i found this page, just copy this.
this is based on one of the previous posts.
void dbRotateSpriteCenter(int iID, int iX, int iY, int fRotate, int iImage)
{
int x = iX
- dbSpriteWidth(iID) / 2 * cos(fRotate * 3.1415926536 / 180)
+ dbSpriteHeight(iID) / 2 * sin(fRotate * 3.1415926536 / 180);
int y = iY
- dbSpriteHeight(iID) / 2 * cos(fRotate * 3.1415926536 / 180)
- dbSpriteWidth(iID) / 2 * sin(fRotate * 3.1415926536 / 180);
dbRotateSprite(iID, fRotate);
dbSprite(iID, x, y, iImage);
}
you could use dbOffsetSprite();
when sprites are created, their insertion point is upper-left corner by default (and dbRotateSprite(); rotates them around the insertion point), you can use this function to change the insertion point. its format is dbOffsetSprite(sprite number, amount to offset X, amount to offset Y);
so you could say
dbOffsetSprite(NUMBER, dbSpriteWidth(NUMBER) / 2, dbSpriteHeight(NUMBER) / 2);
where NUMBER is the sprite ID number.
The sprite's insertion point is now in the center of its image.
Of course, this might open a whole new can of worms, as the insertion point is now in the center of the sprite (or where ever you set it), meaning calling dbSpriteX(NUMBER); will give you the center of the sprite instead of the edge.