#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(){ transition=0.0f; time=ofGetElapsedTimef(); setUseTexture(true); scale=linkScale; //where there is rotation of the link, the path needs to be rotated? 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); //framecount=0; } bool chainImage::update(float 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); if (scale>linkScale*link->linkScale) return false; else { transition = 1.0f; return true; } } 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+ }; void chainImage::makeThumbnail(){ thumbnail=(const ofImage)*this; //copy the ofImage itself 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.setAnchorPoint(thumbnail.getWidth()/2,thumbnail.getHeight()/2); } void chainImage::drawChain(float fadeIn,bool additive, float intensity){ //printf("Drawing chain transition: %f\n",transition); //we are correctly geting to 1 //the transformw don't quite add up? 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); draw(0,0,getWidth(),getHeight()); 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 chainImageSet::drawOutput(){ //movment and rotation are working on their own but not together. float camera_throw= (float)outputSize.y/(float)outputSize.x; //the ratio of z distance to x width camera_throw*=0.9; //fudge factor to allow tweening if (images.size()){ /* glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-ofGetWidth()/2, ofGetWidth()/2, ofGetHeight()/2, -ofGetHeight()/2, 0.0f, 5000.0f); */ glMatrixMode ( GL_MODELVIEW ); glLoadIdentity ( ); gluLookAt( currentImage->getTransform().x, currentImage->getTransform().y, // i1.linkPos.y+(xform.y*intervalpoint), currentImage->getWidth()*camera_throw*currentImage->getScale(), currentImage->getTransform().x, currentImage->getTransform().y, // i1.linkPos.y+(xform.y*intervalpoint), 0, sin(-currentImage->getRotation()*(PI/180)), cos(-currentImage->getRotation()*(PI/180)), 0); currentImage->drawChain(DEFAULT_FADEIN,additive,intensity); } } void chainImageSet::drawGui(){ ofBackground(0,0,0); float t_xoffs=0.0; float borderwidth=THUMB_SIZE*0.1; //ofGetWindowHeight()*(1.0-THUMB_BORDER_RATIO)*0.5; glPushMatrix(); /* float relscale=((float)ofGetWindowHeight())/THUMB_SIZE; glScalef(relscale,relscale,relscale); //scale view by distance betweeen thumnail size and window size: doesn't work */ //draw each image, outlined for(std::list::iterator ii=images.begin(); ii != images.end(); ii++){ ofSetColor(255,255,255); float thumbx=ii->thumbnail.getWidth()/2; float thumby=ii->thumbnail.getHeight()/2; float thumbscale=ii->thumbnail.getWidth()/ii->getWidth(); //why do I have to set this every time?? ii->thumbnail.setAnchorPercent(0.5,0.5); ii->thumbnail.draw( t_xoffs+borderwidth+thumbx, borderwidth+thumby, ii->thumbnail.getWidth(), ii->thumbnail.getHeight() ); if (ii==selected) ofSetColor(255,0,0); else ofSetColor(255,255,255); ofDrawLine(t_xoffs+borderwidth,borderwidth, t_xoffs+borderwidth+ii->thumbnail.getWidth(),borderwidth); ofDrawLine(t_xoffs+borderwidth+ii->thumbnail.getWidth(),borderwidth, t_xoffs+borderwidth+ii->thumbnail.getWidth(),borderwidth+ii->thumbnail.getHeight()); ofDrawLine(t_xoffs+borderwidth+ii->thumbnail.getWidth(),borderwidth+ii->thumbnail.getHeight(), t_xoffs+borderwidth,borderwidth+ii->thumbnail.getHeight()); ofDrawLine(t_xoffs+borderwidth,borderwidth+ii->thumbnail.getHeight(), t_xoffs+borderwidth,borderwidth); ofSetColor(255,255,255); if (ii->link){ ofPoint lp=ii->linkPos; if (ii==selected){ lp+=dragPoint; } float subpictx=t_xoffs+borderwidth+thumbx+(lp.x*thumbscale); float subpicty=borderwidth+thumby+(lp.y*thumbscale); ofDrawLine( subpictx, subpicty, t_xoffs+(borderwidth*3)+ii->thumbnail.getWidth(), borderwidth+thumby ); glPushMatrix(); glTranslatef(subpictx,subpicty,0); float r=ii->linkRot; if (ii==selected) r+=dragRotate; glRotatef(r,0,0,1); //printf("Sub image: centre at %f,%f \n",ii->link->thumbnail.getAnchorPoint().x,ii->link->thumbnail.getAnchorPoint().y); ii->link->thumbnail.setAnchorPercent(0.5,0.5); float thescale=ii->linkScale; if (ii==selected){ thescale*=(1.0f+dragScale); } ii->link->thumbnail.draw( 0, 0, ii->link->thumbnail.getWidth()*thescale, ii->link->thumbnail.getHeight()*thescale ); ofPoint p1=ofPoint( -(ii->link->thumbnail.getWidth()*thescale*0.5), -(ii->link->thumbnail.getHeight()*thescale*0.5)); ofPoint p2=ofPoint( (ii->link->thumbnail.getWidth()*thescale*0.5), -(ii->link->thumbnail.getHeight()*thescale*0.5)); ofPoint p3=ofPoint( (ii->link->thumbnail.getWidth()*thescale*0.5), (ii->link->thumbnail.getHeight()*thescale*0.5)); ofPoint p4=ofPoint( -(ii->link->thumbnail.getWidth()*thescale*0.5), (ii->link->thumbnail.getHeight()*thescale*0.5)); ofDrawLine(p1,p2); ofDrawLine(p2,p3); ofDrawLine(p3,p4); ofDrawLine(p4,p1); glPopMatrix(); } t_xoffs+=ii->thumbnail.getWidth()+(borderwidth*2); //glPopMatrix(); } } bool chainImageSet::add(std::string filename,glm::vec2 pos){ printf("Dropped file: %s at %f,%f \n",filename.c_str(),pos.x,pos.y); /* attempt to add file to chain. find if file exists in data folder if not make a symbolic link */ chainImage image; if (image.load(filename)){ image.init(ofPoint(0,0), currentDefaultImageRatio, 0 //default rotation ); printf("Loaded file: %s at %f,%f \n",filename.c_str(),pos.x,pos.y); images.push_back(image); (*images.rbegin()).link=&(*images.begin()); printf("Linked: %s to %s\n", images.rbegin()->filename.c_str(), images.begin()->filename.c_str()); if (images.size()>1){ (++images.rbegin())->link=&(*(images.rbegin())); printf("Linked: %s to %s\n", (++images.rbegin())->filename.c_str(), images.rbegin()->filename.c_str()); } else { selected=images.begin(); currentImage=&(*images.begin()); currentImage->start(); } return true; } printf("Could not load file: %s \n",filename.c_str()); return false; } void chainImageSet::keyPressed(ofKeyEventArgs &keyargs){ //printf("Got key %i, modifiers:%i\n",keyargs.key,keyargs.modifiers); switch(keyargs.key){ case '[': if (selected==images.begin()){ selected=--images.end(); } else --selected; break; case ']': ++selected; if (selected==images.end()){ selected=images.begin(); } break; case OF_KEY_UP: selected->linkPos.y--; break; case OF_KEY_DOWN: selected->linkPos.y++; break; case OF_KEY_LEFT: selected->linkPos.x--; break; case OF_KEY_RIGHT: selected->linkPos.x++; break; case OF_KEY_BACKSPACE:{ images.clear(); filename.clear(); /* auto previous=selected; previous--; if (previous==images.end()){ previous=images.end()--; } previous->link=selected->link; printf("DELETED: %s \n",selected->filename.c_str()); images.erase(selected); selected=previous++; if (selected==images.end()){ selected=images.begin(); } break; */ } case 's': case 83: { //printf("Saving... keyargs modifiers:%i\n",keyargs.modifiers); //saves over last filename or use control to choose a new one if (!filename.length()||keyargs.hasModifier(OF_KEY_CONTROL)){ ofFileDialogResult saveFileResult = ofSystemSaveDialog(ofGetTimestampString() + ".json" , "Save your file"); if (saveFileResult.bSuccess){ filename=saveFileResult.filePath; //printf("Got filename: %s\n",filename.c_str()); } //else printf("ofSystemSaveDialog failed.\n"); } if (filename.length()){ //printf("Saving %s\n",filename.c_str()); saveJson(filename); } break; } case 'l':{ //load_chain(); ofFileDialogResult openFileResult= ofSystemLoadDialog("Select a json preset"); //Check if the user opened a file if (openFileResult.bSuccess){ bool success=loadJson(openFileResult.fileName); ofLogVerbose("Load %s %s\n", openFileResult.filePath.c_str(), success?"succeeded":"failed"); }else { ofLogVerbose("User hit cancel"); } break; } } } //-------------------------------------------------------------- void chainImageSet::mouseDragged(int x, int y, int button){ switch (button){ case OF_MOUSE_BUTTON_1: dragPoint=ofPoint(x-clickPoint.x,y-clickPoint.y)*(selected->getHeight()/ofGetWindowHeight()); break; case OF_MOUSE_BUTTON_2: //alt-click dragRotate=((clickPoint.x-x)/(selected->thumbnail.getWidth()))*180.0f; break; case OF_MOUSE_BUTTON_3: //control-click dragScale=(y-clickPoint.y)/(selected->thumbnail.getHeight()); //if (dragScale*selected->linkScale<0.15){ // dragScale=0.15/selected->linkScale; //} break; } } //-------------------------------------------------------------- void chainImageSet::mousePressed(int x, int y, int button){ //todo: select clickPoint=ofPoint(x,y); } //-------------------------------------------------------------- void chainImageSet::mouseReleased(int x, int y, int button){ if (images.size()){ selected->linkPos+=dragPoint; dragPoint=ofPoint(0,0); selected->linkScale*=(1.0f+dragScale); dragScale=0.0f; selected->linkRot+=dragRotate; dragRotate=0.0f; } } bool chainImageSet::saveJson(std::string filename){ ofxJSON json; json["images"] = Json::Value(Json::arrayValue); for(std::list::iterator ii=images.begin(); ii != images.end(); ii++){ json["images"].append(ii->toJson()); } json.save(filename, true); } bool chainImageSet::loadJson(std::string _filename){ ofxJSON json; bool parsingSuccessful = json.open(_filename); if (parsingSuccessful) { images.clear(); for (int i=0;i::iterator ii=images.begin(); ii != images.end(); ii++){ auto li=ii; li++; if (li==images.end()) { li=images.begin(); } ii->link=&(*li); } selected=images.begin(); currentImage=&(*images.begin()); currentImage->start(); filename=_filename; return true; } ofLogVerbose("JSON load: parsing unsuccesful\n"); return false; } void chainImageSet::update(){ if (images.size()){ if (currentImage->update(decayFactor)){ //if returns true, switch images currentImage=currentImage->link; currentImage->start(); ofLogNotice() << "Switched images"; currentImage->update(decayFactor); } } }