diff options
Diffstat (limited to 'src/RobotRace.java')
-rw-r--r-- | src/RobotRace.java | 482 |
1 files changed, 197 insertions, 285 deletions
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(); } |