catapult_renderer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. #include "catapult_renderer.h"
  2. #include "../../../../game/core/component.h"
  3. #include "../../../../game/visuals/team_colors.h"
  4. #include "../../../geom/math_utils.h"
  5. #include "../../../geom/transforms.h"
  6. #include "../../../gl/primitives.h"
  7. #include "../../../gl/resources.h"
  8. #include "../../../scene_renderer.h"
  9. #include "../../../submitter.h"
  10. #include "../../registry.h"
  11. #include <QMatrix4x4>
  12. #include <QVector3D>
  13. #include <cmath>
  14. namespace Render::GL::Carthage {
  15. namespace {
  16. using Render::Geom::clamp01;
  17. using Render::Geom::clamp_vec_01;
  18. using Render::Geom::cylinder_between;
  19. struct CarthageCatapultPalette {
  20. QVector3D wood_cedar{0.52F, 0.35F, 0.22F};
  21. QVector3D wood_dark{0.38F, 0.25F, 0.15F};
  22. QVector3D wood_light{0.60F, 0.45F, 0.30F};
  23. QVector3D metal_bronze{0.70F, 0.50F, 0.28F};
  24. QVector3D metal_iron{0.35F, 0.33F, 0.32F};
  25. QVector3D rope{0.58F, 0.50F, 0.38F};
  26. QVector3D leather{0.48F, 0.35F, 0.22F};
  27. QVector3D purple_trim{0.45F, 0.18F, 0.55F};
  28. QVector3D stone{0.55F, 0.52F, 0.48F};
  29. QVector3D team{0.8F, 0.9F, 1.0F};
  30. };
  31. enum class CatapultAnimState { Idle, Loading, Firing, Resetting };
  32. struct CatapultAnimContext {
  33. CatapultAnimState state{CatapultAnimState::Idle};
  34. float loading_progress{0.0F};
  35. float firing_progress{0.0F};
  36. bool show_stone{false};
  37. };
  38. inline auto make_palette(const QVector3D &team) -> CarthageCatapultPalette {
  39. CarthageCatapultPalette p;
  40. p.team = clamp_vec_01(team);
  41. return p;
  42. }
  43. inline auto
  44. get_anim_context(const Engine::Core::Entity *entity) -> CatapultAnimContext {
  45. CatapultAnimContext ctx;
  46. if (entity == nullptr) {
  47. return ctx;
  48. }
  49. auto *loading =
  50. entity->get_component<Engine::Core::CatapultLoadingComponent>();
  51. if (loading == nullptr) {
  52. return ctx;
  53. }
  54. switch (loading->state) {
  55. case Engine::Core::CatapultLoadingComponent::LoadingState::Idle:
  56. ctx.state = CatapultAnimState::Idle;
  57. ctx.show_stone = false;
  58. break;
  59. case Engine::Core::CatapultLoadingComponent::LoadingState::Loading:
  60. ctx.state = CatapultAnimState::Loading;
  61. ctx.loading_progress = loading->get_loading_progress();
  62. ctx.show_stone = true;
  63. break;
  64. case Engine::Core::CatapultLoadingComponent::LoadingState::ReadyToFire:
  65. ctx.state = CatapultAnimState::Firing;
  66. ctx.loading_progress = 1.0F;
  67. ctx.firing_progress = 0.0F;
  68. ctx.show_stone = true;
  69. break;
  70. case Engine::Core::CatapultLoadingComponent::LoadingState::Firing:
  71. ctx.state = CatapultAnimState::Firing;
  72. ctx.firing_progress = loading->get_firing_progress();
  73. ctx.show_stone = ctx.firing_progress < 0.3F;
  74. break;
  75. }
  76. return ctx;
  77. }
  78. inline void draw_box(ISubmitter &out, Mesh *unit, Texture *white,
  79. const QMatrix4x4 &model, const QVector3D &pos,
  80. const QVector3D &size, const QVector3D &color) {
  81. QMatrix4x4 m = model;
  82. m.translate(pos);
  83. m.scale(size);
  84. out.mesh(unit, m, color, white, 1.0F);
  85. }
  86. inline void draw_cyl(ISubmitter &out, const QMatrix4x4 &model,
  87. const QVector3D &a, const QVector3D &b, float r,
  88. const QVector3D &color, Texture *white) {
  89. out.mesh(get_unit_cylinder(), model * cylinder_between(a, b, r), color, white,
  90. 1.0F);
  91. }
  92. void draw_base_frame(const DrawContext &p, ISubmitter &out, Mesh *unit,
  93. Texture *white, const CarthageCatapultPalette &c) {
  94. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.24F, -0.38F),
  95. QVector3D(0.52F, 0.06F, 0.06F), c.wood_dark);
  96. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.24F, 0.38F),
  97. QVector3D(0.52F, 0.06F, 0.06F), c.wood_dark);
  98. draw_box(out, unit, white, p.model, QVector3D(-0.42F, 0.24F, 0.0F),
  99. QVector3D(0.06F, 0.06F, 0.42F), c.wood_cedar);
  100. draw_box(out, unit, white, p.model, QVector3D(0.42F, 0.24F, 0.0F),
  101. QVector3D(0.06F, 0.06F, 0.42F), c.wood_cedar);
  102. draw_box(out, unit, white, p.model, QVector3D(-0.42F, 0.28F, 0.0F),
  103. QVector3D(0.08F, 0.03F, 0.44F), c.metal_bronze);
  104. draw_box(out, unit, white, p.model, QVector3D(0.42F, 0.28F, 0.0F),
  105. QVector3D(0.08F, 0.03F, 0.44F), c.metal_bronze);
  106. draw_cyl(out, p.model, QVector3D(-0.38F, 0.22F, -0.32F),
  107. QVector3D(-0.38F, 0.22F, 0.32F), 0.028F, c.wood_dark, white);
  108. draw_cyl(out, p.model, QVector3D(0.38F, 0.22F, -0.32F),
  109. QVector3D(0.38F, 0.22F, 0.32F), 0.028F, c.wood_dark, white);
  110. }
  111. void draw_wheels(const DrawContext &p, ISubmitter &out, Mesh *unit,
  112. Texture *white, const CarthageCatapultPalette &c) {
  113. float wheel_radius = 0.20F;
  114. float wheel_thickness = 0.045F;
  115. QVector3D left_front(-0.45F, wheel_radius, -0.28F);
  116. QVector3D left_back(-0.45F, wheel_radius, 0.28F);
  117. QVector3D right_front(0.45F, wheel_radius, -0.28F);
  118. QVector3D right_back(0.45F, wheel_radius, 0.28F);
  119. auto drawWheel = [&](const QVector3D &pos, float side_offset) {
  120. QVector3D inner = pos + QVector3D(side_offset * wheel_thickness, 0, 0);
  121. QVector3D outer =
  122. pos + QVector3D(side_offset * (wheel_thickness + 0.07F), 0, 0);
  123. draw_cyl(out, p.model, inner, outer, wheel_radius, c.wood_dark, white);
  124. draw_cyl(out, p.model, inner - QVector3D(side_offset * 0.005F, 0, 0),
  125. outer + QVector3D(side_offset * 0.005F, 0, 0),
  126. wheel_radius + 0.018F, c.metal_bronze, white);
  127. draw_cyl(out, p.model, inner - QVector3D(side_offset * 0.025F, 0, 0),
  128. outer + QVector3D(side_offset * 0.025F, 0, 0), 0.05F,
  129. c.metal_bronze, white);
  130. for (int s = 0; s < 6; ++s) {
  131. float angle = s * 3.14159F / 3.0F;
  132. float spoke_y = std::sin(angle) * wheel_radius * 0.75F;
  133. float spoke_z = std::cos(angle) * wheel_radius * 0.75F;
  134. QVector3D spoke_pos =
  135. pos +
  136. QVector3D(side_offset * (wheel_thickness + 0.035F), spoke_y, spoke_z);
  137. draw_cyl(out, p.model,
  138. pos + QVector3D(side_offset * (wheel_thickness + 0.035F), 0, 0),
  139. spoke_pos, 0.012F, c.wood_cedar, white);
  140. }
  141. };
  142. drawWheel(left_front, -1.0F);
  143. drawWheel(left_back, -1.0F);
  144. drawWheel(right_front, 1.0F);
  145. drawWheel(right_back, 1.0F);
  146. draw_cyl(out, p.model, QVector3D(-0.44F, wheel_radius, -0.28F),
  147. QVector3D(0.44F, wheel_radius, -0.28F), 0.028F, c.metal_iron, white);
  148. draw_cyl(out, p.model, QVector3D(-0.44F, wheel_radius, 0.28F),
  149. QVector3D(0.44F, wheel_radius, 0.28F), 0.028F, c.metal_iron, white);
  150. }
  151. void drawThrowingArm(const DrawContext &p, ISubmitter &out, Mesh *unit,
  152. Texture *white, const CarthageCatapultPalette &c,
  153. const CatapultAnimContext &anim_ctx) {
  154. draw_cyl(out, p.model, QVector3D(-0.30F, 0.22F, -0.10F),
  155. QVector3D(-0.20F, 0.70F, 0.05F), 0.055F, c.wood_cedar, white);
  156. draw_cyl(out, p.model, QVector3D(0.30F, 0.22F, -0.10F),
  157. QVector3D(0.20F, 0.70F, 0.05F), 0.055F, c.wood_cedar, white);
  158. draw_cyl(out, p.model, QVector3D(-0.22F, 0.68F, 0.03F),
  159. QVector3D(0.22F, 0.68F, 0.03F), 0.045F, c.wood_dark, white);
  160. draw_cyl(out, p.model, QVector3D(-0.08F, 0.65F, 0.03F),
  161. QVector3D(0.08F, 0.65F, 0.03F), 0.06F, c.metal_bronze, white);
  162. float arm_angle = 0.75F;
  163. switch (anim_ctx.state) {
  164. case CatapultAnimState::Idle:
  165. arm_angle = 0.75F;
  166. break;
  167. case CatapultAnimState::Loading:
  168. arm_angle = 0.75F + anim_ctx.loading_progress * 0.55F;
  169. break;
  170. case CatapultAnimState::Firing:
  171. arm_angle = 1.30F - anim_ctx.firing_progress * 1.9F;
  172. arm_angle = std::max(arm_angle, -0.35F);
  173. break;
  174. case CatapultAnimState::Resetting:
  175. arm_angle = 0.75F;
  176. break;
  177. }
  178. QMatrix4x4 armMatrix = p.model;
  179. armMatrix.translate(0.0F, 0.60F, 0.03F);
  180. armMatrix.rotate(arm_angle * 57.3F, 1.0F, 0.0F, 0.0F);
  181. draw_cyl(out, armMatrix, QVector3D(0.0F, 0.0F, -0.65F),
  182. QVector3D(0.0F, 0.0F, 0.35F), 0.05F, c.wood_cedar, white);
  183. draw_box(out, unit, white, armMatrix, QVector3D(0.0F, -0.06F, -0.60F),
  184. QVector3D(0.10F, 0.08F, 0.12F), c.leather);
  185. draw_box(out, unit, white, armMatrix, QVector3D(0.0F, 0.0F, 0.30F),
  186. QVector3D(0.08F, 0.08F, 0.08F), c.metal_bronze);
  187. if (anim_ctx.show_stone) {
  188. QMatrix4x4 stone_matrix = armMatrix;
  189. stone_matrix.translate(0.0F, 0.10F, -0.58F);
  190. float const stone_scale = 0.09F;
  191. stone_matrix.scale(stone_scale, stone_scale, stone_scale);
  192. out.mesh(get_unit_cube(), stone_matrix, c.stone, white, 1.0F);
  193. }
  194. }
  195. void drawTorsionMechanism(const DrawContext &p, ISubmitter &out, Mesh *unit,
  196. Texture *white, const CarthageCatapultPalette &c) {
  197. draw_box(out, unit, white, p.model, QVector3D(-0.22F, 0.40F, 0.0F),
  198. QVector3D(0.05F, 0.20F, 0.18F), c.wood_dark);
  199. draw_box(out, unit, white, p.model, QVector3D(0.22F, 0.40F, 0.0F),
  200. QVector3D(0.05F, 0.20F, 0.18F), c.wood_dark);
  201. for (int i = 0; i < 4; ++i) {
  202. float offset = (float(i) - 1.5F) * 0.035F;
  203. draw_cyl(out, p.model, QVector3D(-0.15F, 0.28F + offset, -0.10F),
  204. QVector3D(-0.15F, 0.52F + offset, 0.10F), 0.028F, c.rope, white);
  205. draw_cyl(out, p.model, QVector3D(0.15F, 0.28F + offset, -0.10F),
  206. QVector3D(0.15F, 0.52F + offset, 0.10F), 0.028F, c.rope, white);
  207. }
  208. draw_cyl(out, p.model, QVector3D(-0.24F, 0.32F, 0.0F),
  209. QVector3D(-0.18F, 0.32F, 0.0F), 0.14F, c.metal_bronze, white);
  210. draw_cyl(out, p.model, QVector3D(0.18F, 0.32F, 0.0F),
  211. QVector3D(0.24F, 0.32F, 0.0F), 0.14F, c.metal_bronze, white);
  212. }
  213. void drawDecorations(const DrawContext &p, ISubmitter &out, Mesh *unit,
  214. Texture *white, const CarthageCatapultPalette &c) {
  215. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.72F, -0.12F),
  216. QVector3D(0.04F, 0.08F, 0.02F), c.metal_bronze);
  217. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.78F, -0.12F),
  218. QVector3D(0.06F, 0.02F, 0.02F), c.metal_bronze);
  219. draw_box(out, unit, white, p.model, QVector3D(-0.57F, 0.22F, -0.35F),
  220. QVector3D(0.05F, 0.05F, 0.05F), c.metal_bronze);
  221. draw_box(out, unit, white, p.model, QVector3D(0.57F, 0.22F, -0.35F),
  222. QVector3D(0.05F, 0.05F, 0.05F), c.metal_bronze);
  223. draw_box(out, unit, white, p.model, QVector3D(-0.57F, 0.22F, 0.35F),
  224. QVector3D(0.05F, 0.05F, 0.05F), c.metal_bronze);
  225. draw_box(out, unit, white, p.model, QVector3D(0.57F, 0.22F, 0.35F),
  226. QVector3D(0.05F, 0.05F, 0.05F), c.metal_bronze);
  227. }
  228. void drawWindlass(const DrawContext &p, ISubmitter &out, Mesh *unit,
  229. Texture *white, const CarthageCatapultPalette &c) {
  230. draw_cyl(out, p.model, QVector3D(-0.22F, 0.25F, 0.35F),
  231. QVector3D(0.22F, 0.25F, 0.35F), 0.06F, c.wood_cedar, white);
  232. draw_cyl(out, p.model, QVector3D(-0.15F, 0.25F, 0.35F),
  233. QVector3D(0.15F, 0.25F, 0.35F), 0.07F, c.metal_bronze, white);
  234. draw_cyl(out, p.model, QVector3D(-0.28F, 0.25F, 0.35F),
  235. QVector3D(-0.28F, 0.38F, 0.35F), 0.025F, c.wood_dark, white);
  236. draw_cyl(out, p.model, QVector3D(0.28F, 0.25F, 0.35F),
  237. QVector3D(0.28F, 0.38F, 0.35F), 0.025F, c.wood_dark, white);
  238. draw_cyl(out, p.model, QVector3D(-0.12F, 0.25F, 0.35F),
  239. QVector3D(0.12F, 0.25F, 0.35F), 0.065F, c.rope, white);
  240. }
  241. } // namespace
  242. void register_catapult_renderer(EntityRendererRegistry &registry) {
  243. registry.register_renderer(
  244. "troops/carthage/catapult", [](const DrawContext &p, ISubmitter &out) {
  245. Mesh *unit_cube = get_unit_cube();
  246. Texture *white_tex = nullptr;
  247. if (auto *scene_renderer = dynamic_cast<Renderer *>(&out)) {
  248. unit_cube = scene_renderer->get_mesh_cube();
  249. white_tex = scene_renderer->get_white_texture();
  250. }
  251. if (unit_cube == nullptr || white_tex == nullptr) {
  252. return;
  253. }
  254. QVector3D team_color{0.4F, 0.2F, 0.6F};
  255. if (p.entity != nullptr) {
  256. if (auto *r =
  257. p.entity
  258. ->get_component<Engine::Core::RenderableComponent>()) {
  259. team_color = QVector3D(r->color[0], r->color[1], r->color[2]);
  260. }
  261. }
  262. auto palette = make_palette(team_color);
  263. auto anim_ctx = get_anim_context(p.entity);
  264. draw_base_frame(p, out, unit_cube, white_tex, palette);
  265. draw_wheels(p, out, unit_cube, white_tex, palette);
  266. drawTorsionMechanism(p, out, unit_cube, white_tex, palette);
  267. drawThrowingArm(p, out, unit_cube, white_tex, palette, anim_ctx);
  268. drawWindlass(p, out, unit_cube, white_tex, palette);
  269. drawDecorations(p, out, unit_cube, white_tex, palette);
  270. });
  271. }
  272. } // namespace Render::GL::Carthage