#include "QuadSurface.h" namespace ofx { namespace piMapper { QuadSurface::QuadSurface(){ _perspectiveWarping = false; setup(); } QuadSurface::~QuadSurface(){ std::cout << "QuadSurface destructor." << std::endl; } void QuadSurface::setup(){ // Create 4 points for the 2 triangles Vec3 p1 = Vec3(0.0f, 0.0f, 0.0f); Vec3 p2 = Vec3(0.0f, ofGetHeight(), 0.0f); Vec3 p3 = Vec3(ofGetWidth(), ofGetHeight(), 0.0f); Vec3 p4 = Vec3(ofGetWidth(), 0.0f, 0.0f); // Create 4 point for the texture coordinates Vec2 t1 = Vec2(0.0f, 0.0f); Vec2 t2 = Vec2(1.0f, 0.0f); Vec2 t3 = Vec2(1.0f, 1.0f); Vec2 t4 = Vec2(0.0f, 1.0f); setup(p1, p2, p3, p4, t1, t2, t3, t4, source); } void QuadSurface::setup(Vec3 p1, Vec3 p2, Vec3 p3, Vec3 p4, Vec2 t1, Vec2 t2, Vec2 t3, Vec2 t4, BaseSource * newSource){ // Assign texture source = newSource; // Clear mesh mesh.clear(); // Create a surface with the points mesh.addVertex(p1.toOf()); mesh.addVertex(p2.toOf()); mesh.addVertex(p3.toOf()); mesh.addVertex(p4.toOf()); // Add 2 triangles mesh.addTriangle(0, 2, 3); mesh.addTriangle(0, 1, 2); // Add texture coordinates mesh.addTexCoord(t1.toOf()); mesh.addTexCoord(t2.toOf()); mesh.addTexCoord(t3.toOf()); mesh.addTexCoord(t4.toOf()); } void QuadSurface::draw(){ if(source->getTexture() == 0){ return; } if(!source->getTexture()->isAllocated()){ return; } if(_perspectiveWarping){ if(mesh.haveVertsChanged() || mesh.haveTexCoordsChanged()){ calculateHomography(); } ofRectangle box = getMeshBoundingBox(); ofMesh m = mesh; m.setVertex(0, Vec3(0, 0, 0).toOf()); m.setVertex(1, Vec3(box.width, 0, 0).toOf()); m.setVertex(2, Vec3(box.width, box.height, 0).toOf()); m.setVertex(3, Vec3(0, box.height, 0).toOf()); ofPushMatrix(); if(true){ bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); ofEnableNormalizedTexCoords(); glMultMatrixf(_matrix); source->getTexture()->bind(); m.draw(); source->getTexture()->unbind(); if(!normalizedTexCoords){ ofDisableNormalizedTexCoords(); } } ofPopMatrix(); }else{ bool normalizedTexCoords = ofGetUsingNormalizedTexCoords(); ofEnableNormalizedTexCoords(); ofPushStyle(); ofSetColor(255, 255, 255); source->getTexture()->bind(); mesh.draw(); source->getTexture()->unbind(); ofPopStyle(); if(!normalizedTexCoords){ ofDisableNormalizedTexCoords(); } } } void QuadSurface::setVertex(int index, Vec3 p){ if(index > 3){ ofLog() << "Vertex with this index does not exist: " << index << std::endl; return; } mesh.setVertex(index, p.toOf()); ofNotifyEvent(vertexChangedEvent, index, this); } void QuadSurface::setVertices(std::vector v){ if(v.size() != 4){ throw runtime_error("Wrong number of vertices"); } for(int i = 0; i < 4; ++i){ mesh.setVertex(i, v[i].toOf()); } std::vector vertices = Vec3::fromOf(mesh.getVertices()); ofNotifyEvent(verticesChangedEvent, vertices, this); } void QuadSurface::setTexCoord(int index, Vec2 t){ if(index > 3){ ofLog() << "Texture coordinate with this index does not exist: " << index << std::endl; return; } mesh.setTexCoord(index, t.toOf()); } void QuadSurface::setTexCoords(std::vector t){ if(t.size() != 4){ throw runtime_error("Wrong number of vertices"); } for(int i = 0; i < 4; ++i){ mesh.setTexCoord(i, t[i].toOf()); } } void QuadSurface::moveBy(Vec3 v){ for(int i = 0; i < mesh.getVertices().size(); i++){ mesh.getVertices()[i] += v.toOf(); } setMoved(true); std::vector vertices = Vec3::fromOf(mesh.getVertices()); ofNotifyEvent(verticesChangedEvent, vertices, this); } int QuadSurface::getType(){ return SurfaceType::QUAD_SURFACE; } bool QuadSurface::hitTest(Vec2 p){ ofPolyline line = getHitArea(); if(line.inside(p.x, p.y)){ return true; }else{ return false; } } Vec3 QuadSurface::getVertex(int index){ if(index > 3){ ofLog() << "Vertex with this index does not exist: " << index << std::endl; throw runtime_error("Vertex index out of bounds."); } return Vec3( mesh.getVertex(index).x, mesh.getVertex(index).y, mesh.getVertex(index).z); } Vec2 QuadSurface::getTexCoord(int index){ if(index > 3){ throw runtime_error("Texture coordinate index out of bounds."); } return Vec2( mesh.getTexCoord(index).x, mesh.getTexCoord(index).y); } ofPolyline QuadSurface::getHitArea(){ ofPolyline line; line.addVertex(ofPoint(mesh.getVertex(0).x, mesh.getVertex(0).y)); line.addVertex(ofPoint(mesh.getVertex(1).x, mesh.getVertex(1).y)); line.addVertex(ofPoint(mesh.getVertex(2).x, mesh.getVertex(2).y)); line.addVertex(ofPoint(mesh.getVertex(3).x, mesh.getVertex(3).y)); line.close(); return line; } ofPolyline QuadSurface::getTextureHitArea(){ ofPolyline line; Vec2 textureSize = Vec2(source->getTexture()->getWidth(), source->getTexture()->getHeight()); for(int i = 0; i < mesh.getTexCoords().size(); i++){ line.addVertex(ofPoint(mesh.getTexCoords()[i] * textureSize.toOf())); } line.close(); return line; } std::vector QuadSurface::getVertices(){ return Vec3::fromOf(mesh.getVertices()); } std::vector QuadSurface::getTexCoords(){ return Vec2::fromOf(mesh.getTexCoords()); } void QuadSurface::calculateHomography(){ float src[4][2]; float dst[4][2]; ofRectangle box = getMeshBoundingBox(); src[0][0] = 0; src[0][1] = 0; src[1][0] = box.width; src[1][1] = 0; src[2][0] = box.width; src[2][1] = box.height; src[3][0] = 0; src[3][1] = box.height; Vec3 p0(mesh.getVertex(0).x, mesh.getVertex(0).y, mesh.getVertex(0).z); Vec3 p1(mesh.getVertex(1).x, mesh.getVertex(1).y, mesh.getVertex(1).z); Vec3 p2(mesh.getVertex(2).x, mesh.getVertex(2).y, mesh.getVertex(2).z); Vec3 p3(mesh.getVertex(3).x, mesh.getVertex(3).y, mesh.getVertex(3).z); dst[0][0] = p0.x; dst[0][1] = p0.y; dst[1][0] = p1.x; dst[1][1] = p1.y; dst[2][0] = p2.x; dst[2][1] = p2.y; dst[3][0] = p3.x; dst[3][1] = p3.y; HomographyHelper::findHomography(src, dst, _matrix); } void QuadSurface::setPerspectiveWarping(bool b){ _perspectiveWarping = b; } bool QuadSurface::getPerspectiveWarping(){ return _perspectiveWarping; } ofRectangle QuadSurface::getMeshBoundingBox(){ float minX = 10000.0f; float minY = 10000.0f; float maxX = 0.0f; float maxY = 0.0f; for(int i = 0; i < mesh.getVertices().size(); ++i){ if(mesh.getVertices()[i].x < minX){ minX = mesh.getVertices()[i].x; } if(mesh.getVertices()[i].y < minY){ minY = mesh.getVertices()[i].y; } if(mesh.getVertices()[i].x > maxX){ maxX = mesh.getVertices()[i].x; } if(mesh.getVertices()[i].y > maxY){ maxY = mesh.getVertices()[i].y; } } ofRectangle boundingBox = ofRectangle(ofPoint(minX, minY), ofPoint(maxX, maxY)); return boundingBox; } BaseSurface * QuadSurface::clone(){ QuadSurface * s = new QuadSurface(); s->setVertices(getVertices()); s->setTexCoords(getTexCoords()); s->setPerspectiveWarping(getPerspectiveWarping()); BaseSource * src = getSource(); src->referenceCount++; s->setSource(src); return s; } } // namespace piMapper } // namespace ofx