简体   繁体   中英

OpenGL/GLUT Simple issue in making ride to be smooth

I am almost done with the program that I am asked to do but I am stuck in a very simple logical issue and that is:

  • Increasing the speed of ride smoothly by left click of mouse till we reach a max speed or right click of mouse got hit.

  • Smoothly decrease the speed of ride by right click of mouse till we reach a zero speed or left click of mouse got hit.

I am using signal and speed int variables to achieve my goal but I have 2 problems:

  1. If I use Sleep() function to slow down the finite while loop the program simply freezes and nothing works. If I don't use the Sleep() function simply the movement becomes instant jump and there is no sense of anything is moving at all.
  2. In addition the right and left click of the mouse only works for 2 times and simply they don't work after that.

Screenshot of the program

Any hint would be great.

My Switch statement for mouse:

 switch (button) {
    case GLUT_LEFT_BUTTON:
        signal = 0;
        smothIncrease();
        break;
    case GLUT_MIDDLE_BUTTON:
    case GLUT_RIGHT_BUTTON:
        signal = 1;
        smothDecrease();
        break;
    default:
        break;
    }

Helper functions:

void smothIncrease(){
    while (true){
        if (signal == 0){
            if (speed == 15)
                break;
            angle++;
            speed++;
            Sleep(15);
            glutPostRedisplay();
        }
        else if (signal == 1)
            break;
    }
}


void smothDecrease(){
    while (true){
        if (signal == 1){
            if (speed == 0)
                break;
            angle--;
            speed--;
            Sleep(15);
            glutPostRedisplay();
        }
        else if (signal == 0)
            break;
    }
}

Here is the complete source code:

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#define PI 3.14159265

static GLfloat lpos[] = { 0.0, 5.0, 4.0, 1.0 };
static GLfloat black[] = { 0.0, 0.0, 0.0, 1.0 };
static GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
static GLfloat red[] = { 1.0, 0.0, 0.0, 1.0 };
static GLfloat lightgreen[] = { 0.5, 1.0, 0.5, 1.0 };
static float alpha = 0.0;
static float beta = PI / 6.0;
static float zoom = 25.0;
static bool lightSource = true;

float numberOfTriangles = 1;
static GLdouble cpos[3];

static double fenceHeight = -0.5;
static int angle = 0;
static int angle__IN_RANGE = 0.0;
static double radian__IN_RANGE = 0.0;
static int arrayOfAnglesInRange[181];
static int id = 0;

static int speed = 0;
static int signal = 0;

void writemessage()
{
}

void processAngle(){
    angle__IN_RANGE = arrayOfAnglesInRange[abs(angle) % 181];
}

void setRadian_IN_RANGE(){
    radian__IN_RANGE = ((float)angle__IN_RANGE / 180) * PI;
}

void fillArray(){
    int j = -45;
    for (int i = 0; i < 181; i++)
    {
        if (i < 90)
            arrayOfAnglesInRange[i] = j++;
        else
            arrayOfAnglesInRange[i] = j--;
    }

    //for (int i = 0; i < 182; i++)
    //{
    //  printf("%d\n", arrayOfAnglesInRange[i]);
    //}
}

void keepTrackOfID(){
    int tempAngle = angle;

    //if (id % 4 == 0)
    //  angle += 0;
    //else if (id % 4 == 1)
    //  angle += 60;
    //else if (id % 4 == 2)
    //  angle += 120;
    //else if (id % 4 == 3)
    //  angle += 180;

    //if (id % 4 == 0)
    //  angle += 0;
    //else if (id % 4 == 1)
    //  angle += 45;
    //else if (id % 4 == 2)
    //  angle += 90;
    //else if (id % 4 == 3)
    //  angle += 135;

    if (id % 4 == 0)
        angle += 0;
    else if (id % 4 == 1)
        angle += 30;
    else if (id % 4 == 2)
        angle += 60;
    else if (id % 4 == 3)
        angle += 90;

    processAngle();
    setRadian_IN_RANGE();
    angle = tempAngle;
}

void smothIncrease(){
    while (true){
        if (signal == 0){
            if (speed == 15)
                break;
            angle++;
            speed++;
            Sleep(15);
            glutPostRedisplay();
        }
        else if (signal == 1)
            break;
    }
}


void smothDecrease(){
    while (true){
        if (signal == 1){
            if (speed == 0)
                break;
            angle--;
            speed--;
            Sleep(15);
            glutPostRedisplay();
        }
        else if (signal == 0)
            break;
    }
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.01, 50.0);
    glMatrixMode(GL_MODELVIEW);
}

void DrawSticksArroundYard(){
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
    glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, black);
    GLUquadricObj *quadObj;

    // Right-Line
    glPushMatrix();
    glTranslatef(6.8, 1.0 + fenceHeight, -7.0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.1, 0.1, 14.0, 10, 10);
    glPopMatrix();

    // Left-Line
    glPushMatrix();
    glTranslatef(-6.8, 1.0 + fenceHeight, -7.0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.1, 0.1, 14.0, 10, 10);
    glPopMatrix();

    // Back-Line
    glPushMatrix();
    glTranslatef(-6.8, 1.0 + fenceHeight, -7.0);
    glRotatef(90, 0, 1, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.1, 0.1, 13.7, 10, 10);
    glRotatef(-90, 0, 1, 0);
    glPopMatrix();

    // Front-Line
    glPushMatrix();
    glTranslatef(6.8, 1.0 + fenceHeight, 7.0);
    glRotatef(-90, 0, 1, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.1, 0.1, 13.7, 10, 10);
    glRotatef(90, 0, 1, 0);
    glPopMatrix();

    // Pin-Front-Right
    glPushMatrix();
    glTranslatef(6.8, 0, 7.0);
    glRotatef(-90, 1, 0, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.1, 1.3 + fenceHeight, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();

    // Pin-Front-Left
    glPushMatrix();
    glTranslatef(-6.8, 0, 7.0);
    glRotatef(-90, 1, 0, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.1, 1.3 + fenceHeight, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();

    // Pin-Back-Left
    glPushMatrix();
    glTranslatef(-6.8, 0, -7.0);
    glRotatef(-90, 1, 0, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.1, 1.3 + fenceHeight, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();

    // Pin-Back-Right
    glPushMatrix();
    glTranslatef(6.8, 0, -7.0);
    glRotatef(-90, 1, 0, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.1, 1.3 + fenceHeight, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();

    // Pin-Back-Center
    glPushMatrix();
    glTranslatef(0, 0, -7.0);
    glRotatef(-90, 1, 0, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.1, 1.3 + fenceHeight, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();

    // Pin-Front-Center
    glPushMatrix();
    glTranslatef(0, 0, 7.0);
    glRotatef(-90, 1, 0, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.1, 1.3 + fenceHeight, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();

    // Pin-Right-Center
    glPushMatrix();
    glTranslatef(6.8, 0, 0);
    glRotatef(-90, 1, 0, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.1, 1.3 + fenceHeight, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();

    // Pin-Left-Center
    glPushMatrix();
    glTranslatef(-6.8, 0, 0);
    glRotatef(-90, 1, 0, 0);
    quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.1, 1.3 + fenceHeight, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();
}

void DrawYardFloor(){
    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lightgreen);
    glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, lightgreen);
    glBegin(GL_POLYGON);
    glNormal3f(0, 1, 0);
    glVertex3f(-7.3, -0.005, -7.3);
    glVertex3f(-7.3, -0.005, 7.3);
    glVertex3f(7.3, -0.005, 7.3);
    glVertex3f(7.3, -0.005, -7.3);
    glEnd();
}

void DrawCenterPin(){
    glRotatef(-90, 1, 0, 0);
    GLUquadricObj *quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.2, 7, 10, 10);
    glRotatef(90, 1, 0, 0);
}

void DrawBase(){
    glRotatef(-90, 1, 0, 0);
    GLUquadricObj *quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.5, 0.1, 2, 10, 10);
    glRotatef(90, 1, 0, 0);

}

void DrawTop(){
    glPushMatrix();
    glTranslatef(0, 7, 0);
    glRotatef(-90, 1, 0, 0);
    GLUquadricObj *quadObj = gluNewQuadric();
    gluCylinder(quadObj, 0.2, 0.0, 0.5, 10, 10);
    glRotatef(90, 1, 0, 0);
    glPopMatrix();
}


void DrawHorizontalStick(){
    glLineWidth(15);
    glColor3f(1.0, 0.0, 0.0);
    glBegin(GL_LINES);
    glVertex3f(0.0, 7.0, 0.0);
    glVertex3f(4.0 * cos(radian__IN_RANGE), 7.0 + 3.0 * sin(radian__IN_RANGE), 0.0);
    glEnd();
}

void DrawVerticalStick(){
    glLineWidth(5);
    glColor3f(1.0, 0.0, 0.0);
    glBegin(GL_LINES);
    glVertex3f(4.0 * cos(radian__IN_RANGE), 7.0 + 3.0 * sin(radian__IN_RANGE), 0.0);
    glVertex3f(4.0 * cos(radian__IN_RANGE), 7.0 + 3.0 * sin(radian__IN_RANGE) - 1, 0.0);
    glEnd();
}

void DrawCabin(){

    // Back
    glNormal3f(0.0, 0.0, -1.0);
    glBegin(GL_POLYGON);
    glVertex3f(0, 0, -1);
    glVertex3f(0, 1, -1);
    glVertex3f(2, 1, -1);
    glVertex3f(2, 0, -1);
    glEnd();

    glNormal3f(0.0, 0.0, -1.0);
    glBegin(GL_POLYGON);
    glVertex3f(0, 1.7, -1);
    glVertex3f(0, 2, -1);
    glVertex3f(2, 2, -1);
    glVertex3f(2, 1.7, -1);
    glEnd();

    glNormal3f(0.0, 0.0, -1.0);
    glBegin(GL_POLYGON);
    glVertex3f(0, 1, -1);
    glVertex3f(0, 1.7, -1);
    glVertex3f(0.2, 1.7, -1);
    glVertex3f(0.2, 1, -1);
    glEnd();

    glNormal3f(0.0, 0.0, -1.0);
    glBegin(GL_POLYGON);
    glVertex3f(1.8, 1, -1);
    glVertex3f(1.8, 1.7, -1);
    glVertex3f(2, 1.7, -1);
    glVertex3f(2, 1, -1);
    glEnd();


    // Front
    glNormal3f(0.0, 0.0, 1.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 0, 1);
    glVertex3f(2, 1, 1);
    glVertex3f(0, 1, 1);
    glVertex3f(0, 0, 1);
    glEnd();

    glNormal3f(0.0, 0.0, 1.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 1.7, 1);
    glVertex3f(2, 2, 1);
    glVertex3f(0, 2, 1);
    glVertex3f(0, 1.7, 1);
    glEnd();

    glNormal3f(0.0, 0.0, 1.0);
    glBegin(GL_POLYGON);
    glVertex3f(0.2, 1, 1);
    glVertex3f(0.2, 1.7, 1);
    glVertex3f(0, 1.7, 1);
    glVertex3f(0, 1, 1);
    glEnd();

    glNormal3f(0.0, 0.0, 1.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 1, 1);
    glVertex3f(2, 1.7, 1);
    glVertex3f(1.8, 1.7, 1);
    glVertex3f(1.8, 1, 1);
    glEnd();


    // Floor
    glNormal3f(0.0, -1.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 0, -1);
    glVertex3f(2, 0, 1);
    glVertex3f(0, 0, 1);
    glVertex3f(0, 0, -1);
    glEnd();


    // Top
    glNormal3f(0.0, 1.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 2, 1);
    glVertex3f(2, 2, -1);
    glVertex3f(0, 2, -1);
    glVertex3f(0, 2, 1);
    glEnd();

    // Right
    glNormal3f(1.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 0, -1);
    glVertex3f(2, 1, -1);
    glVertex3f(2, 1, 1);
    glVertex3f(2, 0, 1);
    glEnd();

    glNormal3f(1.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 1.7, -1);
    glVertex3f(2, 2, -1);
    glVertex3f(2, 2, 1);
    glVertex3f(2, 1.7, 1);
    glEnd();

    glNormal3f(1.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 1, -1);
    glVertex3f(2, 1.7, -1);
    glVertex3f(2, 1.7, -0.8);
    glVertex3f(2, 1, -0.8);
    glEnd();

    glNormal3f(1.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(2, 1, 0.8);
    glVertex3f(2, 1.7, 0.8);
    glVertex3f(2, 1.7, 1);
    glVertex3f(2, 1, 1);
    glEnd();

    // Left
    glNormal3f(-1.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(0, 0, -1);
    glVertex3f(0, 0, 1);
    glVertex3f(0, 1, 1);
    glVertex3f(0, 1, -1);
    glEnd();

    glNormal3f(-1.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(0, 1.7, -1);
    glVertex3f(0, 1.7, 1);
    glVertex3f(0, 2, 1);
    glVertex3f(0, 2, -1);
    glEnd();

    glNormal3f(-1.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(0, 1, -1);
    glVertex3f(0, 1, -0.8);
    glVertex3f(0, 1.7, -0.8);
    glVertex3f(0, 1.7, -1);
    glEnd();

    glNormal3f(-1.0, 0.0, 0.0);
    glBegin(GL_POLYGON);
    glVertex3f(0, 1, 0.8);
    glVertex3f(0, 1, 1);
    glVertex3f(0, 1.7, 1);
    glVertex3f(0, 1.7, 0.8);
    glEnd();
}

void darwCabin__FINAL(){
    glPushMatrix();
    glTranslatef(4.0 * cos(radian__IN_RANGE), 7.0 + 3.0 * sin(radian__IN_RANGE) - 3, 0.0);
    glRotatef(angle, 0, 1, 0);
    glPushMatrix();
    glTranslatef(-1, 0, 0);
    DrawCabin();
    glPopMatrix();
    glRotatef(-angle, 0, 1, 0);
    glPopMatrix();
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 64);
    cpos[0] = zoom * cos(beta) * sin(alpha);
    cpos[1] = zoom * sin(beta);
    cpos[2] = zoom * cos(beta) * cos(alpha);
    gluLookAt(cpos[0], cpos[1], cpos[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    if (lightSource == true){
        glLightfv(GL_LIGHT0, GL_POSITION, lpos);
        glMaterialfv(GL_FRONT, GL_EMISSION, white);
        glPushMatrix();
        glTranslatef(lpos[0], lpos[1], lpos[2]);
        glutSolidSphere(0.1, 10, 8);
        glPopMatrix();
        glMaterialfv(GL_FRONT, GL_EMISSION, black);
    }

    DrawYardFloor();
    DrawSticksArroundYard();
    DrawCenterPin();
    DrawBase();
    DrawTop();

    glRotatef(angle, 0, 1, 0);
    for (int i = 0; i < 4; i++){
        glPushMatrix();
        glRotatef(i * 360 / 4, 0, 1, 0);
        keepTrackOfID();

        DrawHorizontalStick();
        DrawVerticalStick();
        darwCabin__FINAL();

        id++;
        glPopMatrix();
    }
    glRotatef(-angle, 0, 1, 0);

    glutSwapBuffers();
    glFlush();
}


void keyboard(unsigned char key, int x, int y)
{
    static int polygonmode[2];

    switch (key) {
    case 27:
        exit(0);
        break;
    case 'x':
        if (lightSource == true)
            lpos[0] = lpos[0] + 0.2;
        glutPostRedisplay();
        break;
    case 'X':
        if (lightSource == true)
            lpos[0] = lpos[0] - 0.2;
        glutPostRedisplay();
        break;
    case 'y':
        if (lightSource == true)
            lpos[1] = lpos[1] + 0.2;
        glutPostRedisplay();
        break;
    case 'Y':
        if (lightSource == true)
            lpos[1] = lpos[1] - 0.2;
        glutPostRedisplay();
        break;
    case 'z':
        if (lightSource == true)
            lpos[2] = lpos[2] + 0.2;
        glutPostRedisplay();
        break;
    case 'Z':
        if (lightSource == true)
            lpos[2] = lpos[2] - 0.2;
        glutPostRedisplay();
        break;

    case '+':
        if (zoom != 1.5)zoom = zoom - 0.5;
        glutPostRedisplay();
        break;
    case '-':
        if (zoom != 30)zoom = zoom + 0.5;
        glutPostRedisplay();
        break;
    case '0':
        if (lightSource == true){
            glDisable(GL_LIGHT0);
            lightSource = false;
        }
        else{
            glEnable(GL_LIGHT0);
            lightSource = true;
        }
        glutPostRedisplay();
        break;

    case 'e':
        if (fenceHeight < 2)
            fenceHeight += 0.5;
        glutPostRedisplay();
        break;
    case 'd':
        if (fenceHeight > -0.5)
            fenceHeight -= 0.5;
        glutPostRedisplay();
        break;

    case 'w':
        glGetIntegerv(GL_POLYGON_MODE, polygonmode);
        if (polygonmode[0] == GL_FILL)
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glutPostRedisplay();
        break;
    case 'n':
        angle++;
        processAngle();
        setRadian_IN_RANGE();
        glutPostRedisplay();
        break;
    case 'm':
        angle--;
        processAngle();
        setRadian_IN_RANGE();
        glutPostRedisplay();
        break;
    default:
        break;
    }
}

void mouse(int button, int state, int x, int y)
{
    switch (button) {
    case GLUT_LEFT_BUTTON:
        signal = 0;
        smothIncrease();
        break;
    case GLUT_MIDDLE_BUTTON:
    case GLUT_RIGHT_BUTTON:
        signal = 1;
        smothDecrease();
        break;
    default:
        break;
    }
}

void specialkey(GLint key, int x, int y)
{
    switch (key) {
    case GLUT_KEY_RIGHT:
        alpha = alpha + PI / 180;
        if (alpha > 2 * PI) alpha = alpha - 2 * PI;
        glutPostRedisplay();
        break;
    case GLUT_KEY_LEFT:
        alpha = alpha - PI / 180;
        if (alpha < 0) alpha = alpha + 2 * PI;
        glutPostRedisplay();
        break;
    case GLUT_KEY_UP:
        if (beta < 0.45*PI) beta = beta + PI / 180;
        glutPostRedisplay();
        break;
    case GLUT_KEY_DOWN:
        if (beta > -0.05*PI) beta = beta - PI / 180;
        glutPostRedisplay();
        break;
    default:
        break;
    }
}


int main(int argc, char** argv)
{
    writemessage();
    fillArray();
    processAngle();
    setRadian_IN_RANGE();
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(1200, 800);
    glutInitWindowPosition(0, 0);
    glutCreateWindow(argv[0]);

    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);

    /* initially GL_FILL mode (default), later GL_LINE to show wireframe */
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    glEnable(GL_LIGHTING);
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
    glEnable(GL_LIGHT0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 5.0, 10.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0);

    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMouseFunc(mouse);
    glutKeyboardFunc(keyboard);
    glutSpecialFunc(specialkey);
    glutMainLoop();
    return 0;
}

There are several problems with your code, I'll explain as I spot them.

First thing is that you're using int data type for all your variables (such as speed and angle), and you won't get anything smooth using integer, so you should change all those ints to float .

glutPostRedisplay will only mark your frame to be rendered again. In other words, the function will return immediately and nothing would happen until the next render frame event. The Sleep call makes your process freeze (it will interrupt any processing in your program including the glut render loop). There's no need to put an while loop on this function since you cannot control the render loop this way.

You should have a new variable to control the speed change, and in your display function you should change the speed of the movement. Your new smothIncrease may look like this:

float speedChange = 0.0f;
void smothIncrease(){
    speedChange += 1.0f; // you may want to have other increment factor
    glutPostRedisplay();

}

And in your display function you should change the speed by the factor you just incremented:

if (speed < 15.0f)
    speed += speedChange;

But this way how do we redraw the frame when there's no event happening (mouse click, key press)? The best approach I know is to set an idle function and on this idle function just call glutPostRedisplay . This will guarantee your window is always being updated.

Take a look on those links

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM