creating a rotating car - I'm terrible at this!!

Hey everyone,

so I’m just starting out with OpenGL here and I’m just awful at it.
My first assignment is to draw a rotating car with 4 wheels with spokes. The car is supposed to rotate around a plane (my choosing) and the user should be able to control the speed of the wheels and the direction of the car with the arrow keys. The assignment should be done without GLUT and without glRotate(), glTranslate(), glScale()

The thing is, I just cant get a grasp on a few things:

  1. lighting - when lighting is enabled the wheel colors become all distorted. Am I doing something wrong with calculating the normals? I’m not really sure how the rules apply for approximating a wheel?
  2. Viewing? I just can’t get a handle on this. When viewed from the side using something like
gluLookAt(0,0,1,0.5,0.5,0,0,1,0);

The car looks extremely distorted (car is a loose term here :slight_smile: )
3. When I try to rotate the car around the y axis relative to the car center being the origin it looks terrible!!

Anyway, this is my first post and hope to get a grip here on things so I can become more active. Here’s my code attached. Please be gentle but do feel free to provide constructive criticism that will help me (just don’t tell me it sucks… I know it sucks :wink: )

P.S. the Vector headers here are from my teacher and they have been debugged and known to be error free. Also please do let me know if I’m violating any forum rules (not using correct tags etc) and I’ll make an effort to alter my following posts



/* 
 * File:   main.cpp
 *
 * Created on February 10, 2011, 4:53 PM
 */

#include <iostream>
#include <GLUT/glut.h>
#include <math.h>
#include "cvec3t.h"
#include "cvec2t.h"
using namespace std;


typedef CVec3T<float> Vec3f;
typedef CVec2T<float> Vec2f;

namespace Params {
    const float WorldWidth = 1;
    const float WorldHeight = 1;
    const int TimerStep = 16;
};

namespace WindowParams {
    static int WindowWidth = 600;
    static int WindowHeight = 600;
    static int MainWindow;
};

// Globals
int angle = 0, carAngle = 0;
float increment = 1, carIncrement = 0;
float carL, carW, alpha, beta;
Vec3f d(1.0,0.0,0.0);
Vec3f p(0.0,0.0,0.0);
Vec3f ex(1,0,0), ey(0,1,0), ez(0,0,1);
Vec3f origin(0,0,0);
	
Vec3f red(1.0f,0.0f,0.0f);
Vec3f green(0.0f,1.0f,0.0f);
Vec3f blue(0.0f,0.0f,1.0f);

void Reshape (int width, int height) {
    WindowParams::WindowWidth = width;
    WindowParams::WindowHeight = height;
    glViewport(0,0,width,height);


	/* ************** VERY IMPORTANT!!!!  **************** */
	// If making any changes in this section please make the same changes in the keyboard section 
	// DELETE THIS BEFORE FINAL SUBMISSION - KEYBOARD SHOULDNT CONTROL VIEWING ANGLE
	
	
	glMatrixMode(GL_PROJECTION);
    glLoadIdentity();    
	//Orthographic projection  - maps objects directly onto screen without affecting their relative size
	// This one puts the origin right in the middle of the screen
	//glOrtho(-Params::WorldWidth/2, Params::WorldWidth/2, -Params::WorldHeight/2, Params::WorldHeight/2, 0.1, 100);
	
	// This one is used to get a different view
	glOrtho(-Params::WorldWidth/6, Params::WorldWidth, -Params::WorldHeight/6, Params::WorldHeight, 0.1, 100);
	
	//Perspective projection - makes objects that are farther away appear smaller
	
	//gluPerspective(60.0, (float)width/(float)height, 1.0, 5.0);

	
	glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();	
	gluLookAt(0, 0, 1, 0, 0, 0, 0, 1, 0);

	


	
}



// All of my utility routines will go here: glTranslate, glRotate, glScale
void translateMat(GLfloat xcor, GLfloat ycor, GLfloat zcor) {
	//glTranslatef(xcor, ycor, zcor);
	float m[16] = {1.0f,0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f,0.0f, 0.0f,0.0f,1.0f,0.0f, xcor, ycor, zcor, 1.0f};
	glMultMatrixf(m);

	return;
}


void rotateMat(GLfloat _angle, GLfloat xcor, GLfloat ycor, GLfloat zcor) {
	//glRotatef(_angle,xcor,ycor,zcor);
	

	_angle = (_angle*M_PI)/180;
	
	float m[16];
	GLfloat len = sqrtf((xcor*xcor)+(ycor*ycor)+(zcor*zcor));
	if (len == 0.0) {
		xcor = 1.0;
		ycor = 0.0;
		zcor = 0.0;
	}
	else if (len != 1.0) {
		xcor /= len;
		ycor /= len;
		zcor /= len;
	}
	
	GLfloat c = cosf(_angle);
	GLfloat s = sinf(_angle);
	m[3] = 0.0f; m[7] = 0.0f; m[11] = 0.0f; m[12] = 0.0f; m[13] = 0.0f; m[14] = 0.0f;
	m[15] = 1.0f;
	
	
	m[0] = (xcor*xcor)*(1-c)+c;
	m[1] = (ycor*xcor)*(1-c)+(zcor*s);
	m[2] = (xcor*zcor)*(1-c)-(ycor*s);
	m[4] = (xcor*ycor)*(1-c)-(zcor*s);
	m[5] = (ycor*ycor)*(1-c)+c;
	m[6] = (ycor*zcor)*(1-c)+(xcor*s);
	m[8] = (xcor*zcor)*(1-c)-(xcor*s);
	m[9] = (ycor*zcor)*(1-c)-(xcor*s);
	m[10] = (zcor*zcor)*(1-c)+c;
	
	glMultMatrixf(m);
	
	
	return;
}

void scaleMat(GLfloat xcor, GLfloat ycor, GLfloat zcor) {
	float m[16] = {xcor,0.0f,0.0f,0.0f, 0.0f,ycor,0.0f,0.0f, 0.0f,0.0f,zcor,0.0f, 0.0f,0.0f,0.0f,1.0f};
	glMultMatrixf(m);
	return;
}
			
// END OF TRANSFORMATIONS




// These functions should implement the basic objects, such that I can simply call them
// and create the wheel or square or whatever
void wheel (float wheelRadius, float thickness) {
	Vec3f temp;
	
	glPushMatrix();
	rotateMat(-angle, 0.0, 0.0, 1.0);
	
	int numSpokes = 5;
	
	//The spokes of the wheel
	glPushMatrix();
	for (int i = 0; i < numSpokes; i++) {
		rotateMat(35, 0.0, 0.0, 1.0);
		glBegin(GL_LINES);
		glVertex3f(0.0,-wheelRadius,0.0);
		glVertex3f(0.0, wheelRadius, 0.0);
		glEnd();
	}
	glPopMatrix();

	
	glLineWidth(thickness);

	
	// draw the actual wheel using estimation
	glBegin(GL_LINE_LOOP);
		
	for (double i = 0; i < 360; i ++) {
		float degInRad = (i*M_PI)/180;
		temp = Vec3f(cos(degInRad)*wheelRadius,sin(degInRad)*wheelRadius,0.0);
		temp.normalize();
		glNormal3fv(temp);
		glVertex3f(cos(degInRad)*wheelRadius,sin(degInRad)*wheelRadius,0.0);
	}
	glEnd();

	
	glPopMatrix();

}	



void specialKeys (int key, int, int) {
	if (key == GLUT_KEY_UP) {
		if (increment > 22)
			increment = 22;
		else increment++;
	}
	else if (key == GLUT_KEY_DOWN) {
		if (increment < 1)
			increment = 0;
		else increment--;
	}
	else if (key == GLUT_KEY_LEFT) {
		if (carIncrement < -360)
			carIncrement = 360;
			else
				carIncrement--;
	}
	else if (key == GLUT_KEY_RIGHT) {
		if (carIncrement > 360)
			carIncrement = 360;
		else carIncrement++;


	}
	return;
}
			


// Can be deleted later, since none of these are required except for spacebar
void Keyboard (unsigned char key, int, int) {
    switch(key) {
		case 27:
			exit(0);
			break;
		case 'q':
			exit(0);
			break;
		case 'x':
			glMatrixMode(GL_MODELVIEW);
			glLoadIdentity();
			gluLookAt(-1, 0, 0, 0, 0, 0, 0, 1, 0);
			glutPostRedisplay();
			break;
		case 'y':
			glMatrixMode(GL_MODELVIEW);
			glLoadIdentity();
			glOrtho(-Params::WorldWidth/2, Params::WorldWidth/2, -Params::WorldHeight/2, Params::WorldHeight/2, 0.1, 100);
			gluLookAt(0, 0, 1, 0.5, 0.5, 0, 0, 1, 0);
			glutPostRedisplay();
			break;
		case 'z':
			glMatrixMode(GL_MODELVIEW);
			glLoadIdentity();
			gluLookAt(0, 0, 1.5, 0, 0, 0, 0, 1, 0);
			glutPostRedisplay();
			break;
		case 32:
			
			// Spacebar resets everything
			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();    
			//Orthographic projection  - maps objects directly onto screen without affecting their relative size
			// This one puts the origin right in the middle of the screen
			//glOrtho(-Params::WorldWidth/2, Params::WorldWidth/2, -Params::WorldHeight/2, Params::WorldHeight/2, 0.1, 100);
			
			// This one is used to get a different view
			glOrtho(-Params::WorldWidth/6, Params::WorldWidth, -Params::WorldHeight/6, Params::WorldHeight, 0.1, 100);
			
			//Perspective projection - makes objects that are farther away appear smaller
			//gluPerspective(60.0, (float)width/(float)height, 1.0, 5.0);
			
			
			
			glMatrixMode(GL_MODELVIEW);
			glLoadIdentity();	
			gluLookAt(-1, 0, 0, 0, 0, 0, 0, 1, 0);
			angle = 0;
			carAngle = 0;
			increment = 0;
			carIncrement = 0;
			carL, carW, alpha, beta;
			

			
			break;
			

    }
}


//animate function

void Animate(int time) {
	
    glutTimerFunc(Params::TimerStep,Animate,0);

	angle += increment;
	carAngle += carIncrement;
	
	glutPostRedisplay();

}




void drawQuad(Vec3f n1, Vec3f n2, Vec3f n3, Vec3f n4) {
	glBegin(GL_QUADS);
	Vec3f v1(n2-n1);
	Vec3f v2(n3-n1);
	
	Vec3f normal = cross(v1,v2);
	normal.normalize();
	glNormal3fv(normal);
	
	glVertex3fv(n1);
	glVertex3fv(n2);
	glVertex3fv(n3);
	glVertex3fv(n4);
	glEnd();
}




void drawCube(GLfloat size) {
	drawQuad(Vec3f(size/2,size/2,size/2),Vec3f(-size/2,size/2,size/2),Vec3f(-size/2,-size/2,size/2),Vec3f(size/2,-size/2,size/2));
	drawQuad(Vec3f(size/2,size/2,size/2),Vec3f(-size/2,size/2,size/2),Vec3f(-size/2,size/2,-size/2),Vec3f(size/2,size/2,-size/2));
	drawQuad(Vec3f(size/2,size/2,size/2), Vec3f(size/2,size/2,-size/2), Vec3f(size/2,-size/2,-size/2), Vec3f(size/2,-size/2,size/2));
	drawQuad(Vec3f(-size/2,size/2,-size/2), Vec3f(size/2,size/2,-size/2), Vec3f(size/2,-size/2,-size/2), Vec3f(-size/2,-size/2,-size/2));
	drawQuad(Vec3f(-size/2,size/2,size/2), Vec3f(-size/2,size/2,-size/2), Vec3f(-size/2,-size/2,-size/2), Vec3f(-size/2,-size/2,size/2));
	drawQuad(Vec3f(-size/2,-size/2,-size/2), Vec3f(size/2,-size/2,-size/2), Vec3f(size/2,-size/2,size/2), Vec3f(-size/2,-size/2,size/2));
}


void drawCar (GLfloat length, GLfloat width, GLfloat wheelRadius, GLfloat wheelThickness) {
	glPushMatrix();

	
	// rotate the car for different viewing angles
	rotateMat(carAngle, 0.0, 1.0, 0.0);
	
	
	
	// position the car so it sits on the x axis (this can change given different wheel radius and wheel thickness
	// This accomodates ANY wheel radius but a wheel thickness between {3,8} are preferred.
	translateMat(0.0, 0.106+wheelRadius+0.0006*wheelThickness, 0.0);
	scaleMat(1.0, 1.0, 2.5);


	
	
	
	
	glPushMatrix();
	
	// Position the car relative to the wheels based on the wheel radius and increase its size on scale with wheel radius
	translateMat(0.0, -0.05+wheelRadius, 0.0);

	
	
	// The body section of the car
	glNormal3f(0.0, 0.5, 0.5);
	//glDisable(GL_LIGHTING);
	//the bottom of the body
	glColor3fv(red);

	scaleMat(0.3, 0.1, 0.1);
	drawCube(1);

	// The front of the body
	glPushMatrix();
	translateMat(0.5, 0.0, 0.0);
	scaleMat(0.5, 0.5, 0.0);
	glColor3fv(blue);
	drawCube(1);
	glPopMatrix();
	
	//the top of the body
	glPushMatrix();
	translateMat(0.0, 0.5, 0.0);
	scaleMat(0.5, 1.0, 1.0);
	glColor3fv(green);
	drawCube(1);
	glPopMatrix();
	
	glPopMatrix();
	// Draw the wheels starting from origin
	// start with left side of car
	glPushMatrix();
	
	translateMat(0.1, -0.10, -0.03);
	glColor3f(0.5,0.5,0.5);
	wheel(wheelRadius,wheelThickness);
	
	glPushMatrix();
	// back wheel
	translateMat(-0.2,0.0,0.0);
	wheel(wheelRadius, wheelThickness);
	
	glPopMatrix();
	
	// right side of car
	
	translateMat(0.0, 0.0, 0.06);
	wheel(wheelRadius, wheelThickness);
	glPushMatrix();
	translateMat(-0.2, 0.0, 0.0);
	wheel(wheelRadius, wheelThickness);
	glPopMatrix();
	
	
	
	glPopMatrix();
	


	glPopMatrix();
	

	return;
}


void Draw() {
	
	


	
	float wheelRadius = 0.05;
	float thickness = 5;

	float carLength;
	float carWidth;

    glClearColor(0.0,0.0,0.0,0.0);
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	// Draw the axes
	glDisable(GL_LIGHTING);
	glBegin(GL_LINES);
	glColor3fv(red); glVertex3fv(-ex); glVertex3fv(ex);	// x axis
	glColor3fv(green); glVertex3fv(-ey); glVertex3fv(ey);	// y axis
	glColor3fv(blue); glVertex3fv(-ez); glVertex3fv(ez);	// z axis
	glEnd();
	
	glEnable(GL_LIGHTING);

	
	drawCar(carLength, carWidth, wheelRadius, thickness);
	
	// Draw a plane
//	glBegin(GL_POLYGON);
//	glNormal3f(1.0, 1.0, 1.0);
//	glVertex3fv(origin);
//	glVertex3fv(ex);
//	glVertex3fv(Vec3f(1,0,0.9));
//	glVertex3fv(Vec3f(0,0,0.9));
//	glEnd();
	
    glutSwapBuffers();
	
}


int main(int argc, char** argv) {
	
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
    glutInitWindowSize(WindowParams::WindowWidth, WindowParams::WindowHeight);
    WindowParams::MainWindow = glutCreateWindow("Moving car");
    
    
    
    // callbacks
    glutDisplayFunc(Draw);
    glutReshapeFunc(Reshape);
    glutKeyboardFunc(Keyboard);

    glutTimerFunc(Params::TimerStep,Animate,0);
	glutSpecialFunc(specialKeys);
	
	
    GLfloat diffuse[] = {0.8, 0.8, 0.8, 1.0};
    GLfloat lgt1_diffuse[] = { 0.05f, 0.05f, 0.6f, 1.0f };
    GLfloat lgt2_diffuse[] = { 0.6f, 0.05f, 0.05f, 1.0f };
    GLfloat light_pos1[] = { 5.0f, 5.0f, 0.0f, 1.0f };
    GLfloat light_pos2[] = { -5.0f, 5.0f, 0.0f, 1.0f };
	
	
	// this is from professor
    glEnable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glMaterialfv( GL_FRONT, GL_DIFFUSE, diffuse);
    glLightfv(GL_LIGHT1, GL_POSITION,light_pos1);
    glLightfv(GL_LIGHT1, GL_DIFFUSE, lgt1_diffuse);
    glLightfv(GL_LIGHT2, GL_POSITION,light_pos2);
    glLightfv(GL_LIGHT2, GL_DIFFUSE, lgt2_diffuse);
    glEnable(GL_LIGHT1);
    glEnable(GL_LIGHT2);
	
	
	
    glutMainLoop();
	
    return 0;
}

The assignment should be done without GLUT
???


    glutInit            (&argc, argv);
    glutInitDisplayMode (GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
    glutInitWindowSize  (WindowParams::WindowWidth, WindowParams::WindowHeight);
    WindowParams::MainWindow = glutCreateWindow("Moving car");
    glutDisplayFunc  (Draw);
    glutReshapeFunc  (Reshape);
    glutKeyboardFunc (Keyboard);
    glutTimerFunc(Params::TimerStep,Animate,0);
    glutSpecialFunc(specialKeys);