/* * Daniel King * gtg351x * 901856535 * * CS 4496 Project 4 * Professor Jarek Rossignac */ /** * Made by:
* Daniel King
* gtg351x
* 901856535
*
* For:
* Jarek Rossignac's CS 4496 Course
* at Georgia Tech
*
* Go back for instructions and more information. */ import processing.opengl.*; import java.util.ArrayList; /* Filename of start image. */ String filenameA = "1.jpg"; /* Filename of final image. */ String filenameB = "2.jpg"; /* Current mouse position. */ pt mouse = new pt(0, 0, 0); /* Mouse coordinates relative to the center of the window. */ pt mouseRel = new pt(0, 0, 0); /* Coordinate of the mouse when last pressed. */ pt lastPressed = new pt(0, 0, 0); /* Currently selected corner. */ int selectedCorner = 0; /* True if a corner is selected and being dragged. */ boolean selected = false; /* Flag for showing vertices. */ boolean showVertices = true; /* Flag for showing edges. */ boolean showEdges = true; /* Flag for showing control point numbers. */ boolean showPNumbers = false; /* Size of the mesh grid. */ int size = 25; /* Number of parts in the morph sequence. */ int numGrids = 4; /* Morph sequence. */ Grid animation[] = new Grid[numGrids]; /* Currently Selected grid. */ Grid currentGrid; /* True if animating the morph. */ boolean animate = false; /* Time in the animation. */ int time = 0; /* True if the animation is paused. */ boolean pause = false; /* Font used for labels. */ PFont font; /* Current editing mode. */ int currentMode = 0; /* GUI BUTTONS AND LABELS. */ Button saveConstraints[] = new Button[9]; Label saveConstLabel; Button loadConstraints[] = new Button[9]; Label loadConstLabel; Button loadSequence[] = new Button[9]; Label loadSequenceLabel; Button saveSequence[] = new Button[9]; Label saveSequenceLabel; Button resetConstraints; Button loadImages[] = new Button[9]; Label loadImageLabel; Button resetTexture; Button currentSegment[] = new Button[numGrids]; Label currentSegmentLabel; Button modeButtons[] = new Button[8]; Label modeLabel; Button showControls[] = new Button[3]; Label controlsLabel; Scrollbar alphaBar; Label alphaLabel; Button smoothButton[] = new Button[3]; /* Alpha transparency amounts for each grid. */ int alpha[] = new int[numGrids]; /* Time for a single segment. */ int segmentTime = 20; /* Current smooth mode. */ int smoothMode = 0; /* List of shapes. */ ArrayList shapes; /* Shape currently being created. */ ArrayList currentShape; /* Number of times to smooth while editing. */ int editSmoothTimes = 1; /* Number of times to smooth while animating. */ int animateSmoothTimes = 25; /* Sets up the morpher. */ void setup() { // Create an OpenGL window. size(920, 700, OPENGL); framerate(30); font = loadFont("Courier-14.vlw"); setupGUI(); shapes = new ArrayList(); for (int i = 0; i < numGrids; i++) { if (i < 2) { animation[i] = new Grid(filenameA, 600, 700, 0, 0, 0, i); } else { animation[i] = new Grid(filenameB, 600, 700, 0, 0, 0, i); } alpha[i] = 255; } currentGrid = animation[0]; } /* Sets up the user interface. */ void setupGUI() { int savePos = 30; saveConstLabel = new Label(620, savePos, 0, black, "Save Constraints:"); for (int i = 0; i < saveConstraints.length; i++) { saveConstraints[i] = new Button(20, 20, 630 + 29 * i, savePos + 5, 0, false, blue, yellow, lightblue, str(i + 1)); } int loadPos = 80; loadConstLabel = new Label(620, loadPos, 0, black, "Load Constraints:"); for (int i = 0; i < loadConstraints.length; i++) { loadConstraints[i] = new Button(20, 20, 630 + 29 * i, loadPos + 5, 0, false, blue, yellow, lightblue, str(i + 1)); } int resetPos = 110; resetConstraints = new Button(185, 20, 630, resetPos, 0, false, blue, yellow, lightblue, "Reset Constraints"); int loadImagePos = 165; loadImageLabel = new Label(620, loadImagePos, 0, black, "Load Image:"); for (int i = 0; i < loadImages.length; i++) { loadImages[i] = new Button(20, 20, 630 + 29 * i, loadImagePos + 5, 0, false, blue, yellow, lightblue, str(i + 1)); } int resetTextPos = 195; resetTexture = new Button(245, 20, 630, resetTextPos, 0, false, blue, yellow, lightblue, "Set Texture Coordinates"); int curSegPos = 250; currentSegmentLabel = new Label(620, curSegPos, 0, black, "Current Segment in Morph:"); for (int i = 0; i < currentSegment.length; i++) { currentSegment[i] = new Button(20, 20, 630 + 29 * i, curSegPos + 5, 0, false, blue, yellow, lightblue, str(i + 1)); } currentSegment[0].selected = true; int alphaPos = 295; alphaLabel = new Label(620, alphaPos, 0, black, "Segment Transparency:"); alphaBar = new Scrollbar(260, 20, 25, 630, alphaPos + 5, 0, 1.0, blue, yellow, lightblue); int saveMorphPos = 340; saveSequenceLabel = new Label(620, saveMorphPos, 0, black, "Save Morph Sequence:"); for (int i = 0; i < saveSequence.length; i++) { saveSequence[i] = new Button(20, 20, 630 + 29 * i, saveMorphPos + 5, 0, false, blue, yellow, lightblue, str(i + 1)); } int loadMorphPos = 395; loadSequenceLabel = new Label(620, loadMorphPos, 0, black, "Load Morph Sequence:"); for (int i = 0; i < loadSequence.length; i++) { loadSequence[i] = new Button(20, 20, 630 + 29 * i, loadMorphPos + 5, 0, false, blue, yellow, lightblue, str(i + 1)); } int modePos = 450; modeLabel = new Label(620, modePos, 0, black, "Mode:"); modeButtons[0] = new Button(163, 20, 630, modePos + 5, 0, true, blue, yellow, lightblue, "Define Features"); modeButtons[6] = new Button(101, 20, 798, modePos + 5, 0, false, blue, yellow, lightblue, "New Shape"); modeButtons[1] = new Button(163, 20, 630, modePos + 30, 0, false, blue, yellow, lightblue, "Delete Features"); modeButtons[7] = new Button(101, 20, 798, modePos + 30, 0, false, blue, yellow, lightblue, "Del Shape"); modeButtons[2] = new Button(153, 20, 630, modePos + 55, 0, false, blue, yellow, lightblue, "Morph Features"); modeButtons[3] = new Button(113, 20, 630, modePos + 80, 0, false, blue, yellow, lightblue, "Play Morph"); modeButtons[4] = new Button(60, 20, 748, modePos + 80, 0, false, blue, yellow, lightblue, "Pause"); modeButtons[5] = new Button(70, 20, 813, modePos + 80, 0, false, blue, yellow, lightblue, "Rewind"); int smoothPos = 560; smoothButton[0] = new Button(100, 20, 630, smoothPos, 0, true, blue, yellow, lightblue, "Bilaplace"); smoothButton[1] = new Button(100, 20, 735, smoothPos, 0, false, blue, yellow, lightblue, "Tuck-Tuck"); smoothButton[2] = new Button(45, 20, 840, smoothPos, 0, false, blue, yellow, lightblue, "None"); int showPos = 620; controlsLabel = new Label(620, showPos, 0, black, "Show:"); showControls[0] = new Button(155, 20, 630, showPos + 5, 0, true, blue, yellow, lightblue, "Control Points"); showControls[1] = new Button(155, 20, 630, showPos + 30, 0, true, blue, yellow, lightblue, "Triangle Edges"); showControls[2] = new Button(140, 20, 630, showPos + 55, 0, false, blue, yellow, lightblue, "Point Numbers"); } /* Draws the user interface. */ void drawGUI() { alpha[currentGrid.id] = (int)(alphaBar.update() * 255); saveConstLabel.drawLabel(); for (int i = 0; i < saveConstraints.length; i++) { saveConstraints[i].drawButton(); } loadConstLabel.drawLabel(); for (int i = 0; i < loadConstraints.length; i++) { loadConstraints[i].drawButton(); } resetConstraints.drawButton(); loadImageLabel.drawLabel(); for (int i = 0; i < loadImages.length; i++) { loadImages[i].drawButton(); } alphaLabel.drawLabel(); alphaBar.drawScrollbar(); resetTexture.drawButton(); currentSegmentLabel.drawLabel(); for (int i = 0; i < currentSegment.length; i++) { currentSegment[i].drawButton(); } saveSequenceLabel.drawLabel(); for (int i = 0; i < saveSequence.length; i++) { saveSequence[i].drawButton(); } loadSequenceLabel.drawLabel(); for (int i = 0; i < loadSequence.length; i++) { loadSequence[i].drawButton(); } modeLabel.drawLabel(); for (int i = 0; i < modeButtons.length; i++) { modeButtons[i].drawButton(); } controlsLabel.drawLabel(); for (int i = 0; i < showControls.length; i++) { showControls[i].drawButton(); } for (int i = 0; i < smoothButton.length; i++) { smoothButton[i].drawButton(); } } /* Handles mouse presses on the user interface. */ void pressedGUI() { for (int i = 0; i < saveConstraints.length; i++) { if (saveConstraints[i].mouseOver()) { saveConstraints[i].selected = true; } } for (int i = 0; i < loadConstraints.length; i++) { if (loadConstraints[i].mouseOver()) { loadConstraints[i].selected = true; } } if (resetConstraints.mouseOver()) { resetConstraints.selected = true; } for (int i = 0; i < loadImages.length; i++) { if (loadImages[i].mouseOver()) { loadImages[i].selected = true; } } if (alphaBar.mouseOver()) { alphaBar.selected = true; } if (resetTexture.mouseOver()) { resetTexture.selected = true; } for (int i = 0; i < currentSegment.length; i++) { if (currentSegment[i].mouseOver()) { currentSegment[i].selected = true; } } for (int i = 0; i < saveSequence.length; i++) { if (saveSequence[i].mouseOver()) { saveSequence[i].selected = true; } } for (int i = 0; i < loadSequence.length; i++) { if (loadSequence[i].mouseOver()) { loadSequence[i].selected = true; } } for (int i = 0; i < smoothButton.length; i++) { if (smoothButton[i].mouseOver()) { smoothButton[i].selected = true; } } } /* Handles mouse releases on the user interface. */ void mouseGUI() { for (int i = 0; i < saveConstraints.length; i++) { if (saveConstraints[i].mouseOver()) { currentGrid.saveConstraints(str(i + 1) + ".m"); saveConstraints[i].selected = false; } } for (int i = 0; i < loadConstraints.length; i++) { if (loadConstraints[i].mouseOver()) { currentGrid.loadConstraints(str(i + 1) + ".m"); loadConstraints[i].selected = false; } } if (resetConstraints.mouseOver()) { currentGrid.setupGrid(); resetConstraints.selected = false; } for (int i = 0; i < loadImages.length; i++) { if (loadImages[i].mouseOver()) { currentGrid.image = loadImage(str(i + 1) + ".jpg"); loadImages[i].selected = false; } } if (alphaBar.selected) { alphaBar.selected = false; } if (resetTexture.mouseOver()) { currentGrid.setTextureCoords(); resetTexture.selected = false; } for (int i = 0; i < currentSegment.length; i++) { if (currentSegment[i].mouseOver()) { currentGrid = animation[i]; alphaBar.percent = alpha[i] / 255.0; for (int j = 0; j < currentSegment.length; j++) { currentSegment[j].selected = false; } currentSegment[i].selected = true; } } for (int i = 0; i < saveSequence.length; i++) { if (saveSequence[i].mouseOver()) { saveMorphSequence(i + 1); saveSequence[i].selected = false; } } for (int i = 0; i < loadSequence.length; i++) { if (loadSequence[i].mouseOver()) { loadMorphSequence(i + 1); loadSequence[i].selected = false; } } for (int i = 0; i < modeButtons.length; i++) { if (modeButtons[i].mouseOver()) { currentMode = i; if (i == 6) { currentShape = new ArrayList(); shapes.add(currentShape); } if ((modeButtons[0].selected && i != 0) || (!modeButtons[0].selected && i == 0)) { for (int j = 0; j < numGrids; j++) { animation[j].swapVertices(); } } for (int j = 0; j < modeButtons.length; j++) { modeButtons[j].selected = false; } modeButtons[i].selected = true; } } for (int i = 0; i < showControls.length; i++) { if (showControls[i].mouseOver()) { showControls[i].selected = !showControls[i].selected; switch (i) { case 0: showVertices = showControls[i].selected; break; case 1: showEdges = showControls[i].selected; break; case 2: showPNumbers = showControls[i].selected; break; } } } for (int i = 0; i < smoothButton.length; i++) { if (smoothButton[i].mouseOver()) { smoothMode = i; for (int j = 0; j < smoothButton.length; j++) { smoothButton[j].selected = false; } smoothButton[i].selected = true; } } } /* Draws the contents of the morpher window. */ void draw() { background(255); sphereDetail(4); drawGUI(); if (currentMode == 3) { animate = true; pause = false; } else if (currentMode == 4) { animate = true; pause = true; } else if (currentMode == 5) { setupAnimation(); animate = true; pause = true; } else { animate = false; pause = false; } /* If animating, interpolate between the parts of the morph sequence. */ if (animate) { int seg = time / segmentTime; int nextseg = seg + 1; int segTime = time % segmentTime; if (seg >= numGrids - 1) { animation[numGrids - 1].drawGrid(255); } else { animation[nextseg].interpolateTo(animation[seg], 1 - (float)segTime / segmentTime, 1.0, animateSmoothTimes); animation[seg].interpolateTo(animation[seg + 1], (float) segTime / segmentTime, 1 - (float)segTime / segmentTime, animateSmoothTimes); } if (!pause) { time++; } } /* Otherwise, it is in editing mode; draw all the segments on top of eachother for editing. */ else { if (selected) { if (currentMode == 6) { currentShape.add(new Integer(currentGrid.v(selectedCorner))); } else if (currentMode == 7) { removeShape(currentGrid.v(selectedCorner)); } else { currentGrid.g(selectedCorner).setToMouse(); } } for (int i = 0; i < animation.length; i++) { animation[i].smooth(editSmoothTimes); } if (currentMode == 0) { currentGrid.setTextureCoords(); } for (int i = 0; i < numGrids; i++) { animation[numGrids - i - 1].drawGrid(alpha[numGrids - i - 1]); } if (showEdges) { currentGrid.drawEdges(black); } if (showVertices) { currentGrid.drawVertices(red); drawShapes(); } } } /* Draw user defined shapes. */ void drawShapes() { for (int i = 0; i < shapes.size(); i++) { ArrayList shape = (ArrayList)(shapes.get(i)); strokeWeight(3); if (i < 5) { stroke( color( 51 * i, 255 - 51 * i, 125 ) ); } else { stroke( color( (51 * (i - 5)) % 256, 125, (255 - 51 * (i - 5)) % 256) ); } noFill(); for (int j = 0; j < shape.size() - 1; j++) { currentGrid.vertices[ ( (Integer)(shape.get(j)) ).intValue() ].showLineTo( currentGrid.vertices[ ((Integer)(shape.get(j + 1))).intValue() ] ); } strokeWeight(1); } } /* Remove a user defined shape. */ void removeShape(int corner) { boolean found = false; for (int i = 0; i < shapes.size() && !found; i++) { ArrayList shape = (ArrayList)(shapes.get(i)); for (int j = 0; j < shape.size() && !found; j++) { if ( ( (Integer)( shape.get(j) ) ).intValue() == corner ) { shapes.remove(i); found = true; } } } } /* Setup the animation. */ void setupAnimation() { time = 0; } /* Handles mouse presses. */ void mousePressed() { currentGrid.mousePressed(); pressedGUI(); } /* Handles mouse releases. */ void mouseReleased() { currentGrid.mouseReleased(); mouseGUI(); } /* Saves a morph sequence from file. */ void saveMorphSequence(int m) { String[] output = new String [1 + numGrids * 2]; int s = 0; output[s++] = str(numGrids); for (int i = 0; i < numGrids; i++) { String morphName = str(m) + "-" + str(i) + "-m.m"; String featureName = str(m) + "-" + str(i) + "-f.m"; if (currentMode != 0) { animation[i].swapVertices(); } animation[i].saveConstraints(featureName); animation[i].swapVertices(); animation[i].saveConstraints(morphName); if (currentMode == 0) { animation[i].swapVertices(); } output[s++] = featureName; output[s++] = morphName; } saveStrings(str(m) + ".ms", output); } /* Loads a morph sequence from file. */ void loadMorphSequence(int m) { String[] input = loadStrings(str(m) + ".ms"); int s = 0; numGrids = int(input[s++]); // Commented out for speed - only needed if number of grids varies. //for (int i = 0; i < numGrids; i++) { // animation[i] = new Grid(filenameA, 600, 700, 0, 0, 0, i); //} currentGrid = animation[0]; for (int j = 0; j < currentSegment.length; j++) { currentSegment[j].selected = false; } currentSegment[0].selected = true; for (int i = 0; i < numGrids; i++) { if (currentMode != 0) { animation[i].swapVertices(); } animation[i].loadConstraints(input[s++]); animation[i].smooth(100); animation[i].setTextureCoords(); animation[i].swapVertices(); animation[i].loadConstraints(input[s++]); if (currentMode == 0) { animation[i].swapVertices(); } } } /* Handles keypresses, which probably should not be used * since the GUI is available. */ void keyPressed() { if (key=='+') { if ((alpha[currentGrid.id] += 4) > 255) { alpha[currentGrid.id] = 255; } } if (key == '-') { if ((alpha[currentGrid.id] -= 4) < 0) { alpha[currentGrid.id] = 0; } } if (key == 'e') { showEdges = !showEdges; } if (key == 'v') { showVertices = !showVertices; } if (key == '!') { currentGrid.saveConstraints("1.m"); } if (key == '@') { currentGrid.saveConstraints("2.m"); } if (key == '#') { currentGrid.saveConstraints("3.m"); } if (key == '$') { currentGrid.saveConstraints("4.m"); } if (key == '1') { currentGrid.loadConstraints("1.m"); } if (key == '2') { currentGrid.loadConstraints("2.m"); } if (key == '3') { currentGrid.loadConstraints("3.m"); } if (key == '4') { currentGrid.loadConstraints("4.m"); } if (key == ' ') { animate = !animate; } if (key == 'r') { setupAnimation(); } if (key == 'p') { pause = !pause; } }