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; } get { value = orientation; } };
17 property Vector3D cPosition { get { value = cPosition; } };
18 property Quaternion cOrientation { get { value = cAngle; } };
19 property Degrees fov { set { fov = value; } get { return fov; } };
20 property float zMin { set { zMin = value; } get { return zMin; } };
21 property float zMax { set { zMax = value; } get { return zMax; } };
22 property Object target { set { target = value; } get { return target; } };
23 property FovDirection fovDirection { set { fovDirection = value; } get { return fovDirection; } };
24 property float aspectRatio { set { aspectRatio = value; } get { return aspectRatio; } };
25 property Size focal { get { value = { focalX, focalY }; } };
27 void Setup(int width, int height, Point origin)
31 Vector3D vector {0,0,1};
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 };
166 Euler eulerCamera = orientation, euler;
168 euler.Add(eulerCamera, this.target.eulerOrientation);
170 // Logf("yaw = %f, pitch = %f\n", eulerCamera.yaw, eulerCamera.pitch);
175 toAngle = orientation;
177 matrix.RotationQuaternion(toAngle);
178 newPosition.MultMatrix(position, matrix);
180 newPosition.Add(newPosition, target->position);
183 case attachedQuaternion:
185 toAngle = { 1,0,0,0 };
188 /*if(type == attached)
190 Euler eulerCamera = orientation, eulerTarget = target->orientation, euler;
192 euler.Add(eulerCamera, eulerTarget);
194 // Logf("yaw = %f, pitch = %f\n", eulerCamera.yaw, eulerCamera.pitch);
198 else if(type == attachedQuaternion)*/
199 toAngle.Multiply(orientation, target->orientation);
202 toAngle = orientation;
204 matrix.RotationQuaternion(toAngle);
205 newPosition.MultMatrix(position, matrix);
207 newPosition.Add(newPosition, target->position);
214 newPosition = position;
217 direction.Subtract(target->position, position);
218 toAngle.RotationDirection(direction);
222 Vector3D position { 0, 0, 0 };
223 direction.Subtract(position, this.position);
224 toAngle.RotationDirection(direction);
226 result.Multiply(orientation, toAngle);
232 Object cameraObject = this.cameraObject;
233 toAngle = cameraObject.transform.orientation;
234 if(cameraObject.flags.root || !cameraObject.parent)
235 newPosition = cameraObject.transform.position;
237 newPosition.MultMatrix(cameraObject.transform.position, cameraObject.parent.matrix);
242 if(cAngle.w != toAngle.w || cAngle.x != toAngle.x ||
243 cAngle.y != toAngle.y || cAngle.z != toAngle.z ||
246 cPosition = newPosition;
247 if(slerpAmount && slerpPosition < 1.0)
250 slerpPosition += slerpAmount;
251 slerpPosition = Min(slerpPosition, 1.0);
252 angle.Slerp(fromAngle, toAngle, slerpPosition);
256 AdjustAngle(toAngle);
259 this.needUpdate = false;
261 else if(newPosition.x != oldPosition.x || newPosition.y != oldPosition.y || newPosition.z != oldPosition.z)
263 AdjustPosition(newPosition);
270 bool SphereVisible(Vector3D center, float radius)
274 if(wLeftNormal.DotProduct(center) + wLeftD < -radius)
276 if(wRightNormal.DotProduct(center) + wRightD < -radius)
278 if(wTopNormal.DotProduct(center) + wTopD < -radius)
280 if(wBottomNormal.DotProduct(center) + wBottomD < -radius)
282 if(wNearNormal.DotProduct(center) + wNearD < -radius)
284 /-* if(wFarNormal.DotProduct(center) + wFarD < -radius)
290 bool PointsVisible(Vector3D * points, int numPoints, double threshold)
294 for(p = 0; p<=ClippingPlane::bottom; p+=2)
296 bool out1a = true, out2a = true;
297 bool out1b = true, out2b = true;
298 Plane * plane = &worldClippingPlanes[p];
299 for(c = 0; c<numPoints; c++)
302 plane->a * points[c].x +
303 plane->b * points[c].y +
304 plane->c * points[c].z;
305 if(dot + plane->d > 0)
307 out1a = out1b = false;
310 else if(dot + plane->d > -threshold)
314 plane = &worldClippingPlanes[p+1];
315 for(c = 0; c<numPoints; c++)
318 plane->a * points[c].x +
319 plane->b * points[c].y +
320 plane->c * points[c].z;
321 if(dot + plane->d > 0)
323 out2a = out2b = false;
326 else if(dot + plane->d > -threshold)
330 if((out1a && !out2b) || (out2a && !out1b))
337 bool PointsVisible(Vector3D * origPoints, int numPoints, double threshold)
339 Plane * planes = worldClippingPlanes;
340 static byte goodPoints[50];
341 static Vector3D points[50];
342 static Vector3D newPoints[50];
343 bool outside = false;
349 for(c = 0; c<numPoints; c++)
350 points[c] = origPoints[c];
352 for(p = 0; p < 6; p++)
354 Plane * plane = &planes[p];
356 int numGoodPoints = 0;
358 memset(goodPoints, 0, n);
359 for(i = 0; i < n; i++)
361 double dot = plane->normal.DotProduct(points[i]);
362 double distance = dot + plane->d;
363 if(distance > -threshold)
375 if(numGoodPoints < n)
386 newPoints[newN++] = points[j];
395 for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
397 edge.p0 = points[lastGood];
398 edge.delta.Subtract(points[j], edge.p0);
399 plane->IntersectLine(edge, newPoints[newN++]);
401 for(next = j+1; next != j; next++)
403 if(next == n) next = 0;
407 if(prev < 0) prev = n-1;
409 edge.p0 = points[prev];
410 edge.delta.Subtract(points[next], edge.p0);
411 plane->IntersectLine(edge, newPoints[newN++]);
421 // Use the new points
422 memcpy(points, newPoints, newN * sizeof(Vector3D));
430 void TransformPoint(Vector3D dest, Vector3D src)
432 Vector3D vector { src.x - cPosition.x, src.y - cPosition.y, src.z - cPosition.z };
433 dest.MultMatrix(vector, viewMatrix);
436 void TransformNormal(Vector3D dest, Vector3D src)
438 dest.MultMatrix(src, viewMatrix);
441 void TransformMatrix(Matrix dest, Matrix src)
444 matrix.m[3][0] -= cPosition.x;
445 matrix.m[3][1] -= cPosition.y;
446 matrix.m[3][2] -= cPosition.z;
447 dest.Multiply(matrix, viewMatrix);
450 void RotatePitch(Degrees amount, Degrees min, Degrees max)
452 if(type == fixedQuaternion)
454 orientation.RotatePitch(amount);
458 Euler euler = orientation;
459 euler.pitch += amount;
462 euler.pitch = Min(euler.pitch, max);
463 euler.pitch = Max(euler.pitch, min);
469 void RotateYaw(Degrees amount, Degrees min, Degrees max)
471 if(type == fixedQuaternion)
473 orientation.RotateYaw(amount);
477 Euler euler = orientation;
481 euler.yaw = Min(euler.yaw, max);
482 euler.yaw = Max(euler.yaw, min);
488 void RotateRoll(Degrees amount, Degrees min, Degrees max)
490 if(type == fixedQuaternion)
492 orientation.RotateRoll(amount);
496 Euler euler = orientation;
497 euler.roll += amount;
500 euler.roll = Min(euler.roll, max);
501 euler.roll = Max(euler.roll, min);
507 void Slerp(float amount)
510 slerpAmount = amount;
514 void Move(Vector3D direction)
523 matrix.RotationQuaternion(orientation);
524 offset.MultMatrix(direction, matrix);
525 position.Add(position, offset);
528 case attachedQuaternion:
532 position.Add(position, direction);
538 bool Project(Vector3D vector, Vector3D point)
543 point.x = (vector.x*focalX/vector.z);
544 point.y = (vector.y*focalY/vector.z);
545 point.z = (((zMax * zMin / -vector.z) + zMax) / (zMax - zMin));
546 floatZ = ((((float)zMax * (float)zMin / -(float)vector.z) + (float)zMax) / ((float)zMax - (float)zMin));
549 return (point.x >= 0 && point.y >= 0 &&
550 point.x < width && point.y < height);
555 void Unproject(Vector3D point, Vector3D vector)
557 vector.z = (zMax * zMin / (zMax - (double)point.z * (zMax-zMin)));
558 vector.y = ((point.y - origin.y) * (double)vector.z / focalY);
559 vector.x = ((point.x - origin.x) * (double)vector.z / focalX);
562 bool ProjectSize(Vector3D vector, Point point)
566 point.x = (int)((double)vector.x*(double)focalX/(double)vector.z);
567 point.y = (int)((double)vector.y*(double)focalY/(double)vector.z);
573 void Untransform(Vector3D src, Vector3D result)
575 result.MultMatrix(src, inverseMatrix);
576 result.x += cPosition.x;
577 result.y += cPosition.y;
578 result.z += cPosition.z;
594 FovDirection fovDirection;
598 Quaternion orientation;
606 Angle fovLeft, fovRight, fovTop, fovBottom;
607 float focalX, focalY;
610 float slerpAmount, slerpPosition;
611 Plane viewClippingPlanes[ClippingPlane], worldClippingPlanes[ClippingPlane];
612 Matrix inverseTranspose, inverseMatrix;
613 Quaternion fromAngle, toAngle;