Search code examples
c++openglglutopengl-compat

How to fix zoom in & out with mouse scroll wheel?


I'm trying to make a program where I'm able to zoom in & out on the figures I've drawn, but is not doing it; it's switching the orientation of the figures and if I keep scrolling, it just disappears. The function that are suppose to be executed for this to work are the MouseFunc() along with the renderScene(). Any explanation for the problem or help is welcomed.

#include"glut.h"
#include<cmath>
#include<iostream>
using namespace std;

float xr = 0, yr = 0; //to control the object's movement from left to right

// XZ position of the camera
float x = 0.0f, z = 5.0f; //Module 4
float angleX = 0.0f; //Module 4

//Shift + ArrowKey rotation
float transX = 0.0f;
float transY = 0.0f;
float rotY = 0.0f;
//end

//Mouse Commands
//float ZoomFactor = 0.5;
GLfloat theta3 = 0;
GLfloat phi = 0;
GLfloat rho = 5;

GLfloat camX = 0;
GLfloat camY = 0;
GLfloat camZ = 0;
GLfloat upX = 0;
GLfloat upY = 0;
GLfloat upZ = 0;
//end

GLfloat angle = 0.0f;
int refreshmill = 1;

void timer(int value) { //to control the rotation of the object
    glutTimerFunc(refreshmill, timer, 0);
}

void myDisplay(void) {
    //Circle One
    float theta;
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1, 0, 0);

    glPushMatrix();
    glBegin(GL_POLYGON);
    for (int x = 0; x < 360; x++) {
        theta = x * 3.142 / 180;
        glVertex2f(150 * cos(theta) + xr, 150 * sin(theta) + yr);
    }
    glEnd();
    glPopMatrix();

    //Circle Two
    float theta2;

    glPushMatrix();
    glTranslatef(0.5f, 0.0f, 0.0f); // rotation
    glRotatef(angle, 0.0f, 0.0f, -0.5f); // rotation
    glBegin(GL_POLYGON);
    glColor3f(0, 0, 1);
    for (int x = 0; x < 360; x++) {
        theta2 = x * 3.142 / 180;
        glVertex2f(150 + 15 * cos(theta2) + xr, 15 * sin(theta2) + yr);
    }

    angle += 0.2; // rotation
    glEnd();
    glPopMatrix();

    //Draw Star
    glColor3ub(119, 193, 15);

    glPushMatrix();
    glBegin(GL_POLYGON);
    glVertex2d(15 + xr, 60 + yr);
    glVertex2d(75 + xr, 75 + yr); //right peak
    glVertex2d(15 + xr, 90 + yr);
    glVertex2d(0 + xr, 150 + yr); //Up-peak Changed
    glVertex2d(-15 + xr, 90 + yr);
    glVertex2d(-75 + xr, 75 + yr);
    glVertex2d(-15 + xr, 60 + yr);
    glVertex2d(0 + xr, 0 + yr);
    glEnd();
    glPopMatrix();
}

//Close code
void handleKeypress(unsigned char key, int x, int y){
    switch (key){
    case 27: //when the escape key is pressed the program will exit.
        exit(0);
    }
}

//Movement of drawing
void keyboard(int key, int x, int y) {

    float fraction = 0.1f;
    bool shift = false;
    int mod = glutGetModifiers();
    if (mod == GLUT_ACTIVE_SHIFT) {
        shift = true;
    }
    if (!shift) {
        switch (key) {

        case GLUT_KEY_RIGHT: xr++; break;
        case GLUT_KEY_LEFT:  xr--; break;
        case GLUT_KEY_UP:    angleX -= 1.0f; break; //Module 4
        case GLUT_KEY_DOWN:  angleX += 1.0f; break; //Module 4
        }
    }
    else {
        switch (key) {

        case GLUT_KEY_LEFT:// Rotación del dibujo hacia la izquierda en el eje de Y
            rotY -= 1.0f;
            break;
        case GLUT_KEY_RIGHT:// Rotación del dibujo hacia la derecha en el eje de Y
            rotY += 1.0f;
            break;
        }
    }
}

//Mouse Function
void MouseFunc(int button, int state, int x, int y){
    if (button > 4){
        rho = rho + 3.0;
    }
    else (button < 3);{
        rho = rho - 3.0;
    }
}

void renderScene(void) {

    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(0.0, 1.0, 0.0);
    glRotatef(rotY, 0.0, 1.0, 0.0); //Rotation with Shift + ArrowKey

    GLfloat camX = rho * cos(theta3*3.1415926f / 180)*sin(phi*3.1415926f / 180);
    GLfloat camY = rho * sin(theta3*3.1415926f / 180);
    GLfloat camZ = rho * cos(theta3*3.1415926f / 180)*cos(phi*3.1415926f / 180);

    // Reduce theta slightly to obtain another point on the same longitude line on the sphere.
    GLfloat dt = 1;
    GLfloat eyeXtemp = -rho * cos((theta3 - dt)*3.1415926f / 180)*sin(phi*3.1415926f / 180);
    GLfloat eyeYtemp = -rho * sin((theta3 - dt)*3.1415926f / 180);
    GLfloat eyeZtemp = -rho * cos((theta3 - dt)*3.1415926f / 180)*cos(phi*3.1415926f / 180);

    // Connect these two points to obtain the camera's up vector.
    GLfloat upX = eyeXtemp - camX;
    GLfloat upY = eyeYtemp - camY;
    GLfloat upZ = eyeZtemp - camZ;

    // Clear Color and Depth Buffers
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Reset transformations
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // Set the camera
    gluLookAt(camX, camY, camZ, 0, 0, 0, upX, upY, upZ);
    gluLookAt(x, 0.0f, z, x, 0.0f, z - 1.0f, 0.0f, 1.0f, 0.0f); //Module 4
    glRotatef(angleX, 1, 0, 0); //Module 4

    myDisplay();

    glFlush();
    glutPostRedisplay();
    glutSwapBuffers();
}

void init() {
    glClearColor(0, 0, 0, 1);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(0.0f, 0.1f, 0.1f, 0.0f);
    glOrtho(-250, 250, -250, 250, -250, 250); //IMPORTANT- Define from negative to positive
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv) {
    // init GLUT and create window
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Homework: Circle");
    // register callbacks
    glutDisplayFunc(renderScene);
    glutTimerFunc(0,timer,0);
    glutKeyboardFunc(handleKeypress);
    glutSpecialFunc(keyboard);
    glutMouseFunc(MouseFunc);
    // OpenGL init
    init();
    // enter GLUT event processing cycle
    glutMainLoop();
}

Solution

  • Is wired to set a perspective and an orthographic projection. Delete the perspective projection gluPerspective:

    void init() {
        glClearColor(0, 0, 0, 1);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
    
        //gluPerspective(0.0f, 0.1f, 0.1f, 0.0f); <---- delete
    
        glOrtho(-250, 250, -250, 250, -250, 250);
        glMatrixMode(GL_MODELVIEW);
    }
    

    If you want to zoom, the the orthographic projection has to be changed (glOrtho). The projection matrix describes the mapping from 3D points of a scene, to 2D points of the viewport.

    Implement a mouse wheel event, which changes the zoom, in a restricted range:

    e.g.

    GLdouble zoom = 0.0f;
    void MouseFunc(int button, int state, int x, int y){
    
        GLdouble min_z = -100.0;
        GLdouble max_z = 100.0;
    
        if (button == 4 && zoom < max_z) {
            zoom += 3.0;
        }
        else if (button == 3 && zoom > min_z) {
            zoom -= 3.0;
        }
    }
    

    Modify the orthographic projection, dependent on the zoom in the display loop renderScene:

    void renderScene(void) {
    
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
    
        GLdouble ortho = 250 + zoom;
        glOrtho(-ortho, ortho, -ortho, ortho, -250, 250);
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
    
        // [...]
    }