horse_spearman_renderer_base.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #include "horse_spearman_renderer_base.h"
  2. #include "../equipment/equipment_registry.h"
  3. #include "../equipment/weapons/shield_renderer.h"
  4. #include "../equipment/weapons/spear_renderer.h"
  5. #include "../humanoid/humanoid_math.h"
  6. #include "../humanoid/humanoid_specs.h"
  7. #include "../humanoid/mounted_pose_controller.h"
  8. #include "../palette.h"
  9. #include "../../game/core/component.h"
  10. #include "../../game/core/entity.h"
  11. #include "../../game/systems/nation_id.h"
  12. #include "mounted_knight_pose.h"
  13. #include "renderer_constants.h"
  14. #include <QVector3D>
  15. #include <algorithm>
  16. #include <cmath>
  17. #include <utility>
  18. namespace Render::GL {
  19. namespace {
  20. constexpr QVector3D k_default_proportion_scale{0.80F, 0.88F, 0.88F};
  21. }
  22. HorseSpearmanRendererBase::HorseSpearmanRendererBase(
  23. HorseSpearmanRendererConfig config)
  24. : m_config(std::move(config)) {
  25. m_config.has_spear =
  26. m_config.has_spear && !m_config.spear_equipment_id.empty();
  27. if (!m_config.has_spear) {
  28. m_config.spear_equipment_id.clear();
  29. }
  30. m_config.has_shield =
  31. m_config.has_shield && !m_config.shield_equipment_id.empty();
  32. if (!m_config.has_shield) {
  33. m_config.shield_equipment_id.clear();
  34. }
  35. m_horseRenderer.set_attachments(m_config.horse_attachments);
  36. cache_equipment();
  37. }
  38. auto HorseSpearmanRendererBase::get_proportion_scaling() const -> QVector3D {
  39. return QVector3D{0.78F, 0.84F, 0.84F};
  40. }
  41. auto HorseSpearmanRendererBase::get_mount_scale() const -> float {
  42. return m_config.mount_scale;
  43. }
  44. void HorseSpearmanRendererBase::adjust_variation(
  45. const DrawContext &, uint32_t, VariationParams &variation) const {
  46. variation.height_scale = 0.90F;
  47. variation.bulk_scale = 0.70F;
  48. variation.stance_width = 0.60F;
  49. variation.arm_swing_amp = 0.40F;
  50. variation.walk_speed_mult = 1.0F;
  51. variation.posture_slump = 0.0F;
  52. variation.shoulder_tilt = 0.0F;
  53. }
  54. void HorseSpearmanRendererBase::get_variant(const DrawContext &ctx,
  55. uint32_t seed,
  56. HumanoidVariant &v) const {
  57. QVector3D const team_tint = resolve_team_tint(ctx);
  58. v.palette = make_humanoid_palette(team_tint, seed);
  59. }
  60. void HorseSpearmanRendererBase::apply_riding_animation(
  61. MountedPoseController &mounted_controller, MountedAttachmentFrame &mount,
  62. const HumanoidAnimationContext &anim_ctx, HumanoidPose &pose,
  63. const HorseDimensions &dims, const ReinState &reins) const {
  64. (void)dims;
  65. (void)reins;
  66. const AnimationInputs &anim = anim_ctx.inputs;
  67. float const speed_norm = anim_ctx.locomotion_normalized_speed();
  68. bool const is_charging = speed_norm > 0.65F;
  69. if (anim.is_attacking && anim.is_melee) {
  70. if (is_charging) {
  71. mounted_controller.ridingCharging(mount, 1.0F);
  72. mounted_controller.holdSpearMounted(mount, SpearGrip::COUCHED);
  73. pose.neck_base -= mount.seat_forward * 0.03F;
  74. } else {
  75. float const attack_phase =
  76. std::fmod(anim.time * SPEARMAN_INV_ATTACK_CYCLE_TIME, 1.0F);
  77. mounted_controller.ridingSpearThrust(mount, attack_phase);
  78. }
  79. } else {
  80. mounted_controller.ridingIdle(mount);
  81. }
  82. }
  83. void HorseSpearmanRendererBase::draw_equipment(
  84. const DrawContext &ctx, const HumanoidVariant &v, const HumanoidPose &pose,
  85. const HumanoidAnimationContext &anim_ctx, ISubmitter &out) const {
  86. uint32_t horse_seed = 0U;
  87. if (ctx.entity != nullptr) {
  88. horse_seed = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ctx.entity) &
  89. 0xFFFFFFFFU);
  90. }
  91. float spear_length = 1.15F + (hash_01(horse_seed ^ 0xABCDU) - 0.5F) * 0.10F;
  92. float spear_shaft_radius =
  93. 0.018F + (hash_01(horse_seed ^ 0x7777U) - 0.5F) * 0.003F;
  94. if (m_config.has_spear && m_cached_spear) {
  95. SpearRenderConfig spear_config;
  96. spear_config.shaft_color =
  97. v.palette.leather * QVector3D(0.85F, 0.75F, 0.65F);
  98. spear_config.spearhead_color = m_config.metal_color;
  99. spear_config.spear_length = spear_length;
  100. spear_config.shaft_radius = spear_shaft_radius;
  101. spear_config.spearhead_length = 0.18F;
  102. if (auto *spear_renderer =
  103. dynamic_cast<SpearRenderer *>(m_cached_spear.get())) {
  104. spear_renderer->set_config(spear_config);
  105. }
  106. m_cached_spear->render(ctx, pose.body_frames, v.palette, anim_ctx, out);
  107. }
  108. if (m_config.has_shield && m_cached_shield) {
  109. m_cached_shield->render(ctx, pose.body_frames, v.palette, anim_ctx, out);
  110. }
  111. if (m_config.has_shoulder && m_cached_shoulder) {
  112. m_cached_shoulder->render(ctx, pose.body_frames, v.palette, anim_ctx, out);
  113. }
  114. }
  115. void HorseSpearmanRendererBase::draw_helmet(const DrawContext &ctx,
  116. const HumanoidVariant &v,
  117. const HumanoidPose &pose,
  118. ISubmitter &out) const {
  119. if (m_config.helmet_equipment_id.empty()) {
  120. return;
  121. }
  122. if (m_cached_helmet) {
  123. HumanoidAnimationContext anim_ctx{};
  124. BodyFrames frames = pose.body_frames;
  125. if (ctx.entity != nullptr) {
  126. auto *move = ctx.entity->get_component<Engine::Core::MovementComponent>();
  127. if (move != nullptr) {
  128. float speed_sq = move->vx * move->vx + move->vz * move->vz;
  129. if (speed_sq > 0.0001F && m_config.helmet_offset_moving > 0.0F) {
  130. frames.head.origin +=
  131. frames.head.forward * m_config.helmet_offset_moving;
  132. }
  133. }
  134. }
  135. m_cached_helmet->render(ctx, frames, v.palette, anim_ctx, out);
  136. }
  137. }
  138. void HorseSpearmanRendererBase::draw_armor(const DrawContext &ctx,
  139. const HumanoidVariant &v,
  140. const HumanoidPose &pose,
  141. const HumanoidAnimationContext &anim,
  142. ISubmitter &out) const {
  143. if (m_config.armor_equipment_id.empty()) {
  144. return;
  145. }
  146. if (m_cached_armor) {
  147. m_cached_armor->render(ctx, pose.body_frames, v.palette, anim, out);
  148. }
  149. }
  150. void HorseSpearmanRendererBase::cache_equipment() {
  151. auto &registry = EquipmentRegistry::instance();
  152. if (!m_config.spear_equipment_id.empty()) {
  153. m_cached_spear =
  154. registry.get(EquipmentCategory::Weapon, m_config.spear_equipment_id);
  155. }
  156. if (!m_config.shield_equipment_id.empty()) {
  157. m_cached_shield =
  158. registry.get(EquipmentCategory::Weapon, m_config.shield_equipment_id);
  159. }
  160. if (!m_config.shoulder_equipment_id.empty()) {
  161. m_cached_shoulder =
  162. registry.get(EquipmentCategory::Armor, m_config.shoulder_equipment_id);
  163. }
  164. if (!m_config.helmet_equipment_id.empty()) {
  165. m_cached_helmet =
  166. registry.get(EquipmentCategory::Helmet, m_config.helmet_equipment_id);
  167. }
  168. if (!m_config.armor_equipment_id.empty()) {
  169. m_cached_armor =
  170. registry.get(EquipmentCategory::Armor, m_config.armor_equipment_id);
  171. }
  172. }
  173. auto HorseSpearmanRendererBase::resolve_shader_key(const DrawContext &ctx) const
  174. -> QString {
  175. std::string nation;
  176. if (ctx.entity != nullptr) {
  177. if (auto *unit = ctx.entity->get_component<Engine::Core::UnitComponent>()) {
  178. nation = Game::Systems::nation_id_to_string(unit->nation_id);
  179. }
  180. }
  181. if (!nation.empty()) {
  182. return QString::fromStdString(std::string("horse_spearman_") + nation);
  183. }
  184. return QStringLiteral("horse_spearman");
  185. }
  186. } // namespace Render::GL