diff --git a/.gitignore b/.gitignore index 8e6ec8f..a55a03d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,9 @@ build/ *.perspectivev3 *.mode1v3 *.mode2v3 -/example/bin/ -/example/obj/ -/example/build/ -example/*.layout +/example-ofxBezierWarp/bin/ +/example-ofxBezierWarp/nbproject/ +/example-ofxBezierWarp/obj/ +/example-ofxBezierWarp/build/ +example-ofxBezierWarp/*.layout + diff --git a/README.md b/README.md index 995fe11..0d3d5b6 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,10 @@ It's pretty fast. Code was adapted from the method described here: http://forum.openframeworks.cc/index.php/topic,4002.0.html -If you're using this software for something cool consider sending me an email to let me know about your project: m@gingold.com.au \ No newline at end of file +If you're using this software for something cool consider sending me an email to let me know about your project: m@gingold.com.au + + +##Fork by dasoe: + +Added new (kind of hidden) functionality: +When hitting SHIFT while grabbing a corner point of the warp grid all points turn red instead of green. When realeasing the mouse while they are red, all points are rearranged equally - subject to the position of the 4 corners. This is especially useful for (perspective) warping before doing any fine-tuning. \ No newline at end of file diff --git a/example-ofxBezierWarp/src/main.cpp b/example-ofxBezierWarp/src/main.cpp index 6a32c6a..3fd6308 100644 --- a/example-ofxBezierWarp/src/main.cpp +++ b/example-ofxBezierWarp/src/main.cpp @@ -5,8 +5,7 @@ //======================================================================== int main( ){ - ofAppGlutWindow window; - ofSetupOpenGL(&window, 1024,768, OF_WINDOW); // <-------- setup the GL context + ofSetupOpenGL(1024,768, OF_WINDOW); // <-------- setup the GL context // this kicks off the running of my app // can be OF_WINDOW or OF_FULLSCREEN diff --git a/example-ofxBezierWarp/src/testApp.cpp b/example-ofxBezierWarp/src/testApp.cpp index d434c24..bed883f 100644 --- a/example-ofxBezierWarp/src/testApp.cpp +++ b/example-ofxBezierWarp/src/testApp.cpp @@ -2,11 +2,11 @@ //-------------------------------------------------------------- void testApp::setup(){ - + ofSetFrameRate(60); bUseWarp = true; // load a movie for testing purposes - vid.loadMovie("pathtoyourmovie.mov"); + vid.loadMovie("val_h.mp4"); vid.play(); // allocate the warp with width, height, numXControlPoints, diff --git a/src/ofxBezierWarp.cpp b/src/ofxBezierWarp.cpp index ab9781b..ea0e0d9 100644 --- a/src/ofxBezierWarp.cpp +++ b/src/ofxBezierWarp.cpp @@ -32,16 +32,28 @@ * */ +#include +#include +#include + #include "ofxBezierWarp.h" GLfloat texpts [2][2][2] = { - { {0, 0}, {1, 0} }, { {0, 1}, {1, 1} } + { + {0, 0}, + {1, 0} + }, + { + {0, 1}, + {1, 1} + } }; //-------------------------------------------------------------- -ofxBezierWarp::ofxBezierWarp(){ - currentCntrlX = -1; + +ofxBezierWarp::ofxBezierWarp() { currentCntrlY = -1; + currentCntrlX = -1; numXPoints = 0; numYPoints = 0; warpX = 0; @@ -55,27 +67,34 @@ ofxBezierWarp::ofxBezierWarp(){ } //-------------------------------------------------------------- -ofxBezierWarp::~ofxBezierWarp(){ + +ofxBezierWarp::~ofxBezierWarp() { //fbo.destroy(); cntrlPoints.clear(); } //-------------------------------------------------------------- -void ofxBezierWarp::allocate(int _w, int _h, int pixelFormat){ + +void ofxBezierWarp::allocate(int _w, int _h, int pixelFormat) { allocate(_w, _h, 2, 2, 100.0f, pixelFormat); } //-------------------------------------------------------------- -void ofxBezierWarp::allocate(int _w, int _h, int _numXPoints, int _numYPoints, float pixelsPerGridDivision, int pixelFormat){ + +void ofxBezierWarp::allocate(int _w, int _h, int _numXPoints, int _numYPoints, float pixelsPerGridDivision, int pixelFormat) { + + for (int i = 0; i < 4; i++) { + showHelperOnCorner[i] = false; + } //disable arb textures (so we use texture 2d instead) - if(_w == 0 || _h == 0 || _numXPoints == 0 || _numYPoints == 0){ - ofLogError() << "Cannot accept 0 as value for w, h numXPoints or numYPoints"; + if (_w == 0 || _h == 0 || _numXPoints == 0 || _numYPoints == 0) { + ofLogError("Cannot accept 0 as value for w, h numXPoints or numYPoints"); return; } - if(_w != fbo.getWidth() || _h != fbo.getHeight()){ + if (_w != fbo.getWidth() || _h != fbo.getHeight()) { fbo.allocate(_w, _h, pixelFormat); ofLogVerbose() << "Allocating bezier fbo texture as: " << fbo.getWidth() << " x " << fbo.getHeight(); @@ -90,13 +109,15 @@ void ofxBezierWarp::allocate(int _w, int _h, int _numXPoints, int _numYPoints, f glEnable(GL_AUTO_NORMAL); setWarpGridResolution(pixelsPerGridDivision); - + //glShadeModel(GL_FLAT); + } //-------------------------------------------------------------- -void ofxBezierWarp::begin(){ + +void ofxBezierWarp::begin() { fbo.begin(); ofPushMatrix(); glClearColor(0.0, 0.0, 0.0, 1.0); @@ -104,135 +125,196 @@ void ofxBezierWarp::begin(){ } //-------------------------------------------------------------- -void ofxBezierWarp::end(){ + +void ofxBezierWarp::end() { ofPopMatrix(); fbo.end(); } //-------------------------------------------------------------- -void ofxBezierWarp::draw(){ + +void ofxBezierWarp::draw() { draw(0, 0, fbo.getWidth(), fbo.getHeight()); } //-------------------------------------------------------------- -void ofxBezierWarp::draw(float x, float y){ + +void ofxBezierWarp::draw(float x, float y) { draw(x, y, fbo.getWidth(), fbo.getHeight()); } //-------------------------------------------------------------- -void ofxBezierWarp::draw(float x, float y, float w, float h){ - if(!fbo.isAllocated()) return; +void ofxBezierWarp::draw(float x, float y, float w, float h) { + + if (!fbo.isAllocated()) return; ofPushMatrix(); - if(bDoWarp){ - + if (bDoWarp) { + ofTranslate(x, y); - ofScale(w/fbo.getWidth(), h/fbo.getHeight()); - + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + ofTexture & fboTex = fbo.getTextureReference(); - + // upload the bezier control points to the map surface // this can be done just once (or when control points change) // if there is only one bezier surface - but with multiple // it needs to be done every frame glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); - + fboTex.bind(); - + glMatrixMode(GL_TEXTURE); glPushMatrix(); glLoadIdentity(); - + glScalef(fboTex.getWidth(), fboTex.getHeight(), 1.0f); glMatrixMode(GL_MODELVIEW); - -// glEnable(GL_MAP2_VERTEX_3); -// glEnable(GL_AUTO_NORMAL); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); glEvalMesh2(GL_FILL, 0, gridDivX, 0, gridDivY); -// glDisable(GL_MAP2_VERTEX_3); -// glDisable(GL_AUTO_NORMAL); - + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + fboTex.unbind(); - + glMatrixMode(GL_TEXTURE); glPopMatrix(); glMatrixMode(GL_MODELVIEW); - - }else{ - + + } else { + fbo.draw(x, y, w, h); - + } ofPopMatrix(); - if(bShowWarpGrid){ - if(bWarpPositionDiff){ + if (bShowWarpGrid) { + if (bWarpPositionDiff) { drawWarpGrid(warpX, warpY, warpWidth, warpHeight); - }else{ + } else { setWarpGridPosition(x, y, w, h); } } - -// glFinish(); + + // glFinish(); } //-------------------------------------------------------------- -void ofxBezierWarp::drawWarpGrid(float x, float y, float w, float h){ + +void ofxBezierWarp::drawWarpGrid(float x, float y, float w, float h) { ofPushStyle(); ofPushMatrix(); ofSetColor(255, 255, 255); ofTranslate(x, y); - ofScale(w/fbo.getWidth(), h/fbo.getHeight()); - -// glEnable(GL_MAP2_VERTEX_3); -// glEnable(GL_AUTO_NORMAL); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + if ( + any_of( + std::begin(showHelperOnCorner), + std::end(showHelperOnCorner), + [](bool ii) { return ii; } + ) || + any_of( + std::begin(showHelperOnCornerMouse), + std::end(showHelperOnCornerMouse), + [](bool iii) { return iii; } + ) + ) { + ofSetColor(150); + } else { + ofSetColor(255); + } glEvalMesh2(GL_LINE, 0, gridDivX, 0, gridDivY); -// glDisable(GL_MAP2_VERTEX_3); -// glDisable(GL_AUTO_NORMAL); - - for(int i = 0; i < numYPoints; i++){ - for(int j = 0; j < numXPoints; j++){ + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { ofFill(); - ofSetColor(255, 0, 0); - ofCircle(cntrlPoints[(i*numXPoints+j)*3+0], cntrlPoints[(i*numXPoints+j)*3+1], 5); + if (bRealignPlease) { + ofSetColor(255, 0, 0); + } else { + ofSetColor(100, 255, 100); + } + ofCircle(cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1], 5); ofNoFill(); } } - + ofSetColor(255); + + // check if a corner-Point is touched + if (showHelperOnCorner[0] || showHelperOnCornerMouse[0]) { + int x = cntrlPoints[(0 + 0)*3 + 0]; + int y = cntrlPoints[(0 + 0)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[1] || showHelperOnCornerMouse[1]) { + int x = cntrlPoints[(0 + numYPoints)*3 + 0]; + int y = cntrlPoints[(0 + numYPoints)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[2] || showHelperOnCornerMouse[2]) { + int x = cntrlPoints[(numXPoints*numYPoints -1)*3 + 0]; + int y = cntrlPoints[(numXPoints*numYPoints -1)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[3] || showHelperOnCornerMouse[3]) { + int x = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 0]; + int y = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + ofPopMatrix(); ofPopStyle(); } //-------------------------------------------------------------- -void ofxBezierWarp::setWarpGrid(int _numXPoints, int _numYPoints, bool forceReset){ - if(_numXPoints != numXPoints || _numYPoints != numYPoints) forceReset = true; +void ofxBezierWarp::setWarpGrid(int _numXPoints, int _numYPoints, bool forceReset) { + + if (_numXPoints != numXPoints || _numYPoints != numYPoints) forceReset = true; - if(_numXPoints < 2 || _numYPoints < 2){ + if (_numXPoints < 2 || _numYPoints < 2) { ofLogError() << "Can't have less than 2 X or Y grid points"; return; } - if(forceReset){ + if (forceReset) { numXPoints = _numXPoints; numYPoints = _numYPoints; // calculate an even distribution of X and Y control points across fbo width and height cntrlPoints.resize(numXPoints * numYPoints * 3); - for(int i = 0; i < numYPoints; i++){ + for (int i = 0; i < numYPoints; i++) { GLfloat x, y; y = (fbo.getHeight() / (numYPoints - 1)) * i; - for(int j = 0; j < numXPoints; j++){ + for (int j = 0; j < numXPoints; j++) { x = (fbo.getWidth() / (numXPoints - 1)) * j; - cntrlPoints[(i*numXPoints+j)*3+0] = x; - cntrlPoints[(i*numXPoints+j)*3+1] = y; - cntrlPoints[(i*numXPoints+j)*3+2] = 0; + cntrlPoints[(i * numXPoints + j)*3 + 0] = x; + cntrlPoints[(i * numXPoints + j)*3 + 1] = y; + cntrlPoints[(i * numXPoints + j)*3 + 2] = 0; //cout << x << ", " << y << ", " << "0" << endl; } } @@ -242,7 +324,8 @@ void ofxBezierWarp::setWarpGrid(int _numXPoints, int _numYPoints, bool forceRese } //-------------------------------------------------------------- -void ofxBezierWarp::setWarpGridPosition(float x, float y, float w, float h){ + +void ofxBezierWarp::setWarpGridPosition(float x, float y, float w, float h) { warpX = x; warpY = y; warpWidth = w; @@ -251,214 +334,453 @@ void ofxBezierWarp::setWarpGridPosition(float x, float y, float w, float h){ } //-------------------------------------------------------------- -void ofxBezierWarp::setWarpGridResolution(float pixelsPerGridDivision){ + +void ofxBezierWarp::setWarpGridResolution(float pixelsPerGridDivision) { gridResolution = pixelsPerGridDivision; setWarpGridResolution(ceil(fbo.getWidth() / pixelsPerGridDivision), ceil(fbo.getHeight() / pixelsPerGridDivision)); } //-------------------------------------------------------------- -float ofxBezierWarp::getWarpGridResolution(){ + +float ofxBezierWarp::getWarpGridResolution() { assert(gridResolution > 0); // tis since if set via gridDivY/X it won't be a single number... return gridResolution; } //-------------------------------------------------------------- -void ofxBezierWarp::setWarpGridResolution(int gridDivisionsX, int gridDivisionsY){ + +void ofxBezierWarp::setWarpGridResolution(int gridDivisionsX, int gridDivisionsY) { // NB: at the moment this sets the resolution for all mapGrid // objects (since I'm not calling it every frame as it is expensive) // so if you try to set different resolutions // for different instances it won't work as expected - + gridDivX = gridDivisionsX; gridDivY = gridDivisionsY; glMapGrid2f(gridDivX, 0, 1, gridDivY, 0, 1); } //-------------------------------------------------------------- -void ofxBezierWarp::resetWarpGrid(){ + +void ofxBezierWarp::resetWarpGrid() { setWarpGrid(numXPoints, numYPoints, true); } //-------------------------------------------------------------- -void ofxBezierWarp::resetWarpGridPosition(){ + +void ofxBezierWarp::resetWarpGridPosition() { bWarpPositionDiff = false; } //-------------------------------------------------------------- -float ofxBezierWarp::getWidth(){ + +float ofxBezierWarp::getWidth() { return fbo.getWidth(); } //-------------------------------------------------------------- -float ofxBezierWarp::getHeight(){ + +float ofxBezierWarp::getHeight() { return fbo.getHeight(); } //-------------------------------------------------------------- -int ofxBezierWarp::getNumXPoints(){ + +int ofxBezierWarp::getNumXPoints() { return numXPoints; } //-------------------------------------------------------------- -int ofxBezierWarp::getNumYPoints(){ + +int ofxBezierWarp::getNumYPoints() { return numYPoints; } //-------------------------------------------------------------- -int ofxBezierWarp::getGridDivisionsX(){ + +int ofxBezierWarp::getGridDivisionsX() { return gridDivX; } //-------------------------------------------------------------- -int ofxBezierWarp::getGridDivisionsY(){ + +int ofxBezierWarp::getGridDivisionsY() { return gridDivY; } //-------------------------------------------------------------- -void ofxBezierWarp::toggleShowWarpGrid(){ + +void ofxBezierWarp::toggleShowWarpGrid() { setShowWarpGrid(!getShowWarpGrid()); } //-------------------------------------------------------------- -void ofxBezierWarp::setShowWarpGrid(bool b){ + +void ofxBezierWarp::setShowWarpGrid(bool b) { bShowWarpGrid = b; - if(bShowWarpGrid){ + bRealignPlease = false; + if (bShowWarpGrid) { ofRegisterMouseEvents(this); - }else{ + ofRegisterKeyEvents(this); + } else { ofUnregisterMouseEvents(this); + ofUnregisterKeyEvents(this); } } //-------------------------------------------------------------- -bool ofxBezierWarp::getShowWarpGrid(){ + +bool ofxBezierWarp::getShowWarpGrid() { return bShowWarpGrid; } //-------------------------------------------------------------- -void ofxBezierWarp::setDoWarp(bool b){ + +void ofxBezierWarp::setDoWarp(bool b) { bDoWarp = b; } //-------------------------------------------------------------- -bool ofxBezierWarp::getDoWarp(){ + +bool ofxBezierWarp::getDoWarp() { return bDoWarp; } //-------------------------------------------------------------- -void ofxBezierWarp::toggleDoWarp(){ + +void ofxBezierWarp::toggleDoWarp() { bDoWarp = !bDoWarp; } //-------------------------------------------------------------- -ofFbo& ofxBezierWarp::getFBO(){ + +ofFbo& ofxBezierWarp::getFBO() { return fbo; } //-------------------------------------------------------------- -ofTexture& ofxBezierWarp::getTextureReference(){ + +ofTexture& ofxBezierWarp::getTextureReference() { return fbo.getTextureReference(); } //-------------------------------------------------------------- -void ofxBezierWarp::setControlPoints(vector _cntrlPoints){ + +void ofxBezierWarp::setControlPoints(vector _cntrlPoints) { cntrlPoints.clear(); cntrlPoints = _cntrlPoints; glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); } //-------------------------------------------------------------- -vector ofxBezierWarp::getControlPoints(){ + +vector ofxBezierWarp::getControlPoints() { return cntrlPoints; } //-------------------------------------------------------------- -void ofxBezierWarp::setOffset(ofPoint p){ + +void ofxBezierWarp::setOffset(ofVec2f p) { offset = p; } //-------------------------------------------------------------- -ofPoint ofxBezierWarp::getOffset(){ + +ofVec2f ofxBezierWarp::getOffset() { return offset; } //-------------------------------------------------------------- -ofPoint& ofxBezierWarp::getOffsetReference(){ + +ofVec2f& ofxBezierWarp::getOffsetReference() { return offset; } //-------------------------------------------------------------- -vector& ofxBezierWarp::getControlPointsReference(){ + +vector& ofxBezierWarp::getControlPointsReference() { return cntrlPoints; } //-------------------------------------------------------------- -void ofxBezierWarp::mouseMoved(ofMouseEventArgs & e){ + +void ofxBezierWarp::keyPressed(ofKeyEventArgs & e) { + if (e.key == OF_KEY_SHIFT && bGrabbedACorner) { + bRealignPlease = true; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyReleased(ofKeyEventArgs & e) { + bRealignPlease = false; +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseMoved(ofMouseEventArgs & e) { + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY_2 = i; + currentCntrlX_2 = j; + } + } + } + + // check if a corner-Point is touched + // Upper Left + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[0] = true; + } else { + showHelperOnCornerMouse[0] = false; + } + // Upper Right + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[1] = true; + } else { + showHelperOnCornerMouse[1] = false; + } + // Lower Left + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[3] = true; + } else { + showHelperOnCornerMouse[3] = false; + } + // Lower Right + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[2] = true; + } else { + showHelperOnCornerMouse[2] = false; + } } //-------------------------------------------------------------- -void ofxBezierWarp::mouseDragged(ofMouseEventArgs & e){ - if(!bShowWarpGrid) mouseReleased(e); +void ofxBezierWarp::mouseDragged(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); float x = e.x; float y = e.y; - if(bWarpPositionDiff){ - x = (e.x - warpX) * fbo.getWidth()/warpWidth; - y = (e.y - warpY) * fbo.getHeight()/warpHeight; + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; } - if(currentCntrlX != -1 && currentCntrlY != -1){ - cntrlPoints[(currentCntrlX*numXPoints+currentCntrlY)*3+0] = x; - cntrlPoints[(currentCntrlX*numXPoints+currentCntrlY)*3+1] = y; + if (currentCntrlY != -1 && currentCntrlX != -1) { + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 0] = x; + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 1] = y; glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); } + } //-------------------------------------------------------------- -void ofxBezierWarp::mousePressed(ofMouseEventArgs & e){ - if(!bShowWarpGrid) mouseReleased(e); +void ofxBezierWarp::mousePressed(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); float x = e.x; float y = e.y; - if(bWarpPositionDiff){ - x = (e.x - warpX) * fbo.getWidth()/warpWidth; - y = (e.y - warpY) * fbo.getHeight()/warpHeight; + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; } float dist = 10.0f; - for(int i = 0; i < numYPoints; i++){ - for(int j = 0; j < numXPoints; j++){ - if(x - cntrlPoints[(i*numXPoints+j)*3+0] >= -dist && x - cntrlPoints[(i*numXPoints+j)*3+0] <= dist && - y - cntrlPoints[(i*numXPoints+j)*3+1] >= -dist && y - cntrlPoints[(i*numXPoints+j)*3+1] <= dist){ - currentCntrlX = i; - currentCntrlY = j; + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY = i; + currentCntrlX = j; } } } + // check if a corner-Point is touched + if ( + (currentCntrlY == 0 && currentCntrlX == 0) || + (currentCntrlY == 0 && currentCntrlX == numXPoints - 1) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == 0) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == numXPoints - 1) + ) { + bGrabbedACorner = true; + } else { + bGrabbedACorner = false; + } } //-------------------------------------------------------------- -void ofxBezierWarp::mouseReleased(ofMouseEventArgs & e){ - currentCntrlX = -1; + +void ofxBezierWarp::mouseReleased(ofMouseEventArgs & e) { + if (bRealignPlease) { + rearrangeAllPoints(); + } currentCntrlY = -1; + currentCntrlX = -1; + bGrabbedACorner = false; } + + //-------------------------------------------------------------- -void ofxBezierWarp::mouseScrolled(ofMouseEventArgs & e){ + +void ofxBezierWarp::rearrangeAllPoints() { + ofLogNotice("rearrange all points!"); + + // left upper corner + int luNumber = (0 * numXPoints + 0); + //ofLog() << luNumber; + int luX = cntrlPoints[luNumber * 3 + 0]; + int luY = cntrlPoints[luNumber * 3 + 1]; + + // right upper corner + int ruNumber = (numXPoints * 0 + (numXPoints - 1)); + //ofLog() << ruNumber; + int ruX = cntrlPoints[ruNumber * 3 + 0]; + int ruY = cntrlPoints[ruNumber * 3 + 1]; + + // left lower corner + int llNumber = ((numYPoints - 1) * numXPoints + 0); + //ofLog() << llNumber; + int llX = cntrlPoints[llNumber * 3 + 0]; + int llY = cntrlPoints[llNumber * 3 + 1]; + + // right lower corner + int rlNumber = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + //ofLog() << rlNumber; + int rlX = cntrlPoints[rlNumber * 3 + 0]; + int rlY = cntrlPoints[rlNumber * 3 + 1]; + + // getting the projection matrix + // calculate from: 4 corner points of original original, non-warped grid (screen) + // and 4 corner points of the warp grid + int x = 0; + int y = 0; + int w = getWidth(); + int h = getHeight(); + + cv::Point2f src_points[] = { + cv::Point2f( x, y ), + cv::Point2f( x + w, y ), + cv::Point2f( x + w, y + h ), + cv::Point2f( x, y + h ) + }; + + cv::Point2f dst_points[] = { + cv::Point2f( luX, luY ), + cv::Point2f( ruX, ruY ), + cv::Point2f( rlX, rlY ), + cv::Point2f( llX, llY ) + }; + + auto Matrix = cv::getPerspectiveTransform( src_points, dst_points ); + + // going through all points and apply the matrix + + int urX; + int urY; + for (int i = 0; i < numYPoints; i++) { + urY = h / (numYPoints-1) * i ; + for (int j = 0; j < numXPoints; j++) { + vector sourcePoints; + vector targetPoints; + // Source points are all points from original, non-warped grid + // so simple division of width and height + urX = w / (numXPoints-1) * j; + sourcePoints.push_back( cv::Point2f( urX, urY ) ); + perspectiveTransform(sourcePoints, targetPoints, Matrix); + cout << ofPoint ( cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1] ) << "\n" ; + cntrlPoints[(i * numXPoints + j)*3 + 0] = targetPoints[0].x; + cntrlPoints[(i * numXPoints + j)*3 + 1] = targetPoints[0].y; + cout << ofPoint ( cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1] ) << "\n" << "\n"; + } + } + + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseScrolled(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseEntered(ofMouseEventArgs & e) { } //-------------------------------------------------------------- -void ofxBezierWarp::mouseEntered(ofMouseEventArgs & e){ + +void ofxBezierWarp::mouseExited(ofMouseEventArgs & e) { } + //-------------------------------------------------------------- -void ofxBezierWarp::mouseExited(ofMouseEventArgs & e){ + +void ofxBezierWarp::moveCorner(ofOeCorner corner, ofOeDirection direction) { + int oePoint; + // getting control points + switch (corner) { + case OE_UPPER_LEFT: + oePoint = (0 * numXPoints + 0); + break; + case OE_UPPER_RIGHT: + oePoint = (numXPoints * 0 + (numXPoints - 1)); + break; + case OE_LOWER_LEFT: + oePoint = ((numYPoints - 1) * numXPoints + 0); + break; + case OE_LOWER_RIGHT: + oePoint = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + break; + } + + switch (direction) { + case OE_DIRECTION_UP: + cntrlPoints[oePoint * 3 + 1]--; + break; + case OE_DIRECTION_DOWN: + cntrlPoints[oePoint * 3 + 1]++; + break; + case OE_DIRECTION_LEFT: + cntrlPoints[oePoint * 3 + 0]--; + break; + case OE_DIRECTION_RIGHT: + cntrlPoints[oePoint * 3 + 0]++; + break; + + } } diff --git a/src/ofxBezierWarp.h b/src/ofxBezierWarp.h index 4e58d6f..d4f625e 100644 --- a/src/ofxBezierWarp.h +++ b/src/ofxBezierWarp.h @@ -34,6 +34,21 @@ #ifndef _H_OFXBEZIERWARP #define _H_OFXBEZIERWARP +enum ofOeDirection : const unsigned int { + OE_DIRECTION_UP = 0, + OE_DIRECTION_DOWN = 1, + OE_DIRECTION_LEFT = 2, + OE_DIRECTION_RIGHT = 3 +}; +enum ofOeCorner : const unsigned int { + OE_UPPER_LEFT = 1, + OE_UPPER_RIGHT = 2, + OE_LOWER_LEFT = 3, + OE_LOWER_RIGHT = 4, + OE_NONE = 0 +}; + +#include "ofMain.h" #include "ofFbo.h" #include "ofGraphics.h" #include "ofEvents.h" @@ -64,6 +79,9 @@ class ofxBezierWarp { void resetWarpGrid(); void resetWarpGridPosition(); + void moveCorner(ofOeCorner corner, ofOeDirection direction); + + float getWidth(); float getHeight(); @@ -82,10 +100,10 @@ class ofxBezierWarp { void setDoWarp(bool b); bool getDoWarp(); - void setOffset(ofPoint p); + void setOffset(ofVec2f p); - ofPoint getOffset(); - ofPoint& getOffsetReference(); + ofVec2f getOffset(); + ofVec2f& getOffsetReference(); ofFbo& getFBO(); @@ -95,7 +113,10 @@ class ofxBezierWarp { vector getControlPoints(); vector& getControlPointsReference(); + + void keyPressed(ofKeyEventArgs & e); + void keyReleased(ofKeyEventArgs & e); void mouseMoved(ofMouseEventArgs & e); void mouseDragged(ofMouseEventArgs & e); void mousePressed(ofMouseEventArgs & e); @@ -103,27 +124,32 @@ class ofxBezierWarp { void mouseScrolled(ofMouseEventArgs & e); void mouseEntered(ofMouseEventArgs & e); void mouseExited(ofMouseEventArgs & e); - + void rearrangeAllPoints(); + bool showHelperOnCorner[4]; protected: void drawWarpGrid(float x, float y, float w, float h); + bool bShowWarpGrid; bool bWarpPositionDiff; bool bDoWarp; - + bool bRealignPlease; + bool bGrabbedACorner; + bool showHelperOnCornerMouse[4]; + ofFbo fbo; - ofPoint offset; - ofPoint sOffset; + ofVec2f offset; + ofVec2f sOffset; float warpWidth; float warpHeight; float warpX; float warpY; - int currentCntrlX; - int currentCntrlY; + int currentCntrlX, currentCntrlX_2; + int currentCntrlY, currentCntrlY_2; int numXPoints; int numYPoints; diff --git a/src/ofxBezierWarp_BACKUP_410183.cpp b/src/ofxBezierWarp_BACKUP_410183.cpp new file mode 100644 index 0000000..278641d --- /dev/null +++ b/src/ofxBezierWarp_BACKUP_410183.cpp @@ -0,0 +1,806 @@ + +/* + * ofxBezierWarp.cpp + * + * Copyright 2013 (c) Matthew Gingold http://gingold.com.au + * Adapted from: http://forum.openframeworks.cc/index.php/topic,4002.0.html + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * If you're using this software for something cool consider sending + * me an email to let me know about your project: m@gingold.com.au + * + */ + +#include +#include +#include + +#include "ofxBezierWarp.h" + +GLfloat texpts [2][2][2] = { + { + {0, 0}, + {1, 0} + }, + { + {0, 1}, + {1, 1} + } +}; + +//-------------------------------------------------------------- + +ofxBezierWarp::ofxBezierWarp() { + currentCntrlY = -1; + currentCntrlX = -1; + numXPoints = 0; + numYPoints = 0; + warpX = 0; + warpY = 0; + warpWidth = 0; + warpHeight = 0; + gridResolution = -1; + bShowWarpGrid = false; + bWarpPositionDiff = false; + bDoWarp = true; +} + +//-------------------------------------------------------------- + +ofxBezierWarp::~ofxBezierWarp() { + //fbo.destroy(); + cntrlPoints.clear(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::allocate(int _w, int _h, int pixelFormat) { + allocate(_w, _h, 2, 2, 100.0f, pixelFormat); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::allocate(int _w, int _h, int _numXPoints, int _numYPoints, float pixelsPerGridDivision, int pixelFormat) { + + for (int i = 0; i < 4; i++) { + showHelperOnCorner[i] = false; + } + + //disable arb textures (so we use texture 2d instead) + + if (_w == 0 || _h == 0 || _numXPoints == 0 || _numYPoints == 0) { + ofLogError("Cannot accept 0 as value for w, h numXPoints or numYPoints"); + return; + } + + if (_w != fbo.getWidth() || _h != fbo.getHeight()) { + + fbo.allocate(_w, _h, pixelFormat); + ofLogVerbose() << "Allocating bezier fbo texture as: " << fbo.getWidth() << " x " << fbo.getHeight(); + } + + setWarpGrid(_numXPoints, _numYPoints); + + //set up texture map for bezier surface + glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &texpts[0][0][0]); + glEnable(GL_MAP2_TEXTURE_COORD_2); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + setWarpGridResolution(pixelsPerGridDivision); + + //glShadeModel(GL_FLAT); + + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::begin() { + fbo.begin(); + ofPushMatrix(); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::end() { + ofPopMatrix(); + fbo.end(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw() { + draw(0, 0, fbo.getWidth(), fbo.getHeight()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw(float x, float y) { + draw(x, y, fbo.getWidth(), fbo.getHeight()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw(float x, float y, float w, float h) { + + if (!fbo.isAllocated()) return; + + ofPushMatrix(); + + if (bDoWarp) { + + ofTranslate(x, y); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + ofTexture & fboTex = fbo.getTextureReference(); + + // upload the bezier control points to the map surface + // this can be done just once (or when control points change) + // if there is only one bezier surface - but with multiple + // it needs to be done every frame + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); + + fboTex.bind(); + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + + glScalef(fboTex.getWidth(), fboTex.getHeight(), 1.0f); + glMatrixMode(GL_MODELVIEW); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + glEvalMesh2(GL_FILL, 0, gridDivX, 0, gridDivY); + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + fboTex.unbind(); + + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + } else { + + fbo.draw(x, y, w, h); + + } + + ofPopMatrix(); + + if (bShowWarpGrid) { + if (bWarpPositionDiff) { + drawWarpGrid(warpX, warpY, warpWidth, warpHeight); + } else { + setWarpGridPosition(x, y, w, h); + } + } + + // glFinish(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::drawWarpGrid(float x, float y, float w, float h) { + + ofPushStyle(); + ofPushMatrix(); + + ofSetColor(255, 255, 255); + ofTranslate(x, y); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + if ( + any_of( + std::begin(showHelperOnCorner), + std::end(showHelperOnCorner), + [](bool ii) { return ii; } + ) || + any_of( + std::begin(showHelperOnCornerMouse), + std::end(showHelperOnCornerMouse), + [](bool iii) { return iii; } + ) + ) { + ofSetColor(150); + } else { + ofSetColor(255); + } + glEvalMesh2(GL_LINE, 0, gridDivX, 0, gridDivY); + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + ofFill(); + if (bRealignPlease) { + ofSetColor(255, 0, 0); + } else { + ofSetColor(100, 255, 100); + } + ofCircle(cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1], 5); + ofNoFill(); + } + } + ofSetColor(255); + + // check if a corner-Point is touched + if (showHelperOnCorner[0] || showHelperOnCornerMouse[0]) { + int x = cntrlPoints[(0 + 0)*3 + 0]; + int y = cntrlPoints[(0 + 0)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[1] || showHelperOnCornerMouse[1]) { + int x = cntrlPoints[(0 + numYPoints)*3 + 0]; + int y = cntrlPoints[(0 + numYPoints)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[2] || showHelperOnCornerMouse[2]) { + int x = cntrlPoints[(numXPoints*numYPoints -1)*3 + 0]; + int y = cntrlPoints[(numXPoints*numYPoints -1)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[3] || showHelperOnCornerMouse[3]) { + int x = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 0]; + int y = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + + ofPopMatrix(); + ofPopStyle(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGrid(int _numXPoints, int _numYPoints, bool forceReset) { + + if (_numXPoints != numXPoints || _numYPoints != numYPoints) forceReset = true; + + if (_numXPoints < 2 || _numYPoints < 2) { + ofLogError() << "Can't have less than 2 X or Y grid points"; + return; + } + + if (forceReset) { + + numXPoints = _numXPoints; + numYPoints = _numYPoints; + + // calculate an even distribution of X and Y control points across fbo width and height + cntrlPoints.resize(numXPoints * numYPoints * 3); + for (int i = 0; i < numYPoints; i++) { + GLfloat x, y; + y = (fbo.getHeight() / (numYPoints - 1)) * i; + for (int j = 0; j < numXPoints; j++) { + x = (fbo.getWidth() / (numXPoints - 1)) * j; + cntrlPoints[(i * numXPoints + j)*3 + 0] = x; + cntrlPoints[(i * numXPoints + j)*3 + 1] = y; + cntrlPoints[(i * numXPoints + j)*3 + 2] = 0; + //cout << x << ", " << y << ", " << "0" << endl; + } + } + } + + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridPosition(float x, float y, float w, float h) { + warpX = x; + warpY = y; + warpWidth = w; + warpHeight = h; + bWarpPositionDiff = true; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridResolution(float pixelsPerGridDivision) { + gridResolution = pixelsPerGridDivision; + setWarpGridResolution(ceil(fbo.getWidth() / pixelsPerGridDivision), ceil(fbo.getHeight() / pixelsPerGridDivision)); +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getWarpGridResolution() { + assert(gridResolution > 0); // tis since if set via gridDivY/X it won't be a single number... + return gridResolution; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridResolution(int gridDivisionsX, int gridDivisionsY) { + // NB: at the moment this sets the resolution for all mapGrid + // objects (since I'm not calling it every frame as it is expensive) + // so if you try to set different resolutions + // for different instances it won't work as expected + + gridDivX = gridDivisionsX; + gridDivY = gridDivisionsY; + glMapGrid2f(gridDivX, 0, 1, gridDivY, 0, 1); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::resetWarpGrid() { + setWarpGrid(numXPoints, numYPoints, true); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::resetWarpGridPosition() { + bWarpPositionDiff = false; +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getWidth() { + return fbo.getWidth(); +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getHeight() { + return fbo.getHeight(); +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getNumXPoints() { + return numXPoints; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getNumYPoints() { + return numYPoints; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getGridDivisionsX() { + return gridDivX; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getGridDivisionsY() { + return gridDivY; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::toggleShowWarpGrid() { + setShowWarpGrid(!getShowWarpGrid()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setShowWarpGrid(bool b) { + bShowWarpGrid = b; + bRealignPlease = false; + if (bShowWarpGrid) { + ofRegisterMouseEvents(this); + ofRegisterKeyEvents(this); + } else { + ofUnregisterMouseEvents(this); + ofUnregisterKeyEvents(this); + } +} + +//-------------------------------------------------------------- + +bool ofxBezierWarp::getShowWarpGrid() { + return bShowWarpGrid; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setDoWarp(bool b) { + bDoWarp = b; +} + +//-------------------------------------------------------------- + +bool ofxBezierWarp::getDoWarp() { + return bDoWarp; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::toggleDoWarp() { + bDoWarp = !bDoWarp; +} + +//-------------------------------------------------------------- + +ofFbo& ofxBezierWarp::getFBO() { + return fbo; +} + +//-------------------------------------------------------------- + +ofTexture& ofxBezierWarp::getTextureReference() { + return fbo.getTextureReference(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setControlPoints(vector _cntrlPoints) { + cntrlPoints.clear(); + cntrlPoints = _cntrlPoints; + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); +} + +//-------------------------------------------------------------- + +vector ofxBezierWarp::getControlPoints() { + return cntrlPoints; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setOffset(ofVec2f p) { + offset = p; +} + +//-------------------------------------------------------------- + +ofVec2f ofxBezierWarp::getOffset() { + return offset; +} + +//-------------------------------------------------------------- + +ofVec2f& ofxBezierWarp::getOffsetReference() { + return offset; +} + +//-------------------------------------------------------------- + +vector& ofxBezierWarp::getControlPointsReference() { + return cntrlPoints; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyPressed(ofKeyEventArgs & e) { + if (e.key == OF_KEY_SHIFT && bGrabbedACorner) { + bRealignPlease = true; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyReleased(ofKeyEventArgs & e) { + bRealignPlease = false; +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseMoved(ofMouseEventArgs & e) { + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY_2 = i; + currentCntrlX_2 = j; + } + } + } + + // check if a corner-Point is touched + // Upper Left + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[0] = true; + } else { + showHelperOnCornerMouse[0] = false; + } + // Upper Right + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[1] = true; + } else { + showHelperOnCornerMouse[1] = false; + } + // Lower Left + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[3] = true; + } else { + showHelperOnCornerMouse[3] = false; + } + // Lower Right + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[2] = true; + } else { + showHelperOnCornerMouse[2] = false; + } + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseDragged(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + if (currentCntrlY != -1 && currentCntrlX != -1) { + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 0] = x; + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 1] = y; + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); + } + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mousePressed(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY = i; + currentCntrlX = j; + } + } + } + // check if a corner-Point is touched + if ( + (currentCntrlY == 0 && currentCntrlX == 0) || + (currentCntrlY == 0 && currentCntrlX == numXPoints - 1) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == 0) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == numXPoints - 1) + ) { + bGrabbedACorner = true; + } else { + bGrabbedACorner = false; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseReleased(ofMouseEventArgs & e) { + if (bRealignPlease) { + rearrangeAllPoints(); + } + currentCntrlY = -1; + currentCntrlX = -1; + bGrabbedACorner = false; +} + + + +//-------------------------------------------------------------- + +void ofxBezierWarp::rearrangeAllPoints() { + ofLogNotice("rearrange all points!"); + + // left upper corner + int luNumber = (0 * numXPoints + 0); + //ofLog() << luNumber; + int luX = cntrlPoints[luNumber * 3 + 0]; + int luY = cntrlPoints[luNumber * 3 + 1]; + + // right upper corner + int ruNumber = (numXPoints * 0 + (numXPoints - 1)); + //ofLog() << ruNumber; + int ruX = cntrlPoints[ruNumber * 3 + 0]; + int ruY = cntrlPoints[ruNumber * 3 + 1]; + + // left lower corner + int llNumber = ((numYPoints - 1) * numXPoints + 0); + //ofLog() << llNumber; + int llX = cntrlPoints[llNumber * 3 + 0]; + int llY = cntrlPoints[llNumber * 3 + 1]; + + // right lower corner + int rlNumber = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + //ofLog() << rlNumber; + int rlX = cntrlPoints[rlNumber * 3 + 0]; + int rlY = cntrlPoints[rlNumber * 3 + 1]; + +<<<<<<< HEAD + int teilLeftX = (luX - llX) / (numYPoints-1); + int teilRightX = (ruX - rlX) / (numYPoints-1); + int teilLeftY = (luY - llY) / (numYPoints-1); + int teilRightY = (ruY - rlY) / (numYPoints-1); + + // rearranging the vertical outer lines, left and right + for (int i = 0; i < numYPoints - 1; i++) { + // left side + cntrlPoints[(i * numXPoints + 0)*3 + 0] = luX - (i * teilLeftX); + cntrlPoints[(i * numXPoints + 0)*3 + 1] = luY - (i * teilLeftY); +// ofLog() << (i * numXPoints + 0)*3 + 0 << ": " << luX - (i * teilLeftX); +// ofLog() << (i * numXPoints + 0)*3 + 1 << ": " << luY - (i * teilLeftY) << " | " << llY; + // right side + cntrlPoints[(i * numXPoints + numXPoints - 1)*3 + 0] = ruX - (i * teilRightX); + cntrlPoints[(i * numXPoints + numXPoints - 1)*3 + 1] = ruY - (i * teilRightY); + } +======= + // getting the projection matrix + // calculate from: 4 corner points of original original, non-warped grid (screen) + // and 4 corner points of the warp grid + int x = 0; + int y = 0; + int w = getWidth(); + int h = getHeight(); +>>>>>>> 70cc4b8 (bugfix/feature: real perspective warping when using "rearrange all points") + + cv::Point2f src_points[] = { + cv::Point2f( x, y ), + cv::Point2f( x + w, y ), + cv::Point2f( x + w, y + h ), + cv::Point2f( x, y + h ) + }; + + cv::Point2f dst_points[] = { + cv::Point2f( luX, luY ), + cv::Point2f( ruX, ruY ), + cv::Point2f( rlX, rlY ), + cv::Point2f( llX, llY ) + }; + + auto Matrix = cv::getPerspectiveTransform( src_points, dst_points ); + + // going through all points and apply the matrix + + int urX; + int urY; + for (int i = 0; i < numYPoints; i++) { + urY = h / (numYPoints-1) * i ; + for (int j = 0; j < numXPoints; j++) { + vector sourcePoints; + vector targetPoints; + // Source points are all points from original, non-warped grid + // so simple division of width and height + urX = w / (numXPoints-1) * j; + sourcePoints.push_back( cv::Point2f( urX, urY ) ); + perspectiveTransform(sourcePoints, targetPoints, Matrix); + cout << ofPoint ( cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1] ) << "\n" ; + cntrlPoints[(i * numXPoints + j)*3 + 0] = targetPoints[0].x; + cntrlPoints[(i * numXPoints + j)*3 + 1] = targetPoints[0].y; + cout << ofPoint ( cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1] ) << "\n" << "\n"; + } + } + + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseScrolled(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseEntered(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseExited(ofMouseEventArgs & e) { + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::moveCorner(ofOeCorner corner, ofOeDirection direction) { + int oePoint; + // getting control points + switch (corner) { + case OE_UPPER_LEFT: + oePoint = (0 * numXPoints + 0); + break; + case OE_UPPER_RIGHT: + oePoint = (numXPoints * 0 + (numXPoints - 1)); + break; + case OE_LOWER_LEFT: + oePoint = ((numYPoints - 1) * numXPoints + 0); + break; + case OE_LOWER_RIGHT: + oePoint = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + break; + } + + switch (direction) { + case OE_DIRECTION_UP: + cntrlPoints[oePoint * 3 + 1]--; + break; + case OE_DIRECTION_DOWN: + cntrlPoints[oePoint * 3 + 1]++; + break; + case OE_DIRECTION_LEFT: + cntrlPoints[oePoint * 3 + 0]--; + break; + case OE_DIRECTION_RIGHT: + cntrlPoints[oePoint * 3 + 0]++; + break; + + } + +} + diff --git a/src/ofxBezierWarp_BASE_410183.cpp b/src/ofxBezierWarp_BASE_410183.cpp new file mode 100644 index 0000000..ebed1ad --- /dev/null +++ b/src/ofxBezierWarp_BASE_410183.cpp @@ -0,0 +1,787 @@ + +/* + * ofxBezierWarp.cpp + * + * Copyright 2013 (c) Matthew Gingold http://gingold.com.au + * Adapted from: http://forum.openframeworks.cc/index.php/topic,4002.0.html + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * If you're using this software for something cool consider sending + * me an email to let me know about your project: m@gingold.com.au + * + */ + +#include "ofxBezierWarp.h" + +GLfloat texpts [2][2][2] = { + { + {0, 0}, + {1, 0} + }, + { + {0, 1}, + {1, 1} + } +}; + +//-------------------------------------------------------------- + +ofxBezierWarp::ofxBezierWarp() { + currentCntrlY = -1; + currentCntrlX = -1; + numXPoints = 0; + numYPoints = 0; + warpX = 0; + warpY = 0; + warpWidth = 0; + warpHeight = 0; + gridResolution = -1; + bShowWarpGrid = false; + bWarpPositionDiff = false; + bDoWarp = true; + + +} + +//-------------------------------------------------------------- + +ofxBezierWarp::~ofxBezierWarp() { + //fbo.destroy(); + cntrlPoints.clear(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::allocate(int _w, int _h, int pixelFormat) { + allocate(_w, _h, 2, 2, 100.0f, pixelFormat); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::allocate(int _w, int _h, int _numXPoints, int _numYPoints, float pixelsPerGridDivision, int pixelFormat) { + + for (int i = 0; i < 4; i++) { + showHelperOnCorner[i] = false; + } + + //disable arb textures (so we use texture 2d instead) + + if (_w == 0 || _h == 0 || _numXPoints == 0 || _numYPoints == 0) { + ofLogError("Cannot accept 0 as value for w, h numXPoints or numYPoints"); + return; + } + + if (_w != fbo.getWidth() || _h != fbo.getHeight()) { + + fbo.allocate(_w, _h, pixelFormat); + ofLogVerbose() << "Allocating bezier fbo texture as: " << fbo.getWidth() << " x " << fbo.getHeight(); + } + + setWarpGrid(_numXPoints, _numYPoints); + + //set up texture map for bezier surface + glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &texpts[0][0][0]); + glEnable(GL_MAP2_TEXTURE_COORD_2); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + setWarpGridResolution(pixelsPerGridDivision); + + //glShadeModel(GL_FLAT); + + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::begin() { + fbo.begin(); + ofPushMatrix(); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::end() { + ofPopMatrix(); + fbo.end(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw() { + draw(0, 0, fbo.getWidth(), fbo.getHeight()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw(float x, float y) { + draw(x, y, fbo.getWidth(), fbo.getHeight()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw(float x, float y, float w, float h) { + + if (!fbo.isAllocated()) return; + + ofPushMatrix(); + + if (bDoWarp) { + + ofTranslate(x, y); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + ofTexture & fboTex = fbo.getTextureReference(); + + // upload the bezier control points to the map surface + // this can be done just once (or when control points change) + // if there is only one bezier surface - but with multiple + // it needs to be done every frame + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); + + fboTex.bind(); + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + + glScalef(fboTex.getWidth(), fboTex.getHeight(), 1.0f); + glMatrixMode(GL_MODELVIEW); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + glEvalMesh2(GL_FILL, 0, gridDivX, 0, gridDivY); + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + fboTex.unbind(); + + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + } else { + + fbo.draw(x, y, w, h); + + } + + ofPopMatrix(); + + if (bShowWarpGrid) { + if (bWarpPositionDiff) { + drawWarpGrid(warpX, warpY, warpWidth, warpHeight); + } else { + setWarpGridPosition(x, y, w, h); + } + } + + // glFinish(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::drawWarpGrid(float x, float y, float w, float h) { + + ofPushStyle(); + ofPushMatrix(); + + ofSetColor(255, 255, 255); + ofTranslate(x, y); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + if ( + any_of( + std::begin(showHelperOnCorner), + std::end(showHelperOnCorner), + [](bool ii) { return ii; } + ) || + any_of( + std::begin(showHelperOnCornerMouse), + std::end(showHelperOnCornerMouse), + [](bool iii) { return iii; } + ) + ) { + ofSetColor(150); + } else { + ofSetColor(255); + } + glEvalMesh2(GL_LINE, 0, gridDivX, 0, gridDivY); + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + ofFill(); + if (bRealignPlease) { + ofSetColor(255, 0, 0); + } else { + ofSetColor(100, 255, 100); + } + ofCircle(cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1], 5); + ofNoFill(); + } + } + ofSetColor(255); + + // check if a corner-Point is touched + if (showHelperOnCorner[0] || showHelperOnCornerMouse[0]) { + int x = cntrlPoints[(0 + 0)*3 + 0]; + int y = cntrlPoints[(0 + 0)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[1] || showHelperOnCornerMouse[1]) { + int x = cntrlPoints[(0 + numYPoints)*3 + 0]; + int y = cntrlPoints[(0 + numYPoints)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[2] || showHelperOnCornerMouse[2]) { + int x = cntrlPoints[(numXPoints*numYPoints -1)*3 + 0]; + int y = cntrlPoints[(numXPoints*numYPoints -1)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[3] || showHelperOnCornerMouse[3]) { + int x = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 0]; + int y = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + + ofPopMatrix(); + ofPopStyle(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGrid(int _numXPoints, int _numYPoints, bool forceReset) { + + if (_numXPoints != numXPoints || _numYPoints != numYPoints) forceReset = true; + + if (_numXPoints < 2 || _numYPoints < 2) { + ofLogError() << "Can't have less than 2 X or Y grid points"; + return; + } + + if (forceReset) { + + numXPoints = _numXPoints; + numYPoints = _numYPoints; + + // calculate an even distribution of X and Y control points across fbo width and height + cntrlPoints.resize(numXPoints * numYPoints * 3); + for (int i = 0; i < numYPoints; i++) { + GLfloat x, y; + y = (fbo.getHeight() / (numYPoints - 1)) * i; + for (int j = 0; j < numXPoints; j++) { + x = (fbo.getWidth() / (numXPoints - 1)) * j; + cntrlPoints[(i * numXPoints + j)*3 + 0] = x; + cntrlPoints[(i * numXPoints + j)*3 + 1] = y; + cntrlPoints[(i * numXPoints + j)*3 + 2] = 0; + //cout << x << ", " << y << ", " << "0" << endl; + } + } + } + + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridPosition(float x, float y, float w, float h) { + warpX = x; + warpY = y; + warpWidth = w; + warpHeight = h; + bWarpPositionDiff = true; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridResolution(float pixelsPerGridDivision) { + gridResolution = pixelsPerGridDivision; + setWarpGridResolution(ceil(fbo.getWidth() / pixelsPerGridDivision), ceil(fbo.getHeight() / pixelsPerGridDivision)); +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getWarpGridResolution() { + assert(gridResolution > 0); // tis since if set via gridDivY/X it won't be a single number... + return gridResolution; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridResolution(int gridDivisionsX, int gridDivisionsY) { + // NB: at the moment this sets the resolution for all mapGrid + // objects (since I'm not calling it every frame as it is expensive) + // so if you try to set different resolutions + // for different instances it won't work as expected + + gridDivX = gridDivisionsX; + gridDivY = gridDivisionsY; + glMapGrid2f(gridDivX, 0, 1, gridDivY, 0, 1); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::resetWarpGrid() { + setWarpGrid(numXPoints, numYPoints, true); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::resetWarpGridPosition() { + bWarpPositionDiff = false; +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getWidth() { + return fbo.getWidth(); +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getHeight() { + return fbo.getHeight(); +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getNumXPoints() { + return numXPoints; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getNumYPoints() { + return numYPoints; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getGridDivisionsX() { + return gridDivX; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getGridDivisionsY() { + return gridDivY; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::toggleShowWarpGrid() { + setShowWarpGrid(!getShowWarpGrid()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setShowWarpGrid(bool b) { + bShowWarpGrid = b; + bRealignPlease = false; + if (bShowWarpGrid) { + ofRegisterMouseEvents(this); + ofRegisterKeyEvents(this); + } else { + ofUnregisterMouseEvents(this); + ofUnregisterKeyEvents(this); + } +} + +//-------------------------------------------------------------- + +bool ofxBezierWarp::getShowWarpGrid() { + return bShowWarpGrid; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setDoWarp(bool b) { + bDoWarp = b; +} + +//-------------------------------------------------------------- + +bool ofxBezierWarp::getDoWarp() { + return bDoWarp; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::toggleDoWarp() { + bDoWarp = !bDoWarp; +} + +//-------------------------------------------------------------- + +ofFbo& ofxBezierWarp::getFBO() { + return fbo; +} + +//-------------------------------------------------------------- + +ofTexture& ofxBezierWarp::getTextureReference() { + return fbo.getTextureReference(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setControlPoints(vector _cntrlPoints) { + cntrlPoints.clear(); + cntrlPoints = _cntrlPoints; + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); +} + +//-------------------------------------------------------------- + +vector ofxBezierWarp::getControlPoints() { + return cntrlPoints; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setOffset(ofVec2f p) { + offset = p; +} + +//-------------------------------------------------------------- + +ofVec2f ofxBezierWarp::getOffset() { + return offset; +} + +//-------------------------------------------------------------- + +ofVec2f& ofxBezierWarp::getOffsetReference() { + return offset; +} + +//-------------------------------------------------------------- + +vector& ofxBezierWarp::getControlPointsReference() { + return cntrlPoints; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyPressed(ofKeyEventArgs & e) { + if (e.key == OF_KEY_SHIFT && bGrabbedACorner) { + bRealignPlease = true; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyReleased(ofKeyEventArgs & e) { + bRealignPlease = false; +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseMoved(ofMouseEventArgs & e) { + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY_2 = i; + currentCntrlX_2 = j; + } + } + } + + // check if a corner-Point is touched + // Upper Left + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[0] = true; + } else { + showHelperOnCornerMouse[0] = false; + } + // Upper Right + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[1] = true; + } else { + showHelperOnCornerMouse[1] = false; + } + // Lower Left + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[3] = true; + } else { + showHelperOnCornerMouse[3] = false; + } + // Lower Right + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[2] = true; + } else { + showHelperOnCornerMouse[2] = false; + } + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseDragged(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + if (currentCntrlY != -1 && currentCntrlX != -1) { + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 0] = x; + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 1] = y; + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); + } + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mousePressed(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY = i; + currentCntrlX = j; + } + } + } + // check if a corner-Point is touched + if ( + (currentCntrlY == 0 && currentCntrlX == 0) || + (currentCntrlY == 0 && currentCntrlX == numXPoints - 1) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == 0) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == numXPoints - 1) + ) { + bGrabbedACorner = true; + } else { + bGrabbedACorner = false; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseReleased(ofMouseEventArgs & e) { + if (bRealignPlease) { + rearrangeAllPoints(); + } + currentCntrlY = -1; + currentCntrlX = -1; + bGrabbedACorner = false; +} + + + +//-------------------------------------------------------------- + +void ofxBezierWarp::rearrangeAllPoints() { + ofLogNotice("rearrange all points!"); + // outer lines vertical + // ofVec2f topPoint = ofVec2f(cntrlPoints[0], ); + // ofVec2f lowestPoint = ofVec2f(cntrlPoints[0], ); + + // + // cntrlPoints[(currentCntrlY*numXPoints+currentCntrlX)*3+0] = x; + // cntrlPoints[(currentCntrlY*numXPoints+currentCntrlX)*3+1] = y; + + // cntrlPoints[(i*numXPoints+j)*3+0] = x; + // cntrlPoints[(i*numXPoints+j)*3+1] = y; + // + // i = yPoints, j = xPoints + + // left upper corner + int luNumber = (0 * numXPoints + 0); + //ofLog() << luNumber; + int luX = cntrlPoints[luNumber * 3 + 0]; + int luY = cntrlPoints[luNumber * 3 + 1]; + + // right upper corner + int ruNumber = (numXPoints * 0 + (numXPoints - 1)); + //ofLog() << ruNumber; + int ruX = cntrlPoints[ruNumber * 3 + 0]; + int ruY = cntrlPoints[ruNumber * 3 + 1]; + + // left lower corner + int llNumber = ((numYPoints - 1) * numXPoints + 0); + //ofLog() << llNumber; + int llX = cntrlPoints[llNumber * 3 + 0]; + int llY = cntrlPoints[llNumber * 3 + 1]; + + // right lower corner + int rlNumber = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + //ofLog() << rlNumber; + int rlX = cntrlPoints[rlNumber * 3 + 0]; + int rlY = cntrlPoints[rlNumber * 3 + 1]; + + int teilLeftX = (luX - llX) / (numYPoints-1); + int teilRightX = (ruX - rlX) / (numYPoints-1); + int teilLeftY = (luY - llY) / (numYPoints-1); + int teilRightY = (ruY - rlY) / (numYPoints-1); + + // rearranging the vertical lines left and right + for (int i = 0; i < numYPoints - 1; i++) { + cntrlPoints[(i * numXPoints + 0)*3 + 0] = luX - (i * teilLeftX); + cntrlPoints[(i * numXPoints + 0)*3 + 1] = luY - (i * teilLeftY); +// ofLog() << (i * numXPoints + 0)*3 + 0 << ": " << luX - (i * teilLeftX); +// ofLog() << (i * numXPoints + 0)*3 + 1 << ": " << luY - (i * teilLeftY) << " | " << llY; + cntrlPoints[(i * numXPoints + numXPoints - 1)*3 + 0] = ruX - (i * teilRightX); + cntrlPoints[(i * numXPoints + numXPoints - 1)*3 + 1] = ruY - (i * teilRightY); + } + + // rearranging the horizontal lines + // (we are not efficient here, yes - but we do not actually need to be + // at this point, so we prefer easier to understand code...) + for (int i = 0; i < numYPoints; i++) { + // in this row we do: + // left point + int lpX = cntrlPoints[(i * numXPoints + 0)*3 + 0]; + int lpY = cntrlPoints[(i * numXPoints + 0)*3 + 1]; + // right point + int rpX = cntrlPoints[((i * numXPoints) + numXPoints-1)*3 + 0]; + int rpY = cntrlPoints[((i * numXPoints) + numXPoints-1)*3 + 1]; + // calculate parts to add + int teilX = (lpX - rpX) / (numXPoints-1); + int teilY = (lpY - rpY) / (numXPoints-1); + // rearranging the app. horizontal line + for (int j = 0; j < numXPoints-1; j++) { + cntrlPoints[(i * numXPoints + j)*3 + 0] = lpX - (j * teilX); + cntrlPoints[(i * numXPoints + j)*3 + 1] = lpY - (j * teilY); + } + } + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseScrolled(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseEntered(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseExited(ofMouseEventArgs & e) { + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::moveCorner(ofOeCorner corner, ofOeDirection direction) { + int oePoint; + // getting control points + switch (corner) { + case OE_UPPER_LEFT: + oePoint = (0 * numXPoints + 0); + break; + case OE_UPPER_RIGHT: + oePoint = (numXPoints * 0 + (numXPoints - 1)); + break; + case OE_LOWER_LEFT: + oePoint = ((numYPoints - 1) * numXPoints + 0); + break; + case OE_LOWER_RIGHT: + oePoint = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + break; + } + + switch (direction) { + case OE_DIRECTION_UP: + cntrlPoints[oePoint * 3 + 1]--; + break; + case OE_DIRECTION_DOWN: + cntrlPoints[oePoint * 3 + 1]++; + break; + case OE_DIRECTION_LEFT: + cntrlPoints[oePoint * 3 + 0]--; + break; + case OE_DIRECTION_RIGHT: + cntrlPoints[oePoint * 3 + 0]++; + break; + + } + +} + diff --git a/src/ofxBezierWarp_LOCAL_410183.cpp b/src/ofxBezierWarp_LOCAL_410183.cpp new file mode 100644 index 0000000..637ffe6 --- /dev/null +++ b/src/ofxBezierWarp_LOCAL_410183.cpp @@ -0,0 +1,789 @@ + +/* + * ofxBezierWarp.cpp + * + * Copyright 2013 (c) Matthew Gingold http://gingold.com.au + * Adapted from: http://forum.openframeworks.cc/index.php/topic,4002.0.html + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * If you're using this software for something cool consider sending + * me an email to let me know about your project: m@gingold.com.au + * + */ + +#include "ofxBezierWarp.h" + +GLfloat texpts [2][2][2] = { + { + {0, 0}, + {1, 0} + }, + { + {0, 1}, + {1, 1} + } +}; + +//-------------------------------------------------------------- + +ofxBezierWarp::ofxBezierWarp() { + currentCntrlY = -1; + currentCntrlX = -1; + numXPoints = 0; + numYPoints = 0; + warpX = 0; + warpY = 0; + warpWidth = 0; + warpHeight = 0; + gridResolution = -1; + bShowWarpGrid = false; + bWarpPositionDiff = false; + bDoWarp = true; + + +} + +//-------------------------------------------------------------- + +ofxBezierWarp::~ofxBezierWarp() { + //fbo.destroy(); + cntrlPoints.clear(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::allocate(int _w, int _h, int pixelFormat) { + allocate(_w, _h, 2, 2, 100.0f, pixelFormat); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::allocate(int _w, int _h, int _numXPoints, int _numYPoints, float pixelsPerGridDivision, int pixelFormat) { + + for (int i = 0; i < 4; i++) { + showHelperOnCorner[i] = false; + } + + //disable arb textures (so we use texture 2d instead) + + if (_w == 0 || _h == 0 || _numXPoints == 0 || _numYPoints == 0) { + ofLogError("Cannot accept 0 as value for w, h numXPoints or numYPoints"); + return; + } + + if (_w != fbo.getWidth() || _h != fbo.getHeight()) { + + fbo.allocate(_w, _h, pixelFormat); + ofLogVerbose() << "Allocating bezier fbo texture as: " << fbo.getWidth() << " x " << fbo.getHeight(); + } + + setWarpGrid(_numXPoints, _numYPoints); + + //set up texture map for bezier surface + glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &texpts[0][0][0]); + glEnable(GL_MAP2_TEXTURE_COORD_2); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + setWarpGridResolution(pixelsPerGridDivision); + + //glShadeModel(GL_FLAT); + + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::begin() { + fbo.begin(); + ofPushMatrix(); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::end() { + ofPopMatrix(); + fbo.end(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw() { + draw(0, 0, fbo.getWidth(), fbo.getHeight()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw(float x, float y) { + draw(x, y, fbo.getWidth(), fbo.getHeight()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw(float x, float y, float w, float h) { + + if (!fbo.isAllocated()) return; + + ofPushMatrix(); + + if (bDoWarp) { + + ofTranslate(x, y); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + ofTexture & fboTex = fbo.getTextureReference(); + + // upload the bezier control points to the map surface + // this can be done just once (or when control points change) + // if there is only one bezier surface - but with multiple + // it needs to be done every frame + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); + + fboTex.bind(); + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + + glScalef(fboTex.getWidth(), fboTex.getHeight(), 1.0f); + glMatrixMode(GL_MODELVIEW); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + glEvalMesh2(GL_FILL, 0, gridDivX, 0, gridDivY); + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + fboTex.unbind(); + + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + } else { + + fbo.draw(x, y, w, h); + + } + + ofPopMatrix(); + + if (bShowWarpGrid) { + if (bWarpPositionDiff) { + drawWarpGrid(warpX, warpY, warpWidth, warpHeight); + } else { + setWarpGridPosition(x, y, w, h); + } + } + + // glFinish(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::drawWarpGrid(float x, float y, float w, float h) { + + ofPushStyle(); + ofPushMatrix(); + + ofSetColor(255, 255, 255); + ofTranslate(x, y); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + if ( + any_of( + std::begin(showHelperOnCorner), + std::end(showHelperOnCorner), + [](bool ii) { return ii; } + ) || + any_of( + std::begin(showHelperOnCornerMouse), + std::end(showHelperOnCornerMouse), + [](bool iii) { return iii; } + ) + ) { + ofSetColor(150); + } else { + ofSetColor(255); + } + glEvalMesh2(GL_LINE, 0, gridDivX, 0, gridDivY); + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + ofFill(); + if (bRealignPlease) { + ofSetColor(255, 0, 0); + } else { + ofSetColor(100, 255, 100); + } + ofCircle(cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1], 5); + ofNoFill(); + } + } + ofSetColor(255); + + // check if a corner-Point is touched + if (showHelperOnCorner[0] || showHelperOnCornerMouse[0]) { + int x = cntrlPoints[(0 + 0)*3 + 0]; + int y = cntrlPoints[(0 + 0)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[1] || showHelperOnCornerMouse[1]) { + int x = cntrlPoints[(0 + numYPoints)*3 + 0]; + int y = cntrlPoints[(0 + numYPoints)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[2] || showHelperOnCornerMouse[2]) { + int x = cntrlPoints[(numXPoints*numYPoints -1)*3 + 0]; + int y = cntrlPoints[(numXPoints*numYPoints -1)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[3] || showHelperOnCornerMouse[3]) { + int x = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 0]; + int y = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + + ofPopMatrix(); + ofPopStyle(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGrid(int _numXPoints, int _numYPoints, bool forceReset) { + + if (_numXPoints != numXPoints || _numYPoints != numYPoints) forceReset = true; + + if (_numXPoints < 2 || _numYPoints < 2) { + ofLogError() << "Can't have less than 2 X or Y grid points"; + return; + } + + if (forceReset) { + + numXPoints = _numXPoints; + numYPoints = _numYPoints; + + // calculate an even distribution of X and Y control points across fbo width and height + cntrlPoints.resize(numXPoints * numYPoints * 3); + for (int i = 0; i < numYPoints; i++) { + GLfloat x, y; + y = (fbo.getHeight() / (numYPoints - 1)) * i; + for (int j = 0; j < numXPoints; j++) { + x = (fbo.getWidth() / (numXPoints - 1)) * j; + cntrlPoints[(i * numXPoints + j)*3 + 0] = x; + cntrlPoints[(i * numXPoints + j)*3 + 1] = y; + cntrlPoints[(i * numXPoints + j)*3 + 2] = 0; + //cout << x << ", " << y << ", " << "0" << endl; + } + } + } + + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridPosition(float x, float y, float w, float h) { + warpX = x; + warpY = y; + warpWidth = w; + warpHeight = h; + bWarpPositionDiff = true; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridResolution(float pixelsPerGridDivision) { + gridResolution = pixelsPerGridDivision; + setWarpGridResolution(ceil(fbo.getWidth() / pixelsPerGridDivision), ceil(fbo.getHeight() / pixelsPerGridDivision)); +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getWarpGridResolution() { + assert(gridResolution > 0); // tis since if set via gridDivY/X it won't be a single number... + return gridResolution; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridResolution(int gridDivisionsX, int gridDivisionsY) { + // NB: at the moment this sets the resolution for all mapGrid + // objects (since I'm not calling it every frame as it is expensive) + // so if you try to set different resolutions + // for different instances it won't work as expected + + gridDivX = gridDivisionsX; + gridDivY = gridDivisionsY; + glMapGrid2f(gridDivX, 0, 1, gridDivY, 0, 1); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::resetWarpGrid() { + setWarpGrid(numXPoints, numYPoints, true); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::resetWarpGridPosition() { + bWarpPositionDiff = false; +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getWidth() { + return fbo.getWidth(); +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getHeight() { + return fbo.getHeight(); +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getNumXPoints() { + return numXPoints; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getNumYPoints() { + return numYPoints; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getGridDivisionsX() { + return gridDivX; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getGridDivisionsY() { + return gridDivY; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::toggleShowWarpGrid() { + setShowWarpGrid(!getShowWarpGrid()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setShowWarpGrid(bool b) { + bShowWarpGrid = b; + bRealignPlease = false; + if (bShowWarpGrid) { + ofRegisterMouseEvents(this); + ofRegisterKeyEvents(this); + } else { + ofUnregisterMouseEvents(this); + ofUnregisterKeyEvents(this); + } +} + +//-------------------------------------------------------------- + +bool ofxBezierWarp::getShowWarpGrid() { + return bShowWarpGrid; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setDoWarp(bool b) { + bDoWarp = b; +} + +//-------------------------------------------------------------- + +bool ofxBezierWarp::getDoWarp() { + return bDoWarp; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::toggleDoWarp() { + bDoWarp = !bDoWarp; +} + +//-------------------------------------------------------------- + +ofFbo& ofxBezierWarp::getFBO() { + return fbo; +} + +//-------------------------------------------------------------- + +ofTexture& ofxBezierWarp::getTextureReference() { + return fbo.getTextureReference(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setControlPoints(vector _cntrlPoints) { + cntrlPoints.clear(); + cntrlPoints = _cntrlPoints; + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); +} + +//-------------------------------------------------------------- + +vector ofxBezierWarp::getControlPoints() { + return cntrlPoints; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setOffset(ofVec2f p) { + offset = p; +} + +//-------------------------------------------------------------- + +ofVec2f ofxBezierWarp::getOffset() { + return offset; +} + +//-------------------------------------------------------------- + +ofVec2f& ofxBezierWarp::getOffsetReference() { + return offset; +} + +//-------------------------------------------------------------- + +vector& ofxBezierWarp::getControlPointsReference() { + return cntrlPoints; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyPressed(ofKeyEventArgs & e) { + if (e.key == OF_KEY_SHIFT && bGrabbedACorner) { + bRealignPlease = true; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyReleased(ofKeyEventArgs & e) { + bRealignPlease = false; +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseMoved(ofMouseEventArgs & e) { + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY_2 = i; + currentCntrlX_2 = j; + } + } + } + + // check if a corner-Point is touched + // Upper Left + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[0] = true; + } else { + showHelperOnCornerMouse[0] = false; + } + // Upper Right + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[1] = true; + } else { + showHelperOnCornerMouse[1] = false; + } + // Lower Left + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[3] = true; + } else { + showHelperOnCornerMouse[3] = false; + } + // Lower Right + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[2] = true; + } else { + showHelperOnCornerMouse[2] = false; + } + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseDragged(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + if (currentCntrlY != -1 && currentCntrlX != -1) { + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 0] = x; + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 1] = y; + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); + } + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mousePressed(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY = i; + currentCntrlX = j; + } + } + } + // check if a corner-Point is touched + if ( + (currentCntrlY == 0 && currentCntrlX == 0) || + (currentCntrlY == 0 && currentCntrlX == numXPoints - 1) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == 0) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == numXPoints - 1) + ) { + bGrabbedACorner = true; + } else { + bGrabbedACorner = false; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseReleased(ofMouseEventArgs & e) { + if (bRealignPlease) { + rearrangeAllPoints(); + } + currentCntrlY = -1; + currentCntrlX = -1; + bGrabbedACorner = false; +} + + + +//-------------------------------------------------------------- + +void ofxBezierWarp::rearrangeAllPoints() { + ofLogNotice("rearrange all points!"); + // outer lines vertical + // ofVec2f topPoint = ofVec2f(cntrlPoints[0], ); + // ofVec2f lowestPoint = ofVec2f(cntrlPoints[0], ); + + // + // cntrlPoints[(currentCntrlY*numXPoints+currentCntrlX)*3+0] = x; + // cntrlPoints[(currentCntrlY*numXPoints+currentCntrlX)*3+1] = y; + + // cntrlPoints[(i*numXPoints+j)*3+0] = x; + // cntrlPoints[(i*numXPoints+j)*3+1] = y; + // + // i = yPoints, j = xPoints + + // left upper corner + int luNumber = (0 * numXPoints + 0); + //ofLog() << luNumber; + int luX = cntrlPoints[luNumber * 3 + 0]; + int luY = cntrlPoints[luNumber * 3 + 1]; + + // right upper corner + int ruNumber = (numXPoints * 0 + (numXPoints - 1)); + //ofLog() << ruNumber; + int ruX = cntrlPoints[ruNumber * 3 + 0]; + int ruY = cntrlPoints[ruNumber * 3 + 1]; + + // left lower corner + int llNumber = ((numYPoints - 1) * numXPoints + 0); + //ofLog() << llNumber; + int llX = cntrlPoints[llNumber * 3 + 0]; + int llY = cntrlPoints[llNumber * 3 + 1]; + + // right lower corner + int rlNumber = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + //ofLog() << rlNumber; + int rlX = cntrlPoints[rlNumber * 3 + 0]; + int rlY = cntrlPoints[rlNumber * 3 + 1]; + + int teilLeftX = (luX - llX) / (numYPoints-1); + int teilRightX = (ruX - rlX) / (numYPoints-1); + int teilLeftY = (luY - llY) / (numYPoints-1); + int teilRightY = (ruY - rlY) / (numYPoints-1); + + // rearranging the vertical outer lines, left and right + for (int i = 0; i < numYPoints - 1; i++) { + // left side + cntrlPoints[(i * numXPoints + 0)*3 + 0] = luX - (i * teilLeftX); + cntrlPoints[(i * numXPoints + 0)*3 + 1] = luY - (i * teilLeftY); +// ofLog() << (i * numXPoints + 0)*3 + 0 << ": " << luX - (i * teilLeftX); +// ofLog() << (i * numXPoints + 0)*3 + 1 << ": " << luY - (i * teilLeftY) << " | " << llY; + // right side + cntrlPoints[(i * numXPoints + numXPoints - 1)*3 + 0] = ruX - (i * teilRightX); + cntrlPoints[(i * numXPoints + numXPoints - 1)*3 + 1] = ruY - (i * teilRightY); + } + + // rearranging the horizontal lines + // (we are not efficient here, yes - but we do not actually need to be + // at this point, so we prefer easier to understand code...) + for (int i = 0; i < numYPoints; i++) { + // in this row we do: + // left point + int lpX = cntrlPoints[(i * numXPoints + 0)*3 + 0]; + int lpY = cntrlPoints[(i * numXPoints + 0)*3 + 1]; + // right point + int rpX = cntrlPoints[((i * numXPoints) + numXPoints-1)*3 + 0]; + int rpY = cntrlPoints[((i * numXPoints) + numXPoints-1)*3 + 1]; + // calculate parts to add + int teilX = (lpX - rpX) / (numXPoints-1); + int teilY = (lpY - rpY) / (numXPoints-1); + // rearranging the app. horizontal line + for (int j = 0; j < numXPoints-1; j++) { + cntrlPoints[(i * numXPoints + j)*3 + 0] = lpX - (j * teilX); + cntrlPoints[(i * numXPoints + j)*3 + 1] = lpY - (j * teilY); + } + } + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseScrolled(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseEntered(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseExited(ofMouseEventArgs & e) { + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::moveCorner(ofOeCorner corner, ofOeDirection direction) { + int oePoint; + // getting control points + switch (corner) { + case OE_UPPER_LEFT: + oePoint = (0 * numXPoints + 0); + break; + case OE_UPPER_RIGHT: + oePoint = (numXPoints * 0 + (numXPoints - 1)); + break; + case OE_LOWER_LEFT: + oePoint = ((numYPoints - 1) * numXPoints + 0); + break; + case OE_LOWER_RIGHT: + oePoint = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + break; + } + + switch (direction) { + case OE_DIRECTION_UP: + cntrlPoints[oePoint * 3 + 1]--; + break; + case OE_DIRECTION_DOWN: + cntrlPoints[oePoint * 3 + 1]++; + break; + case OE_DIRECTION_LEFT: + cntrlPoints[oePoint * 3 + 0]--; + break; + case OE_DIRECTION_RIGHT: + cntrlPoints[oePoint * 3 + 0]++; + break; + + } + +} + diff --git a/src/ofxBezierWarp_REMOTE_410183.cpp b/src/ofxBezierWarp_REMOTE_410183.cpp new file mode 100644 index 0000000..0831b42 --- /dev/null +++ b/src/ofxBezierWarp_REMOTE_410183.cpp @@ -0,0 +1,787 @@ + +/* + * ofxBezierWarp.cpp + * + * Copyright 2013 (c) Matthew Gingold http://gingold.com.au + * Adapted from: http://forum.openframeworks.cc/index.php/topic,4002.0.html + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * If you're using this software for something cool consider sending + * me an email to let me know about your project: m@gingold.com.au + * + */ + +#include +#include +#include + +#include "ofxBezierWarp.h" + +GLfloat texpts [2][2][2] = { + { + {0, 0}, + {1, 0} + }, + { + {0, 1}, + {1, 1} + } +}; + +//-------------------------------------------------------------- + +ofxBezierWarp::ofxBezierWarp() { + currentCntrlY = -1; + currentCntrlX = -1; + numXPoints = 0; + numYPoints = 0; + warpX = 0; + warpY = 0; + warpWidth = 0; + warpHeight = 0; + gridResolution = -1; + bShowWarpGrid = false; + bWarpPositionDiff = false; + bDoWarp = true; +} + +//-------------------------------------------------------------- + +ofxBezierWarp::~ofxBezierWarp() { + //fbo.destroy(); + cntrlPoints.clear(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::allocate(int _w, int _h, int pixelFormat) { + allocate(_w, _h, 2, 2, 100.0f, pixelFormat); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::allocate(int _w, int _h, int _numXPoints, int _numYPoints, float pixelsPerGridDivision, int pixelFormat) { + + for (int i = 0; i < 4; i++) { + showHelperOnCorner[i] = false; + } + + //disable arb textures (so we use texture 2d instead) + + if (_w == 0 || _h == 0 || _numXPoints == 0 || _numYPoints == 0) { + ofLogError("Cannot accept 0 as value for w, h numXPoints or numYPoints"); + return; + } + + if (_w != fbo.getWidth() || _h != fbo.getHeight()) { + + fbo.allocate(_w, _h, pixelFormat); + ofLogVerbose() << "Allocating bezier fbo texture as: " << fbo.getWidth() << " x " << fbo.getHeight(); + } + + setWarpGrid(_numXPoints, _numYPoints); + + //set up texture map for bezier surface + glMap2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, &texpts[0][0][0]); + glEnable(GL_MAP2_TEXTURE_COORD_2); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + setWarpGridResolution(pixelsPerGridDivision); + + //glShadeModel(GL_FLAT); + + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::begin() { + fbo.begin(); + ofPushMatrix(); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::end() { + ofPopMatrix(); + fbo.end(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw() { + draw(0, 0, fbo.getWidth(), fbo.getHeight()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw(float x, float y) { + draw(x, y, fbo.getWidth(), fbo.getHeight()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::draw(float x, float y, float w, float h) { + + if (!fbo.isAllocated()) return; + + ofPushMatrix(); + + if (bDoWarp) { + + ofTranslate(x, y); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + ofTexture & fboTex = fbo.getTextureReference(); + + // upload the bezier control points to the map surface + // this can be done just once (or when control points change) + // if there is only one bezier surface - but with multiple + // it needs to be done every frame + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); + + fboTex.bind(); + + glMatrixMode(GL_TEXTURE); + glPushMatrix(); + glLoadIdentity(); + + glScalef(fboTex.getWidth(), fboTex.getHeight(), 1.0f); + glMatrixMode(GL_MODELVIEW); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + glEvalMesh2(GL_FILL, 0, gridDivX, 0, gridDivY); + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + fboTex.unbind(); + + glMatrixMode(GL_TEXTURE); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + + } else { + + fbo.draw(x, y, w, h); + + } + + ofPopMatrix(); + + if (bShowWarpGrid) { + if (bWarpPositionDiff) { + drawWarpGrid(warpX, warpY, warpWidth, warpHeight); + } else { + setWarpGridPosition(x, y, w, h); + } + } + + // glFinish(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::drawWarpGrid(float x, float y, float w, float h) { + + ofPushStyle(); + ofPushMatrix(); + + ofSetColor(255, 255, 255); + ofTranslate(x, y); + ofScale(w / fbo.getWidth(), h / fbo.getHeight()); + + // glEnable(GL_MAP2_VERTEX_3); + // glEnable(GL_AUTO_NORMAL); + if ( + any_of( + std::begin(showHelperOnCorner), + std::end(showHelperOnCorner), + [](bool ii) { return ii; } + ) || + any_of( + std::begin(showHelperOnCornerMouse), + std::end(showHelperOnCornerMouse), + [](bool iii) { return iii; } + ) + ) { + ofSetColor(150); + } else { + ofSetColor(255); + } + glEvalMesh2(GL_LINE, 0, gridDivX, 0, gridDivY); + // glDisable(GL_MAP2_VERTEX_3); + // glDisable(GL_AUTO_NORMAL); + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + ofFill(); + if (bRealignPlease) { + ofSetColor(255, 0, 0); + } else { + ofSetColor(100, 255, 100); + } + ofCircle(cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1], 5); + ofNoFill(); + } + } + ofSetColor(255); + + // check if a corner-Point is touched + if (showHelperOnCorner[0] || showHelperOnCornerMouse[0]) { + int x = cntrlPoints[(0 + 0)*3 + 0]; + int y = cntrlPoints[(0 + 0)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[1] || showHelperOnCornerMouse[1]) { + int x = cntrlPoints[(0 + numYPoints)*3 + 0]; + int y = cntrlPoints[(0 + numYPoints)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[2] || showHelperOnCornerMouse[2]) { + int x = cntrlPoints[(numXPoints*numYPoints -1)*3 + 0]; + int y = cntrlPoints[(numXPoints*numYPoints -1)*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + if (showHelperOnCorner[3] || showHelperOnCornerMouse[3]) { + int x = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 0]; + int y = cntrlPoints[(numXPoints*(numYPoints-1))*3 + 1]; + ofDrawLine(x-350, y, x+350, y); + ofDrawLine(x, y-350, x, y+350); + ofDrawLine(x-150, y-150, x+150, y+150); + ofDrawLine(x+150, y-150, x-150, y+150); + } + + ofPopMatrix(); + ofPopStyle(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGrid(int _numXPoints, int _numYPoints, bool forceReset) { + + if (_numXPoints != numXPoints || _numYPoints != numYPoints) forceReset = true; + + if (_numXPoints < 2 || _numYPoints < 2) { + ofLogError() << "Can't have less than 2 X or Y grid points"; + return; + } + + if (forceReset) { + + numXPoints = _numXPoints; + numYPoints = _numYPoints; + + // calculate an even distribution of X and Y control points across fbo width and height + cntrlPoints.resize(numXPoints * numYPoints * 3); + for (int i = 0; i < numYPoints; i++) { + GLfloat x, y; + y = (fbo.getHeight() / (numYPoints - 1)) * i; + for (int j = 0; j < numXPoints; j++) { + x = (fbo.getWidth() / (numXPoints - 1)) * j; + cntrlPoints[(i * numXPoints + j)*3 + 0] = x; + cntrlPoints[(i * numXPoints + j)*3 + 1] = y; + cntrlPoints[(i * numXPoints + j)*3 + 2] = 0; + //cout << x << ", " << y << ", " << "0" << endl; + } + } + } + + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridPosition(float x, float y, float w, float h) { + warpX = x; + warpY = y; + warpWidth = w; + warpHeight = h; + bWarpPositionDiff = true; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridResolution(float pixelsPerGridDivision) { + gridResolution = pixelsPerGridDivision; + setWarpGridResolution(ceil(fbo.getWidth() / pixelsPerGridDivision), ceil(fbo.getHeight() / pixelsPerGridDivision)); +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getWarpGridResolution() { + assert(gridResolution > 0); // tis since if set via gridDivY/X it won't be a single number... + return gridResolution; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setWarpGridResolution(int gridDivisionsX, int gridDivisionsY) { + // NB: at the moment this sets the resolution for all mapGrid + // objects (since I'm not calling it every frame as it is expensive) + // so if you try to set different resolutions + // for different instances it won't work as expected + + gridDivX = gridDivisionsX; + gridDivY = gridDivisionsY; + glMapGrid2f(gridDivX, 0, 1, gridDivY, 0, 1); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::resetWarpGrid() { + setWarpGrid(numXPoints, numYPoints, true); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::resetWarpGridPosition() { + bWarpPositionDiff = false; +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getWidth() { + return fbo.getWidth(); +} + +//-------------------------------------------------------------- + +float ofxBezierWarp::getHeight() { + return fbo.getHeight(); +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getNumXPoints() { + return numXPoints; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getNumYPoints() { + return numYPoints; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getGridDivisionsX() { + return gridDivX; +} + +//-------------------------------------------------------------- + +int ofxBezierWarp::getGridDivisionsY() { + return gridDivY; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::toggleShowWarpGrid() { + setShowWarpGrid(!getShowWarpGrid()); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setShowWarpGrid(bool b) { + bShowWarpGrid = b; + bRealignPlease = false; + if (bShowWarpGrid) { + ofRegisterMouseEvents(this); + ofRegisterKeyEvents(this); + } else { + ofUnregisterMouseEvents(this); + ofUnregisterKeyEvents(this); + } +} + +//-------------------------------------------------------------- + +bool ofxBezierWarp::getShowWarpGrid() { + return bShowWarpGrid; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setDoWarp(bool b) { + bDoWarp = b; +} + +//-------------------------------------------------------------- + +bool ofxBezierWarp::getDoWarp() { + return bDoWarp; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::toggleDoWarp() { + bDoWarp = !bDoWarp; +} + +//-------------------------------------------------------------- + +ofFbo& ofxBezierWarp::getFBO() { + return fbo; +} + +//-------------------------------------------------------------- + +ofTexture& ofxBezierWarp::getTextureReference() { + return fbo.getTextureReference(); +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setControlPoints(vector _cntrlPoints) { + cntrlPoints.clear(); + cntrlPoints = _cntrlPoints; + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); +} + +//-------------------------------------------------------------- + +vector ofxBezierWarp::getControlPoints() { + return cntrlPoints; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::setOffset(ofVec2f p) { + offset = p; +} + +//-------------------------------------------------------------- + +ofVec2f ofxBezierWarp::getOffset() { + return offset; +} + +//-------------------------------------------------------------- + +ofVec2f& ofxBezierWarp::getOffsetReference() { + return offset; +} + +//-------------------------------------------------------------- + +vector& ofxBezierWarp::getControlPointsReference() { + return cntrlPoints; +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyPressed(ofKeyEventArgs & e) { + if (e.key == OF_KEY_SHIFT && bGrabbedACorner) { + bRealignPlease = true; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::keyReleased(ofKeyEventArgs & e) { + bRealignPlease = false; +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseMoved(ofMouseEventArgs & e) { + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY_2 = i; + currentCntrlX_2 = j; + } + } + } + + // check if a corner-Point is touched + // Upper Left + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[0] = true; + } else { + showHelperOnCornerMouse[0] = false; + } + // Upper Right + if ( + (currentCntrlY_2 == 0 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[1] = true; + } else { + showHelperOnCornerMouse[1] = false; + } + // Lower Left + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == 0) + ) { + showHelperOnCornerMouse[3] = true; + } else { + showHelperOnCornerMouse[3] = false; + } + // Lower Right + if ( + (currentCntrlY_2 == numYPoints - 1 && currentCntrlX_2 == numXPoints - 1) + ) { + showHelperOnCornerMouse[2] = true; + } else { + showHelperOnCornerMouse[2] = false; + } + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseDragged(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + if (currentCntrlY != -1 && currentCntrlX != -1) { + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 0] = x; + cntrlPoints[(currentCntrlY * numXPoints + currentCntrlX)*3 + 1] = y; + glMap2f(GL_MAP2_VERTEX_3, 0, 1, 3, numXPoints, 0, 1, numXPoints * 3, numYPoints, &(cntrlPoints[0])); + } + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mousePressed(ofMouseEventArgs & e) { + + if (!bShowWarpGrid) mouseReleased(e); + + float x = e.x; + float y = e.y; + + if (bWarpPositionDiff) { + x = (e.x - warpX) * fbo.getWidth() / warpWidth; + y = (e.y - warpY) * fbo.getHeight() / warpHeight; + } + + float dist = 10.0f; + + for (int i = 0; i < numYPoints; i++) { + for (int j = 0; j < numXPoints; j++) { + if (x - cntrlPoints[(i * numXPoints + j)*3 + 0] >= -dist && x - cntrlPoints[(i * numXPoints + j)*3 + 0] <= dist && + y - cntrlPoints[(i * numXPoints + j)*3 + 1] >= -dist && y - cntrlPoints[(i * numXPoints + j)*3 + 1] <= dist) { + currentCntrlY = i; + currentCntrlX = j; + } + } + } + // check if a corner-Point is touched + if ( + (currentCntrlY == 0 && currentCntrlX == 0) || + (currentCntrlY == 0 && currentCntrlX == numXPoints - 1) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == 0) || + (currentCntrlY == numYPoints - 1 && currentCntrlX == numXPoints - 1) + ) { + bGrabbedACorner = true; + } else { + bGrabbedACorner = false; + } +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseReleased(ofMouseEventArgs & e) { + if (bRealignPlease) { + rearrangeAllPoints(); + } + currentCntrlY = -1; + currentCntrlX = -1; + bGrabbedACorner = false; +} + + + +//-------------------------------------------------------------- + +void ofxBezierWarp::rearrangeAllPoints() { + ofLogNotice("rearrange all points!"); + + // left upper corner + int luNumber = (0 * numXPoints + 0); + //ofLog() << luNumber; + int luX = cntrlPoints[luNumber * 3 + 0]; + int luY = cntrlPoints[luNumber * 3 + 1]; + + // right upper corner + int ruNumber = (numXPoints * 0 + (numXPoints - 1)); + //ofLog() << ruNumber; + int ruX = cntrlPoints[ruNumber * 3 + 0]; + int ruY = cntrlPoints[ruNumber * 3 + 1]; + + // left lower corner + int llNumber = ((numYPoints - 1) * numXPoints + 0); + //ofLog() << llNumber; + int llX = cntrlPoints[llNumber * 3 + 0]; + int llY = cntrlPoints[llNumber * 3 + 1]; + + // right lower corner + int rlNumber = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + //ofLog() << rlNumber; + int rlX = cntrlPoints[rlNumber * 3 + 0]; + int rlY = cntrlPoints[rlNumber * 3 + 1]; + + // getting the projection matrix + // calculate from: 4 corner points of original original, non-warped grid (screen) + // and 4 corner points of the warp grid + int x = 0; + int y = 0; + int w = getWidth(); + int h = getHeight(); + + cv::Point2f src_points[] = { + cv::Point2f( x, y ), + cv::Point2f( x + w, y ), + cv::Point2f( x + w, y + h ), + cv::Point2f( x, y + h ) + }; + + cv::Point2f dst_points[] = { + cv::Point2f( luX, luY ), + cv::Point2f( ruX, ruY ), + cv::Point2f( rlX, rlY ), + cv::Point2f( llX, llY ) + }; + + auto Matrix = cv::getPerspectiveTransform( src_points, dst_points ); + + // going through all points and apply the matrix + + int urX; + int urY; + for (int i = 0; i < numYPoints; i++) { + urY = h / (numYPoints-1) * i ; + for (int j = 0; j < numXPoints; j++) { + vector sourcePoints; + vector targetPoints; + // Source points are all points from original, non-warped grid + // so simple division of width and height + urX = w / (numXPoints-1) * j; + sourcePoints.push_back( cv::Point2f( urX, urY ) ); + perspectiveTransform(sourcePoints, targetPoints, Matrix); + cout << ofPoint ( cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1] ) << "\n" ; + cntrlPoints[(i * numXPoints + j)*3 + 0] = targetPoints[0].x; + cntrlPoints[(i * numXPoints + j)*3 + 1] = targetPoints[0].y; + cout << ofPoint ( cntrlPoints[(i * numXPoints + j)*3 + 0], cntrlPoints[(i * numXPoints + j)*3 + 1] ) << "\n" << "\n"; + } + } + + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseScrolled(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseEntered(ofMouseEventArgs & e) { + +} + +//-------------------------------------------------------------- + +void ofxBezierWarp::mouseExited(ofMouseEventArgs & e) { + +} + + +//-------------------------------------------------------------- + +void ofxBezierWarp::moveCorner(ofOeCorner corner, ofOeDirection direction) { + int oePoint; + // getting control points + switch (corner) { + case OE_UPPER_LEFT: + oePoint = (0 * numXPoints + 0); + break; + case OE_UPPER_RIGHT: + oePoint = (numXPoints * 0 + (numXPoints - 1)); + break; + case OE_LOWER_LEFT: + oePoint = ((numYPoints - 1) * numXPoints + 0); + break; + case OE_LOWER_RIGHT: + oePoint = ((numYPoints - 1) * numXPoints + (numXPoints - 1)); + break; + } + + switch (direction) { + case OE_DIRECTION_UP: + cntrlPoints[oePoint * 3 + 1]--; + break; + case OE_DIRECTION_DOWN: + cntrlPoints[oePoint * 3 + 1]++; + break; + case OE_DIRECTION_LEFT: + cntrlPoints[oePoint * 3 + 0]--; + break; + case OE_DIRECTION_RIGHT: + cntrlPoints[oePoint * 3 + 0]++; + break; + + } + +} +