PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/lipsofsuna/algorithm/algorithm-camera.c

https://github.com/deldiablo/GodheadLips
C | 710 lines | 442 code | 64 blank | 204 comment | 16 complexity | 2e322c5053141b53c933871e677833ee MD5 | raw file
  1. /* Lips of Suna
  2. * Copyright© 2007-2010 Lips of Suna development team.
  3. *
  4. * Lips of Suna is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as
  6. * published by the Free Software Foundation, either version 3 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * Lips of Suna is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License
  15. * along with Lips of Suna. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. /**
  18. * \addtogroup LIAlg Algorithm
  19. * @{
  20. * \addtogroup LIAlgCamera Camera
  21. * @{
  22. */
  23. #include <lipsofsuna/system.h>
  24. #include "algorithm-camera.h"
  25. #define LIALG_CAMERA_DEFAULT_FOV (M_PI / 5.0f)
  26. #define LIALG_CAMERA_DEFAULT_NEAR 1.0f
  27. #define LIALG_CAMERA_DEFAULT_FAR 75.0f
  28. #define LIALG_CAMERA_DEFAULT_ZOOM 14.0f
  29. #define LIALG_CAMERA_INTERPOLATION_WARP 50.0f
  30. #define LIALG_CAMERA_MINIMUM_ZOOM 1.5f
  31. #define LIALG_CAMERA_MAXIMUM_ZOOM 100.0f
  32. #define LIALG_CAMERA_SENSITIVITY_ZOOM 1.0f
  33. #define LIALG_CAMERA_SMOOTHING_TIMESTEP (1.0f / 60.0f)
  34. static void private_update_1st_person (
  35. LIAlgCamera* self);
  36. static void private_update_3rd_person (
  37. LIAlgCamera* self,
  38. float dist);
  39. static void private_update_modelview (
  40. LIAlgCamera* self);
  41. static void private_update_orientation (
  42. LIAlgCamera* self,
  43. float secs);
  44. static void private_update_projection (
  45. LIAlgCamera* self);
  46. /*****************************************************************************/
  47. /**
  48. * \brief Creates a new camera.
  49. * \return New camera or NULL.
  50. */
  51. LIAlgCamera* lialg_camera_new ()
  52. {
  53. LIAlgCamera* self;
  54. /* Allocate self. */
  55. self = lisys_calloc (1, sizeof (LIAlgCamera));
  56. if (self == NULL)
  57. return NULL;
  58. self->config.collision_group = 0xFFFF;
  59. self->config.collision_mask = 0xFFFF;
  60. self->config.driver = LIALG_CAMERA_FIRSTPERSON;
  61. self->config.distance = LIALG_CAMERA_DEFAULT_ZOOM;
  62. self->smoothing.pos = 0.5f;
  63. self->smoothing.rot = 0.5f;
  64. self->transform.center = limat_transform_identity ();
  65. self->transform.current = limat_transform_identity ();
  66. self->transform.local = limat_transform_identity ();
  67. self->transform.target = limat_transform_identity ();
  68. self->transform.inverse = limat_transform_identity ();
  69. self->view.fov = LIALG_CAMERA_DEFAULT_FOV;
  70. self->view.nearplane = LIALG_CAMERA_DEFAULT_NEAR;
  71. self->view.farplane = LIALG_CAMERA_DEFAULT_FAR;
  72. self->view.aspect = 1.0f;
  73. private_update_modelview (self);
  74. private_update_projection (self);
  75. return self;
  76. }
  77. /**
  78. * \brief Frees the camera.
  79. * \param self Camera.
  80. */
  81. void lialg_camera_free (
  82. LIAlgCamera* self)
  83. {
  84. lisys_free (self);
  85. }
  86. /**
  87. * \brief Moves the camera by the specified amount.
  88. * \param self Camera.
  89. * \param value Movement amount.
  90. */
  91. void lialg_camera_move (
  92. LIAlgCamera* self,
  93. float value)
  94. {
  95. LIMatVector dir;
  96. LIMatVector src;
  97. LIMatVector dst;
  98. LIMatQuaternion rot;
  99. /* Calculate eye position. */
  100. rot = limat_quaternion_conjugate (self->transform.current.rotation);
  101. dir = limat_quaternion_get_basis (rot, 2);
  102. src = self->transform.current.position;
  103. dst = limat_vector_add (src, limat_vector_multiply (dir, -value));
  104. self->transform.target.position = dst;
  105. private_update_modelview (self);
  106. }
  107. /**
  108. * \brief Projects a point to the viewport plane of the camera.
  109. * \param self Camera.
  110. * \param object Point in object space.
  111. * \param window Return location for a point in window space.
  112. * \return Nonzero on success.
  113. */
  114. int lialg_camera_project (
  115. LIAlgCamera* self,
  116. const LIMatVector* object,
  117. LIMatVector* window)
  118. {
  119. return limat_matrix_project (
  120. self->view.projection, self->view.modelview,
  121. self->view.viewport, object, window);
  122. }
  123. /**
  124. * \brief Tilts the camera by the specified amount.
  125. * \param self Camera.
  126. * \param value Rotation in radians.
  127. */
  128. void lialg_camera_tilt (
  129. LIAlgCamera* self,
  130. float value)
  131. {
  132. LIMatQuaternion rot;
  133. LIMatTransform transform;
  134. LIMatVector axis;
  135. axis = limat_vector_init (1.0f, 0.0f, 0.0f);
  136. rot = limat_quaternion_rotation (value, axis);
  137. if (self->config.driver == LIALG_CAMERA_MANUAL)
  138. {
  139. transform = limat_convert_quaternion_to_transform (rot);
  140. transform = limat_transform_multiply (self->transform.target, transform);
  141. transform.rotation = limat_quaternion_normalize (transform.rotation);
  142. self->transform.target = transform;
  143. }
  144. else
  145. {
  146. transform = limat_convert_quaternion_to_transform (rot);
  147. transform = limat_transform_multiply (self->transform.local, transform);
  148. transform.rotation = limat_quaternion_normalize (transform.rotation);
  149. self->transform.local = transform;
  150. }
  151. private_update_modelview (self);
  152. }
  153. /**
  154. * \brief Turns the camera by the specified amount.
  155. * \param self Camera.
  156. * \param value Rotation in radians.
  157. */
  158. void lialg_camera_turn (
  159. LIAlgCamera* self,
  160. float value)
  161. {
  162. LIMatQuaternion rot;
  163. LIMatTransform transform;
  164. LIMatVector axis;
  165. if (self->config.driver == LIALG_CAMERA_MANUAL)
  166. {
  167. rot = limat_quaternion_conjugate (self->transform.target.rotation);
  168. axis = limat_vector_init (0.0f, 1.0f, 0.0f);
  169. axis = limat_quaternion_transform (rot, axis);
  170. rot = limat_quaternion_rotation (value, axis);
  171. transform = limat_convert_quaternion_to_transform (rot);
  172. transform = limat_transform_multiply (self->transform.target, transform);
  173. transform.rotation = limat_quaternion_normalize (transform.rotation);
  174. self->transform.target = transform;
  175. }
  176. else
  177. {
  178. rot = limat_quaternion_conjugate (self->transform.local.rotation);
  179. axis = limat_vector_init (0.0f, 1.0f, 0.0f);
  180. axis = limat_quaternion_transform (rot, axis);
  181. rot = limat_quaternion_rotation (value, axis);
  182. transform = limat_convert_quaternion_to_transform (rot);
  183. transform = limat_transform_multiply (self->transform.local, transform);
  184. transform.rotation = limat_quaternion_normalize (transform.rotation);
  185. self->transform.local = transform;
  186. }
  187. private_update_modelview (self);
  188. }
  189. /**
  190. * \brief Projects a point on the viewport plane to the scene.
  191. * \param self Camera.
  192. * \param object Point in viewport.
  193. * \param window Return location for a point in world space.
  194. * \return Nonzero on success.
  195. */
  196. int lialg_camera_unproject (
  197. LIAlgCamera* self,
  198. const LIMatVector* window,
  199. LIMatVector* object)
  200. {
  201. return limat_matrix_unproject (
  202. self->view.projection, self->view.modelview,
  203. self->view.viewport, window, object);
  204. }
  205. /**
  206. * \brief Updates the position of the camera.
  207. * \param self Camera.
  208. * \param secs Number of seconds since the last update.
  209. */
  210. void lialg_camera_update (
  211. LIAlgCamera* self,
  212. float secs)
  213. {
  214. lialg_camera_move (self, secs * self->controls.move_rate);
  215. lialg_camera_tilt (self, secs * self->controls.tilt_rate);
  216. lialg_camera_turn (self, secs * self->controls.turn_rate);
  217. lialg_camera_zoom (self, secs * self->controls.zoom_rate);
  218. switch (self->config.driver)
  219. {
  220. case LIALG_CAMERA_FIRSTPERSON:
  221. private_update_1st_person (self);
  222. private_update_orientation (self, secs);
  223. private_update_modelview (self);
  224. break;
  225. case LIALG_CAMERA_THIRDPERSON:
  226. private_update_3rd_person (self, self->config.distance);
  227. private_update_orientation (self, secs);
  228. private_update_modelview (self);
  229. break;
  230. default:
  231. private_update_orientation (self, secs);
  232. private_update_modelview (self);
  233. break;
  234. }
  235. }
  236. /**
  237. * \brief Warps the camera to the target position.
  238. * \param self Camera.
  239. */
  240. void lialg_camera_warp (
  241. LIAlgCamera* self)
  242. {
  243. switch (self->config.driver)
  244. {
  245. case LIALG_CAMERA_FIRSTPERSON:
  246. private_update_1st_person (self);
  247. break;
  248. case LIALG_CAMERA_THIRDPERSON:
  249. private_update_3rd_person (self, self->config.distance);
  250. break;
  251. default:
  252. break;
  253. }
  254. self->transform.current = self->transform.target;
  255. private_update_modelview (self);
  256. }
  257. /**
  258. * \brief Zooms in or out.
  259. * \param self Camera.
  260. * \param value Amount and direction of zoom.
  261. */
  262. void lialg_camera_zoom (
  263. LIAlgCamera* self,
  264. float value)
  265. {
  266. self->config.distance += value * LIALG_CAMERA_SENSITIVITY_ZOOM;
  267. if (self->config.distance < LIALG_CAMERA_MINIMUM_ZOOM)
  268. self->config.distance = LIALG_CAMERA_MINIMUM_ZOOM;
  269. if (self->config.distance > LIALG_CAMERA_MAXIMUM_ZOOM)
  270. self->config.distance = LIALG_CAMERA_MAXIMUM_ZOOM;
  271. private_update_modelview (self);
  272. }
  273. /**
  274. * \brief Gets the size of the camera.
  275. * \param self Camera.
  276. * \param aabb Return location for the bounding box.
  277. */
  278. void lialg_camera_get_bounds (
  279. const LIAlgCamera* self,
  280. LIMatAabb* aabb)
  281. {
  282. float max;
  283. float top;
  284. float right;
  285. float nearplane;
  286. LIMatVector size;
  287. LIMatVector zero;
  288. nearplane = self->view.nearplane;
  289. top = tan (self->view.fov * M_PI / 360.0f) * nearplane;
  290. right = top * self->view.aspect;
  291. max = 1.7f * LIMAT_MAX (LIMAT_MAX (top, right), nearplane);
  292. size = limat_vector_init (max, max, max);
  293. zero = limat_vector_init (0.0f, 0.0f, 0.0f);
  294. limat_aabb_init_from_center (aabb, &zero, &size);
  295. }
  296. /**
  297. * \brief Gets the point of interest for automatic camera modes.
  298. * \param self Camera.
  299. * \param result Return location for transformation.
  300. */
  301. void lialg_camera_get_center (
  302. LIAlgCamera* self,
  303. LIMatTransform* result)
  304. {
  305. *result = self->transform.center;
  306. }
  307. /**
  308. * \brief Sets the point of interest for automatic camera modes.
  309. * \param self Camera.
  310. * \param value Center transformation.
  311. */
  312. void lialg_camera_set_center (
  313. LIAlgCamera* self,
  314. const LIMatTransform* value)
  315. {
  316. self->transform.center = *value;
  317. }
  318. /**
  319. * \brief Sets the external clipping function of the camera.
  320. *
  321. * When the clipping function is set, the camera ensures that its distance to the
  322. * target in the third person mode isn't more than that returned by the clip
  323. * function.
  324. *
  325. * \param self Camera.
  326. * \param func Clipping function or NULL to disable.
  327. * \param data Userdata to be passed to the clipping function.
  328. */
  329. void lialg_camera_set_clipping (
  330. LIAlgCamera* self,
  331. LIAlgCameraClip func,
  332. void* data)
  333. {
  334. self->config.clip_func = func;
  335. self->config.clip_data = data;
  336. }
  337. /**
  338. * \brief Gets the driver type of the camera.
  339. * \param self Camera.
  340. * \return Camera driver type.
  341. */
  342. LIAlgCameraDriver lialg_camera_get_driver (
  343. LIAlgCamera* self)
  344. {
  345. return self->config.driver;
  346. }
  347. /**
  348. * \brief Sets the driver type of the camera.
  349. * \param self Camera.
  350. * \param value Camera driver type.
  351. */
  352. void lialg_camera_set_driver (
  353. LIAlgCamera* self,
  354. LIAlgCameraDriver value)
  355. {
  356. self->config.driver = value;
  357. }
  358. /**
  359. * \brief Sets the far plane of the camera.
  360. * \param self Camera.
  361. * \param value Far plane distance.
  362. */
  363. void lialg_camera_set_far (
  364. LIAlgCamera* self,
  365. float value)
  366. {
  367. self->view.farplane = value;
  368. private_update_projection (self);
  369. }
  370. /**
  371. * \brief Gets the field of view of the camera.
  372. * \param self Camera.
  373. * \return Field of view in radians.
  374. */
  375. float lialg_camera_get_fov (
  376. const LIAlgCamera* self)
  377. {
  378. return self->view.fov;
  379. }
  380. /**
  381. * \brief Sets the field of view of the camera.
  382. * \param self Camera.
  383. * \param value Field of view in radians.
  384. */
  385. void lialg_camera_set_fov (
  386. LIAlgCamera* self,
  387. float value)
  388. {
  389. self->view.fov = value;
  390. private_update_projection (self);
  391. }
  392. /**
  393. * \brief Gets the frustum of the camera.
  394. * \param self Camera.
  395. * \param result Return location for frustum.
  396. */
  397. void lialg_camera_get_frustum (
  398. const LIAlgCamera* self,
  399. LIMatFrustum* result)
  400. {
  401. limat_frustum_init (result,
  402. &self->view.modelview,
  403. &self->view.projection);
  404. }
  405. /**
  406. * \brief Gets the modelview matrix of the camera.
  407. * \param self Camera.
  408. * \param value Return location for the matrix.
  409. */
  410. void lialg_camera_get_modelview (
  411. const LIAlgCamera* self,
  412. LIMatMatrix* value)
  413. {
  414. *value = self->view.modelview;
  415. }
  416. /**
  417. * \brief Sets the near plane of the camera.
  418. * \param self Camera.
  419. * \param value Near plane distance.
  420. */
  421. void lialg_camera_set_near (
  422. LIAlgCamera* self,
  423. float value)
  424. {
  425. self->view.nearplane = value;
  426. private_update_projection (self);
  427. }
  428. /**
  429. * \brief Gets the projection matrix of the camera.
  430. * \param self Camera.
  431. * \param value Return location for the matrix.
  432. */
  433. void lialg_camera_get_projection (
  434. const LIAlgCamera* self,
  435. LIMatMatrix* value)
  436. {
  437. *value = self->view.projection;
  438. }
  439. /**
  440. * \brief Sets the projection settings of the camera.
  441. * \param self Camera.
  442. * \param fov Field of view.
  443. * \param aspect Ascpect ratio of the viewport.
  444. * \param nearplane Near plane distance.
  445. * \param farplane Far plane distance.
  446. */
  447. void lialg_camera_set_projection (
  448. LIAlgCamera* self,
  449. float fov,
  450. float aspect,
  451. float nearplane,
  452. float farplane)
  453. {
  454. self->view.fov = fov;
  455. self->view.aspect = aspect;
  456. self->view.nearplane = nearplane;
  457. self->view.farplane = farplane;
  458. private_update_projection (self);
  459. }
  460. /**
  461. * \brief Gets the smoothing rates of the camera.
  462. * \param self Camera.
  463. * \param pos Return location for the position smoothing rate.
  464. * \param rot Return location for the rotation smoothing rate.
  465. */
  466. void lialg_camera_get_smoothing (
  467. const LIAlgCamera* self,
  468. float* pos,
  469. float* rot)
  470. {
  471. *pos = self->smoothing.pos;
  472. *rot = self->smoothing.rot;
  473. }
  474. /**
  475. * \brief Sets the smoothing rates of the camera.
  476. * \param self Camera.
  477. * \param pos Position smoothing rate.
  478. * \param rot Rotation smoothing rate.
  479. */
  480. void lialg_camera_set_smoothing (
  481. LIAlgCamera* self,
  482. float pos,
  483. float rot)
  484. {
  485. self->smoothing.pos = pos;
  486. self->smoothing.rot = rot;
  487. }
  488. /**
  489. * \brief Gets the current transformation of the camera.
  490. *
  491. * \param self Camera.
  492. * \param value Return location for the transformation.
  493. */
  494. void lialg_camera_get_transform (
  495. const LIAlgCamera* self,
  496. LIMatTransform* value)
  497. {
  498. *value = limat_transform_init (
  499. self->transform.current.position,
  500. self->transform.current.rotation);
  501. }
  502. /**
  503. * \brief Sets the target transformation of the camera.
  504. * \param self Camera.
  505. * \param value Transformation.
  506. */
  507. void lialg_camera_set_transform (
  508. LIAlgCamera* self,
  509. const LIMatTransform* value)
  510. {
  511. self->transform.target = *value;
  512. private_update_modelview (self);
  513. }
  514. /**
  515. * \brief Gets the up vector of the camera.
  516. * \param self Camera.
  517. * \param result Return location for the up vector.
  518. */
  519. void lialg_camera_get_up (
  520. const LIAlgCamera* self,
  521. LIMatVector* result)
  522. {
  523. result->x = self->view.modelview.m[1];
  524. result->y = self->view.modelview.m[4];
  525. result->z = self->view.modelview.m[9];
  526. }
  527. /**
  528. * \brief Sets the viewport of the camera.
  529. * \param self Camera.
  530. * \param x Left border of the viewport.
  531. * \param y Bottom border of the viewport.
  532. * \param width Width of the viewport.
  533. * \param height Height of the viewport.
  534. */
  535. void lialg_camera_set_viewport (
  536. LIAlgCamera* self,
  537. int x,
  538. int y,
  539. int width,
  540. int height)
  541. {
  542. self->view.viewport[0] = x;
  543. self->view.viewport[1] = y;
  544. self->view.viewport[2] = width;
  545. self->view.viewport[3] = height;
  546. self->view.aspect = (float) width / height;
  547. private_update_projection (self);
  548. }
  549. /*****************************************************************************/
  550. static void private_update_1st_person (
  551. LIAlgCamera* self)
  552. {
  553. /* Copy center position and rotation. */
  554. self->transform.target = self->transform.center;
  555. self->transform.current.position = self->transform.target.position;
  556. /* Apply local rotation. */
  557. self->transform.target = limat_transform_multiply (self->transform.target, self->transform.local);
  558. self->transform.target.rotation = limat_quaternion_normalize (self->transform.target.rotation);
  559. }
  560. static void private_update_3rd_person (
  561. LIAlgCamera* self,
  562. float dist)
  563. {
  564. float frac;
  565. LIMatTransform transform;
  566. LIMatTransform target;
  567. LIMatTransform center;
  568. /* Copy center position and rotation. */
  569. center = self->transform.center;
  570. /* Apply local rotation. */
  571. center = limat_transform_multiply (center, self->transform.local);
  572. center.rotation = limat_quaternion_normalize (center.rotation);
  573. /* Project backwards. */
  574. transform = limat_transform_init (
  575. limat_vector_init (0.0f, 0.0f, dist),
  576. limat_quaternion_init (0.0f, 0.0f, 0.0f, 1.0f));
  577. target = limat_transform_multiply (center, transform);
  578. target.rotation = limat_quaternion_normalize (target.rotation);
  579. /* Apply clipping. */
  580. if (self->config.clip_func != NULL)
  581. {
  582. frac = self->config.clip_func (self->config.clip_data, self, &center, &target);
  583. transform = limat_transform_init (
  584. limat_vector_init (0.0f, 0.0f, dist * frac),
  585. limat_quaternion_init (0.0f, 0.0f, 0.0f, 1.0f));
  586. target = limat_transform_multiply (center, transform);
  587. target.rotation = limat_quaternion_normalize (target.rotation);
  588. }
  589. /* Set the target position. */
  590. self->transform.target = target;
  591. }
  592. static void private_update_modelview (
  593. LIAlgCamera* self)
  594. {
  595. LIMatTransform t;
  596. self->transform.current.rotation = limat_quaternion_normalize (self->transform.current.rotation);
  597. self->transform.target.rotation = limat_quaternion_normalize (self->transform.target.rotation);
  598. t = limat_transform_invert (self->transform.current);
  599. self->transform.inverse = t;
  600. self->view.modelview = limat_convert_transform_to_matrix (t);
  601. }
  602. static void private_update_orientation (
  603. LIAlgCamera* self,
  604. float secs)
  605. {
  606. float dist;
  607. LIMatVector disp;
  608. LIMatTransform transform;
  609. LIMatTransform transform0;
  610. LIMatTransform transform1;
  611. /* Update timer. */
  612. self->smoothing.timer += secs;
  613. if (self->smoothing.timer < LIALG_CAMERA_SMOOTHING_TIMESTEP)
  614. return;
  615. /* Check if it'd be better to warp than interpolate. */
  616. disp = limat_vector_subtract (self->transform.target.position, self->transform.current.position);
  617. dist = limat_vector_get_length (disp);
  618. if (self->smoothing.timer >= 1.0f || dist >= LIALG_CAMERA_INTERPOLATION_WARP)
  619. {
  620. self->transform.current = self->transform.target;
  621. self->smoothing.timer = 0.0f;
  622. return;
  623. }
  624. /* Interpolate the transformation. */
  625. while (self->smoothing.timer >= LIALG_CAMERA_SMOOTHING_TIMESTEP)
  626. {
  627. transform0 = self->transform.current;
  628. transform1 = self->transform.target;
  629. transform0.rotation = limat_quaternion_get_nearest (transform0.rotation, transform1.rotation);
  630. transform.position = limat_vector_lerp (
  631. transform1.position, transform0.position, self->smoothing.pos);
  632. transform.rotation = limat_quaternion_nlerp (
  633. transform1.rotation, transform0.rotation, self->smoothing.rot);
  634. self->transform.current = transform;
  635. self->smoothing.timer -= LIALG_CAMERA_SMOOTHING_TIMESTEP;
  636. }
  637. }
  638. static void private_update_projection (
  639. LIAlgCamera* self)
  640. {
  641. self->view.projection = limat_matrix_perspective (
  642. self->view.fov, self->view.aspect,
  643. self->view.nearplane, self->view.farplane);
  644. }
  645. /** @} */
  646. /** @} */