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;
Related
On a C++ game, we're using Pango to render text with cairo and from there to an OpenGL texture.
I noticed this problem recently while working on implementing text-wrapping via Pango.
What I'm doing is calculating the width by translating our own coordinate system to pixels and then using that as a fraction of the window width in PANGO UNITS, or in code:
float screenEdge = _w * m * static_cast<float>(PANGO_SCALE);
float tempMaxWidth = _owner->m_wrapping.m_maxWidth;
tempMaxWidth = std::min(_owner->m_wrapping.m_maxWidth, (0.48f - _owner->dimensions().x1()));
float wrapWidth = screenEdge * tempMaxWidth;
maxWidth = static_cast<int>(std::round(wrapWidth));
pango_layout_set_width(_owner->m_pangoLayout.get(), maxWidth);
Then we get a rectangle from the layout an pass that to cairo with:
float border = 2.0f;
PangoRectangle lRec;
pango_layout_get_pixel_extents(_owner->m_pangoLayout.get(), nullptr, &lRec);
m_width = (lRec.width + border); // Add twice half a border for margins
m_height = (lRec.height + border);
std::unique_ptr<cairo_surface_t, decltype(&cairo_surface_destroy)> m_cairoSurface(
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, m_width, m_height),
&cairo_surface_destroy);
std::unique_ptr<cairo_t, decltype(&cairo_destroy)> m_cairoDc(
cairo_create(m_cairoSurface.get()),
&cairo_destroy);
cairo_set_antialias(m_cairoDc.get(), CAIRO_ANTIALIAS_FAST);
cairo_push_group_with_content (m_cairoDc.get(), CAIRO_CONTENT_COLOR_ALPHA);
cairo_set_operator(m_cairoDc.get(), CAIRO_OPERATOR_SOURCE);
// Add Pango line and path to proper position on the DC
cairo_move_to(m_cairoDc.get(), (0.5f * border), (0.5f * border)); // Margins needed for border stroke to fit in
But the output, as you can see below, is cut-off; this does not happen if I use PANGO_ALIGN_LEFT
Searching around here, I found Cairo + Pango layout non-left alignment
Which appears related to my issue but does not quite provide a solution (or I didn't get it properly); what I tried was to calculate the different between the x and y coordinates of the logical and ink rectangles and adding that to cairo_move_to but that made no real difference in the output, so I just pasted the original code here.
I am trying to use the function mouseMove(int x, int y) to draw a circle centered at my mouse as I click and drag it across the screen. Circles will be drawn on the moving mouse like a spray paint. So far, this is what I have
void mouseMove(int x, int y) {
glBegin(GL_POLYGON);
for (int i = 0; i <= 360; i++)
{
float theta = (2 * 3.14 * i) / 360;
glVertex2f((size/2 + x) * cos(theta), (size/2 + y) * sin(theta));
}
glEnd();
glutPostRedisplay();
}
But when using this, it draws very large circles that aren't centered around my mouse. How would I alter this to make the program draw circles centered at my mouse?
To describe the project, I am creating a painting program that changes shapes, colors, sizes, and rotations of the drawing done in mouseMove. For now, the size is an int set to 32. When the user selects the shape using the 'b' key in a keyboard function, he/she can switch the shapes that are drawn around the mouse as the user clicks and drags the mouse around. Like a spray paint. All the other shapes work shaped around the mouse except for the circle shape spray.
This answer assumes that things like your viewport and projection matrices are set up correctly, and that the input to this function is taking into account the fact that "screen coordinates" (what the mouse uses) are not the same thing as "OpenGL Coordinate Space" (this usually implies reversing the direction of the y-axis for one or the other).
The math you're using for setting your vertex coordinates is wrong. The mouse's x and y coordinates should not be multiplied by the sine/cosine functions.
The correct way to write it is
glVertex2f((size/2) * cos(theta) + x, (size/2) * sin(theta) + y);
I would also add that you appear to still be using OpenGL's Immediate Mode rendering, which is Deprecated and will offer extremely poor training for a professional setting. I highly advise you learn Modern OpenGL (3.x+) and reapply those concepts to whatever projects you're already working on. This is a very good tutorial.
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
So I am working on a simple project in openGL and C++ where i have just a white circle drawn on screen for now.
I added a function to maintain the aspect ratio in the canvas i am using and it seems to be working flawlessly.
If you resize the window horizontally, clipping will occur (this is what i intended)
But if you resize the window vertically, no clipping occurs and instead the objects scale down/up..
Now i am stuck at figuring out how to keep the aspect ratio correct, while also preventing the objects from scaling and while keeping in mind that i will be implementing Panning and Zoom later on.
With that in mind, here is the code i am using to adjust the ratio.
Please note that glViewPort is also set correctly on resize, but i only copied this section because i know the problem is somewhere here.
if ( dx/dy < w/h ){
// Need to expand dx
GLdouble diff = w/h*dy - dx;
minX -= 0.5*diff;
maxX += 0.5*diff;
}
else{
// Need to shrink dx
GLdouble diff = h/w * dx - dy;
minX += 0.5*diff;
maxX -= 0.5*diff;
}
glOrtho( minX, maxX, minY, maxY, minZ, maxZ );
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;