5 public enum CameraType { fixed, fixedQuaternion, attached, attachedQuaternion, lookAt, lookAtObject };
6 public enum FovDirection { widest, horizontal, vertical };
8 public enum ClippingPlane { left, right, top, bottom, near, far };
13 // Change type to inherited types...
14 property CameraType type { set { type = value; } get { return type; } };
15 property Vector3D position { set { position = value; } get { value = position; } };
16 property Quaternion orientation { set { orientation = value; if(type == attached || type == fixed) eulerOrientation = value; } get { value = orientation; } };
17 property Euler eulerOrientation { set { eulerOrientation = value; if(type != attached && type != fixed) orientation = value; } get { value = eulerOrientation; } };
18 property Vector3D cPosition { get { value = cPosition; } };
19 property Quaternion cOrientation { get { value = cAngle; } };
20 property Degrees fov { set { fov = value; } get { return fov; } };
21 property float zMin { set { zMin = value; } get { return zMin; } };
22 property float zMax { set { zMax = value; } get { return zMax; } };
23 property Object target { set { target = value; } get { return target; } };
24 property FovDirection fovDirection { set { fovDirection = value; } get { return fovDirection; } };
25 property float aspectRatio { set { aspectRatio = value; } get { return aspectRatio; } };
26 property Size focal { get { value = { focalX, focalY }; } };
28 void Setup(int width, int height, Point origin)
34 float aspectRatio = this.aspectRatio;
38 aspectRatio = (float)width/height;
46 this.origin.x = width/2;
47 this.origin.y = height/2;
50 l = this.origin.x - 0;
51 r = this.origin.x - width;
52 t = 0 - this.origin.y;
53 b = height - this.origin.y;
55 if(fovDirection == horizontal || (fovDirection == widest && width * aspectRatio > height))
57 focalX = (float)((width / 2) / tan(fov/2));
58 focalY = focalX * height / width;
59 focalY *= aspectRatio;
64 focalY = (float)((height / 2) / tan(fov/2));
65 focalX = focalY * width / height;
66 focalX /= aspectRatio;
70 fovX = atan((width / 2) / focalX) * 2;
71 fovY = atan((height / 2) / focalY) * 2;
73 fovLeft = atan(l / focalX);
74 fovRight = atan(r / focalX);
75 fovTop = atan(t / focalY);
76 fovBottom = atan(b / focalY);
78 // Compute Clipping Planes
80 Vector3D normal, point = {0,0,0};
83 quat.Yaw(fovLeft - Pi/2);
84 quat.ToDirection(normal);
85 viewClippingPlanes[left].FromPointNormal(normal, point);
88 quat.Yaw(fovRight + Pi/2);
89 quat.ToDirection(normal);
90 viewClippingPlanes[right].FromPointNormal(normal, point);
93 quat.Pitch(fovTop + Pi/2);
94 quat.ToDirection(normal);
95 viewClippingPlanes[top].FromPointNormal(normal, point);
98 quat.Pitch(fovBottom - Pi/2);
99 quat.ToDirection(normal);
100 viewClippingPlanes[bottom].FromPointNormal(normal, point);
103 normal.x = 0; normal.y = 0; normal.z = 1;
105 viewClippingPlanes[near].FromPointNormal(normal, point);
108 normal.x = 0; normal.y = 0; normal.z = -1;
110 viewClippingPlanes[far].FromPointNormal(normal, point);
117 void AdjustPosition(Vector3D position)
120 Matrix transpose = viewMatrix;
122 cPosition = position;
124 transpose.m[0][3] = cPosition.x;
125 transpose.m[1][3] = cPosition.y;
126 transpose.m[2][3] = cPosition.z;
127 inverseTranspose.Inverse(transpose);
129 for(c = 0; c<ClippingPlane::enumSize; c++)
130 worldClippingPlanes[c].MultMatrix(viewClippingPlanes[c], inverseTranspose);
133 void AdjustAngle(Quaternion angle)
137 inverseMatrix.RotationQuaternion(angle);
138 viewMatrix.Transpose(inverseMatrix);
140 AdjustPosition(cPosition);
149 Transform * target = this.target ? &this.target.transform : null;
150 Vector3D oldPosition = cPosition, newPosition;
155 case fixedQuaternion:
157 newPosition = position;
158 toAngle = orientation;
163 toAngle = { 1,0,0,0 };
167 Euler eulerTarget = this.target.eulerOrientation;
169 euler.Add(eulerOrientation, eulerTarget);
171 // Logf("yaw = %f, pitch = %f\n", eulerCamera.yaw, eulerCamera.pitch);
176 toAngle = orientation;
178 matrix.RotationQuaternion(toAngle);
179 newPosition.MultMatrix(position, matrix);
181 newPosition.Add(newPosition, target->position);
184 case attachedQuaternion:
186 toAngle = { 1,0,0,0 };
189 /*if(type == attached)
191 Euler eulerCamera = orientation, eulerTarget = target->orientation, euler;
193 euler.Add(eulerCamera, eulerTarget);
195 // Logf("yaw = %f, pitch = %f\n", eulerCamera.yaw, eulerCamera.pitch);
199 else if(type == attachedQuaternion)*/
200 toAngle.Multiply(orientation, target->orientation);
203 toAngle = orientation;
205 matrix.RotationQuaternion(toAngle);
206 newPosition.MultMatrix(position, matrix);
208 newPosition.Add(newPosition, target->position);
215 newPosition = position;
218 direction.Subtract(target->position, position);
219 toAngle.RotationDirection(direction);
223 Vector3D position { 0, 0, 0 };
224 direction.Subtract(position, this.position);
225 toAngle.RotationDirection(direction);
227 result.Multiply(orientation, toAngle);
233 Object cameraObject = this.cameraObject;
234 toAngle = cameraObject.transform.orientation;
235 if(cameraObject.flags.root || !cameraObject.parent)
236 newPosition = cameraObject.transform.position;
238 newPosition.MultMatrix(cameraObject.transform.position, cameraObject.parent.matrix);
243 if(cAngle.w != toAngle.w || cAngle.x != toAngle.x ||
244 cAngle.y != toAngle.y || cAngle.z != toAngle.z ||
247 cPosition = newPosition;
248 if(slerpAmount && slerpPosition < 1.0)
251 slerpPosition += slerpAmount;
252 slerpPosition = Min(slerpPosition, 1.0);
253 angle.Slerp(fromAngle, toAngle, slerpPosition);
257 AdjustAngle(toAngle);
260 this.needUpdate = false;
262 else if(newPosition.x != oldPosition.x || newPosition.y != oldPosition.y || newPosition.z != oldPosition.z)
264 AdjustPosition(newPosition);
271 bool SphereVisible(Vector3D center, float radius)
275 if(wLeftNormal.DotProduct(center) + wLeftD < -radius)
277 if(wRightNormal.DotProduct(center) + wRightD < -radius)
279 if(wTopNormal.DotProduct(center) + wTopD < -radius)
281 if(wBottomNormal.DotProduct(center) + wBottomD < -radius)
283 if(wNearNormal.DotProduct(center) + wNearD < -radius)
285 /-* if(wFarNormal.DotProduct(center) + wFarD < -radius)
291 bool PointsVisible(Vector3D * points, int numPoints, double threshold)
295 for(p = 0; p<=ClippingPlane::bottom; p+=2)
297 bool out1a = true, out2a = true;
298 bool out1b = true, out2b = true;
299 Plane * plane = &worldClippingPlanes[p];
300 for(c = 0; c<numPoints; c++)
303 plane->a * points[c].x +
304 plane->b * points[c].y +
305 plane->c * points[c].z;
306 if(dot + plane->d > 0)
308 out1a = out1b = false;
311 else if(dot + plane->d > -threshold)
315 plane = &worldClippingPlanes[p+1];
316 for(c = 0; c<numPoints; c++)
319 plane->a * points[c].x +
320 plane->b * points[c].y +
321 plane->c * points[c].z;
322 if(dot + plane->d > 0)
324 out2a = out2b = false;
327 else if(dot + plane->d > -threshold)
331 if((out1a && !out2b) || (out2a && !out1b))
338 bool PointsVisible(Vector3D * origPoints, int numPoints, double threshold)
340 Plane * planes = worldClippingPlanes;
341 static byte goodPoints[50];
342 static Vector3D points[50];
343 static Vector3D newPoints[50];
344 bool outside = false;
350 for(c = 0; c<numPoints; c++)
351 points[c] = origPoints[c];
353 for(p = 0; p < 6; p++)
355 Plane * plane = &planes[p];
357 int numGoodPoints = 0;
359 memset(goodPoints, 0, n);
360 for(i = 0; i < n; i++)
362 double dot = plane->normal.DotProduct(points[i]);
363 double distance = dot + plane->d;
364 if(distance > -threshold)
376 if(numGoodPoints < n)
387 newPoints[newN++] = points[j];
396 for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
398 edge.p0 = points[lastGood];
399 edge.delta.Subtract(points[j], edge.p0);
400 plane->IntersectLine(edge, newPoints[newN++]);
402 for(next = j+1; next != j; next++)
404 if(next == n) next = 0;
408 if(prev < 0) prev = n-1;
410 edge.p0 = points[prev];
411 edge.delta.Subtract(points[next], edge.p0);
412 plane->IntersectLine(edge, newPoints[newN++]);
422 // Use the new points
423 memcpy(points, newPoints, newN * sizeof(Vector3D));
431 void TransformPoint(Vector3D dest, Vector3D src)
433 Vector3D vector { src.x - cPosition.x, src.y - cPosition.y, src.z - cPosition.z };
434 dest.MultMatrix(vector, viewMatrix);
437 void TransformNormal(Vector3D dest, Vector3D src)
439 dest.MultMatrix(src, viewMatrix);
442 void TransformMatrix(Matrix dest, Matrix src)
445 matrix.m[3][0] -= cPosition.x;
446 matrix.m[3][1] -= cPosition.y;
447 matrix.m[3][2] -= cPosition.z;
448 dest.Multiply(matrix, viewMatrix);
451 void RotatePitch(Degrees amount, Degrees min, Degrees max)
453 if(type == fixedQuaternion)
455 orientation.RotatePitch(amount);
459 Euler euler = eulerOrientation;
460 euler.pitch += amount;
463 euler.pitch = Min(euler.pitch, max);
464 euler.pitch = Max(euler.pitch, min);
466 eulerOrientation = euler;
471 void RotateYaw(Degrees amount, Degrees min, Degrees max)
473 if(type == fixedQuaternion)
475 orientation.RotateYaw(amount);
479 Euler euler = eulerOrientation;
483 euler.yaw = Min(euler.yaw, max);
484 euler.yaw = Max(euler.yaw, min);
486 eulerOrientation = euler;
491 void RotateRoll(Degrees amount, Degrees min, Degrees max)
493 if(type == fixedQuaternion)
495 orientation.RotateRoll(amount);
499 Euler euler = eulerOrientation;
500 euler.roll += amount;
503 euler.roll = Min(euler.roll, max);
504 euler.roll = Max(euler.roll, min);
506 eulerOrientation = euler;
511 void Slerp(float amount)
514 slerpAmount = amount;
518 void Move(Vector3D direction)
527 matrix.RotationQuaternion(orientation);
528 offset.MultMatrix(direction, matrix);
529 position.Add(position, offset);
532 case attachedQuaternion:
536 position.Add(position, direction);
542 bool Project(Vector3D vector, Vector3D point)
547 point.x = (vector.x*focalX/vector.z);
548 point.y = (vector.y*focalY/vector.z);
549 point.z = (((zMax * zMin / -vector.z) + zMax) / (zMax - zMin));
550 //floatZ = ((((float)zMax * (float)zMin / -(float)vector.z) + (float)zMax) / ((float)zMax - (float)zMin));
553 return (point.x >= 0 && point.y >= 0 &&
554 point.x < width && point.y < height);
559 void Unproject(Vector3D point, Vector3D vector)
561 vector.z = (zMax * zMin / (zMax - (double)point.z * (zMax-zMin)));
562 vector.y = ((point.y - origin.y) * (double)vector.z / focalY);
563 vector.x = ((point.x - origin.x) * (double)vector.z / focalX);
566 bool ProjectSize(Vector3D vector, Point point)
570 point.x = (int)((double)vector.x*(double)focalX/(double)vector.z);
571 point.y = (int)((double)vector.y*(double)focalY/(double)vector.z);
577 void Untransform(Vector3D src, Vector3D result)
579 result.MultMatrix(src, inverseMatrix);
580 result.x += cPosition.x;
581 result.y += cPosition.y;
582 result.z += cPosition.z;
585 public void setViewMatrix(Matrix value)
590 public void setCPosition(Vector3D value)
608 FovDirection fovDirection;
611 public Vector3D position;
612 Quaternion orientation;
613 Euler eulerOrientation;
621 Angle fovLeft, fovRight, fovTop, fovBottom;
622 float focalX, focalY;
625 float slerpAmount, slerpPosition;
626 Matrix inverseTranspose, inverseMatrix;
627 Quaternion fromAngle, toAngle;
632 Plane viewClippingPlanes[ClippingPlane], worldClippingPlanes[ClippingPlane];