#include "chainImage.h" #define min(a,b) ((a) < (b) ? (a) : (b)) #define max(a,b) ((a) > (b) ? (a) : (b)) float distance(ofPoint p1,ofPoint p2){ return pow(pow(p1.x-p2.x,2)+pow(p1.y-p2.y,2),0.5); } void chainImage::init(ofPoint _linkPos,float _linkScale,float _linkRot){ linkPos=_linkPos; linkScale=_linkScale; linkRot=_linkRot; setAnchorPercent(0.5,0.5); } void chainImage::start(bool reverse){ transition=reverse?1.0f:0.0f; time=ofGetElapsedTimef(); setUseTexture(true); scale=reverse?linkScale*link->linkScale:linkScale; /* printf("Started: %s: link %f current scale %f transition %f\n", filename.c_str(), linkScale, scale, transition ); */ } void chainImage::updateRotationTimeline(){ rotationTimeline.clear(); //need to compare 5 points to generate this segment //quick and dirty approach, bezier handles take the slope between the //previous and subsequent points, unless it's a horizontal turning point //rotation curve always starts at the origin as it's relative to where we have already rotated to rotationTimeline.addVertex(0,0); ofPoint cp1,cp2,p; if(linked->linkRot==0.0f){ //hmm, shouldn't use float equality cp1=ofPoint(ROTATION_BEZIER_FRACTION, 0); } else { float slope=link->linkRot-linked->linkRot; cp1=ofPoint(ROTATION_BEZIER_FRACTION,slope/ROTATION_BEZIER_FRACTION); } if(link->linkRot==link->link->linkRot){ //hmm, shouldn't use float equality cp2=ofPoint(1.0f-ROTATION_BEZIER_FRACTION, link->linkRot); } else { float slope=link->link->linkRot-linkRot; cp2=ofPoint(1.0f-ROTATION_BEZIER_FRACTION, link->linkRot); } p=ofPoint(1.0f, link->linkRot); rotationTimeline.bezierTo(cp1,cp2,p); } int chainImage::updateOutput(float decayRatio){ //where there is rotation of the link, the path needs to be rotated updateRotationTimeline(); path.clear(); path.addVertex(linkPos); //path.addVertex(linkPos+(link->linkPos*linkScale)); ofPoint rotated_destination=ofPoint( (link->linkPos.x*cos(linkRot*(PI/180)))-(link->linkPos.y*sin(linkRot*(PI/180))), (link->linkPos.y*cos(linkRot*(PI/180)))+(link->linkPos.x*sin(linkRot*(PI/180))) ); ofPoint destination=linkPos+(rotated_destination*linkScale); ofPoint previous=linkPos+(rotated_destination*linkScale*(1.0f-BEZIER_IN)); path.bezierTo( linkPos.x*(1.0f+BEZIER_OUT),linkPos.y*(1.0f+BEZIER_OUT), previous.x,previous.y, destination.x,destination.y); //totalframes=log(1.0f/256)/log(decayRatio); scale*=decayRatio; //framecount++; //find n such that decayRatio^n=1/256 //logarithm of x base b = log(x)/log(b) //log(decayRatio,decayRatio^n) //n = log(decayRatio,1/256) transition=-(scale-linkScale)/(linkScale-(linkScale*link->linkScale)); //transition=min(1.0f,((float)framecount)/totalframes); /* printf("ChainImage %f: scale %f linkscale %f transition %f \n", decayRatio, scale, linkScale, transition); */ if (scale>linkScale){ transition = 0.0f; return SWITCH_REVERSE; } if (scale>linkScale*link->linkScale){ return SWITCH_NONE; } transition = 1.0f; return SWITCH_FORWARD; } ofVec3f chainImage::getTransform(){ //ofVec3f _scaledTarget = link->linkPos * linkScale; //return linkPos + ( _scaledTarget * transition ); //ofPoint return path.getPointAtPercent(transition); } float chainImage::getScale(){ return scale; } float chainImage::getRotation(){ //this is the camera rotation //at the beginning of the transition //this should rotate to match linkRot //at the end, it should match link->linkRot //when we switch image, link->linkRot becomes linkRot //linkRot is no longer seen //return linkRot+(transition*link->linkRot); //linkRot+ return linkRot+rotationTimeline.getPointAtPercent(transition).y; }; void chainImage::makeThumbnail(){ thumbnail.setUseTexture(false); thumbnail=(const ofImage)*this; //copy the ofImage itself // thumbnail.setFromPixels(this->getPixels()); float thumbheight=THUMB_SIZE; //ofGetWindowHeight()*THUMB_BORDER_RATIO; float thumbwidth=(thumbnail.getWidth()/thumbnail.getHeight())*thumbheight; float borderwidth=ofGetWindowHeight()*(1.0-THUMB_BORDER_RATIO)*0.5; printf("Rescaling: %fx%f to %fx%f for screen %fx%f, border %f\n", thumbnail.getWidth(),thumbnail.getHeight(), thumbwidth,thumbheight, (float)ofGetWindowWidth(),(float)ofGetWindowHeight(), borderwidth); thumbnail.resize(thumbwidth,thumbheight); thumbnail.update(); printf("Rescaled %s: %fx%f\n", filename.c_str(), thumbnail.getWidth(), thumbnail.getHeight() ); thumbnail.setAnchorPoint(thumbnail.getWidth()/2,thumbnail.getHeight()/2); } void chainImage::drawChain(float fadeIn,bool additive,float intensity,float zoomMultiplier){ //printf("Drawing chain transition: %f\n",transition); //we are correctly geting to 1 //the transformw don't quite add up? //we are drawing each image twice? glPushMatrix(); if (additive){ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); ofSetColor(255,255,255,255*(1.0f-min(1.0,transition/fadeIn))*intensity); } else { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); ofSetColor(255,255,255,255*intensity); } //ofDisableAlphaBlending(); setAnchorPoint(getWidth()/2,getHeight()/2); //add a scale factor to the outgoing image that builds up over the transition glPushMatrix(); //if this is linear we see the jump from the unaccelerated phase //float zoomFactor=((zoomMultiplier-1.0f)*transition)+1.0f; //this is worse why? float zoomFactor=pow(zoomMultiplier,1.0f+transition); glScalef(zoomFactor,zoomFactor,zoomFactor); draw(0,0,getWidth(),getHeight()); glPopMatrix(); glTranslatef(linkPos.x,linkPos.y,0); glRotatef(linkRot,0,0,1); glScalef(linkScale,linkScale,linkScale); //ofEnableAlphaBlending(); glEnable(GL_BLEND); ofSetColor(255,255,255,255*min(1.0,transition/fadeIn)*intensity); link->setAnchorPoint(link->getWidth()/2,link->getHeight()/2); link->draw(0,0,link->getWidth(),link->getHeight()); glDisable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPopMatrix(); } Json::Value chainImage::toJson(){ Json::Value json=Json::Value(Json::objectValue); json["linkPos"]=Json::Value(Json::arrayValue); json["linkPos"].append(linkPos.x); json["linkPos"].append(linkPos.y); json["linkScale"]=linkScale; json["linkRot"]=linkRot; json["filename"]=filename; return json; } bool chainImage::fromJson(Json::Value json){ if (load(json["filename"].asString())){ linkPos=ofPoint(json["linkPos"][0].asDouble(),json["linkPos"][1].asDouble()); linkScale=json["linkScale"].asDouble(); linkRot=json["linkRot"].asDouble(); return true; } return false; } void chainImage::setupTextures(){ setUseTexture(true); update(); thumbnail.setUseTexture(true); thumbnail.update(); }