var Arcball, Mat4, Plane, Quat, Vec2, Vec3, Vec4, _ref;
_ref = require('pex-geom'), Vec2 = _ref.Vec2, Vec3 = _ref.Vec3, Vec4 = _ref.Vec4, Quat = _ref.Quat, Mat4 = _ref.Mat4, Plane = _ref.Plane;
Arcball = (function() {
function Arcball(window, camera, distance) {
this.camera = camera;
this.window = window;
this.radius = Math.min(window.width / 2, window.height / 2) * 2;
this.center = Vec2.create(window.width / 2, window.height / 2);
this.currRot = Quat.create();
this.currRot.setAxisAngle(Vec3.create(0, 1, 0), 0);
this.clickRot = Quat.create();
this.dragRot = Quat.create();
this.clickPos = Vec3.create();
this.clickPosWindow = Vec2.create();
this.dragPos = Vec3.create();
this.dragPosWindow = Vec2.create();
this.rotAxis = Vec3.create();
this.allowZooming = true;
this.enabled = true;
this.clickTarget = Vec3.create(0, 0, 0);
this.setDistance(distance || 2);
this.updateCamera();
this.addEventHanlders();
}
Arcball.prototype.setTarget = function(target) {
this.camera.setTarget(target);
return this.updateCamera();
};
Arcball.prototype.setOrientation = function(dir) {
this.currRot.setDirection(dir);
this.currRot.w *= -1;
this.updateCamera();
return this;
};
Arcball.prototype.setPosition = function(pos) {
var dir;
dir = Vec3.create().asSub(pos, this.camera.getTarget());
this.setOrientation(dir.dup().normalize());
this.setDistance(dir.length());
return this.updateCamera();
};
Arcball.prototype.addEventHanlders = function() {
this.window.on('leftMouseDown', (function(_this) {
return function(e) {
if (e.handled || !_this.enabled) {
return;
}
return _this.down(e.x, e.y, e.shift);
};
})(this));
this.window.on('leftMouseUp', (function(_this) {
return function(e) {
return _this.up(e.x, e.y, e.shift);
};
})(this));
this.window.on('mouseDragged', (function(_this) {
return function(e) {
if (e.handled || !_this.enabled) {
return;
}
return _this.drag(e.x, e.y, e.shift);
};
})(this));
return this.window.on('scrollWheel', (function(_this) {
return function(e) {
if (e.handled || !_this.enabled) {
return;
}
if (!_this.allowZooming) {
return;
}
_this.distance = Math.min(_this.maxDistance, Math.max(_this.distance + e.dy / 100 * (_this.maxDistance - _this.minDistance), _this.minDistance));
return _this.updateCamera();
};
})(this));
};
Arcball.prototype.mouseToSphere = function(x, y) {
var dist, v;
y = this.window.height - y;
v = Vec3.create((x - this.center.x) / this.radius, (y - this.center.y) / this.radius, 0);
dist = v.x * v.x + v.y * v.y;
if (dist > 1) {
v.normalize();
} else {
v.z = Math.sqrt(1.0 - dist);
}
return v;
};
Arcball.prototype.down = function(x, y, shift) {
var target, targetInViewSpace;
this.dragging = true;
this.clickPos = this.mouseToSphere(x, y);
this.clickRot.copy(this.currRot);
this.updateCamera();
if (shift) {
this.clickPosWindow.set(x, y);
target = this.camera.getTarget();
this.clickTarget = target.dup();
targetInViewSpace = target.dup().transformMat4(this.camera.getViewMatrix());
this.panPlane = new Plane(targetInViewSpace, new Vec3(0, 0, 1));
this.clickPosPlane = this.panPlane.intersectRay(this.camera.getViewRay(this.clickPosWindow.x, this.clickPosWindow.y, this.window.width, this.window.height));
return this.dragPosPlane = this.panPlane.intersectRay(this.camera.getViewRay(this.dragPosWindow.x, this.dragPosWindow.y, this.window.width, this.window.height));
} else {
return this.panPlane = null;
}
};
Arcball.prototype.up = function(x, y, shift) {
this.dragging = false;
return this.panPlane = null;
};
Arcball.prototype.drag = function(x, y, shift) {
var invViewMatrix, theta;
if (!this.dragging) {
return;
}
if (shift && this.panPlane) {
this.dragPosWindow.set(x, y);
this.clickPosPlane = this.panPlane.intersectRay(this.camera.getViewRay(this.clickPosWindow.x, this.clickPosWindow.y, this.window.width, this.window.height));
this.dragPosPlane = this.panPlane.intersectRay(this.camera.getViewRay(this.dragPosWindow.x, this.dragPosWindow.y, this.window.width, this.window.height));
invViewMatrix = this.camera.getViewMatrix().dup().invert();
this.clickPosWorld = this.clickPosPlane.dup().transformMat4(invViewMatrix);
this.dragPosWorld = this.dragPosPlane.dup().transformMat4(invViewMatrix);
this.diffWorld = this.dragPosWorld.dup().sub(this.clickPosWorld);
this.camera.setTarget(this.clickTarget.dup().sub(this.diffWorld));
this.updateCamera();
} else {
this.dragPos = this.mouseToSphere(x, y);
this.rotAxis.asCross(this.clickPos, this.dragPos);
theta = this.clickPos.dot(this.dragPos);
this.dragRot.set(this.rotAxis.x, this.rotAxis.y, this.rotAxis.z, theta);
this.currRot.asMul(this.dragRot, this.clickRot);
}
return this.updateCamera();
};
Arcball.prototype.updateCamera = function() {
var eye, offset, q, target, up;
q = this.currRot.clone();
q.w *= -1;
target = this.camera.getTarget();
offset = Vec3.create(0, 0, this.distance).transformQuat(q);
eye = Vec3.create().asAdd(target, offset);
up = Vec3.create(0, 1, 0).transformQuat(q);
return this.camera.lookAt(target, eye, up);
};
Arcball.prototype.disableZoom = function() {
return this.allowZooming = false;
};
Arcball.prototype.setDistance = function(distance) {
this.distance = distance || 2;
this.minDistance = distance / 2 || 0.3;
this.maxDistance = distance * 2 || 5;
return this.updateCamera();
};
return Arcball;
})();
module.exports = Arcball;