Skip to main content
gamedev.net
🔒 Locked

rotational problem

Started by sergzone Feb 24, 2008 at 2:02 AM 0 replies 450+ views
Original Post
sergzone
sergzone
Hey guys. I wrote the following code that generates a clock. I'm reading system time, calculating angle for minute/hour hand and rotating them accordingly. My problem is that when i attempt to rotate my viewing volume, my minute hand keeps rotating around the z-axis and goes inside the clock. This happens with the minute hand only. When i remove glLoadIdentity() before i start drawing the minute hand, it appears okay, but my minute hand is no longer displaying at the right angle. This is why i initially added glLoadIdentity() because i figured something must be accumulating in the matrix. Does anybody have any suggestions? Thanks!

#include <gl/glut.h>
#include <iostream>
#include <math.h>
#include <time.h>

// Function prototypes
void mDisplay();
void mReshape(int prmWidth, int prmHeight);
void mInit();
void mTimer(int value);
void mCalculateTime();
void mKey(unsigned char prmKey, int prmX, int prmY);
void mDrawFillCircle(GLfloat prmX, 
                     GLfloat prmY, 
                     GLfloat prmRadius);
void mDrawCylinder(GLfloat prmArc, 
                   GLfloat prmRadius, 
                   GLfloat prmHeight, 
                   GLint prmSlices, 
                   GLint prmStacks);

// Enable/Disable wireframe view
const bool USE_WIREFRAME = false;

// Initial minute/hour hand angles
float thetaHour = 90;
float thetaMin = 90;

int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(600, 600);
    glutCreateWindow("Clock");

    mInit();
    mCalculateTime();

    glutTimerFunc(10, mTimer, 0);
    glutDisplayFunc(mDisplay);
    glutReshapeFunc(mReshape);
    glutKeyboardFunc(mKey);
    glutMainLoop();
    return 0;
}

/**
 * mTimer()
 * Precondition:    value != null
 * Postcondition:   mCalculateTime() is called.
 */
void mTimer(int value)
{
    glLoadIdentity();

	mCalculateTime();
    mDisplay();

	glutTimerFunc(10, mTimer, 0);
	glutPostRedisplay();
}

/**
 * mCalculateTime()
 * Precondition:    none
 * Postcondition:   System time is retrieved and the new minute/hour 
 *                  hand angles are calculated.
 */
void mCalculateTime()
{
	time_t tval = time(0);
    struct tm *tm_struct = localtime(&tval);

    thetaHour = 30 * tm_struct->tm_hour + tm_struct->tm_min / 2 + tm_struct->tm_sec / 120;
    thetaMin = 6 * tm_struct->tm_min + tm_struct->tm_sec / 10;
}

/**
 * mDisplay()
 * Precondition:    none
 * Postcondition:   Clock is drawn.
 */
void mDisplay()
{
    // Initialize viewing volume
    glClearColor(0,0,0,0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    // Draw bottom disk
    glColor3d(0.1,0.4,0.6);
    mDrawFillCircle(0.0,0.0,300.0);

    // Draw cylinder sides
    glColor3d(0.8,0.1,0.6);
    mDrawCylinder(360.0,300.0,76.0,40.0,40.0);

    // Move to the top of the cylinder
    glTranslatef(0.0, 0.0, 76.0);

    // Draw top disk
    glColor3d(0.4,0.3,0.4);
    mDrawFillCircle(0.0,0.0,300.0);

    // Rotate hour hand
    glRotatef(-thetaHour,0.0,0.0,1.0);

    // Draw hour hand
	glBegin(GL_QUADS);
        // Front (center)
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(-5.0,0.0,-80.0);
	    glVertex3f(5.0,0.0,-80.0);
	    glVertex3f(5.0,0.0,-86.0);
	    glVertex3f(-5.0,0.0,-86.0);

        // Right side
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(5.0,0.0,-86.0);
	    glVertex3f(5.0,0.0,-80.0);
	    glVertex3f(5.0,143.0,-80.0);
	    glVertex3f(5.0,143.0,-86.0);

        // Front (far)
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(5.0,143.0,-80.0);
	    glVertex3f(-5.0,143.0,-80.0);
	    glVertex3f(-5.0,143.0,-86.0);
	    glVertex3f(5.0,143.0,-86.0);

        // Left side
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(-5.0,143.0,-80.0);
	    glVertex3f(-5.0,0.0,-80.0);
	    glVertex3f(-5.0,0.0,-86.0);
	    glVertex3f(-5.0,143.0,-86.0);

        // Bottom
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(5.0,0.0,-80.0);
	    glVertex3f(-5.0,0.0,-80.0);
	    glVertex3f(-5.0,143.0,-80.0);
	    glVertex3f(5.0,143.0,-80.0);

        // Top
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(5.0,0.0,-86.0);
	    glVertex3f(-5.0,0.0,-86.0);
	    glVertex3f(-5.0,143.0,-86.0);
	    glVertex3f(5.0,143.0,-86.0);
	glEnd();

    // Move 10 units up
    glTranslatef(0.0,0.0,-10);

    // Clear identity matrix
    glLoadIdentity();

    // Rotate minute hand
    glRotatef(-thetaMin,0.0,0.0,1.0);

    // Draw minute hand
	glBegin(GL_QUADS);
        // Front (center)
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(-5.0,0.0,-80.0);
	    glVertex3f(5.0,0.0,-80.0);
	    glVertex3f(5.0,0.0,-86.0);
	    glVertex3f(-5.0,0.0,-86.0);

        // Right side
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(5.0,0.0,-86.0);
	    glVertex3f(5.0,0.0,-80.0);
	    glVertex3f(5.0,212.0,-80.0);
	    glVertex3f(5.0,212.0,-86.0);

        // Front (far)
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(5.0,212.0,-80.0);
	    glVertex3f(-5.0,212.0,-80.0);
	    glVertex3f(-5.0,212.0,-86.0);
	    glVertex3f(5.0,212.0,-86.0);

        // Left side
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(-5.0,212.0,-80.0);
	    glVertex3f(-5.0,0.0,-80.0);
	    glVertex3f(-5.0,0.0,-86.0);
	    glVertex3f(-5.0,212.0,-86.0);

        // Bottom
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(5.0,0.0,-80.0);
	    glVertex3f(-5.0,0.0,-80.0);
	    glVertex3f(-5.0,212.0,-80.0);
	    glVertex3f(5.0,212.0,-80.0);

        // Top
	    glColor3f(0.0,1.0,0.0);
	    glVertex3f(5.0,0.0,-86.0);
	    glVertex3f(-5.0,0.0,-86.0);
	    glVertex3f(-5.0,212.0,-86.0);
	    glVertex3f(5.0,212.0,-86.0);
	glEnd();

    glFlush();
    glutSwapBuffers();
}

/**
 * mReshape()
 * Precondition:    prmWidth > 0 and prmHeight > 0
 * Postcondition:   Clock is redrawn on window resize event.
 */
void mReshape(int prmWidth, int prmHeight)
{
    glViewport(0, 0, prmWidth, prmWidth);
    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    glOrtho(-300.0,300.0,-300.0,300.0,300.0,-300.0);
    glMatrixMode(GL_MODELVIEW);
}

/**
 * mInit()
 * Precondition:    none
 * Postcondition:   Viewing volume is initialized.
 */
void mInit()
{
    if (USE_WIREFRAME)
    {
        glPolygonMode(GL_FRONT, GL_LINE);
        glPolygonMode(GL_BACK, GL_LINE);
    }
    
    glEnable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    glOrtho(-300,300,-300,300,300,-300);
    glMatrixMode(GL_MODELVIEW);
}

/**
 * mKey()
 * Precondition:    prmKey != null
 * Postcondition:   Program exits.
 */
void mKey(unsigned char prmKey, int prmX, int prmY)
{
    if (prmKey == 'q') exit(0);
}

/**
 * mDrawFillCircle()
 * Precondition:    None
 * Postcondition:   Draws a filled circle.
 */
void mDrawFillCircle(GLfloat prmX, GLfloat prmY, GLfloat prmRadius)
{
    // Surface point
    GLfloat vectorSurfX1 = prmX + prmRadius;
    GLfloat vectorSurfY1 = prmY;

    // Previous surface point
    GLfloat vectorSurfX2;
    GLfloat vectorSurfY2;

    // Start point angle
    GLfloat angle;

    // Constants
    const GLfloat ANGLESTEP = 0.23;
    const GLfloat PI = 3.14159;
    const GLfloat ANGLETOTAL = 2.0 * PI + ANGLESTEP;

    glBegin(GL_TRIANGLES);
    
    for (angle = ANGLESTEP; angle < ANGLETOTAL; angle += ANGLESTEP)
    {
        // Save previous position
        vectorSurfX2 = vectorSurfX1;
        vectorSurfY2 = vectorSurfY1;

        // Calculate next point
        vectorSurfX1 = prmX + prmRadius * cos(angle);
        vectorSurfY1 = prmY + prmRadius * sin(angle);

        // Plot points
        glVertex2d(prmX, prmY);
        glVertex2d(vectorSurfX2, vectorSurfY2);
        glVertex2d(vectorSurfX1, vectorSurfY1);
    }

    glEnd();
    glFlush();
}

/**
 * mDrawCylinder()
 * Precondition:    None
 * Postcondition:   Draws cylinder sides.
 */
void mDrawCylinder(GLfloat prmArc, 
                   GLfloat prmRadius, 
                   GLfloat prmHeight, 
                   GLint prmSlices, 
                   GLint prmStacks)
{
    // Loop variables
    GLint stackCnt;
    GLint sliceCnt;

    // Angle/Height
    GLfloat angle;
    GLfloat height;

    // Constants
    const GLfloat stackHeight = prmHeight/prmStacks;
    const GLfloat PI = 3.14159;
    const GLfloat radian = PI/180;

    for (stackCnt = 0; stackCnt < prmStacks; stackCnt++)
    {
        height = prmHeight * stackCnt / prmStacks;
        glBegin(GL_QUAD_STRIP);

        for (sliceCnt = 0; sliceCnt <= prmSlices; sliceCnt++)
        {
            angle = prmArc * sliceCnt/prmSlices * radian;
            glNormal3f(cos(angle), sin(angle), 0.0);

            glVertex3d(cos(angle) * prmRadius, 
                       sin(angle) * prmRadius, 
                       height);
            glVertex3d(cos(angle) * prmRadius, 
                       sin(angle) * prmRadius, 
                       height + prmHeight);
        }

        glEnd();
        glFlush();
    }
}

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.