horse_equipment_renderers_test.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. #include "render/entity/registry.h"
  2. #include "render/equipment/horse/armor/champion_renderer.h"
  3. #include "render/equipment/horse/armor/crupper_renderer.h"
  4. #include "render/equipment/horse/armor/leather_barding_renderer.h"
  5. #include "render/equipment/horse/armor/scale_barding_renderer.h"
  6. #include "render/equipment/horse/decorations/plume_renderer.h"
  7. #include "render/equipment/horse/decorations/saddle_bag_renderer.h"
  8. #include "render/equipment/horse/decorations/tail_ribbon_renderer.h"
  9. #include "render/equipment/horse/i_horse_equipment_renderer.h"
  10. #include "render/equipment/horse/saddles/carthage_saddle_renderer.h"
  11. #include "render/equipment/horse/saddles/light_cavalry_saddle_renderer.h"
  12. #include "render/equipment/horse/saddles/roman_saddle_renderer.h"
  13. #include "render/equipment/horse/tack/blanket_renderer.h"
  14. #include "render/equipment/horse/tack/bridle_renderer.h"
  15. #include "render/equipment/horse/tack/reins_renderer.h"
  16. #include "render/equipment/horse/tack/stirrup_renderer.h"
  17. #include <algorithm>
  18. #include <gtest/gtest.h>
  19. #include <memory>
  20. #include <vector>
  21. using namespace Render::GL;
  22. namespace {
  23. class MockSubmitter : public ISubmitter {
  24. public:
  25. void mesh(Mesh * /*mesh*/, const QMatrix4x4 & /*model*/,
  26. const QVector3D & /*color*/, Texture * /*tex*/ = nullptr,
  27. float /*alpha*/ = 1.0F, int /*materialId*/ = 0) override {
  28. mesh_count++;
  29. }
  30. void cylinder(const QVector3D & /*start*/, const QVector3D & /*end*/,
  31. float /*radius*/, const QVector3D & /*color*/,
  32. float /*alpha*/ = 1.0F) override {
  33. cylinder_count++;
  34. }
  35. void selection_ring(const QMatrix4x4 & /*model*/, float /*alphaInner*/,
  36. float /*alphaOuter*/,
  37. const QVector3D & /*color*/) override {}
  38. void grid(const QMatrix4x4 & /*model*/, const QVector3D & /*color*/,
  39. float /*cellSize*/, float /*thickness*/,
  40. float /*extent*/) override {}
  41. void selection_smoke(const QMatrix4x4 & /*model*/,
  42. const QVector3D & /*color*/,
  43. float /*baseAlpha*/ = 0.15F) override {}
  44. void healing_beam(const QVector3D & /*start*/, const QVector3D & /*end*/,
  45. const QVector3D & /*color*/, float /*progress*/,
  46. float /*beam_width*/, float /*intensity*/,
  47. float /*time*/) override {}
  48. void healer_aura(const QVector3D & /*position*/, const QVector3D & /*color*/,
  49. float /*radius*/, float /*intensity*/,
  50. float /*time*/) override {}
  51. void combat_dust(const QVector3D & /*position*/, const QVector3D & /*color*/,
  52. float /*radius*/, float /*intensity*/,
  53. float /*time*/) override {}
  54. void stone_impact(const QVector3D & /*position*/, const QVector3D & /*color*/,
  55. float /*radius*/, float /*intensity*/,
  56. float /*time*/) override {}
  57. void mode_indicator(const QMatrix4x4 & /*model*/, int /*mode_type*/,
  58. const QVector3D & /*color*/, float /*alpha*/) override {}
  59. int mesh_count = 0;
  60. int cylinder_count = 0;
  61. };
  62. class CapturingSubmitter : public MockSubmitter {
  63. public:
  64. struct CylinderCall {
  65. QVector3D start;
  66. QVector3D end;
  67. float radius;
  68. };
  69. void cylinder(const QVector3D &start, const QVector3D &end, float radius,
  70. const QVector3D &color, float alpha = 1.0F) override {
  71. cylinders.push_back({start, end, radius});
  72. MockSubmitter::cylinder(start, end, radius, color, alpha);
  73. }
  74. std::vector<CylinderCall> cylinders;
  75. };
  76. } // namespace
  77. class HorseEquipmentRenderersTest : public ::testing::Test {
  78. protected:
  79. void SetUp() override {
  80. ctx.model.setToIdentity();
  81. ctx.entity = nullptr;
  82. frames.back_center.origin = QVector3D(0.0F, 1.0F, 0.0F);
  83. frames.back_center.right = QVector3D(1.0F, 0.0F, 0.0F);
  84. frames.back_center.up = QVector3D(0.0F, 1.0F, 0.0F);
  85. frames.back_center.forward = QVector3D(0.0F, 0.0F, 1.0F);
  86. frames.head.origin = QVector3D(0.0F, 1.5F, 1.0F);
  87. frames.head.right = QVector3D(1.0F, 0.0F, 0.0F);
  88. frames.head.up = QVector3D(0.0F, 1.0F, 0.0F);
  89. frames.head.forward = QVector3D(0.0F, 0.0F, 1.0F);
  90. frames.muzzle.origin = QVector3D(0.0F, 1.4F, 1.2F);
  91. frames.muzzle.right = QVector3D(1.0F, 0.0F, 0.0F);
  92. frames.muzzle.up = QVector3D(0.0F, 1.0F, 0.0F);
  93. frames.muzzle.forward = QVector3D(0.0F, 0.0F, 1.0F);
  94. frames.chest.origin = QVector3D(0.0F, 0.9F, 0.5F);
  95. frames.chest.right = QVector3D(1.0F, 0.0F, 0.0F);
  96. frames.chest.up = QVector3D(0.0F, 1.0F, 0.0F);
  97. frames.chest.forward = QVector3D(0.0F, 0.0F, 1.0F);
  98. frames.barrel.origin = QVector3D(0.0F, 0.8F, 0.0F);
  99. frames.barrel.right = QVector3D(1.0F, 0.0F, 0.0F);
  100. frames.barrel.up = QVector3D(0.0F, 1.0F, 0.0F);
  101. frames.barrel.forward = QVector3D(0.0F, 0.0F, 1.0F);
  102. frames.rump.origin = QVector3D(0.0F, 0.9F, -0.5F);
  103. frames.rump.right = QVector3D(1.0F, 0.0F, 0.0F);
  104. frames.rump.up = QVector3D(0.0F, 1.0F, 0.0F);
  105. frames.rump.forward = QVector3D(0.0F, 0.0F, 1.0F);
  106. frames.tail_base.origin = QVector3D(0.0F, 1.0F, -0.8F);
  107. frames.tail_base.right = QVector3D(1.0F, 0.0F, 0.0F);
  108. frames.tail_base.up = QVector3D(0.0F, 1.0F, 0.0F);
  109. frames.tail_base.forward = QVector3D(0.0F, 0.0F, 1.0F);
  110. variant.saddle_color = QVector3D(0.6F, 0.4F, 0.2F);
  111. variant.blanket_color = QVector3D(0.8F, 0.1F, 0.1F);
  112. variant.tack_color = QVector3D(0.3F, 0.2F, 0.1F);
  113. anim.time = 0.0F;
  114. anim.phase = 0.0F;
  115. anim.bob = 0.0F;
  116. anim.is_moving = false;
  117. anim.rider_intensity = 0.0F;
  118. }
  119. DrawContext ctx;
  120. HorseBodyFrames frames;
  121. HorseVariant variant;
  122. HorseAnimationContext anim;
  123. };
  124. TEST_F(HorseEquipmentRenderersTest, RomanSaddleRendererProducesMeshes) {
  125. RomanSaddleRenderer renderer;
  126. MockSubmitter submitter;
  127. renderer.render(ctx, frames, variant, anim, submitter);
  128. EXPECT_GT(submitter.mesh_count, 0);
  129. }
  130. TEST_F(HorseEquipmentRenderersTest, CarthageSaddleRendererProducesMeshes) {
  131. CarthageSaddleRenderer renderer;
  132. MockSubmitter submitter;
  133. renderer.render(ctx, frames, variant, anim, submitter);
  134. EXPECT_GT(submitter.mesh_count, 0);
  135. }
  136. TEST_F(HorseEquipmentRenderersTest, LightCavalrySaddleRendererProducesMeshes) {
  137. LightCavalrySaddleRenderer renderer;
  138. MockSubmitter submitter;
  139. renderer.render(ctx, frames, variant, anim, submitter);
  140. EXPECT_GT(submitter.mesh_count, 0);
  141. }
  142. TEST_F(HorseEquipmentRenderersTest, BridleRendererProducesCylinders) {
  143. BridleRenderer renderer;
  144. MockSubmitter submitter;
  145. renderer.render(ctx, frames, variant, anim, submitter);
  146. EXPECT_GT(submitter.cylinder_count, 0);
  147. }
  148. TEST_F(HorseEquipmentRenderersTest, StirrupRendererProducesBoth) {
  149. StirrupRenderer renderer;
  150. MockSubmitter submitter;
  151. renderer.render(ctx, frames, variant, anim, submitter);
  152. EXPECT_GT(submitter.cylinder_count, 0);
  153. EXPECT_GT(submitter.mesh_count, 0);
  154. }
  155. TEST_F(HorseEquipmentRenderersTest, BlanketRendererProducesMeshes) {
  156. BlanketRenderer renderer;
  157. MockSubmitter submitter;
  158. renderer.render(ctx, frames, variant, anim, submitter);
  159. EXPECT_GT(submitter.mesh_count, 0);
  160. }
  161. TEST_F(HorseEquipmentRenderersTest, ReinsRendererProducesCylinders) {
  162. ReinsRenderer renderer;
  163. MockSubmitter submitter;
  164. renderer.render(ctx, frames, variant, anim, submitter);
  165. EXPECT_GT(submitter.cylinder_count, 0);
  166. }
  167. TEST_F(HorseEquipmentRenderersTest, ReinsRendererRespectsModelTransform) {
  168. CapturingSubmitter submitter;
  169. ctx.model.translate(2.0F, 1.0F, -3.0F);
  170. ReinsRenderer renderer;
  171. renderer.render(ctx, frames, variant, anim, submitter);
  172. ASSERT_FALSE(submitter.cylinders.empty());
  173. const HorseAttachmentFrame &muzzle = frames.muzzle;
  174. QVector3D const expected_local =
  175. muzzle.origin + muzzle.right * 0.10F + muzzle.forward * 0.10F;
  176. QVector3D const expected_world = ctx.model.map(expected_local);
  177. QVector3D const actual = submitter.cylinders.front().start;
  178. EXPECT_NEAR(actual.x(), expected_world.x(), 1e-4F);
  179. EXPECT_NEAR(actual.y(), expected_world.y(), 1e-4F);
  180. EXPECT_NEAR(actual.z(), expected_world.z(), 1e-4F);
  181. }
  182. TEST_F(HorseEquipmentRenderersTest, ReinsRendererAddsCrossConnections) {
  183. CapturingSubmitter submitter;
  184. ReinsRenderer renderer;
  185. renderer.render(ctx, frames, variant, anim, submitter);
  186. ASSERT_GE(static_cast<int>(submitter.cylinders.size()), 6);
  187. auto const connectors = std::count_if(
  188. submitter.cylinders.begin(), submitter.cylinders.end(),
  189. [](const auto &c) { return c.start.x() * c.end.x() < 0.0F; });
  190. EXPECT_GE(connectors, 2);
  191. ASSERT_FALSE(submitter.cylinders.empty());
  192. EXPECT_NEAR(submitter.cylinders.front().radius, 0.004F, 1e-4F);
  193. }
  194. TEST_F(HorseEquipmentRenderersTest, ScaleBardingRendererProducesMeshes) {
  195. ScaleBardingRenderer renderer;
  196. MockSubmitter submitter;
  197. renderer.render(ctx, frames, variant, anim, submitter);
  198. EXPECT_GT(submitter.mesh_count, 0);
  199. }
  200. TEST_F(HorseEquipmentRenderersTest, LeatherBardingRendererProducesMeshes) {
  201. LeatherBardingRenderer renderer;
  202. MockSubmitter submitter;
  203. renderer.render(ctx, frames, variant, anim, submitter);
  204. EXPECT_GT(submitter.mesh_count, 0);
  205. }
  206. TEST_F(HorseEquipmentRenderersTest, ChampionRendererProducesMeshes) {
  207. ChampionRenderer renderer;
  208. MockSubmitter submitter;
  209. renderer.render(ctx, frames, variant, anim, submitter);
  210. EXPECT_GT(submitter.mesh_count, 0);
  211. }
  212. TEST_F(HorseEquipmentRenderersTest, CrupperRendererProducesMeshes) {
  213. CrupperRenderer renderer;
  214. MockSubmitter submitter;
  215. renderer.render(ctx, frames, variant, anim, submitter);
  216. EXPECT_GT(submitter.mesh_count, 0);
  217. }
  218. TEST_F(HorseEquipmentRenderersTest, PlumeRendererProducesCylinders) {
  219. PlumeRenderer renderer;
  220. MockSubmitter submitter;
  221. renderer.render(ctx, frames, variant, anim, submitter);
  222. EXPECT_GT(submitter.cylinder_count, 0);
  223. }
  224. TEST_F(HorseEquipmentRenderersTest, TailRibbonRendererProducesBoth) {
  225. TailRibbonRenderer renderer;
  226. MockSubmitter submitter;
  227. renderer.render(ctx, frames, variant, anim, submitter);
  228. EXPECT_GT(submitter.cylinder_count, 0);
  229. EXPECT_GT(submitter.mesh_count, 0);
  230. }
  231. TEST_F(HorseEquipmentRenderersTest, SaddleBagRendererProducesBoth) {
  232. SaddleBagRenderer renderer;
  233. MockSubmitter submitter;
  234. renderer.render(ctx, frames, variant, anim, submitter);
  235. EXPECT_GT(submitter.cylinder_count, 0);
  236. EXPECT_GT(submitter.mesh_count, 0);
  237. }