PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/ecere/src/gfx/3D/Camera.ec

https://github.com/thexa4/sdk
C | 618 lines | 431 code | 59 blank | 128 comment | 65 complexity | c2c247d2eb7a14de38baf89528a02844 MD5 | raw file
  1. namespace gfx3D;
  2. import "Display"
  3. public enum CameraType { fixed, fixedQuaternion, attached, attachedQuaternion, lookAt, lookAtObject };
  4. public enum FovDirection { widest, horizontal, vertical };
  5. public enum ClippingPlane { left, right, top, bottom, near, far };
  6. public class Camera
  7. {
  8. public:
  9. // Change type to inherited types...
  10. property CameraType type { set { type = value; } get { return type; } };
  11. property Vector3D position { set { position = value; } get { value = position; } };
  12. property Quaternion orientation { set { orientation = value; } get { value = orientation; } };
  13. property Vector3D cPosition { get { value = cPosition; } };
  14. property Quaternion cOrientation { get { value = cAngle; } };
  15. property Degrees fov { set { fov = value; } get { return fov; } };
  16. property float zMin { set { zMin = value; } get { return zMin; } };
  17. property float zMax { set { zMax = value; } get { return zMax; } };
  18. property Object target { set { target = value; } get { return target; } };
  19. property FovDirection fovDirection { set { fovDirection = value; } get { return fovDirection; } };
  20. property float aspectRatio { set { aspectRatio = value; } get { return aspectRatio; } };
  21. property Size focal { get { value = { focalX, focalY }; } };
  22. void Setup(int width, int height, Point origin)
  23. {
  24. if(this)
  25. {
  26. Vector3D vector {0,0,1};
  27. Quaternion quat;
  28. float aspectRatio = this.aspectRatio;
  29. float l, r, t, b;
  30. if(!aspectRatio)
  31. aspectRatio = (float)width/height;
  32. this.width = width;
  33. this.height = height;
  34. if(origin != null)
  35. this.origin = origin;
  36. else
  37. {
  38. this.origin.x = width/2;
  39. this.origin.y = height/2;
  40. }
  41. l = this.origin.x - 0;
  42. r = this.origin.x - width;
  43. t = 0 - this.origin.y;
  44. b = height - this.origin.y;
  45. if(fovDirection == horizontal || (fovDirection == widest && width * aspectRatio > height))
  46. {
  47. focalX = (float)((width / 2) / tan(fov/2));
  48. focalY = focalX * height / width;
  49. focalY *= aspectRatio;
  50. fovX = fov;
  51. }
  52. else
  53. {
  54. focalY = (float)((height / 2) / tan(fov/2));
  55. focalX = focalY * width / height;
  56. focalX /= aspectRatio;
  57. fovY = fov;
  58. }
  59. fovX = atan((width / 2) / focalX) * 2;
  60. fovY = atan((height / 2) / focalY) * 2;
  61. fovLeft = atan(l / focalX);
  62. fovRight = atan(r / focalX);
  63. fovTop = atan(t / focalY);
  64. fovBottom = atan(b / focalY);
  65. // Compute Clipping Planes
  66. {
  67. Vector3D normal, point = {0,0,0};
  68. // --- Left ---
  69. quat.Yaw(fovLeft - Pi/2);
  70. quat.ToDirection(normal);
  71. viewClippingPlanes[left].FromPointNormal(normal, point);
  72. // --- Right ---
  73. quat.Yaw(fovRight + Pi/2);
  74. quat.ToDirection(normal);
  75. viewClippingPlanes[right].FromPointNormal(normal, point);
  76. // --- Top ---
  77. quat.Pitch(fovTop + Pi/2);
  78. quat.ToDirection(normal);
  79. viewClippingPlanes[top].FromPointNormal(normal, point);
  80. // --- Bottom ---
  81. quat.Pitch(fovBottom - Pi/2);
  82. quat.ToDirection(normal);
  83. viewClippingPlanes[bottom].FromPointNormal(normal, point);
  84. // --- Near ---
  85. normal.x = 0; normal.y = 0; normal.z = 1;
  86. point.z = zMin;
  87. viewClippingPlanes[near].FromPointNormal(normal, point);
  88. // --- Far ---
  89. normal.x = 0; normal.y = 0; normal.z = -1;
  90. point.z = zMax;
  91. viewClippingPlanes[far].FromPointNormal(normal, point);
  92. }
  93. needUpdate = true;
  94. }
  95. }
  96. void AdjustPosition(Vector3D position)
  97. {
  98. ClippingPlane c;
  99. Matrix transpose = viewMatrix;
  100. cPosition = position;
  101. transpose.m[0][3] = cPosition.x;
  102. transpose.m[1][3] = cPosition.y;
  103. transpose.m[2][3] = cPosition.z;
  104. inverseTranspose.Inverse(transpose);
  105. for(c = 0; c<ClippingPlane::enumSize; c++)
  106. worldClippingPlanes[c].MultMatrix(viewClippingPlanes[c], inverseTranspose);
  107. }
  108. void AdjustAngle(Quaternion angle)
  109. {
  110. cAngle = angle;
  111. inverseMatrix.RotationQuaternion(angle);
  112. viewMatrix.Transpose(inverseMatrix);
  113. AdjustPosition(cPosition);
  114. }
  115. bool Update()
  116. {
  117. bool result = false;
  118. if(this)
  119. {
  120. Matrix matrix;
  121. Transform * target = this.target ? &this.target.transform : null;
  122. Vector3D oldPosition = cPosition, newPosition;
  123. switch(this.type)
  124. {
  125. case fixed:
  126. case fixedQuaternion:
  127. {
  128. newPosition = position;
  129. toAngle = orientation;
  130. break;
  131. }
  132. case attached:
  133. {
  134. toAngle = { 1,0,0,0 };
  135. if(target)
  136. {
  137. Euler eulerCamera = orientation, euler;
  138. euler.Add(eulerCamera, this.target.eulerOrientation);
  139. // Logf("yaw = %f, pitch = %f\n", eulerCamera.yaw, eulerCamera.pitch);
  140. toAngle = euler;
  141. }
  142. else
  143. toAngle = orientation;
  144. matrix.RotationQuaternion(toAngle);
  145. newPosition.MultMatrix(position, matrix);
  146. if(target)
  147. newPosition.Add(newPosition, target->position);
  148. break;
  149. }
  150. case attachedQuaternion:
  151. {
  152. toAngle = { 1,0,0,0 };
  153. if(target)
  154. {
  155. /*if(type == attached)
  156. {
  157. Euler eulerCamera = orientation, eulerTarget = target->orientation, euler;
  158. euler.Add(eulerCamera, eulerTarget);
  159. // Logf("yaw = %f, pitch = %f\n", eulerCamera.yaw, eulerCamera.pitch);
  160. toAngle = euler;
  161. }
  162. else if(type == attachedQuaternion)*/
  163. toAngle.Multiply(orientation, target->orientation);
  164. }
  165. else
  166. toAngle = orientation;
  167. matrix.RotationQuaternion(toAngle);
  168. newPosition.MultMatrix(position, matrix);
  169. if(target)
  170. newPosition.Add(newPosition, target->position);
  171. break;
  172. }
  173. case lookAt:
  174. {
  175. Quaternion result;
  176. Vector3D direction;
  177. newPosition = position;
  178. if(target)
  179. {
  180. direction.Subtract(target->position, position);
  181. toAngle.RotationDirection(direction);
  182. }
  183. else
  184. {
  185. Vector3D position { 0, 0, 0 };
  186. direction.Subtract(position, this.position);
  187. toAngle.RotationDirection(direction);
  188. }
  189. result.Multiply(orientation, toAngle);
  190. toAngle = result;
  191. break;
  192. }
  193. case lookAtObject:
  194. {
  195. Object cameraObject = this.cameraObject;
  196. toAngle = cameraObject.transform.orientation;
  197. if(cameraObject.flags.root || !cameraObject.parent)
  198. newPosition = cameraObject.transform.position;
  199. else
  200. newPosition.MultMatrix(cameraObject.transform.position, cameraObject.parent.matrix);
  201. break;
  202. }
  203. }
  204. if(cAngle.w != toAngle.w || cAngle.x != toAngle.x ||
  205. cAngle.y != toAngle.y || cAngle.z != toAngle.z ||
  206. needUpdate)
  207. {
  208. cPosition = newPosition;
  209. if(slerpAmount && slerpPosition < 1.0)
  210. {
  211. Quaternion angle;
  212. slerpPosition += slerpAmount;
  213. slerpPosition = Min(slerpPosition, 1.0);
  214. angle.Slerp(fromAngle, toAngle, slerpPosition);
  215. AdjustAngle(angle);
  216. }
  217. else
  218. AdjustAngle(toAngle);
  219. result = true;
  220. this.needUpdate = false;
  221. }
  222. else if(newPosition.x != oldPosition.x || newPosition.y != oldPosition.y || newPosition.z != oldPosition.z)
  223. {
  224. AdjustPosition(newPosition);
  225. result = true;
  226. }
  227. }
  228. return result;
  229. }
  230. bool SphereVisible(Vector3D center, float radius)
  231. {
  232. // TURN BACK ON
  233. /*
  234. if(wLeftNormal.DotProduct(center) + wLeftD < -radius)
  235. return false;
  236. if(wRightNormal.DotProduct(center) + wRightD < -radius)
  237. return false;
  238. if(wTopNormal.DotProduct(center) + wTopD < -radius)
  239. return false;
  240. if(wBottomNormal.DotProduct(center) + wBottomD < -radius)
  241. return false;
  242. if(wNearNormal.DotProduct(center) + wNearD < -radius)
  243. return false;
  244. /-* if(wFarNormal.DotProduct(center) + wFarD < -radius)
  245. return false;*/
  246. return true;
  247. }
  248. bool PointsVisible(Vector3D * points, int numPoints, double threshold)
  249. {
  250. ClippingPlane p;
  251. int c;
  252. for(p = 0; p<=ClippingPlane::bottom; p+=2)
  253. {
  254. bool out1a = true, out2a = true;
  255. bool out1b = true, out2b = true;
  256. Plane * plane = &worldClippingPlanes[p];
  257. for(c = 0; c<numPoints; c++)
  258. {
  259. double dot =
  260. plane->a * points[c].x +
  261. plane->b * points[c].y +
  262. plane->c * points[c].z;
  263. if(dot + plane->d > 0)
  264. {
  265. out1a = out1b = false;
  266. break;
  267. }
  268. else if(dot + plane->d > -threshold)
  269. out1a = false;
  270. }
  271. plane = &worldClippingPlanes[p+1];
  272. for(c = 0; c<numPoints; c++)
  273. {
  274. double dot =
  275. plane->a * points[c].x +
  276. plane->b * points[c].y +
  277. plane->c * points[c].z;
  278. if(dot + plane->d > 0)
  279. {
  280. out2a = out2b = false;
  281. break;
  282. }
  283. else if(dot + plane->d > -threshold)
  284. out2a = false;
  285. }
  286. if((out1a && !out2b) || (out2a && !out1b))
  287. return false;
  288. }
  289. return true;
  290. }
  291. /*
  292. bool PointsVisible(Vector3D * origPoints, int numPoints, double threshold)
  293. {
  294. Plane * planes = worldClippingPlanes;
  295. static byte goodPoints[50];
  296. static Vector3D points[50];
  297. static Vector3D newPoints[50];
  298. bool outside = false;
  299. int p;
  300. int i;
  301. int c = 0;
  302. int n = numPoints;
  303. for(c = 0; c<numPoints; c++)
  304. points[c] = origPoints[c];
  305. for(p = 0; p < 6; p++)
  306. {
  307. Plane * plane = &planes[p];
  308. int i;
  309. int numGoodPoints = 0;
  310. memset(goodPoints, 0, n);
  311. for(i = 0; i < n; i++)
  312. {
  313. double dot = plane->normal.DotProduct(points[i]);
  314. double distance = dot + plane->d;
  315. if(distance > -threshold)
  316. {
  317. numGoodPoints++;
  318. goodPoints[i] = 1;
  319. }
  320. }
  321. if(!numGoodPoints)
  322. {
  323. outside = true;
  324. break;
  325. }
  326. if(numGoodPoints < n)
  327. {
  328. // Clip the polygon
  329. int newN = 0;
  330. int lastGood = -1;
  331. int j;
  332. for(j = 0; j<n; )
  333. {
  334. if(goodPoints[j])
  335. {
  336. newPoints[newN++] = points[j];
  337. lastGood = j++;
  338. }
  339. else
  340. {
  341. Line edge;
  342. int next;
  343. if(lastGood == -1)
  344. for(lastGood = n-1; !goodPoints[lastGood]; lastGood--);
  345. edge.p0 = points[lastGood];
  346. edge.delta.Subtract(points[j], edge.p0);
  347. plane->IntersectLine(edge, newPoints[newN++]);
  348. for(next = j+1; next != j; next++)
  349. {
  350. if(next == n) next = 0;
  351. if(goodPoints[next])
  352. {
  353. int prev = next - 1;
  354. if(prev < 0) prev = n-1;
  355. edge.p0 = points[prev];
  356. edge.delta.Subtract(points[next], edge.p0);
  357. plane->IntersectLine(edge, newPoints[newN++]);
  358. break;
  359. }
  360. }
  361. if(next <= j)
  362. break;
  363. else
  364. j = next;
  365. }
  366. }
  367. // Use the new points
  368. memcpy(points, newPoints, newN * sizeof(Vector3D));
  369. n = newN;
  370. }
  371. }
  372. return !outside;
  373. }
  374. */
  375. void TransformPoint(Vector3D dest, Vector3D src)
  376. {
  377. Vector3D vector { src.x - cPosition.x, src.y - cPosition.y, src.z - cPosition.z };
  378. dest.MultMatrix(vector, viewMatrix);
  379. }
  380. void TransformNormal(Vector3D dest, Vector3D src)
  381. {
  382. dest.MultMatrix(src, viewMatrix);
  383. }
  384. void TransformMatrix(Matrix dest, Matrix src)
  385. {
  386. Matrix matrix = src;
  387. matrix.m[3][0] -= cPosition.x;
  388. matrix.m[3][1] -= cPosition.y;
  389. matrix.m[3][2] -= cPosition.z;
  390. dest.Multiply(matrix, viewMatrix);
  391. }
  392. void RotatePitch(Degrees amount, Degrees min, Degrees max)
  393. {
  394. if(type == fixedQuaternion)
  395. {
  396. orientation.RotatePitch(amount);
  397. }
  398. else
  399. {
  400. Euler euler = orientation;
  401. euler.pitch += amount;
  402. if(min || max)
  403. {
  404. euler.pitch = Min(euler.pitch, max);
  405. euler.pitch = Max(euler.pitch, min);
  406. }
  407. orientation = euler;
  408. }
  409. }
  410. void RotateYaw(Degrees amount, Degrees min, Degrees max)
  411. {
  412. if(type == fixedQuaternion)
  413. {
  414. orientation.RotateYaw(amount);
  415. }
  416. else
  417. {
  418. Euler euler = orientation;
  419. euler.yaw += amount;
  420. if(min || max)
  421. {
  422. euler.yaw = Min(euler.yaw, max);
  423. euler.yaw = Max(euler.yaw, min);
  424. }
  425. orientation = euler;
  426. }
  427. }
  428. void RotateRoll(Degrees amount, Degrees min, Degrees max)
  429. {
  430. if(type == fixedQuaternion)
  431. {
  432. orientation.RotateRoll(amount);
  433. }
  434. else
  435. {
  436. Euler euler = orientation;
  437. euler.roll += amount;
  438. if(min || max)
  439. {
  440. euler.roll = Min(euler.roll, max);
  441. euler.roll = Max(euler.roll, min);
  442. }
  443. orientation = euler;
  444. }
  445. }
  446. void Slerp(float amount)
  447. {
  448. fromAngle = cAngle;
  449. slerpAmount = amount;
  450. slerpPosition = 0;
  451. }
  452. void Move(Vector3D direction)
  453. {
  454. Matrix matrix;
  455. switch(type)
  456. {
  457. case fixed:
  458. {
  459. Vector3D offset;
  460. matrix.RotationQuaternion(orientation);
  461. offset.MultMatrix(direction, matrix);
  462. position.Add(position, offset);
  463. break;
  464. }
  465. case attachedQuaternion:
  466. case attached:
  467. case lookAt:
  468. {
  469. position.Add(position, direction);
  470. break;
  471. }
  472. }
  473. }
  474. bool Project(Vector3D vector, Vector3D point)
  475. {
  476. if(vector.z >= zMin)
  477. {
  478. float floatZ;
  479. point.x = (vector.x*focalX/vector.z);
  480. point.y = (vector.y*focalY/vector.z);
  481. point.z = (((zMax * zMin / -vector.z) + zMax) / (zMax - zMin));
  482. floatZ = ((((float)zMax * (float)zMin / -(float)vector.z) + (float)zMax) / ((float)zMax - (float)zMin));
  483. point.x += origin.x;
  484. point.y += origin.y;
  485. return (point.x >= 0 && point.y >= 0 &&
  486. point.x < width && point.y < height);
  487. }
  488. return false;
  489. }
  490. void Unproject(Vector3D point, Vector3D vector)
  491. {
  492. vector.z = (zMax * zMin / (zMax - (double)point.z * (zMax-zMin)));
  493. vector.y = ((point.y - origin.y) * (double)vector.z / focalY);
  494. vector.x = ((point.x - origin.x) * (double)vector.z / focalX);
  495. }
  496. bool ProjectSize(Vector3D vector, Point point)
  497. {
  498. if(vector.z >= zMin)
  499. {
  500. point.x = (int)((double)vector.x*(double)focalX/(double)vector.z);
  501. point.y = (int)((double)vector.y*(double)focalY/(double)vector.z);
  502. return true;
  503. }
  504. return false;
  505. }
  506. void Untransform(Vector3D src, Vector3D result)
  507. {
  508. result.MultMatrix(src, inverseMatrix);
  509. result.x += cPosition.x;
  510. result.y += cPosition.y;
  511. result.z += cPosition.z;
  512. }
  513. private:
  514. Camera()
  515. {
  516. needUpdate = true;
  517. type = fixed;
  518. orientation.w = 1;
  519. aspectRatio = 0;
  520. fov = Pi/2;
  521. zMin = 5;//0.1f;
  522. zMax = 10000;
  523. }
  524. CameraType type;
  525. FovDirection fovDirection;
  526. Object cameraObject;
  527. Object target;
  528. Vector3D position;
  529. Quaternion orientation;
  530. float aspectRatio;
  531. Degrees fov;
  532. float zMin, zMax;
  533. // Read only
  534. Vector3D cPosition;
  535. Quaternion cAngle;
  536. Angle fovLeft, fovRight, fovTop, fovBottom;
  537. float focalX, focalY;
  538. Angle fovX, fovY;
  539. float slerpAmount, slerpPosition;
  540. Plane viewClippingPlanes[ClippingPlane], worldClippingPlanes[ClippingPlane];
  541. Matrix inverseTranspose, inverseMatrix;
  542. Quaternion fromAngle, toAngle;
  543. bool needUpdate;
  544. Matrix viewMatrix;
  545. int width, height;
  546. Point origin;
  547. };