helmet_renderers_test.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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 selectionRing(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 selectionSmoke(const QMatrix4x4 & /*model*/, const QVector3D & /*color*/,
  34. float /*baseAlpha*/) override {
  35. // Not used in helmet rendering
  36. }
  37. int mesh_count = 0;
  38. int cylinder_count = 0;
  39. };
  40. // Helper to create a basic DrawContext
  41. DrawContext createTestContext() {
  42. DrawContext ctx;
  43. ctx.model.setToIdentity();
  44. ctx.backend = nullptr;
  45. ctx.entity = nullptr;
  46. return ctx;
  47. }
  48. // Helper to create basic body frames
  49. BodyFrames createTestFrames() {
  50. using HP = HumanProportions;
  51. BodyFrames frames;
  52. float const head_center_y = HP::HEAD_CENTER_Y;
  53. frames.head.origin = QVector3D(0.0F, head_center_y, 0.0F);
  54. frames.head.right = QVector3D(1.0F, 0.0F, 0.0F);
  55. frames.head.up = QVector3D(0.0F, 1.0F, 0.0F);
  56. frames.head.forward = QVector3D(0.0F, 0.0F, 1.0F);
  57. frames.head.radius = HP::HEAD_RADIUS * 1.05F;
  58. return frames;
  59. }
  60. // Helper to create basic palette
  61. HumanoidPalette createTestPalette() {
  62. HumanoidPalette palette;
  63. palette.skin = QVector3D(0.8F, 0.6F, 0.5F);
  64. palette.cloth = QVector3D(0.7F, 0.3F, 0.2F);
  65. palette.leather = QVector3D(0.4F, 0.3F, 0.2F);
  66. palette.leatherDark = QVector3D(0.3F, 0.2F, 0.1F);
  67. palette.metal = QVector3D(0.7F, 0.7F, 0.7F);
  68. palette.wood = QVector3D(0.5F, 0.3F, 0.2F);
  69. return palette;
  70. }
  71. } // namespace
  72. class HelmetRenderersTest : public ::testing::Test {
  73. protected:
  74. void SetUp() override {
  75. // Ensure built-in equipment is registered
  76. registerBuiltInEquipment();
  77. ctx = createTestContext();
  78. frames = createTestFrames();
  79. palette = createTestPalette();
  80. anim.inputs.time = 0.0F;
  81. anim.inputs.is_moving = false;
  82. anim.inputs.is_attacking = false;
  83. anim.inputs.is_melee = false;
  84. }
  85. DrawContext ctx;
  86. BodyFrames frames;
  87. HumanoidPalette palette;
  88. HumanoidAnimationContext anim;
  89. MockSubmitter submitter;
  90. };
  91. TEST_F(HelmetRenderersTest, CarthageHeavyHelmetRendersWithValidFrames) {
  92. CarthageHeavyHelmetRenderer helmet;
  93. helmet.render(ctx, frames, palette, anim, submitter);
  94. // Carthage heavy helmet should render multiple mesh components
  95. EXPECT_GT(submitter.mesh_count, 0);
  96. }
  97. TEST_F(HelmetRenderersTest, CarthageHeavyHelmetHandlesZeroHeadRadius) {
  98. CarthageHeavyHelmetRenderer helmet;
  99. frames.head.radius = 0.0F;
  100. helmet.render(ctx, frames, palette, anim, submitter);
  101. // Should not render anything when head radius is zero
  102. EXPECT_EQ(submitter.mesh_count, 0);
  103. }
  104. TEST_F(HelmetRenderersTest, HeadwrapRendersWithValidFrames) {
  105. HeadwrapRenderer headwrap;
  106. headwrap.render(ctx, frames, palette, anim, submitter);
  107. // Headwrap should render band, knot, and tail
  108. EXPECT_GT(submitter.mesh_count, 0);
  109. }
  110. TEST_F(HelmetRenderersTest, HeadwrapHandlesZeroHeadRadius) {
  111. HeadwrapRenderer headwrap;
  112. frames.head.radius = 0.0F;
  113. headwrap.render(ctx, frames, palette, anim, submitter);
  114. // Should not render anything when head radius is zero
  115. EXPECT_EQ(submitter.mesh_count, 0);
  116. }
  117. TEST_F(HelmetRenderersTest, HelmetsRegisteredInEquipmentRegistry) {
  118. auto &registry = EquipmentRegistry::instance();
  119. // Verify Carthage heavy helmet is registered
  120. EXPECT_TRUE(registry.has(EquipmentCategory::Helmet, "carthage_heavy"));
  121. auto carthage_heavy =
  122. registry.get(EquipmentCategory::Helmet, "carthage_heavy");
  123. ASSERT_NE(carthage_heavy, nullptr);
  124. // Verify headwrap is registered
  125. EXPECT_TRUE(registry.has(EquipmentCategory::Helmet, "headwrap"));
  126. auto headwrap = registry.get(EquipmentCategory::Helmet, "headwrap");
  127. ASSERT_NE(headwrap, nullptr);
  128. }
  129. TEST_F(HelmetRenderersTest, CarthageHeavyHelmetFromRegistryRenders) {
  130. auto &registry = EquipmentRegistry::instance();
  131. auto helmet = registry.get(EquipmentCategory::Helmet, "carthage_heavy");
  132. ASSERT_NE(helmet, nullptr);
  133. helmet->render(ctx, frames, palette, anim, submitter);
  134. EXPECT_GT(submitter.mesh_count, 0);
  135. }
  136. TEST_F(HelmetRenderersTest, HeadwrapFromRegistryRenders) {
  137. auto &registry = EquipmentRegistry::instance();
  138. auto headwrap = registry.get(EquipmentCategory::Helmet, "headwrap");
  139. ASSERT_NE(headwrap, nullptr);
  140. headwrap->render(ctx, frames, palette, anim, submitter);
  141. EXPECT_GT(submitter.mesh_count, 0);
  142. }
  143. TEST_F(HelmetRenderersTest, HelmetsUseHeadFrameCoordinates) {
  144. // Test that helmets use head frame's coordinate system
  145. frames.head.origin = QVector3D(1.0F, 2.0F, 3.0F);
  146. frames.head.right = QVector3D(0.0F, 1.0F, 0.0F); // Rotated frame
  147. frames.head.up = QVector3D(-1.0F, 0.0F, 0.0F);
  148. frames.head.forward = QVector3D(0.0F, 0.0F, 1.0F);
  149. frames.head.radius = 0.12F;
  150. CarthageHeavyHelmetRenderer helmet;
  151. MockSubmitter submitter1;
  152. helmet.render(ctx, frames, palette, anim, submitter1);
  153. // Helmet should still render even with rotated frame
  154. EXPECT_GT(submitter1.mesh_count, 0);
  155. HeadwrapRenderer headwrap;
  156. MockSubmitter submitter2;
  157. headwrap.render(ctx, frames, palette, anim, submitter2);
  158. EXPECT_GT(submitter2.mesh_count, 0);
  159. }