//// // Face blend takes to face warps and combines them together // so that two different face images can be combined together // // Thankfully, you only (hopefully) just need to adjust one mesh, // and copy the warp over to the other image //// class FaceBlend{ // the warps private FaceWarp initWarp; // the warp we warp from private FaceWarp finalWarp; // and the warp we want to end up private float iAlpha; private float fAlpha; // the animation stuff private boolean bAnimating; private float playhead; //// // Construction //// public FaceBlend(FaceWarp initWarp, FaceWarp finalWarp){ this.initWarp = initWarp; this.finalWarp = finalWarp; this.playhead = 0.0; this.iAlpha = 255; this.fAlpha = 255; } //// // The tick! //// public void tick(float delta){ if(this.bAnimating){ this.playhead += delta; // set each of the warps playheads this.initWarp.setPlayhead(this.playhead); this.finalWarp.setPlayhead(this.playhead); // set the alphas for each warp this.initWarp.getMesh().setAlpha(this.getAlphaValue()); this.finalWarp.getMesh().setAlpha(255);// - this.getAlphaValue()); // and interpolate to the new position this.initWarp.interpolateFrames(); this.finalWarp.interpolateFrames(); if(this.playhead >= 1.0){ this.playhead = 1; this.stop(); } } else { //lets see a solid background over the iffy top ground this.initWarp.getMesh().setAlpha(this.iAlpha); this.finalWarp.getMesh().setAlpha(this.fAlpha); } } //// // The draw! //// public void draw(){ this.finalWarp.draw(); this.initWarp.draw(); } //// // Copies the changes from the initWarp and applies it to the // final warp, ya //// public void matchWarps(){ // first generate the difference Vectors for the first mesh QuadMesh initMesh = this.initWarp.getMesh(); Point[][] iStart = this.initWarp.getInitVertex(); Point[][] iEnd = this.initWarp.getFinalVertex(); Vector[][] difference = new Vector[initMesh.meshSize + 1][initMesh.meshSize + 1]; for(int i = 0; i <= initMesh.meshSize; i++){ for(int j = 0; j <= initMesh.meshSize; j++){ difference[i][j] = new Vector(iEnd[i][j].x - iStart[i][j].x, iEnd[i][j].y - iStart[i][j].y); } } // ok, we've made the difference matrix, now apply the reverse to the final warp's inital matrix QuadMesh finalMesh = this.finalWarp.getMesh(); Point[][] fStart = this.finalWarp.getInitVertex(); for(int i = 0; i <= finalMesh.meshSize; i++){ for(int j = 0; j <= finalMesh.meshSize; j++){ fStart[i][j] = fStart[i][j].subVector(difference[i][j]); } } //finalWarp.setInitVertex(fStart); // and set the finals mesh isPinned values boolean[][] iPinned = initMesh.getIsPinned(); boolean[][] fPinned = finalMesh.getIsPinned(); for(int i = 0; i <= finalMesh.meshSize; i++){ for(int j = 0; j <= finalMesh.meshSize; j++){ fPinned[i][j] = iPinned[i][j]; } } //finalMesh.setIsPinned(fPinned); // done? } //// // Uses a correlator to warp the original mesh //// public void useCorrelator(Correlator c){ int markerCount = c.getMarkerCount(); float smallestRadius; int sIndexX; int sIndexY; QuadMesh initMesh = this.initWarp.getMesh(); QuadMesh finalMesh = this.finalWarp.getMesh(); Point[][] iVertex = this.initWarp.getInitVertex(); Vector[][] difference = new Vector[initMesh.meshSize + 1][initMesh.meshSize + 1]; BlendMarker focus; // first, we need to normalize the marker positions c.normalizeMarkers(initMesh.getFinalDrawPoint(), finalMesh.getFinalDrawPoint()); for(int m = 0; m < markerCount; m++){ focus = c.getMarker(m); if(focus.isComplete()){ smallestRadius = 10000000; sIndexX = -1; sIndexY = -1; for(int x = 0; x <= initMesh.meshSize; x ++){ for(int y = 0; y <= initMesh.meshSize; y ++){ // lets find the closetes if(smallestRadius > focus.getInitialMark().distanceTo(iVertex[x][y])){ // found a smaller one set the index smallestRadius = focus.getInitialMark().distanceTo(iVertex[x][y]); sIndexX = x; sIndexY = y; } } } // now lets see if we have a vector to add in if(sIndexX != -1 && sIndexY != -1){ if(! initMesh.isPinned(sIndexX, sIndexY)){ difference[sIndexX][sIndexY] = focus.getDisplacement(); } } } } // now, apply those changes to the initial quad mask! Point[][] iPoints = initWarp.getFinalVertex(); boolean[][] pinned = initMesh.getIsPinned(); for(int x = 0; x <= initMesh.meshSize; x ++){ for(int y = 0; y <= initMesh.meshSize; y ++){ if(difference[x][y] != null){ iPoints[x][y] = iPoints[x][y].addVector(difference[x][y]); pinned[x][y] = true; } } } } //// // Gets the alpha for the initWarp //// public float getAlphaValue(){ return 255 * (1.0 - this.playhead); } ///////////////////////// // GETTERS AND SETTERS // ///////////////////////// public void setPlayhead(float playhead){ this.playhead = playhead; } public void start(){ this.bAnimating = true; this.initWarp.showInitialConstraints(); } public void stop(){ this.bAnimating = false; } public boolean isAnimating(){ return this.bAnimating; } public void setIAlpha(float a){ this.iAlpha = a; } public void setFAlpha(float a){ this.fAlpha = a; } }