void Astrolabe::setRotationTween( string axis, float startVal, float step, float duration, float delay, float increment, float _scale ) { addRotationTween( axis, startVal, step, duration, delay, increment, _scale ); };
//---------------------------------------- void ofEasyFingerCam::begin(ofRectangle viewport) { glEnable(GL_DEPTH_TEST); viewportRect = viewport; ofCamera::begin(viewport); ofPushMatrix(); glGetDoublev(GL_PROJECTION_MATRIX, this->matP); glGetDoublev(GL_MODELVIEW_MATRIX, this->matM); glGetIntegerv(GL_VIEWPORT, this->viewport); bool hasTweens = false; if(rTweens.size()>0) { hasTweens = true; setAnglesFromOrientation(); targetXRot = rTweens[0]->x; targetYRot = rTweens[0]->y; targetZRot = rTweens[0]->z; updateRotation(); if(targetXRot - rotationX <1 && targetXRot - rotationX >-1 && targetYRot - rotationY <1 && targetYRot - rotationY >-1 && targetZRot - rotationZ <1 && targetZRot - rotationZ >-1) { rTweens.erase(rTweens.begin()); } setAnglesFromOrientation(); } if(sTweens.size()>0) { hasTweens = true; if(abs(sTweens.at(0)->scale - getDistance()) < 10) { float newvalue = (getDistance()-sTweens.at(0)->scale)*0.05/100; setDistance(getDistance()+newvalue); } } if(pTweens.size()>0) { hasTweens = true; if(target.getPosition().distance(pTweens.at(0)->pan) > 1) { ofVec3f newTranslation; newTranslation = pTweens.at(0)->pan - target.getPosition(); translation = newTranslation/10; target.move(translation); } else { pTweens.erase(pTweens.begin()); } } if(hasTweens) { currentState = TWEENING; } else { currentState = STABLE; if(bMouseInputEnabled||bFingerInputEnabled) { if(!bDistanceSet) { setDistance(getImagePlaneDistance(viewport), true); } if (fingers.size() > 0 ) { // it's important to check whether we've already accounted for the mouse // just in case you use the camera multiple times in a single frame if (lastFrame != ofGetFrameNum()) { lastFrame = ofGetFrameNum(); currentState = STABLE; if (fingers.size() == 1) { if(selectedPlane->axis == AxisPlane::NOAXIS) { currentState = ROTATING; // if there is some smart way to use dt to scale the values drag, we should do it // you can't simply multiply drag etc because the behavior is unstable at high framerates // float dt = ofGetLastFrameTime(); ofVec2f mousePosScreen = ofVec3f(fingers[0]->getX()*ofGetWidth() - viewport.width/2 - viewport.x, viewport.height/2 - (fingers[0]->getY()*ofGetHeight() - viewport.y), 0); ofVec2f mouseVelScreen = (mousePosScreen - mousePosScreenPrev).lengthSquared(); ofVec3f targetPos = target.getGlobalPosition(); ofVec3f mousePosXYZ = ofVec3f(mousePosScreen.x, mousePosScreen.y, targetPos.z); float sphereRadius = min(viewport.width, viewport.height)/2; float diffSquared = sphereRadius * sphereRadius - (targetPos - mousePosXYZ).lengthSquared(); if(diffSquared <= 0) { mousePosXYZ.z = 0; } else { mousePosXYZ.z = sqrtf(diffSquared); } mousePosXYZ.z += targetPos.z; ofVec3f mousePosView = ofMatrix4x4::getInverseOf(target.getGlobalTransformMatrix()) * mousePosXYZ; //calc new rotation velocity ofQuaternion newRotation; if(fingerPressedPrev[0]) { newRotation.makeRotate(mousePosViewPrev, mousePosView); } fingerPressedPrev[0] = true; //apply drag towards new velocities rotation.slerp(drag, rotation, newRotation); // TODO: add dt mousePosViewPrev = ofMatrix4x4::getInverseOf(target.getGlobalTransformMatrix()) * mousePosXYZ; // apply transforms if they're big enough // TODO: these should be scaled by dt if(translation.lengthSquared() > epsilonTransform) { // TODO: this isn't quite right, it needs to move wrt the rotation target.move(translation); } if (rotation.asVec3().lengthSquared() > epsilonTransform) { target.rotate(rotation.conj()); } if (abs(distanceScaleVelocity - 1.0f) > epsilonTransform) { setDistance(getDistance() * (1.0f + distanceScaleVelocity), false); } mousePosScreenPrev = mousePosScreen; // targetFut.setPosition(target.getPosition()); } } if (fingers.size() == 2) { currentState = SCALING; if(zooming) { ofVec2f pointa = ofVec2f(fingers[0]->getX()*ofGetWidth(),fingers[0]->getY()*ofGetHeight()); ofVec2f pointb = ofVec2f(fingers[1]->getX()*ofGetWidth(),fingers[1]->getY()*ofGetHeight()); float newDistance = pointa.distance(pointb); float newDistanceScaleVelocity = 0.0f; if(prevDistance == 0) { prevDistance = newDistance; } else { newDistanceScaleVelocity = zoomSpeed * ( prevDistance - newDistance) / ofVec2f(0,0).distance(ofVec2f(ofGetHeight(),ofGetWidth())); distanceScaleVelocity = ofLerp(distanceScaleVelocity, newDistanceScaleVelocity, drag); if (abs(distanceScaleVelocity - 1.0f) > epsilonTransform) { setDistance(getDistance() * (1.0f + distanceScaleVelocity), false); } prevDistance = newDistance; } } } else { prevDistance = 0; } if (fingers.size() == 3) { currentState = POINTING; } if (fingers.size() == 5) { if(selectedPlane->axis == AxisPlane::NOAXIS) { currentState = PANNING; //DECIDE LATER } } if (fingers.size() == 10) { if(selectedPlane->axis == AxisPlane::NOAXIS) { currentState = RESET; addPanningTween(ofVec3f(0,0,0)); addRotationTween(0, 0, 0, 1); } } } } else { //MOUSE fingerPressedPrev[0] = false; // it's important to check whether we've already accounted for the mouse // just in case you use the camera multiple times in a single frame if (lastFrame != ofGetFrameNum()) { lastFrame = ofGetFrameNum(); if(selectedPlane->axis == AxisPlane::NOAXIS) { // if there is some smart way to use dt to scale the values drag, we should do it // you can't simply multiply drag etc because the behavior is unstable at high framerates // float dt = ofGetLastFrameTime(); currentState = STABLE; ofVec2f mousePosScreen = ofVec3f(ofGetMouseX() - viewport.width/2 - viewport.x, viewport.height/2 - (ofGetMouseY() - viewport.y), 0); ofVec2f mouseVelScreen = (mousePosScreen - mousePosScreenPrev).lengthSquared(); ofVec3f targetPos = target.getGlobalPosition(); ofVec3f mousePosXYZ = ofVec3f(mousePosScreen.x, mousePosScreen.y, targetPos.z); float sphereRadius = min(viewport.width, viewport.height)/2; float diffSquared = sphereRadius * sphereRadius - (targetPos - mousePosXYZ).lengthSquared(); if(diffSquared <= 0) { mousePosXYZ.z = 0; } else { mousePosXYZ.z = sqrtf(diffSquared); } mousePosXYZ.z += targetPos.z; ofVec3f mousePosView = ofMatrix4x4::getInverseOf(target.getGlobalTransformMatrix()) * mousePosXYZ; bool mousePressedCur[] = {ofGetMousePressed(0), ofGetMousePressed(2)}; //calc new rotation velocity ofQuaternion newRotation; if(mousePressedPrev[0] && mousePressedCur[0]) { newRotation.makeRotate(mousePosViewPrev, mousePosView); } //calc new scale velocity float newDistanceScaleVelocity = 0.0f; if(mousePressedPrev[1] && mousePressedCur[1]) { newDistanceScaleVelocity = zoomSpeed * (mousePosScreenPrev.y - mousePosScreen.y) / viewport.height; } mousePressedPrev[0] = mousePressedCur[0]; mousePressedPrev[1] = mousePressedCur[1]; ofVec3f newTranslation; // TODO: this doesn't work at all. why not? if(ofGetMousePressed() && ofGetKeyPressed(OF_KEY_SHIFT)) { newTranslation = mousePosScreenPrev - mousePosScreen; } //apply drag towards new velocities distanceScaleVelocity = ofLerp(distanceScaleVelocity, newDistanceScaleVelocity, drag); // TODO: add dt rotation.slerp(drag, rotation, newRotation); // TODO: add dt translation.interpolate(newTranslation, drag); mousePosViewPrev = ofMatrix4x4::getInverseOf(target.getGlobalTransformMatrix()) * mousePosXYZ; // apply transforms if they're big enough // TODO: these should be scaled by dt if(translation.lengthSquared() > epsilonTransform) { // TODO: this isn't quite right, it needs to move wrt the rotation target.move(translation); } if (rotation.asVec3().lengthSquared() > epsilonTransform) { target.rotate(rotation.conj()); } if (abs(distanceScaleVelocity - 1.0f) > epsilonTransform) { setDistance(getDistance() * (1.0f + distanceScaleVelocity), false); } mousePosScreenPrev = mousePosScreen; //targetFut.setPosition(target.getPosition()); } } } } setAnglesFromOrientation(); } ofCamera::begin(viewport); }