I'm trying to left click and drag any 3d Object and if i let go of it, it should stay in its new position, how would i achieve this? The 3d object is loaded from the draw function that i have in a header file.
Someone said i should be using glutMouseFunc or glutMotionFunc.
void MouseClickCallbackFunction(int button, int state, int x, int y)
{
if (state == GLUT_DOWN) {
if (button == GLUT_LEFT)
{
std::cout << "Left " << x << " " << y <<std::endl;
leftClick.x = x;
leftClick.y = y;
}
else if (button == GLUT_RIGHT_BUTTON) {
std::cout << "Right " << x << " " << y << std::endl;
rightClick.x = x;
rightClick.y = y;
}
}
theGame->mouseClicked(button, state, x, y);
glutPostRedisplay();
}
/* function MouseMotionCallbackFunction()
* Description:
* - this is called when the mouse is clicked and moves
*/
void MouseMotionCallbackFunction(int x, int y)
{
theGame->mouseMoved(x, y);
glutPostRedisplay();
}
int main(int argc, char **argv)
{
/* initialize the window and OpenGL properly */
glutInit(&argc, argv);
glutInitContextVersion(4, 2);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutCreateWindow("OpenGL Framework");
glewExperimental = true;
if (glewInit() != GLEW_OK)
{
std::cout << "GLEW could not be initialized. \n";
system("pause");
return 0;
}
//glewInit();
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
/* set up our function callbacks */
glutDisplayFunc(DisplayCallbackFunction);
glutKeyboardFunc(KeyboardCallbackFunction);
glutKeyboardUpFunc(KeyboardUpCallbackFunction);
glutMouseFunc(MouseClickCallbackFunction);
glutMotionFunc(MouseMotionCallbackFunction);
glutTimerFunc(1, TimerCallbackFunction, 0);
/* init the game */
theGame = new Game();
theGame->initializeGame();
/* start the game */
glutMainLoop();
return 0;
}
Here is the Draw fucntion with the object
void Game::draw()
{
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
PassThrough.Bind();
PassThrough.SendUniformMat4("uModel", MonkeyTransform.data, false);
PassThrough.SendUniformMat4("uView", CameraTransform.GetInverse().data, false);
PassThrough.SendUniformMat4("uProj", CameraProjection.data, false);
PassThrough.SendUniform("uTex", 0);
PassThrough.SendUniform("LightPosition", CameraTransform.GetInverse() * vec4(4.0f,0.0f,0.0f,1.0f));
PassThrough.SendUniform("LightAmbient", vec3(0.15f, 0.15f, 0.15f));
PassThrough.SendUniform("LightDiffuse", vec3(0.7f,0.1f,0.2f));
PassThrough.SendUniform("LightSpecular", vec3(0.8f,0.1f,0.1f));
PassThrough.SendUniform("LightSpecularExponent", 50.0f);
PassThrough.SendUniform("Attenuation_Constant", 1.0f);
PassThrough.SendUniform("Attenuation_Linear", 0.1f);
PassThrough.SendUniform("Attenuation_Quadratic", 0.01f);
glBindVertexArray(Monkey.VAO);
glDrawArrays(GL_TRIANGLES, 0, Monkey.GetNumVerticies());
glBindVertexArray(0);
PassThrough.unBind();
glutSwapBuffers();
}
The concept is called mouse picking. A method to achieve this is ray casting. Essentially what you want to do is map the mouse coordinates to a region in your scene. In your case you want to check if the position is within the monkey. Then it is as simple as handling the mouse up, down, and move events.
Mouse down: check if object is being picked. If it is, great- maybe highlight it or something. Store ref to object picked; store position of mouse at beginning of pick (pos)
Mouse move: is mouse down? Is picked object ref? Update object position based on delta between pos and coord in mouse move event
Mouse up: clear picked obj ref, position
This link may be of interest http://antongerdelan.net/opengl/raycasting.html
Related
For some reason my Window::callback is being called even after the mouse has left the window. I am unable to find a solution or even something that could help. Is it possible that GLFW updated how the mouse cursor callback operates? I wonder if it is an order of invocation problem?
Window
Window::Window(std::string title, int32_t width, int32_t height) {
// TODO: add support for monitor and share for GLFW
m_window = std::unique_ptr<GLFWwindow, GLFWdeleter>(glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr));
glfwMakeContextCurrent(m_window.get());
glfwSetWindowUserPointer(m_window.get(), this);
glfwSetCursorPosCallback(m_window.get(), Window::callback);
}
void Window::mouse_callback(double xpos, double ypos) {
std::cout << "x: " << xpos << " y: " << ypos << std::endl;
}
void Window::callback(GLFWwindow* window, double xpos, double ypos)
{
auto win = static_cast<Window*>(glfwGetWindowUserPointer(window));
win->mouse_callback(xpos, ypos);
}
Engine
void startup() const
{
if (glfwInit() == 0)
{
LOG(kError, "GLFW init failed!");
exit(-1);
}
}
void Engine::run() {
if (m_main_window_registered)
{
glewExperimental = static_cast<GLboolean>(true);
if (glewInit() != GLEW_OK)
{
std::cout << "Failed to initialize glew" << std::endl;
return;
}
}
while(glfwWindowShouldClose(m_main_window->window()) == 0) {
glClear(GL_COLOR_BUFFER_BIT);
glfwSwapBuffers(m_main_window->window());
glfwPollEvents();
}
}
main.cpp
int main()
{
g_engine.startup();
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
auto window = std::make_unique<Window>("Hello World!", 640, 480);
//window->make_current();
g_engine.registerWindow(std::move(window));
g_engine.run();
glfwTerminate();
return 0;
}
I have figured out what the problem (or better put) issue is. On Windows the callback performs as expected where once the mouse leaves the windows area the callback stops firing. For OSX the window never loses focus and therefore the cursor callback is always being called. To fix the issue you simply have to test the coordinates to ensure that the mouse is in fact inside the window.
I need help in understanding how to scale my coordinates. The instruction says, modify the code to move the triangle to the mouse click position. Can someone explain how this is done?
Here is the source code I'm working with:
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <stddef.h>
#include <iostream>
// values controlled by fast keys
float g_angle = 0.0f;
float g_xoffset = 0.0f;
float g_yoffset = 0.0f;
int x;
int y;
// increments
const float g_angle_step = 32.0f; // degrees
const float g_offset_step = 32.0f; // world coord units
// last cursor click
int g_cursor_x = 0;
int g_cursor_y = 0;
void draw_triangle()
{
// in model cooridnates centred at (0,0)
static float vertex[3][2] =
{
{-1.0f, -1.0f},
{1.0f, -1.0f},
{0.0f, 1.0f}
};
glBegin(GL_LINE_LOOP);
for (size_t i=0;i<3;i++)
glVertex2fv(vertex[i]);
glEnd();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f, 1.0f, 1.0f);
glLineWidth(2.0f);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(500.0f+g_xoffset, 500.0f+g_yoffset, 0.0f);
glScalef(100.0f, 100.0f, 1.0f);
glRotatef(g_angle, 0.0f, 0.0f, 1.0f);
draw_triangle();
glPopMatrix(); // done with stack
glutSwapBuffers();
}
// handles mouse click events
// button will say which button is presed, e.g. GLUT_LEFT_BUTTON, GLUT_RIGHT_BUTTON
// state will say if the button is GLUT_UP or GLUT_DOWN
// x and y are the poitner position
void mouse_click(int button, int state, int x, int y)
{
if (button==GLUT_LEFT_BUTTON)
{
std::cerr << "\t left mouse button pressed!" << std::endl;
if (state==GLUT_UP)
{
std::cerr << "\t button released...click finished" << std::endl;
g_cursor_x = x;
g_cursor_y = y;
std::cerr << "\t cursor at (" << g_cursor_x << ", " <<
g_cursor_y << ")" << std::endl;
}
}
else
if (button==GLUT_RIGHT_BUTTON)
{
std::cerr << "\t right mouse button pressed!" << std::endl;
}
// Here is my attempt:
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
float x_min = (-x+500)/512;
float x_max = (x-500)/512;
float y_min = (-y+500)/512;
float y_max = (y-500)/512;
gluOrtho2D(x_min, x_max, y_min, y_max);
//glTranslatef(x/512, 1-y/512, 0.0f);
std::cerr << x << ", " << y << std::endl;
}
glutPostRedisplay();
}
void mouse_motion(int x, int y)
{
std::cerr << "\t mouse is at (" << x << ", " << y << ")" << std::endl;
glutPostRedisplay();
}
// will get which key was pressed and x and y positions if required
void keyboard(unsigned char key, int, int)
{
std::cerr << "\t you pressed the " << key << " key" << std::endl;
switch (key)
{
case 'q': exit(1); // quit!
// clockwise rotate
case 'r': g_angle += g_angle_step; break;
}
glutPostRedisplay(); // force a redraw
}
// any special key pressed like arrow keys
void special(int key, int, int)
{
// handle special keys
switch (key)
{
case GLUT_KEY_LEFT: g_xoffset -= g_offset_step; break;
case GLUT_KEY_RIGHT: g_xoffset += g_offset_step; break;
case GLUT_KEY_UP: g_yoffset += g_offset_step; break;
case GLUT_KEY_DOWN: g_yoffset -= g_offset_step; break;
}
glutPostRedisplay(); // force a redraw
}
void init()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, 1000, 0, 1000);
glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
g_cursor_x = g_cursor_y = 500; // middle of window
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
glutInitWindowSize(512, 512);
glutInitWindowPosition(50, 50);
glutCreateWindow("Mouse Test");
glutDisplayFunc(display);
// handlers for keyboard input
glutKeyboardFunc(keyboard);
glutSpecialFunc(special);
// mouse event handlers
glutMouseFunc(mouse_click);
glutPassiveMotionFunc(mouse_motion);
init();
glutMainLoop();
return 0;
}
This should solve your issue.replace your code(your attempt) with the code below.
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
g_xoffset = x;
g_yoffset = 1000-y;
} glutPostRedisplay();
I have this code:
#include <iostream>
#include <GL/glut.h>
using namespace std;
bool* Keys = new bool[256];
void keyboardDown(unsigned char key, int x, int y)
{
Keys[key] = true;
}
void keyboardUp(unsigned char key, int x, int y)
{
Keys[key] = false;
}
void reshape(int width, int height)
{
GLfloat fieldOfView = 90.0f;
glViewport(0, 0, (GLsizei)width, (GLsizei)height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(fieldOfView, (GLfloat)width / (GLfloat)height, 0.1, 500.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void draw()
{
if (Keys['e'])
cout << "e" << endl;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glBegin(GL_QUADS);
glColor3f(0.1, 0.1, 0.1); glVertex3f(1.0, 1.0, -1.0);
glColor3f(0.1, 0.9, 0.1); glVertex3f(1.0, -1.0, -1.0);
glColor3f(0.9, 0.1, 0.1); glVertex3f(-1.0, -1.0, -1.0);
glColor3f(0.1, 0.1, 0.9); glVertex3f(-1.0, 1.0, -1.0);
glEnd();
glFlush();
glutSwapBuffers();
}
void initGL(int width, int height)
{
reshape(width, height);
glClearColor(0.1f, 0.5f, 0.7f, 1.0f);
glClearDepth(1.0f);
glOrtho(0, 1, 0, 1, 1, 10);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
}
/* initialize GLUT settings, register callbacks, enter main loop */
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(800, 800);
glutInitWindowPosition(100, 100);
glutCreateWindow("Perspective's GLUT Template");
glutKeyboardFunc(keyboardDown);
glutKeyboardUpFunc(keyboardUp);
glutSpecialFunc(keyboardSpecialDown);
glutSpecialUpFunc(keyboardSpecialUp);
glutReshapeFunc(reshape);
glutDisplayFunc(draw);
glutIgnoreKeyRepeat(true); // ignore keys held down
initGL(800, 600);
glutMainLoop();
return 0;
}
When I start the program, it writes 'e' only when I press on the mouse. I can't find the problem. Why does it only work when the mouse is held down?
You dont have mouse functions in your code, thats why it is not working. Insert from here : http://www.zeuscmd.com/tutorials/glut/03-MouseInput.php
#include <iostream>
#include <gl/glut.h>
using namespace std;
bool lbuttonDown = false;
bool init()
{
return true;
}
void display()
{
}
void mouse(int button, int state, int x, int y)
{
if (button == GLUT_RIGHT_BUTTON)
{
if (state == GLUT_DOWN)
cout << "Right button pressed"
<< endl;
else
cout << "Right button lifted "
<< "at (" << x << "," << y
<< ")" << endl;
}
else if (button == GLUT_LEFT_BUTTON)
{
if (state == GLUT_DOWN)
lbuttonDown = true;
else
lbuttonDown = false;
}
}
void motion(int x, int y)
{
if (lbuttonDown)
cout << "Mouse dragged with left button at "
<< "(" << x << "," << y << ")" << endl;
}
void motionPassive(int x, int y)
{
cout << "Mouse moved at "
<< "(" << x << "," << y << ")" << endl;
}
void entry(int state)
{
if (state == GLUT_ENTERED)
cout << "Mouse Entered" << endl;
else
cout << "Mouse Left" << endl;
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowPosition(200, 200);
glutInitWindowSize(200, 200);
glutCreateWindow("03 - Mouse Input");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutPassiveMotionFunc(motionPassive);
glutEntryFunc(entry);
if (!init())
return 1;
glutMainLoop();
return 0;
}
I had the same problem [using freeglut] and calling 'draw()' [or whatever display callback you use] right after glutPostRedisplay() in the key callback function forced it to do the redraw. I actually don't know why it behaves like this. After data is changed by keyboard input and the key callback returned, a redraw is expected but not executed.
I am trying to draw a line based on the mouse input coordinates.
The following code compiles, however, a line is not displayed from mouse input.
int coord_1[2]; //(x,y) of first point for line
int coord_2[2]; //(x,y) of second point for line
bool ready_1=false;
bool ready_2=false;
void drawLine()
{
glBegin(GL_LINES);
glColor3f(1.0, 0.0, 0.0);
glVertex2f(coord_1[0], coord_1[1]);
glVertex2f(coord_2[0], coord_2[1]);
glEnd();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1,1,-1,1,-1,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if(ready_1 && ready_2)
{
drawLine();
ready_1 = ready_2 = false;
}
glutSwapBuffers();
}
void mouse(int button, int state, int x, int y)
{
switch (button)
{
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN) //button pressed down
{
//only do something on release
}
if (state == GLUT_UP) //released button
{
cout << "right button up" << endl;
}
break;
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) //button pressed down
{
coord_1[0]=x;
coord_2[1]=y;
cout << "first pos" << endl;
ready_1=true;
}
if (state == GLUT_UP) //released button
{
coord_2[0]=x;
coord_2[1]=y;
cout << "second pos" << endl;
ready_2=true;
}
break;
default:
break;
}
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGBA|GLUT_MULTISAMPLE);
glutInitWindowPosition(100,100);
glutInitWindowSize(512,512);
glutCreateWindow("Asn 1");
glutDisplayFunc(display);
glutIdleFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(processNormalKeys);
// GLUT main loop
glutMainLoop();
return(0);
}
Any help or pointers in the right direction?
You probably draw the line, but since you reset your drawing condition afterwards, your line gets hidden in the next draw step (which might be VERY quick).
Remove the ready_1 = ready_2 = false; and the line should stay visible.
Instead you can set ready_2 = false when you receive a left button down event.
I've successfully written code that takes the (x,y) position of one of my fingers measured by my Leap Motion controller (infrared scanning device that tracks finger and hand movements), and draws a point with similar (x,y) coordinates using OpenGL. Basically, you move your finger, you move the point displayed on the screen.
What I'd like to do now is display the last 100 locations recorded - so, instead of seeing a single point move around, you see a serpentine collection of points that snakes around and follows the movement of your fingertip.
I tried to do this using two vectors - one to hold the x and y position during a given frame, and one to hold a bunch of the previously mentioned vectors. By popping off the first element in the vector after its size goes beyond 100, I figured I could loop through all those points and draw them within my display method.
It compiles fine, but after drawing a few points, I get a runtime error saying "vector iterator not incrementable." Not sure how to deal with that.
Code:
#include <iostream>
#include <fstream>
#include "Leap.h"
#include <math.h>
#include "GL/glut.h"
#include <deque>
using namespace Leap;
using namespace std;
bool one = true;
double x = 10, y = 100;
double screenWidth = 480, screenHeight = 480;
double time, timeDisplayed = 5.0 * (pow(10.0, 9.0));
vector < double > entry, *temp;
vector < vector< double > > collection;
class SampleListener : public Listener {
public:
int firstFrame, firstTime;
bool first;
virtual void onInit(const Controller&);
virtual void onConnect(const Controller&);
virtual void onExit(const Controller&);
virtual void onFrame(const Controller&);
};
void SampleListener::onInit(const Controller& controller){
cout << "Initialized.\n";
first = true;
}
void SampleListener::onConnect(const Controller& controller){
cout << "Connected.\n";
controller.enableGesture(Gesture::TYPE_SCREEN_TAP);
}
void SampleListener::onExit(const Controller& controller){
cout << "Exited.\n";
}
void SampleListener::onFrame(const Controller& controller) {
const Frame frame = controller.frame();
//some initial frame processing/file writing
if (first){
first = !first;
firstFrame = frame.id();
firstTime = frame.timestamp();
}
else {
//record hand information
if (!frame.hands().isEmpty()){
const Hand hand = frame.hands().frontmost();
const Finger track = hand.fingers().frontmost();
x = track.tipPosition().x;
y = track.tipPosition().y;
time = frame.timestamp() - firstTime;
entry.push_back(x);
entry.push_back(y);
entry.push_back(time);
collection.push_back(entry);
entry.clear();
while (collection.size() > 100 && !collection.empty()){
collection.erase(collection.begin());
}
}
}
}
// Create a sample listener and controller
SampleListener listener;
Controller controller;
void display(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_POINTS);
for (auto i = collection.begin(); i != collection.end(); *i++){
cout << collection.size() << endl;
glVertex2f(i->at(0), i->at(1));
}
glEnd();
glFlush();
glutSwapBuffers();
}
void init(){
cout << "in init" << endl;
glClearColor(0.0, 0.0, 0.0, 0.0);
glColor3f(1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-screenWidth/2, screenWidth/2, 0, screenHeight);
glViewport(0, 0, screenWidth, screenHeight);
glPointSize(3.0f);
cout << "leaving init" << endl;
}
void idle(void){
glutPostRedisplay();
}
//<<<<<<<<<<<<<<<<<<<<<<< myKeys >>>>>>>>>>>>>>>>>>>>>>>>
void myKeys(unsigned char key, int x, int y)
{
switch(key)
{
case 'q': // Quit
// Remove the sample listener when done
controller.removeListener(listener);
exit(0);
}
}
int main (int argc, char** argv) {
listener.first = true;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(screenWidth, screenHeight);
glutInitWindowPosition(800, 100);
glutCreateWindow("test");
init();
glutDisplayFunc(display);
glutKeyboardFunc(myKeys);
glutIdleFunc(idle);
controller.addListener(listener);
glutMainLoop();
return 0;
}
If this is threaded, then your collection.erase() in SampleListener::onFrame() would invalidate the iterator in display(). You need a mutex there. Heck, the push_back() could invalidate your iterator. Seems like you want a fixed-length structure with head/tail pointers rather than this dynamic vector.