helmet_renderers_test.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. #include "render/equipment/equipment_registry.h"
  2. #include "render/equipment/helmets/carthage_heavy_helmet.h"
  3. #include "render/equipment/helmets/headwrap.h"
  4. #include "render/humanoid/rig.h"
  5. #include "render/palette.h"
  6. #include <gtest/gtest.h>
  7. #include <memory>
  8. using namespace Render::GL;
  9. namespace {
  10. // Mock submitter for testing
  11. class MockSubmitter : public ISubmitter {
  12. public:
  13. void mesh(Mesh * /*mesh*/, const QMatrix4x4 & /*transform*/,
  14. const QVector3D & /*color*/, Texture * /*texture*/, float /*alpha*/,
  15. int /*materialId*/) override {
  16. mesh_count++;
  17. }
  18. void cylinder(const QVector3D & /*start*/, const QVector3D & /*end*/,
  19. float /*radius*/, const QVector3D & /*color*/,
  20. float /*alpha*/) override {
  21. cylinder_count++;
  22. }
  23. void selection_ring(const QMatrix4x4 & /*model*/, float /*alphaInner*/,
  24. float /*alphaOuter*/,
  25. const QVector3D & /*color*/) override {
  26. // Not used in helmet rendering
  27. }
  28. void grid(const QMatrix4x4 & /*model*/, const QVector3D & /*color*/,
  29. float /*cellSize*/, float /*thickness*/,
  30. float /*extent*/) override {
  31. // Not used in helmet rendering
  32. }
  33. void selection_smoke(const QMatrix4x4 & /*model*/,
  34. const QVector3D & /*color*/,
  35. float /*baseAlpha*/) override {
  36. // Not used in helmet rendering
  37. }
  38. void healing_beam(const QVector3D & /*start*/, const QVector3D & /*end*/,
  39. const QVector3D & /*color*/, float /*progress*/,
  40. float /*beam_width*/, float /*intensity*/,
  41. float /*time*/) override {
  42. // Not used in helmet rendering
  43. }
  44. void healer_aura(const QVector3D & /*position*/, const QVector3D & /*color*/,
  45. float /*radius*/, float /*intensity*/,
  46. float /*time*/) override {
  47. // Not used in helmet rendering
  48. }
  49. void combat_dust(const QVector3D & /*position*/, const QVector3D & /*color*/,
  50. float /*radius*/, float /*intensity*/,
  51. float /*time*/) override {
  52. // Not used in helmet rendering
  53. }
  54. void stone_impact(const QVector3D & /*position*/, const QVector3D & /*color*/,
  55. float /*radius*/, float /*intensity*/,
  56. float /*time*/) override {
  57. // Not used in helmet rendering
  58. }
  59. void mode_indicator(const QMatrix4x4 & /*model*/, int /*mode_type*/,
  60. const QVector3D & /*color*/, float /*alpha*/) override {
  61. // Not used in helmet rendering
  62. }
  63. int mesh_count = 0;
  64. int cylinder_count = 0;
  65. };
  66. // Helper to create a basic DrawContext
  67. DrawContext createTestContext() {
  68. DrawContext ctx;
  69. ctx.model.setToIdentity();
  70. ctx.backend = nullptr;
  71. ctx.entity = nullptr;
  72. return ctx;
  73. }
  74. // Helper to create basic body frames
  75. BodyFrames createTestFrames() {
  76. using HP = HumanProportions;
  77. BodyFrames frames;
  78. float const head_center_y = HP::HEAD_CENTER_Y;
  79. frames.head.origin = QVector3D(0.0F, head_center_y, 0.0F);
  80. frames.head.right = QVector3D(1.0F, 0.0F, 0.0F);
  81. frames.head.up = QVector3D(0.0F, 1.0F, 0.0F);
  82. frames.head.forward = QVector3D(0.0F, 0.0F, 1.0F);
  83. frames.head.radius = HP::HEAD_RADIUS * 1.05F;
  84. return frames;
  85. }
  86. // Helper to create basic palette
  87. HumanoidPalette createTestPalette() {
  88. HumanoidPalette palette;
  89. palette.skin = QVector3D(0.8F, 0.6F, 0.5F);
  90. palette.cloth = QVector3D(0.7F, 0.3F, 0.2F);
  91. palette.leather = QVector3D(0.4F, 0.3F, 0.2F);
  92. palette.leather_dark = QVector3D(0.3F, 0.2F, 0.1F);
  93. palette.metal = QVector3D(0.7F, 0.7F, 0.7F);
  94. palette.wood = QVector3D(0.5F, 0.3F, 0.2F);
  95. return palette;
  96. }
  97. } // namespace
  98. class HelmetRenderersTest : public ::testing::Test {
  99. protected:
  100. void SetUp() override {
  101. // Ensure built-in equipment is registered
  102. register_built_in_equipment();
  103. ctx = createTestContext();
  104. frames = createTestFrames();
  105. palette = createTestPalette();
  106. anim.inputs.time = 0.0F;
  107. anim.inputs.is_moving = false;
  108. anim.inputs.is_attacking = false;
  109. anim.inputs.is_melee = false;
  110. }
  111. DrawContext ctx;
  112. BodyFrames frames;
  113. HumanoidPalette palette;
  114. HumanoidAnimationContext anim;
  115. MockSubmitter submitter;
  116. };
  117. TEST_F(HelmetRenderersTest, CarthageHeavyHelmetRendersWithValidFrames) {
  118. CarthageHeavyHelmetRenderer helmet;
  119. helmet.render(ctx, frames, palette, anim, submitter);
  120. // Carthage heavy helmet should render multiple mesh components
  121. EXPECT_GT(submitter.mesh_count, 0);
  122. }
  123. TEST_F(HelmetRenderersTest, CarthageHeavyHelmetHandlesZeroHeadRadius) {
  124. CarthageHeavyHelmetRenderer helmet;
  125. frames.head.radius = 0.0F;
  126. helmet.render(ctx, frames, palette, anim, submitter);
  127. // Should not render anything when head radius is zero
  128. EXPECT_EQ(submitter.mesh_count, 0);
  129. }
  130. TEST_F(HelmetRenderersTest, HeadwrapRendersWithValidFrames) {
  131. HeadwrapRenderer headwrap;
  132. headwrap.render(ctx, frames, palette, anim, submitter);
  133. // Headwrap should render band, knot, and tail
  134. EXPECT_GT(submitter.mesh_count, 0);
  135. }
  136. TEST_F(HelmetRenderersTest, HeadwrapHandlesZeroHeadRadius) {
  137. HeadwrapRenderer headwrap;
  138. frames.head.radius = 0.0F;
  139. headwrap.render(ctx, frames, palette, anim, submitter);
  140. // Should not render anything when head radius is zero
  141. EXPECT_EQ(submitter.mesh_count, 0);
  142. }
  143. TEST_F(HelmetRenderersTest, HelmetsRegisteredInEquipmentRegistry) {
  144. auto &registry = EquipmentRegistry::instance();
  145. // Verify Carthage heavy helmet is registered
  146. EXPECT_TRUE(registry.has(EquipmentCategory::Helmet, "carthage_heavy"));
  147. auto carthage_heavy =
  148. registry.get(EquipmentCategory::Helmet, "carthage_heavy");
  149. ASSERT_NE(carthage_heavy, nullptr);
  150. // Verify headwrap is registered
  151. EXPECT_TRUE(registry.has(EquipmentCategory::Helmet, "headwrap"));
  152. auto headwrap = registry.get(EquipmentCategory::Helmet, "headwrap");
  153. ASSERT_NE(headwrap, nullptr);
  154. }
  155. TEST_F(HelmetRenderersTest, CarthageHeavyHelmetFromRegistryRenders) {
  156. auto &registry = EquipmentRegistry::instance();
  157. auto helmet = registry.get(EquipmentCategory::Helmet, "carthage_heavy");
  158. ASSERT_NE(helmet, nullptr);
  159. helmet->render(ctx, frames, palette, anim, submitter);
  160. EXPECT_GT(submitter.mesh_count, 0);
  161. }
  162. TEST_F(HelmetRenderersTest, HeadwrapFromRegistryRenders) {
  163. auto &registry = EquipmentRegistry::instance();
  164. auto headwrap = registry.get(EquipmentCategory::Helmet, "headwrap");
  165. ASSERT_NE(headwrap, nullptr);
  166. headwrap->render(ctx, frames, palette, anim, submitter);
  167. EXPECT_GT(submitter.mesh_count, 0);
  168. }
  169. TEST_F(HelmetRenderersTest, HelmetsUseHeadFrameCoordinates) {
  170. // Test that helmets use head frame's coordinate system
  171. frames.head.origin = QVector3D(1.0F, 2.0F, 3.0F);
  172. frames.head.right = QVector3D(0.0F, 1.0F, 0.0F); // Rotated frame
  173. frames.head.up = QVector3D(-1.0F, 0.0F, 0.0F);
  174. frames.head.forward = QVector3D(0.0F, 0.0F, 1.0F);
  175. frames.head.radius = 0.12F;
  176. CarthageHeavyHelmetRenderer helmet;
  177. MockSubmitter submitter1;
  178. helmet.render(ctx, frames, palette, anim, submitter1);
  179. // Helmet should still render even with rotated frame
  180. EXPECT_GT(submitter1.mesh_count, 0);
  181. HeadwrapRenderer headwrap;
  182. MockSubmitter submitter2;
  183. headwrap.render(ctx, frames, palette, anim, submitter2);
  184. EXPECT_GT(submitter2.mesh_count, 0);
  185. }