blob: b39dae3a195d9b0e6f16e350260a9a3c867ee390 [file] [log] [blame]
class Camera {
// camera's field of view
float fov;
// camera's position, look at point and axis
PVector pos, center, axis;
PVector init_pos, init_center, init_axis;
float move_speed;
float rot_speed;
Camera(float fov, PVector pos, PVector center, PVector axis) {
this.fov = fov;
this.pos = pos;
this.center = center;
this.axis = axis;
this.axis.normalize();
move_speed = 0.001;
rot_speed = 0.01 * PI;
init_pos = pos.copy();
init_center = center.copy();
init_axis = axis.copy();
}
Camera copy() {
Camera cam = new Camera(fov, pos.copy(), center.copy(), axis.copy());
return cam;
}
PVector project(PVector pos) {
PVector proj = MatxVec3(getCameraMat(), PVector.sub(pos, this.pos));
proj.x = (float)height / 2.0 * proj.x / proj.z / tan(fov / 2.0f);
proj.y = (float)height / 2.0 * proj.y / proj.z / tan(fov / 2.0f);
proj.z = proj.z;
return proj;
}
float[] getCameraMat() {
float[] mat = new float[9];
PVector dir = PVector.sub(center, pos);
dir.normalize();
PVector left = dir.cross(axis);
left.normalize();
// processing camera system does not follow right hand rule
mat[0] = -left.x;
mat[1] = -left.y;
mat[2] = -left.z;
mat[3] = axis.x;
mat[4] = axis.y;
mat[5] = axis.z;
mat[6] = dir.x;
mat[7] = dir.y;
mat[8] = dir.z;
return mat;
}
void run() {
PVector dir, left;
if (mousePressed) {
float angleX = (float)mouseX / width * PI - PI / 2;
float angleY = (float)mouseY / height * PI - PI;
PVector diff = PVector.sub(center, pos);
float radius = diff.mag();
pos.x = radius * sin(angleY) * sin(angleX) + center.x;
pos.y = radius * cos(angleY) + center.y;
pos.z = radius * sin(angleY) * cos(angleX) + center.z;
dir = PVector.sub(center, pos);
dir.normalize();
PVector up = new PVector(0, 1, 0);
left = up.cross(dir);
left.normalize();
axis = dir.cross(left);
axis.normalize();
}
if (keyPressed) {
switch (key) {
case 'w':
dir = PVector.sub(center, pos);
dir.normalize();
pos = PVector.add(pos, PVector.mult(dir, move_speed));
center = PVector.add(center, PVector.mult(dir, move_speed));
break;
case 's':
dir = PVector.sub(center, pos);
dir.normalize();
pos = PVector.sub(pos, PVector.mult(dir, move_speed));
center = PVector.sub(center, PVector.mult(dir, move_speed));
break;
case 'a':
dir = PVector.sub(center, pos);
dir.normalize();
left = axis.cross(dir);
left.normalize();
pos = PVector.add(pos, PVector.mult(left, move_speed));
center = PVector.add(center, PVector.mult(left, move_speed));
break;
case 'd':
dir = PVector.sub(center, pos);
dir.normalize();
left = axis.cross(dir);
left.normalize();
pos = PVector.sub(pos, PVector.mult(left, move_speed));
center = PVector.sub(center, PVector.mult(left, move_speed));
break;
case 'r':
dir = PVector.sub(center, pos);
dir.normalize();
float[] mat = getRotationMat3x3(rot_speed, dir.x, dir.y, dir.z);
axis = MatxVec3(mat, axis);
axis.normalize();
break;
case 'b':
pos = init_pos.copy();
center = init_center.copy();
axis = init_axis.copy();
break;
case '+': move_speed *= 2.0f; break;
case '-': move_speed /= 2.0; break;
case CODED:
if (keyCode == UP) {
pos = PVector.add(pos, PVector.mult(axis, move_speed));
center = PVector.add(center, PVector.mult(axis, move_speed));
} else if (keyCode == DOWN) {
pos = PVector.sub(pos, PVector.mult(axis, move_speed));
center = PVector.sub(center, PVector.mult(axis, move_speed));
}
}
}
}
void open() {
perspective(fov, float(width) / height, 1e-6, 1e5);
camera(pos.x, pos.y, pos.z, center.x, center.y, center.z, axis.x, axis.y,
axis.z);
}
void close() {
ortho(-width, 0, -height, 0);
camera(0, 0, 0, 0, 0, 1, 0, 1, 0);
}
}