summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <lekensteyn@gmail.com>2013-11-28 23:51:56 +0100
committerPeter Wu <lekensteyn@gmail.com>2013-11-28 23:51:56 +0100
commit41e1007da6101cfa7e5cc206d44027fbfe7052b6 (patch)
tree0e17299ad8df64e8f8effe5edf37dbce764e4262
parentc71ba8e4726bf9a904697f7acaf6602f7a2d2c8b (diff)
download2iv60-robots-41e1007da6101cfa7e5cc206d44027fbfe7052b6.tar.gz
Refactor to remove magic numbers, deduplication
Added Colors class that labels the RGB color numbers. Introduce helper function to draw beams that does not change scaling, this allows the push/pop matrix function to be removed from drawTorso. Remove duplicate code from drawLegs, drawArms, drawShoulders. Remove drawStickFigures because it will interfere with animations later, drawBeam will take care of drawing the skeleton if needed. Joints are manually added during the transformations, that are possible points for rotations later.
-rw-r--r--src/Colors.java25
-rw-r--r--src/Direction.java6
-rw-r--r--src/RobotRace.java482
3 files changed, 228 insertions, 285 deletions
diff --git a/src/Colors.java b/src/Colors.java
new file mode 100644
index 0000000..fca191e
--- /dev/null
+++ b/src/Colors.java
@@ -0,0 +1,25 @@
+
+import java.awt.Color;
+
+/**
+ * A collection of colors.
+ */
+public class Colors {
+
+ /**
+ * Made up color names.
+ */
+ public static Color BLUEISH = new Color(100, 130, 255);
+ public static Color GRAYISH = new Color(100, 100, 100);
+ public static Color DIRTY_BLUE = new Color(130, 158, 174);
+ public static Color ARM_GRAY_COLOR = new Color(200, 200, 200);
+
+ /**
+ * Names taken from Wikipedia.
+ *
+ * @see https://en.wikipedia.org/wiki/List_of_colors:_A%E2%80%93F
+ */
+ public static Color LAVENDER = new Color(0xE6E6FA);
+ public static Color PALE_TURQOISE = new Color(0xAFEEEE);
+ public static Color CHOCOLATE = new Color(0x7B3F00);
+}
diff --git a/src/Direction.java b/src/Direction.java
new file mode 100644
index 0000000..dccb87f
--- /dev/null
+++ b/src/Direction.java
@@ -0,0 +1,6 @@
+/**
+ * Specifies the direction of a line segment.
+ */
+public enum Direction {
+ X, Y, Z
+}
diff --git a/src/RobotRace.java b/src/RobotRace.java
index b1bf83a..d715a78 100644
--- a/src/RobotRace.java
+++ b/src/RobotRace.java
@@ -1,4 +1,5 @@
+import java.awt.Color;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.event.KeyEvent;
@@ -136,7 +137,7 @@ public class RobotRace extends Base {
gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
gl.glBindTexture(GL_TEXTURE_2D, 0);
}
-
+
/**
* Configures the viewing transform.
*/
@@ -228,11 +229,11 @@ public class RobotRace extends Base {
* @param g Green color scale (0 to 1).
* @param b Blue color scale (0 to 1).
*/
- private void drawColoredArrow(float r, float g, float b) {
+ private void drawColoredArrow(Color color) {
gl.glPushMatrix();
// change color
- gl.glColor3f(r, g, b);
+ setColor(color);
// draw a thin line from the origin to the right.
gl.glTranslatef(0.5f, 0, 0);
@@ -258,16 +259,16 @@ public class RobotRace extends Base {
*/
public void drawAxisFrame() {
// X-axis: normal orientation
- drawColoredArrow(1, 0, 0);
+ drawColoredArrow(Color.RED);
// Y-axis: rotate 90 degree clockwise in the Z-axis
gl.glRotatef(90, 0, 0, 1);
- drawColoredArrow(0, 1, 0);
+ drawColoredArrow(Color.GREEN);
gl.glRotatef(-90, 0, 0, 1);
// Z-axis: rotate 90 degree in the XY ais
gl.glRotatef(-90, 0, 1, 0);
- drawColoredArrow(0, 0, 1);
+ drawColoredArrow(Color.BLUE);
gl.glRotatef(90, 0, 1, 0);
// yellow sphere of 0.03m (with ten divisions)
@@ -329,18 +330,38 @@ public class RobotRace extends Base {
this.specular = specular;
}
}
-
+
+ /**
+ * Utility method to set color.
+ * @param color An AWT color.
+ */
+ private void setColor(Color color) {
+ // contains four RGBA color components (floats in range 0 to 1)
+ float[] rgba = color.getRGBComponents(null);
+ gl.glColor3fv(rgba, 0);
+ }
+
/**
* Represents a Robot, to be implemented according to the Assignments.
*/
private class Robot {
-
+ private final Color boneColor = Colors.CHOCOLATE;
+
/** The material from which this robot is built. */
private final Material material;
/** Relative lengths, widths and heights of robot model. */
private final float torsoHeight, torsoWidth, shoulderRadius, armLength,
- legLength, armWidth, legWidth, neckHeight, headRadius, depth;
+ legLength, armWidth, legWidth, neckHeight, headRadius, depth,
+ footWidth, footHeight, footLength;
+
+ /** Size of the bone for stick figures. */
+ private final float boneSize;
+
+ /**
+ * True if a skeleton should be drawn instead of a full body.
+ */
+ private boolean asStickFigure;
/**
* Constructs the robot with initial parameters.
@@ -357,6 +378,10 @@ public class RobotRace extends Base {
this.legWidth = 0.06f;
this.neckHeight = 0.15f;
this.headRadius = 0.12f;
+ this.footWidth = legWidth;
+ this.footHeight = legWidth;
+ this.footLength = 2 * legWidth;
+ this.boneSize = 0.02f;
this.depth = 0.24f;
}
@@ -364,336 +389,223 @@ public class RobotRace extends Base {
* Draws this robot (as a {@code stickfigure} if specified).
*/
public void draw(boolean stickFigure) {
+ this.asStickFigure = stickFigure;
// as the components are drawn with the torso as center, move it up
gl.glPushMatrix();
gl.glTranslatef(0, 0, torsoHeight / 2 + legLength);
- if (!stickFigure) {
- // Draw the robot
- drawTorso(); // Torso
- drawShoulders(); // Shoulders
- drawLegs(); // Legs and feet
- drawArms(); // Arms and hands
- drawHead(); // Neck and head
- } else {
- // Draw the stick figure
- drawStickFigure();
+ // These materials control the reflected light
+ gl.glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material.diffuse, 0);
+ gl.glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material.specular, 0);
+
+ gl.glTranslatef(0, 0, footHeight);
+
+ // Draw the robot, everything is relative to the center of torso.
+ // Static parts:
+ drawTorso();
+ drawHead();
+ // only draw the circles in normal, full body mode
+ if (!asStickFigure) {
+ drawShoulderTop();
}
+ // Parts that should be animated:
+ // draw left and right legs
+ drawLeg(false);
+ drawLeg(true);
+ // draw left and right arms
+ drawArm(false);
+ drawArm(true);
+
// restore position
gl.glPopMatrix();
}
-
+
/**
- * Draws the stickfigure of the robot.
+ * Draws a 3d figure with given dimensions and color. If a stick figure
+ * must be drawn, then the figure will become a thin line in the X, Y
+ * or Z direction depending on the direction parameter.
+ * @param dir Direction of the line segment, relevant for stick figures.
+ * @param color If non-null, it becomes the color for this beam. Ignored
+ * when drawing a stick figure, in that case the boneColor constant will
+ * be used.
*/
- private void drawStickFigure() {
- // Create all vectors based on the real position and the
- // translations of the real robot.
- Vector torsoLeftTop = new Vector(torsoWidth /2, 0f, torsoHeight /2);
- Vector torsoRightTop = new Vector(-torsoWidth/2, 0f, torsoHeight/2);
- Vector torsoLeftBottom = new Vector(torsoWidth / 2, 0f,
- -torsoHeight /2);
- Vector torsoRightBottom = new Vector(-torsoWidth /2 , 0f,
- -torsoHeight /2);
-
- Vector leftShoulder = new Vector(torsoWidth / 2 + armWidth * 1.5f,
- 0f, torsoHeight / 2 - 0.05f);
- Vector rightShoulder = new Vector(-torsoWidth / 2 - armWidth * 1.5f,
- 0f, torsoHeight / 2 - 0.05f);
-
- Vector leftHand = new Vector(torsoWidth / 2 + armWidth * 1.5f,
- 0f, torsoHeight / 2 - 0.05f - armLength);
- Vector rightHand = new Vector(-torsoWidth / 2 - armWidth * 1.5f,
- 0f, torsoHeight / 2 - 0.05f - armLength);
-
- Vector neckStart = new Vector(0f, 0f, torsoHeight/2);
- Vector neckEnd = new Vector(0f, 0f, torsoHeight/2 + neckHeight);
-
- Vector leftLegTop = new Vector(torsoWidth / 2 - legWidth * 2, 0f,
- -torsoHeight / 2);
- Vector leftLegBottom = new Vector(torsoWidth / 2 - legWidth * 2,
- 0f, -torsoHeight / 2 - legLength);
-
- Vector rightLegTop = new Vector(-torsoWidth / 2 + legWidth * 2, 0f,
- -torsoHeight / 2);
- Vector rightLegBottom = new Vector(-torsoWidth / 2 + legWidth * 2,
- 0f, -torsoHeight / 2 - legLength);
-
- /*
- * For future, translate all vectors so they are positioned
- * correctly and that they are rotated correctly.
- *
- * Arms and feet should be translated afterwards to represent
- * the angle to simulate movement.
- */
-
- // Set the color to black
- setColorRGB(0, 0, 0);
-
- // Connect all torso points with a line stip
- gl.glBegin(GL_LINE_STRIP);
- stickPoint(torsoLeftTop);
- stickPoint(torsoRightTop);
- stickPoint(torsoRightBottom);
- stickPoint(torsoLeftBottom);
- stickPoint(torsoLeftTop);
- gl.glEnd();
-
- // Draw head lines based on neck start and end
- gl.glBegin(GL_LINES);
- stickPoint(neckStart);
- stickPoint(neckEnd);
- gl.glEnd();
-
- // Draw arm and leg lines, and connect arms with torso (shoulders)
- gl.glBegin(GL_LINES);
- stickPoint(leftLegTop);
- stickPoint(leftLegBottom);
- stickPoint(rightLegTop);
- stickPoint(rightLegBottom);
- stickPoint(leftShoulder);
- stickPoint(leftHand);
- stickPoint(rightShoulder);
- stickPoint(rightHand);
- stickPoint(rightShoulder);
- stickPoint(torsoRightTop);
- stickPoint(leftShoulder);
- stickPoint(torsoLeftTop);
- gl.glEnd();
-
- // Set point size of the stickfigure
- gl.glPointSize(7.5f);
-
- // Begin drawing all points
- gl.glBegin(GL_POINTS);
-
- // First the torso points
- stickPoint(torsoLeftTop);
- stickPoint(torsoRightTop);
- stickPoint(torsoRightBottom);
- stickPoint(torsoLeftBottom);
-
- // Shoulders and the hands
- stickPoint(leftShoulder);
- stickPoint(rightShoulder);
- stickPoint(leftHand);
- stickPoint(rightHand);
-
- // The neck
- stickPoint(neckStart);
- stickPoint(neckEnd);
-
- // And finally the legs
- stickPoint(leftLegTop);
- stickPoint(leftLegBottom);
- stickPoint(rightLegTop);
- stickPoint(rightLegBottom);
-
- // Stop drawing points
- gl.glEnd();
+ private void drawBeam(float x, float y, float z, Direction dir, Color color) {
+ if (asStickFigure) {
+ // for a stick figure, draw a thin figure without colors
+ switch (dir) {
+ case X:
+ assert x != 0;
+ y = z = boneSize;
+ break;
+ case Y:
+ assert y != 0;
+ x = z = boneSize;
+ break;
+ case Z:
+ assert z != 0;
+ x = y = boneSize;
+ break;
+ default:
+ throw new AssertionError(dir.name());
+ }
+ // stick figures always get a "bone" color
+ setColor(boneColor);
+ } else {
+ assert x != 0;
+ assert y != 0;
+ assert z != 0;
+ if (color != null) {
+ setColor(color);
+ }
+ }
+ gl.glScalef(x, y, z);
+ glut.glutSolidCube(1);
+ // return to previous scales
+ gl.glScalef(1 / x, 1 / y, 1 / z);
}
-
+
/**
- * Draws a point with a given vector p
- * @param p Point in space
+ * Draws a joint for stick figure model.
*/
- private void stickPoint(Vector p) {
- gl.glVertex3f((float) p.x(), (float) p.y(), (float) p.z());
+ private void drawJoint() {
+ if (asStickFigure) {
+ glut.glutSolidSphere(boneSize * 1.5, 10, 10);
+ }
}
-
-
+
/**
* Draws the torso of the robot.
*/
private void drawTorso() {
- // Push matrix for returning to origin later
- gl.glPushMatrix();
-
// Scale the torso to specified values
- gl.glScalef(torsoWidth, depth, torsoHeight);
-
- // Draw the torso itself with given color
- setColorRGB(230, 230, 230);
- glut.glutSolidCube(1f);
-
- // Pop matrix so we return to the origin
- gl.glPopMatrix();
+ drawBeam(torsoWidth, depth, torsoHeight, Direction.Z, Color.LIGHT_GRAY);
+
+ if (asStickFigure) {
+ // draw the bone connecting the arms (visible for stick figure)
+ gl.glTranslatef(0, 0, torsoHeight / 2);
+ drawBeam(torsoWidth + armWidth * 3, boneSize, boneSize, Direction.X, null);
+
+ gl.glTranslatef(0, 0, -torsoHeight);
+ // draw the bone connecting the legs (visible for stick figure)
+ drawBeam(.5f * torsoWidth + legWidth / 2, boneSize, boneSize, Direction.X, null);
+
+ // return to torso center
+ gl.glTranslatef(0, 0, torsoHeight / 2);
+ }
}
/**
* Draws both shoulders of the robot.
*/
- private void drawShoulders() {
- // Push the translation matrix so we can return to the origin
+ private void drawShoulderTop() {
+ // save position
gl.glPushMatrix();
-
- // Translate to the left of the robot for left shoulder
- gl.glTranslatef(torsoWidth / 2 + shoulderRadius / 1.5f, 0f,
- torsoHeight / 2);
-
- // Set the drawing color and draw left shoulder
- setColorRGB(100, 130, 255);
- glut.glutSolidSphere(shoulderRadius, 10, 10);
-
- // Pop the matrix and then push it, so we are at the origin
- gl.glPopMatrix();
- gl.glPushMatrix();
-
- // Translate to the right of the robot for right shoulder
- gl.glTranslatef(- torsoWidth / 2 - shoulderRadius / 1.5f, 0f,
- torsoHeight / 2);
-
+
+ float shoulder_x = torsoWidth / 2 + shoulderRadius / 1.5f;
+ // Translate to the left of the robot for left shoulder
+ gl.glTranslatef(shoulder_x, 0f, torsoHeight / 2);
+
+ setColor(Colors.BLUEISH);
+
// Set the drawing color and draw right shoulder
- setColorRGB(100, 130, 255);
glut.glutSolidSphere(shoulderRadius, 10, 10);
-
- // Pop the translation matrix so we are at the origin
+ // left shoulder
+ gl.glTranslatef(-2 * shoulder_x, 0, 0);
+ glut.glutSolidSphere(shoulderRadius, 10, 10);
+
+ // restore position
gl.glPopMatrix();
}
/**
- * Draws the legs and feet of the robot.
+ * Draws the upper and lower legs and feet of the robot.
+ * @param isRight True if at the robot's right (from the robot POV).
*/
- private void drawLegs() {
- // Push the matrix for returning to origin
+ private void drawLeg(boolean isRight) {
+ // save center position
gl.glPushMatrix();
-
- // Translate and scale for the left leg
- gl.glTranslatef(torsoWidth / 2 - legWidth * 2, 0f,
- - legLength / 2 - torsoHeight / 2);
- gl.glScalef(legWidth, legWidth, legLength);
-
- // Set the color and draw the left leg
- setColorRGB(150, 150, 150);
- glut.glutSolidCube(1f);
-
- // First scale and translate back,
- // then new transformation for left foot
- gl.glScalef(1/legWidth, 1/legWidth, 1/legLength);
- gl.glTranslatef(0f, 0f, - legLength / 2);
- gl.glTranslatef(0f, legWidth / 2, -legWidth / 2);
- gl.glScalef(legWidth, legWidth * 2, legWidth);
-
- // Set the color and draw left foot
- setColorRGB(100, 100, 100);
- glut.glutSolidCube(1f);
-
- // Pop the matrix and then push, so we are at the origin
- gl.glPopMatrix();
- gl.glPushMatrix();
-
- // Translate and scale for the right leg
- gl.glTranslatef(-torsoWidth / 2 + legWidth * 2, 0f,
- - legLength / 2 - torsoHeight / 2);
- gl.glScalef(legWidth, legWidth, legLength);
-
- // Set the color and draw right leg
- setColorRGB(150, 150, 150);
- glut.glutSolidCube(1f);
-
- // Scale and translate back,
- // then translate and scale for right foot
- gl.glScalef(1/legWidth, 1/legWidth, 1/legLength);
- gl.glTranslatef(0f, 0f, - legLength / 2);
- gl.glTranslatef(0f, legWidth / 2, -legWidth / 2);
- gl.glScalef(legWidth, legWidth * 2, legWidth);
-
- // Set color and draw right foot
- setColorRGB(100, 100, 100);
- glut.glutSolidCube(1f);
-
- // Pop so we are at the origin
+
+ // The legs are located on the first and third quarter
+ float leg_top_x = -torsoWidth / 4;
+ if (!isRight) {
+ leg_top_x += torsoWidth / 2;
+ }
+ gl.glTranslatef(leg_top_x, 0f, -torsoHeight / 2);
+ drawJoint();
+
+ // upper leg half
+ gl.glTranslatef(0, 0, -legLength / 4);
+ drawBeam(legWidth, legWidth, legLength / 2, Direction.Z, Color.DARK_GRAY);
+
+ // knee
+ gl.glTranslatef(0, 0, -legLength / 4);
+ drawJoint();
+
+ // lower leg half
+ gl.glTranslatef(0, 0, -legLength / 4);
+ drawBeam(legWidth, legWidth, legLength / 2, Direction.Z, Color.DARK_GRAY);
+
+ // draw feet!
+ if (!asStickFigure) {
+ gl.glTranslatef(0, legWidth / 2, -legLength / 4 - footHeight / 2);
+ drawBeam(footWidth, footLength, footHeight, Direction.Y, Colors.GRAYISH);
+ }
+
+ // Restore position
gl.glPopMatrix();
}
/**
* Draw both arms and both hands of the robot.
+ * @param isRight True if at the robot's right (from the robot POV).
*/
- private void drawArms() {
+ private void drawArm(boolean isRight) {
// Push the translation matrix so we can return to the origin
gl.glPushMatrix();
-
- // Translate and scale for the left arm
- gl.glTranslatef(torsoWidth / 2 + armWidth * 1.5f, 0f,
- torsoHeight / 2 - armLength / 2 - 0.05f);
- gl.glScalef(armWidth, armWidth, armLength);
-
- // Set the color and draw the arm itself
- setColorRGB(200, 200, 200);
- glut.glutSolidCube(1f);
-
- // Translate and scale for the left hand
- gl.glScalef(1/armWidth, 1/armWidth, 1/armLength);
- gl.glTranslatef(0f, 0f, - armLength / 2);
-
- // Set the color and draw the left hand
- setColorRGB(130, 158, 174);
- glut.glutSolidSphere(armWidth * 1.25f, 10, 10);
-
- // Pop the translation matrix and return to the origin
- gl.glPopMatrix();
- gl.glPushMatrix();
-
- // Translate and scale for the right arm
- gl.glTranslatef(-(torsoWidth / 2 + armWidth * 1.5f), 0f,
- torsoHeight / 2 - armLength / 2 - 0.05f);
- gl.glScalef(armWidth, armWidth, armLength);
-
- // Set the color and draw the right arm
- setColorRGB(200, 200, 200);
- glut.glutSolidCube(1f);
-
- // Translate and scale for right hand
- gl.glScalef(1/armWidth, 1/armWidth, 1/armLength);
- gl.glTranslatef(0f, 0f, - armLength / 2);
-
- // Set color and draw the right hand
- setColorRGB(130, 158, 174);
- glut.glutSolidSphere(armWidth * 1.25f, 10, 10);
-
- // Pop the translation matrix so we are at the origin again
+
+ // the arm is located outside the torso
+ float arm_x = torsoWidth / 2 + armWidth * 1.5f;
+ if (isRight) {
+ arm_x *= -1;
+ }
+ // arm starts next to the shoulder let's add a joint there...
+ gl.glTranslatef(arm_x, 0, torsoHeight / 2);
+ drawJoint();
+
+ // here is your arm (start drawing from the elbow)
+ gl.glTranslatef(0, 0, - armLength / 2);
+ drawBeam(armWidth, armWidth, armLength, Direction.Z, Colors.ARM_GRAY_COLOR);
+
+ if (!asStickFigure) {
+ // Give me a big hand!
+ setColor(Colors.DIRTY_BLUE);
+ gl.glTranslatef(0f, 0f, - armLength / 2);
+ glut.glutSolidSphere(armWidth * 1.25f, 10, 10);
+ }
+
gl.glPopMatrix();
}
/**
- * Set the color for drawing specified with RGB values.
- *
- * @param r Red parameter (0 - 255)
- * @param g Green parameter (0 - 255)
- * @param b Blue parameter (0 - 255)
- */
- private void setColorRGB(int r, int g, int b) {
- gl.glColor3ub((byte) r, (byte) g, (byte) b);
- }
-
- /**
* Draw the head and the neck of the robot.
*/
private void drawHead() {
// Push matrix so we can go to the origin afterwards
gl.glPushMatrix();
-
- // Translate and scale for the neck
+
+ // position centered above the torso for the neck
gl.glTranslatef(0f, 0f, torsoHeight / 2 + neckHeight / 2);
- gl.glScalef(headRadius / 2.5f, headRadius / 2.5f, neckHeight);
-
- // Set color and draw neck
- setColorRGB(230, 230, 230);
- glut.glutSolidCube(1f);
-
- // Pop the matrix and push so we are at the origin again
- gl.glPopMatrix();
- gl.glPushMatrix();
-
- // Translate so we are above the neck for the head
- gl.glTranslatef(0f, 0f, torsoHeight / 2 + neckHeight
- + headRadius / 2);
-
+ float neckRadius = headRadius / 2.5f;
+ drawBeam(neckRadius, neckRadius, neckHeight, Direction.Z, Colors.LAVENDER);
+
+ // continue moving to the center of the head
+ gl.glTranslatef(0f, 0f, neckHeight / 2 + headRadius / 2);
+
// Set color and draw head
- setColorRGB(190, 210, 220);
+ setColor(asStickFigure ? boneColor : Colors.PALE_TURQOISE);
glut.glutSolidSphere(headRadius, 10, 10);
-
+
// Pop so we are at the origin again
gl.glPopMatrix();
}