💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

93 lines
2.8 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "snapping.hpp"
  20. #include "entity/components/collision.hpp"
  21. #include "entity/components/snap.hpp"
  22. #include "entity/components/transform.hpp"
  23. #include "entity/id.hpp"
  24. #include "utility/fundamental-types.hpp"
  25. namespace entity {
  26. namespace system {
  27. snapping::snapping(entity::registry& registry):
  28. updatable(registry)
  29. {}
  30. void snapping::update(double t, double dt)
  31. {
  32. registry.view<component::transform, component::snap>().each(
  33. [&](entity::id entity_id, auto& snap_transform, auto& snap)
  34. {
  35. bool intersection = false;
  36. float a = std::numeric_limits<float>::infinity();
  37. float3 pick;
  38. geom::ray<float> snap_ray = snap.ray;
  39. if (snap.relative)
  40. {
  41. snap_ray.origin += snap_transform.local.translation;
  42. snap_ray.direction = snap_transform.local.rotation * snap_ray.direction;
  43. }
  44. this->registry.view<component::transform, component::collision>().each(
  45. [&](entity::id entity_id, auto& collision_transform, auto& collision)
  46. {
  47. // Transform ray into local space of collision component
  48. math::transform<float> inverse_transform = math::inverse(collision_transform.local);
  49. float3 origin = inverse_transform * snap_ray.origin;
  50. float3 direction = math::normalize(math::conjugate(collision_transform.local.rotation) * snap_ray.direction);
  51. geom::ray<float> transformed_ray = {origin, direction};
  52. // Broad phase AABB test
  53. auto aabb_result = geom::ray_aabb_intersection(transformed_ray, collision.bounds);
  54. if (!std::get<0>(aabb_result))
  55. {
  56. return;
  57. }
  58. // Narrow phase mesh test
  59. auto mesh_result = collision.mesh_accelerator.query_nearest(transformed_ray);
  60. if (mesh_result)
  61. {
  62. intersection = true;
  63. if (mesh_result->t < a)
  64. {
  65. a = mesh_result->t;
  66. pick = snap_ray.extrapolate(a);
  67. }
  68. }
  69. });
  70. if (intersection)
  71. {
  72. snap_transform.local.translation = pick;
  73. snap_transform.warp = snap.warp;
  74. if (snap.autoremove)
  75. {
  76. this->registry.remove<component::snap>(entity_id);
  77. }
  78. }
  79. });
  80. }
  81. } // namespace system
  82. } // namespace entity