rig.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #pragma once
  2. #include "../entity/registry.h"
  3. #include "../graphics_settings.h"
  4. #include <QMatrix4x4>
  5. #include <QVector3D>
  6. #include <cstdint>
  7. namespace Render::GL {
  8. struct AnimationInputs;
  9. struct HumanoidAnimationContext;
  10. class ISubmitter;
  11. inline auto calculate_elephant_lod(float distance) -> HorseLOD;
  12. struct ElephantRenderStats {
  13. uint32_t elephants_total{0};
  14. uint32_t elephants_rendered{0};
  15. uint32_t elephants_skipped_lod{0};
  16. uint32_t lod_full{0};
  17. uint32_t lod_reduced{0};
  18. uint32_t lod_minimal{0};
  19. void reset() {
  20. elephants_total = 0;
  21. elephants_rendered = 0;
  22. elephants_skipped_lod = 0;
  23. lod_full = 0;
  24. lod_reduced = 0;
  25. lod_minimal = 0;
  26. }
  27. };
  28. auto get_elephant_render_stats() -> const ElephantRenderStats &;
  29. void reset_elephant_render_stats();
  30. struct ElephantDimensions {
  31. float body_length{};
  32. float body_width{};
  33. float body_height{};
  34. float barrel_center_y{};
  35. float neck_length{};
  36. float neck_width{};
  37. float head_length{};
  38. float head_width{};
  39. float head_height{};
  40. float trunk_length{};
  41. float trunk_base_radius{};
  42. float trunk_tip_radius{};
  43. float ear_width{};
  44. float ear_height{};
  45. float ear_thickness{};
  46. float leg_length{};
  47. float leg_radius{};
  48. float foot_radius{};
  49. float tail_length{};
  50. float tusk_length{};
  51. float tusk_radius{};
  52. float howdah_width{};
  53. float howdah_length{};
  54. float howdah_height{};
  55. float idle_bob_amplitude{};
  56. float move_bob_amplitude{};
  57. };
  58. struct ElephantVariant {
  59. QVector3D skin_color;
  60. QVector3D skin_highlight;
  61. QVector3D skin_shadow;
  62. QVector3D ear_inner_color;
  63. QVector3D tusk_color;
  64. QVector3D toenail_color;
  65. QVector3D howdah_wood_color;
  66. QVector3D howdah_fabric_color;
  67. QVector3D howdah_metal_color;
  68. };
  69. struct ElephantGait {
  70. float cycle_time{};
  71. float front_leg_phase{};
  72. float rear_leg_phase{};
  73. float stride_swing{};
  74. float stride_lift{};
  75. };
  76. struct ElephantProfile {
  77. ElephantDimensions dims{};
  78. ElephantVariant variant;
  79. ElephantGait gait{};
  80. };
  81. struct ElephantAttachmentFrame {
  82. QVector3D origin{0.0F, 0.0F, 0.0F};
  83. QVector3D right{1.0F, 0.0F, 0.0F};
  84. QVector3D up{0.0F, 1.0F, 0.0F};
  85. QVector3D forward{0.0F, 0.0F, 1.0F};
  86. auto make_local_transform(const QMatrix4x4 &parent,
  87. const QVector3D &local_offset,
  88. float uniform_scale) const -> QMatrix4x4 {
  89. QMatrix4x4 m = parent;
  90. QVector3D const world_pos = origin + right * local_offset.x() +
  91. up * local_offset.y() +
  92. forward * local_offset.z();
  93. m.translate(world_pos);
  94. QMatrix4x4 basis;
  95. basis.setColumn(0, QVector4D(right * uniform_scale, 0.0F));
  96. basis.setColumn(1, QVector4D(up * uniform_scale, 0.0F));
  97. basis.setColumn(2, QVector4D(forward * uniform_scale, 0.0F));
  98. basis.setColumn(3, QVector4D(0.0F, 0.0F, 0.0F, 1.0F));
  99. return m * basis;
  100. }
  101. };
  102. struct ElephantBodyFrames {
  103. ElephantAttachmentFrame head{};
  104. ElephantAttachmentFrame neck_base{};
  105. ElephantAttachmentFrame back_center{};
  106. ElephantAttachmentFrame howdah{};
  107. ElephantAttachmentFrame rump{};
  108. ElephantAttachmentFrame tail_base{};
  109. ElephantAttachmentFrame trunk_base{};
  110. ElephantAttachmentFrame trunk_tip{};
  111. ElephantAttachmentFrame ear_left{};
  112. ElephantAttachmentFrame ear_right{};
  113. };
  114. struct HowdahAttachmentFrame {
  115. QVector3D howdah_center;
  116. QVector3D seat_position;
  117. QVector3D seat_forward;
  118. QVector3D seat_right;
  119. QVector3D seat_up;
  120. QVector3D ground_offset;
  121. };
  122. struct ElephantMotionSample {
  123. float phase = 0.0F;
  124. float bob = 0.0F;
  125. bool is_moving = false;
  126. float trunk_swing = 0.0F;
  127. float ear_flap = 0.0F;
  128. };
  129. enum class LegIndex : int {
  130. FrontLeft = 0,
  131. FrontRight = 1,
  132. RearLeft = 2,
  133. RearRight = 3
  134. };
  135. struct ElephantLegState {
  136. QVector3D planted_foot{0.0F, 0.0F, 0.0F};
  137. QVector3D swing_start{0.0F, 0.0F, 0.0F};
  138. QVector3D swing_target{0.0F, 0.0F, 0.0F};
  139. float swing_progress = 0.0F;
  140. bool in_swing = false;
  141. };
  142. struct ElephantGaitState {
  143. ElephantLegState legs[4]{};
  144. float cycle_phase = 0.0F;
  145. float weight_shift_x = 0.0F;
  146. float weight_shift_z = 0.0F;
  147. float shoulder_lag = 0.0F;
  148. float hip_lag = 0.0F;
  149. bool initialized = false;
  150. };
  151. struct ElephantLegPose {
  152. QVector3D hip;
  153. QVector3D knee;
  154. QVector3D ankle;
  155. QVector3D foot;
  156. float upper_radius;
  157. float lower_radius;
  158. };
  159. auto make_elephant_dimensions(uint32_t seed) -> ElephantDimensions;
  160. auto make_elephant_variant(uint32_t seed, const QVector3D &fabric_base,
  161. const QVector3D &metal_base) -> ElephantVariant;
  162. auto make_elephant_profile(uint32_t seed, const QVector3D &fabric_base,
  163. const QVector3D &metal_base) -> ElephantProfile;
  164. auto get_or_create_cached_elephant_profile(
  165. uint32_t seed, const QVector3D &fabric_base,
  166. const QVector3D &metal_base) -> ElephantProfile;
  167. void advance_elephant_profile_cache_frame();
  168. auto compute_howdah_frame(const ElephantProfile &profile)
  169. -> HowdahAttachmentFrame;
  170. auto evaluate_elephant_motion(ElephantProfile &profile,
  171. const AnimationInputs &anim)
  172. -> ElephantMotionSample;
  173. void apply_howdah_vertical_offset(HowdahAttachmentFrame &frame, float bob);
  174. void update_elephant_gait(ElephantGaitState &state,
  175. const ElephantProfile &profile,
  176. const AnimationInputs &anim,
  177. const QVector3D &body_world_pos,
  178. float body_forward_z);
  179. auto solve_elephant_leg_ik(const QVector3D &hip, const QVector3D &foot_target,
  180. float upper_len, float lower_len,
  181. float lateral_sign) -> ElephantLegPose;
  182. auto evaluate_swing_position(const ElephantLegState &leg,
  183. float lift_height) -> QVector3D;
  184. inline void scale_elephant_dimensions(ElephantDimensions &dims, float scale) {
  185. dims.body_length *= scale;
  186. dims.body_width *= scale;
  187. dims.body_height *= scale;
  188. dims.neck_length *= scale;
  189. dims.neck_width *= scale;
  190. dims.head_length *= scale;
  191. dims.head_width *= scale;
  192. dims.head_height *= scale;
  193. dims.trunk_length *= scale;
  194. dims.trunk_base_radius *= scale;
  195. dims.trunk_tip_radius *= scale;
  196. dims.ear_width *= scale;
  197. dims.ear_height *= scale;
  198. dims.ear_thickness *= scale;
  199. dims.leg_length *= scale;
  200. dims.leg_radius *= scale;
  201. dims.foot_radius *= scale;
  202. dims.tail_length *= scale;
  203. dims.tusk_length *= scale;
  204. dims.tusk_radius *= scale;
  205. dims.howdah_width *= scale;
  206. dims.howdah_length *= scale;
  207. dims.howdah_height *= scale;
  208. dims.barrel_center_y *= scale;
  209. dims.idle_bob_amplitude *= scale;
  210. dims.move_bob_amplitude *= scale;
  211. }
  212. class ElephantRendererBase {
  213. public:
  214. virtual ~ElephantRendererBase() = default;
  215. void render(const DrawContext &ctx, const AnimationInputs &anim,
  216. ElephantProfile &profile,
  217. const HowdahAttachmentFrame *shared_howdah,
  218. const ElephantMotionSample *shared_motion, ISubmitter &out,
  219. HorseLOD lod) const;
  220. void render(const DrawContext &ctx, const AnimationInputs &anim,
  221. ElephantProfile &profile,
  222. const HowdahAttachmentFrame *shared_howdah,
  223. const ElephantMotionSample *shared_motion, ISubmitter &out) const;
  224. void render_simplified(const DrawContext &ctx, const AnimationInputs &anim,
  225. ElephantProfile &profile,
  226. const HowdahAttachmentFrame *shared_howdah,
  227. const ElephantMotionSample *shared_motion,
  228. ISubmitter &out) const;
  229. void render_minimal(const DrawContext &ctx, ElephantProfile &profile,
  230. const ElephantMotionSample *shared_motion,
  231. ISubmitter &out) const;
  232. protected:
  233. virtual void draw_howdah(const DrawContext &, const AnimationInputs &,
  234. ElephantProfile &, const HowdahAttachmentFrame &,
  235. float, float, const ElephantBodyFrames &,
  236. ISubmitter &) const {}
  237. private:
  238. void render_full(const DrawContext &ctx, const AnimationInputs &anim,
  239. ElephantProfile &profile,
  240. const HowdahAttachmentFrame *shared_howdah,
  241. const ElephantMotionSample *shared_motion,
  242. ISubmitter &out) const;
  243. };
  244. inline auto calculate_elephant_lod(float distance) -> HorseLOD {
  245. const auto &settings = Render::GraphicsSettings::instance();
  246. if (distance < settings.horse_full_detail_distance()) {
  247. return HorseLOD::Full;
  248. }
  249. if (distance < settings.horse_reduced_detail_distance()) {
  250. return HorseLOD::Reduced;
  251. }
  252. if (distance < settings.horse_minimal_detail_distance()) {
  253. return HorseLOD::Minimal;
  254. }
  255. return HorseLOD::Billboard;
  256. }
  257. } // namespace Render::GL