#include "chainImage.h" 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){ #ifdef GPU_ALGORITHM shader.load("shader"); #endif //GPU_ALGORITHM linkPos=_linkPos; linkScale=_linkScale; linkRot=_linkRot; setAnchorPercent(0.5,0.5); dragPos=ofPoint(0,0); dragRot=0; dragScale=0; remap.load(); } 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::gpu_drawImage(){ GLint internalTextureFormat=GL_TEXTURE_2D_ARRAY; GLsizei textureWidth=getWidth(); GLsizei textureHeight=getHeight(); GLsizei numberOfTextures=2; GLint border=0; GLenum textureFormat=GL_RGB; glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, internalTextureFormat, textureWidth, textureHeight, numberOfTextures, 0, textureFormat, GL_UNSIGNED_BYTE, NULL); //bind the texture (using GL_TEXTURE_2D_ARRAY as the texture type) and use glTexParameteri as usual chainImage *thisimage; //iterate through the images to put into your texture array for (int i=0;ilink; glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, thisimage->width, thisimage->height, 1, textureFormat, GL_UNSIGNED_BYTE, &thisimage->getPixels()); } /* //composite the frame and set the next getTransform ofSetColor(255); float basescale=ofGetScreenWidth()/ofGetWidth(); shader.begin(); shader.setUniform3f("transform",getTransform()); shader.setUniform1f("scale",1.0f); //shader.setUniform1f("rotation",getRotation()); //shader.setUniform1f("transition",transition); //shader.setUniform1f("fadeIn",fadeIn); //shader.setUniform1f("intensity",intensity); //shader.setUniform3f("linkPos",linkPos); shader.setUniformTexture("thisImage", getTexture(), 1 ); shader.setUniformTexture("nextImage", link->getTexture(), 2 ); //draw(0, 0,ofGetWidth(),ofGetHeight()); ofDrawRectangle(0, 0, ofGetScreenWidth(), ofGetScreenHeight()); shader.end(); */ } //rotation could be a lot smoother //atm we only do horizontal rotation splines //movement is a bit jerky //could it be possible to visualise the path? 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); //float dR; //if (abs(link->linkRot-linkRot)>abs((link->linkRos+360.0f)-linkRot)){ // dR=link->linkRot; //} //else dR=link->linkRos+360.0f; //try to choose the shortest ofPoint cp1,cp2,p; //if(linked->getLinkRot()==0.0f){ //if this is where the rotation starts cp1=ofPoint(ROTATION_BEZIER_FRACTION, 0); //} //else { // float slope=link->getLinkRot()-linked->getLinkRot(); // cp1=ofPoint(ROTATION_BEZIER_FRACTION,slope/ROTATION_BEZIER_FRACTION); //} //if(link->link->getLinkRot()==0.0f){ //hmm, shouldn't use float equality cp2=ofPoint(1.0f-ROTATION_BEZIER_FRACTION, link->getLinkRot()); //} //else { // float slope=link->link->getLinkRot()-getLinkRot(); // cp2=ofPoint(1.0f-ROTATION_BEZIER_FRACTION, link->getLinkRot()); //} p=ofPoint(1.0f, link->getLinkRot()); rotationTimeline.bezierTo(cp1,cp2,p); } ofPoint chainImage::getPathPoint(){ //printf("get point at transition: %f \n",transition); return path.getPointAtLength(transition); } int chainImage::updateOutput(float decayRatio){ //where there is rotation of the link, the path needs to be rotated updateRotationTimeline(); path.clear(); path.addVertex(getLinkPos()); //path.addVertex(linkPos+(link->linkPos*linkScale)); ofPoint rotated_destination=ofPoint( (link->getLinkPos().x*cos(getLinkRot()*(PI/180)))-(link->getLinkPos().y*sin(getLinkRot()*(PI/180))), (link->getLinkPos().y*cos(getLinkRot()*(PI/180)))+(link->getLinkPos().x*sin(getLinkRot()*(PI/180))) ); ofPoint destination=getLinkPos()+(rotated_destination*getLinkScale()); ofPoint previous=getLinkPos()+(rotated_destination*getLinkScale()*(1.0f-BEZIER_IN)); path.bezierTo( getLinkPos().x*(1.0f+(BEZIER_OUT*linkScale)),getLinkPos().y*(1.0f+(BEZIER_OUT*linkScale)) , 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-getLinkScale())/(getLinkScale()-(getLinkScale()*link->getLinkScale())); //transition=min(1.0f,((float)framecount)/totalframes); /* printf("ChainImage %f: scale %f linkscale %f transition %f \n", decayRatio, scale, linkScale, transition); */ if (scale>getLinkScale()){ transition = 0.0f; return SWITCH_REVERSE; } if (scale>=getLinkScale()*link->getLinkScale()){ 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 getLinkRot()+rotationTimeline.getPointAtPercent(transition).y; //it doesn't seem that beziers are useful for this unless we can intersect a line /* vector rv; rv.push_back(rotationTimeline); ofxSweepLine Sweep= ofxSweepLine(rv); ofPolyline line; line.addVertex(transition,-1.0f); line.addVertex(transition,357.0f); vector lv; lv.push_back(line); vector result=Sweep.sweep(lv); printf("ofxSweepLine: got %f intersections\n",result.size()); if (result.size()) { return result[0].y; } ofxSweepLine crashes float transitionInterpolated=pow(transition,ROTATION_EASE_POWER); printf("rotation: %f of %f at point %f (%f)\n", transitionInterpolated*link->getLinkRot(), link->getLinkRot(), transition, transitionInterpolated ); return getLinkRot()+(transitionInterpolated*link->getLinkRot()); */ ofxeasing::function easing; bool start_turning=(sgn(getLinkRot()-linked->getLinkRot())!=sgn(link->getLinkRot()-getLinkRot())); bool end_turning=(sgn(link->getLinkRot()-getLinkRot())!=sgn(link->link->getLinkRot()-link->getLinkRot())); if (start_turning){ if (end_turning){ easing=ofxeasing::cubic::easeInOut; } else { easing=ofxeasing::cubic::easeIn; } } else { if (end_turning){ easing=ofxeasing::cubic::easeOut; } else { easing=ofxeasing::linear::easeOut; } } return ofxeasing::map_clamp(transition, 0, 1, getLinkRot(), getLinkRot()+link->getLinkRot(), easing); }; ofPoint chainImage::getLinkPos(){ return linkPos+dragPos; } float chainImage::getLinkRot(){ return linkRot+dragRot; } float chainImage::getLinkScale(){ return linkScale*(1.0f+dragScale); } 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::drawRecursive(float fadeIn,bool additive,float intensity,float zoomMultiplier, float fadeStart, float fadeEnd){ //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? float thisAmount=max(0.0,min(1.0((transition-fadeStart)/(fadeEnd-fadeStart))))*intensity; (0,1) , 0 = 0 (0,1) , 0.5 = 0.5 (0,1) , 1.0 = 1.0 (0.5,1) , 0 = 0.0 (0.5,1) , 0.5 = 0.0 (0.5,1) , 0.75 = 0.5 (0.5,1) , 1.0 = 1.0 (0,2) , 0 = 0 (0,2) , 1 = 0.5 (0,2) , = 0.5 glPushMatrix(); if (thisAmount>0){ if (additive){ glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); ofSetColor(255,255,255,255*thisAmount); } 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()); //the animated transform of the zoom is set before calling the first image //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); // //ofSetColor(colour); // glPopMatrix(); } if (fadeEnd>1.0){ glTranslatef(getLinkPos().x,getLinkPos().y,0); glRotatef(getLinkRot(),0,0,1); glScalef(getLinkScale(),getLinkScale(),getLinkScale()); //ofEnableAlphaBlending(); glEnable(GL_BLEND); ofSetColor(255,255,255,255*min(1.0,transition/fadeIn)*intensity); //link->setAnchorPoint(link->getWidth()/2,link->getHeight()/2); //ofSetColor(link->colour); //link->draw(0,0,link->getWidth(),link->getHeight()); link->drawRecursive(fadeIn,additive,intensity,zoomMultiplier,fadeStart-1.0f,fadeEnd-1.0f); glDisable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glPopMatrix(); } */ void chainImage::drawChain(float fadeIn,bool additive,float intensity,float zoomMultiplier,float startGamma){ //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(); //ofDisableAlphaBlending(); setAnchorPoint(getWidth()/2,getHeight()/2); //add a scale factor to the outgoing image that builds up over the transition glDisable(GL_BLEND); glPushMatrix(); //if this is linear we see the jump from the unlessaccelerated phase //float zoomFactor=((zoomMultiplier-1.0f)*transition)+1.0f; //this is worse why? float zoomFactor=pow(zoomMultiplier,1.0f+transition); glScalef(zoomFactor,zoomFactor,zoomFactor); //need to use the LUT shader on both images so the they match //float gamma=1.0f; //float pedestal=0.0f; //float clamp=1.0f; //if (!lutLoaded){ // lut.load(makeLut(gamma,pedestal,clamp,8)); // lutLoaded=true; //} //lut.begin(); //setAlpha(1.0f); draw(0,0,getWidth(),getHeight()); //lut.end(); glPopMatrix(); glTranslatef(getLinkPos().x,getLinkPos().y,0); glRotatef(getLinkRot(),0,0,1); glScalef(getLinkScale(),getLinkScale(),getLinkScale()); //ofEnableAlphaBlending(); 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); } //ofSetColor(255,255,255,255*min(1.0,transition/fadeIn)*intensity); //setting alpha here doesn't work with shader? //possibly if you could set the alpha when drawing? link->setAnchorPoint(link->getWidth()/2,link->getHeight()/2); //gamma=1.0f; //((1.0f-transition)*0.5f)+1.0f; //(startGamma*transition)+(1.0f*(1.0f-transition)); //pedestal=0.0f; //clamp=1.0f; //lut.load(makeLut(gamma,pedestal,clamp,8)); remap.setBlend(transition); remap.setGamma(1.0f+(1.0f-transition)); //(2.0f-transition)*10.0f); remap.setClamp(1.0f); //transition); remap.setPedestal(-1.0f+transition); remap.begin(); //ofSetColor(link->colour); //link->setAlpha(transition); link->draw(0,0,link->getWidth(),link->getHeight()); remap.end(); //potentially glPushMatrix(); glTranslatef(link->getLinkPos().x,link->getLinkPos().y,0); glRotatef(link->getLinkRot(),0,0,1); glScalef(link->getLinkScale(),link->getLinkScale(),link->getLinkScale()); remap.setBlend(link->transition); remap.setGamma(1.0f+(1.0f-link->transition)); remap.setClamp(1.0f); //transition); remap.setPedestal(-1.0f+link->transition); remap.begin(); link->link->draw(0,0,link->link->getWidth(),link->link->getHeight()); remap.end(); glPopMatrix(); glDisable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glPopMatrix(); } void chainImage::gpu_drawChain(float fadeIn,bool additive,float intensity,float zoomMultiplier){ ofSetColor(255); float basescale=ofGetScreenWidth()/ofGetWidth(); shader.begin(); shader.setUniform3f("transform",getTransform()); shader.setUniform1f("scale",1.0f); //shader.setUniform1f("rotation",getRotation()); //shader.setUniform1f("transition",transition); //shader.setUniform1f("fadeIn",fadeIn); //shader.setUniform1f("intensity",intensity); //shader.setUniform3f("linkPos",linkPos); shader.setUniformTexture("thisImage", getTexture(), 1 ); shader.setUniformTexture("nextImage", link->getTexture(), 2 ); //draw(0, 0,ofGetWidth(),ofGetHeight()); ofDrawRectangle(0, 0, ofGetScreenWidth(), ofGetScreenHeight()); shader.end(); //1. can we FILL THE SCREEN? } 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(); }