#include <iostream>
#include <map>
#include "gl/glew.h"
#include "gl/glut.h"
using namespace std;
enum FingerJoint
{
Shoulder_Joint, //The joint which connects the shoulder to the body.
Elbow_Joint, //The joint which connects the two parts of arm.
Wrist_Joint, //The joint which connects the wrist to the arm.
Thumb_1st_Joint, //The joint which connects the thumb to palm
Thumb_2nd_Joint, //The joint which connects two parts of the thumb
Forefinger_1st_Joint, //The joint which connects the forefinger to palm
Forefinger_2nd_Joint, //The joint which connects the two parts of the forefinger
Forefinger_3rd_Joint,
MiddleFinger_1st_Joint, //The joint which connects the middle finger to palm
MiddleFinger_2nd_Joint,
MiddleFinger_3rd_Joint,
Ringfinger_1st_Joint, //The joint which connects the ring finger to palm
Ringfinger_2nd_Joint,
Ringfinger_3rd_Joint,
LittleFinger_1st_Joint, //The joint which connects the little finger to palm
LittleFinger_2nd_Joint, //
LittleFinger_3rd_Joint,
JointCount //Total joints count
};
//The rotation angels of all joints
GLfloat gFingerJointRotations[JointCount];
//The limit of the rotation angel for all fingers is between 0~90
const GLfloat FingerJointRotationMax = 90.0f; //Max rotation angel
const GLfloat FingerJointRotationMin = 0.0f; //Min rotation angel
const GLfloat RotationDelta = 5.0f;
//The rotation Angel of the Shoulder, range between -45.0~90
const GLfloat ShoulderRotationMax = 90.0f;
const GLfloat ShoulderRotationMin = -45.0f;
//The rotation angel of the elbow, range between 0~160
const GLfloat ElbowRotationMax = 160.0f;
const GLfloat ElbowRotationMin = 0.0f;
//The rotation angel of the wrist, range between -60~80
const GLfloat WristRotationMax = 80.0f;
const GLfloat WristRotationMin = -60.0f;
class ControlData
{
public:
ControlData()
{}
ControlData(int index, GLfloat delta, GLfloat min, GLfloat max)
:Index(index), Delta(delta), MinValue(min), MaxValue(max)
{}
ControlData(const ControlData &other)
:Index(other.Index), Delta(other.Delta), MinValue(other.MinValue), MaxValue(other.MaxValue)
{}
ControlData& operator = (const ControlData &other)
{
Index = other.Index;
MaxValue = other.MaxValue;
MinValue = other.MinValue;
Delta = other.Delta;
return *this;
}
int Index; //Index of Joint Rotation Angel
GLfloat MaxValue; //Max angel
GLfloat MinValue; //Min angel
GLfloat Delta; //Delta value
};
std::map<GLubyte, ControlData> gKeyControlDataMap;
/*
Initialize Key-Rotation Data mapping.
**/
void initControlMapping()
{
//All char press without shift will rotate deasil
//All char press with shift will rotate widdershins
gKeyControlDataMap['a'] = ControlData(Shoulder_Joint, RotationDelta, ShoulderRotationMin, ShoulderRotationMax);
gKeyControlDataMap['A'] = ControlData(Shoulder_Joint, -RotationDelta, ShoulderRotationMin, ShoulderRotationMax);
gKeyControlDataMap['s'] = ControlData(Elbow_Joint, RotationDelta, ElbowRotationMin, ElbowRotationMax);
gKeyControlDataMap['S'] = ControlData(Elbow_Joint, -RotationDelta, ElbowRotationMin, ElbowRotationMax);
gKeyControlDataMap['d'] = ControlData(Wrist_Joint, RotationDelta, WristRotationMin, WristRotationMax);
gKeyControlDataMap['D'] = ControlData(Wrist_Joint, -RotationDelta, WristRotationMin, WristRotationMax);
gKeyControlDataMap['n'] = ControlData(Thumb_1st_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['N'] = ControlData(Thumb_1st_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['h'] = ControlData(Thumb_2nd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['H'] = ControlData(Thumb_2nd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['m'] = ControlData(Forefinger_1st_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['M'] = ControlData(Forefinger_1st_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['j'] = ControlData(Forefinger_2nd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['J'] = ControlData(Forefinger_2nd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['u'] = ControlData(Forefinger_3rd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['U'] = ControlData(Forefinger_3rd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap[','] = ControlData(MiddleFinger_1st_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['<'] = ControlData(MiddleFinger_1st_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['k'] = ControlData(MiddleFinger_2nd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['K'] = ControlData(MiddleFinger_2nd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['i'] = ControlData(MiddleFinger_3rd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['I'] = ControlData(MiddleFinger_3rd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['.'] = ControlData(Ringfinger_1st_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['>'] = ControlData(Ringfinger_1st_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['l'] = ControlData(Ringfinger_2nd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['L'] = ControlData(Ringfinger_2nd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['o'] = ControlData(Ringfinger_3rd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['O'] = ControlData(Ringfinger_3rd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['/'] = ControlData(LittleFinger_1st_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['?'] = ControlData(LittleFinger_1st_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap[';'] = ControlData(LittleFinger_2nd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap[':'] = ControlData(LittleFinger_2nd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['p'] = ControlData(LittleFinger_3rd_Joint, RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
gKeyControlDataMap['P'] = ControlData(LittleFinger_3rd_Joint, -RotationDelta, FingerJointRotationMin, FingerJointRotationMax);
}
void init()
{
initControlMapping();
//Set background color : black
glClearColor(0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
//Enable Depth test
glEnable(GL_DEPTH_TEST);
//Enable lighting
glEnable(GL_LIGHTING);
//Set Light source 0
static GLfloat light0_position[] = {1.0, 1.0, 1.0, 0.0};
glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
//Blue light
static GLfloat light0_diffuse[] = {1.0, 1.0, 1.0, 1.0};
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
//Enable the 1st light source.
glEnable(GL_LIGHT0);
}
/*
Window reshape event callback, call the function once the window size changed.
**/
void reshape(GLsizei w, GLsizei h)
{
//Avoid divide 0
if(0==h)
h=1;
//Set the view port
glViewport(0, 0, w, h);
//All matrix operations will affect projection matrix
glMatrixMode(GL_PROJECTION);
//Load an identity matrix
glLoadIdentity();
//Set projection matrix
gluPerspective(45.0, (GLfloat)w/(GLfloat)h, 0.1, 500.0);
//All matrix operations will affect model veiw matrix
glMatrixMode(GL_MODELVIEW);
}
/*
Redraw callback, call this function every time the display need to refresh.
**/
void display()
{
//Clear color buffer and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//Set camera parameters
gluLookAt(0.0, 0.0, 60.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
//Rotate camera
glRotatef(150.0, 0.0, 1.0, 0.0);
//Draw the shoulder
glTranslatef(6.0, 0.0, 0.0);
glRotatef(gFingerJointRotations[Shoulder_Joint], 0.0, 0.0, 1.0);
glScalef(12.0, 2.0, 4.0);
glutSolidCube(1.0);
//Eliminate the impact to following objects
glScalef(1.0/12.0, 1.0/2.0, 1.0/4.0);
//Draw the elbow, use the transform matrix of shoulder as parent matrix
glTranslatef(6.0, 0.0, 0.0);
glRotatef(gFingerJointRotations[Elbow_Joint], 0.0, 0.0, 1.0);
//Translate twice, make sure the rotation center at the end of the elbow
glTranslatef(6.0, 0.0, 0.0);
glScalef(12.0, 2.0, 4.0);
glutSolidCube(1.0);
//Eliminate the impact to following objects
glScalef(1.0/12.0, 1.0/2.0, 1.0/4.0);
{
//Draw the palm, use the transform matrix of elbow as parent matrix
glPushMatrix(); //push current matrix to stack
glTranslatef(6.0, 0.0, 0.0);
glRotatef(gFingerJointRotations[Wrist_Joint], 0.0, 0.0, 1.0);
glTranslatef(3.0, 0.0, 0.0);
glScalef(6.0, 1.0, 4.0);
glutSolidCube(1.0);
//Eliminate the impact to following objects
glScalef(1.0/6.0, 1.0, 1.0/4.0);
{
//Draw thumb, use the transform matrix of palm as parent matrix
glPushMatrix();
glTranslatef(-1.0, 0.0, -1.0);
glRotatef(-gFingerJointRotations[Thumb_1st_Joint], 0.0, 0.0, 1.0);
glRotatef(gFingerJointRotations[Thumb_1st_Joint], 1.0, 0.0, 0.0);
//Translate twice, make sure the rotation center at the end of the thumb
glTranslatef(-1.0, 0.0, -2.0);
glScalef(1.0, 1.0, 2.0);
glutSolidCube(1.0);
//Eliminate the impact to following objects
glScalef(1.0, 1.0, 1.0/2.0);
{
//Draw the 2nd part of thumb,
//use the transform matrix of the first part of thumb as parent matrix
glPushMatrix();
glTranslatef(0.0, 0.0, -1.0);
glRotatef(gFingerJointRotations[Thumb_2nd_Joint], 1.0, 0.0, 0.0);
glTranslatef(0.0, 0.0, 0.0);
glScalef(1.0, 1.0, 2.0);
glutSolidCube(1.0);
glPopMatrix();
}
glPopMatrix();
}
{
//Draw the forefinger, use the transform matrix of palm as parent matrix
glPushMatrix();
glTranslatef(3.0, 0.0, -1.5);
glRotatef(gFingerJointRotations[Forefinger_1st_Joint], 0.0, 0.0, 1.0);
//Translate twice, make sure the rotation center at the end of the 1st part of forefinger
glTranslatef(1.0, 0.0, 0.0);
glScalef(2.0, 1.0, 1.0);
glutSolidCube(1.0);
//Eliminate the impact to following objects
glScalef(1.0/2.0, 1.0, 1.0);
{
//Draw the 2nd part of forefinger,
//use the transform matrix of the first part of forefinger as parent matrix
glPushMatrix();
glTranslatef(1.0, 0.0, 0.0);
glRotatef(gFingerJointRotations[Forefinger_2nd_Joint], 0.0, 0.0, 1.0);
glTranslatef(1.25, 0.0, 0.0);
glScalef(2.5, 1.0, 1.0);
glutSolidCube(1.0);
glPopMatrix();
}
glPopMatrix();
}
{
//Draw middle finger, use the transform matrix of palm as parent matrix
glPushMatrix();
glTranslatef(3.0, 0.0, -0.5);
glRotatef(gFingerJointRotations[MiddleFinger_1st_Joint], 0.0, 0.0, 1.0);
//Translate twice, make sure the rotation center at the end of the 1st part of middle finger
glTranslatef(1.25, 0.0, 0.0);
glScalef(2.5, 1.0, 1.0);
glutSolidCube(1.0);
//Eliminate the impact to following objects
glScalef(1.0/2.5, 1.0, 1.0);
{
//Draw the 2nd part of middle finger,
//use the transform matrix of the first part of middle finger as parent matrix
glPushMatrix();
glTranslatef(1.25, 0.0, 0.0);
glRotatef(gFingerJointRotations[MiddleFinger_2nd_Joint], 0.0, 0.0, 1.0);
//Translate twice, make sure the rotation center at the end of the 2nd part of middle finger
glTranslatef(1.5, 0.0, 0.0);
glScalef(3.0, 1.0, 1.0);
glutSolidCube(1.0);
glPopMatrix();
}
glPopMatrix();
}
{
//Draw ring finger, use the transform matrix of palm as parent matrix
glPushMatrix();
glTranslatef(3.0, 0.0, 0.5);
glRotatef(gFingerJointRotations[Ringfinger_1st_Joint], 0.0, 0.0, 1.0);
//Translate twice, make sure the rotation center at the end of the 1st part of ring finger
glTranslatef(1.0, 0.0, 0.0);
glScalef(2.0, 1.0, 1.0);
glutSolidCube(1.0);
//Eliminate the impact to following objects
glScalef(1.0/2.0, 1.0, 1.0);
{
//Draw the 2nd part of ring finger,
//use the transform matrix of the first part of ring finger as parent matrix
glPushMatrix();
glTranslatef(1.0, 0.0, 0.0);
glRotatef(gFingerJointRotations[Ringfinger_2nd_Joint], 0.0, 0.0, 1.0);
//Translate twice, make sure the rotation center at the end of the 2nd part of ring finger
glTranslatef(1.5, 0.0, 0.0);
glScalef(3.0, 1.0, 1.0);
glutSolidCube(1.0);
glPopMatrix();
}
glPopMatrix();
}
{
//Draw little finger, use the transform matrix of palm as parent matrix
glPushMatrix();
glTranslatef(3.0, 0.0, 1.5);
glRotatef(gFingerJointRotations[LittleFinger_1st_Joint], 0.0, 0.0, 1.0);
//Translate twice, make sure the rotation center at the end of the 1st part of little finger
glTranslatef(0.75, 0.0, 0.0);
glScalef(1.5, 1.0, 1.0);
glutSolidCube(1.0);
//Eliminate the impact to following objects
glScalef(1.0/1.5, 1.0, 1.0);
{
//Draw the 2nd part of little finger,
//use the transform matrix of the first part of little finger as parent matrix
glPushMatrix();
glTranslatef(0.75, 0.0, 0.0);
glRotatef(gFingerJointRotations[LittleFinger_2nd_Joint], 0.0, 0.0, 1.0);
//Translate twice, make sure the rotation center at the end of the 2nd part of little finger
glTranslatef(1.0, 0.0, 0.0);
glScalef(2.0, 1.0, 1.0);
glutSolidCube(1.0);
glPopMatrix();
}
glPopMatrix();
}
glPopMatrix(); //pop the palm matrix out
}
//Swap the buffers
glutSwapBuffers();
}
/*
Keyboard event callback
Handle key down event
**/
void keyboard(GLubyte key, GLint, GLint)
{
std::map<GLubyte, ControlData>::iterator it = gKeyControlDataMap.find(key);
if(it != gKeyControlDataMap.end())
{//If find the registed key, update the rotation of joint
if ( gFingerJointRotations[it->second.Index] >= it->second.MinValue &&
it->second.Delta < 0.0f )
{
gFingerJointRotations[it->second.Index] += it->second.Delta;
glutPostRedisplay();
}
else if ( gFingerJointRotations[it->second.Index] <= it->second.MaxValue &&
it->second.Delta > 0.0f)
{//Within limit
//Update Rotation Angel
gFingerJointRotations[it->second.Index] += it->second.Delta;
//Refresh window
glutPostRedisplay();
}
}
}
int main(int argc, char** argv)
{
//Initialize glut
glutInit(&argc, argv);
//Initialize display mode, use double buffers
//Color buffer use RGBA format
//Create depth buffer
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
//Create rendering target
glutInitWindowPosition(200, 100);
glutInitWindowSize(400, 300);
glutCreateWindow("Robot");
init();
//Register redraw callback
glutDisplayFunc(display);
//Register window reshape callback
glutReshapeFunc(reshape);
//Register keyboard event callback
glutKeyboardFunc(keyboard);
//Start message loop
glutMainLoop();
return 0;
}