barracks_renderer.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. #include "barracks_renderer.h"
  2. #include "../../../../game/core/component.h"
  3. #include "../../../../game/visuals/team_colors.h"
  4. #include "../../../geom/flag.h"
  5. #include "../../../geom/math_utils.h"
  6. #include "../../../geom/transforms.h"
  7. #include "../../../gl/backend.h"
  8. #include "../../../gl/backend/banner_pipeline.h"
  9. #include "../../../gl/primitives.h"
  10. #include "../../../gl/resources.h"
  11. #include "../../../submitter.h"
  12. #include "../../barracks_flag_renderer.h"
  13. #include "../../building_state.h"
  14. #include "../../registry.h"
  15. #include <QMatrix4x4>
  16. #include <QVector3D>
  17. #include <algorithm>
  18. namespace Render::GL::Roman {
  19. namespace {
  20. using Render::Geom::clamp01;
  21. using Render::Geom::clamp_vec_01;
  22. using Render::Geom::cylinder_between;
  23. struct RomanPalette {
  24. QVector3D limestone{0.96F, 0.94F, 0.88F};
  25. QVector3D limestone_shade{0.88F, 0.85F, 0.78F};
  26. QVector3D limestone_dark{0.80F, 0.76F, 0.70F};
  27. QVector3D marble{0.98F, 0.97F, 0.95F};
  28. QVector3D cedar{0.52F, 0.38F, 0.26F};
  29. QVector3D cedar_dark{0.38F, 0.26F, 0.16F};
  30. QVector3D terracotta{0.82F, 0.62F, 0.45F};
  31. QVector3D terracotta_dark{0.68F, 0.48F, 0.32F};
  32. QVector3D blue_accent{0.28F, 0.48F, 0.68F};
  33. QVector3D blue_light{0.40F, 0.60F, 0.80F};
  34. QVector3D gold{0.85F, 0.72F, 0.35F};
  35. QVector3D team{0.8F, 0.9F, 1.0F};
  36. QVector3D team_trim{0.48F, 0.54F, 0.60F};
  37. };
  38. inline auto make_palette(const QVector3D &team) -> RomanPalette {
  39. RomanPalette p;
  40. p.team = clamp_vec_01(team);
  41. p.team_trim = clamp_vec_01(
  42. QVector3D(team.x() * 0.6F, team.y() * 0.6F, team.z() * 0.6F));
  43. return p;
  44. }
  45. inline void draw_box(ISubmitter &out, Mesh *unit, Texture *white,
  46. const QMatrix4x4 &model, const QVector3D &pos,
  47. const QVector3D &size, const QVector3D &color) {
  48. QMatrix4x4 m = model;
  49. m.translate(pos);
  50. m.scale(size);
  51. out.mesh(unit, m, color, white, 1.0F);
  52. }
  53. inline void draw_cyl(ISubmitter &out, const QMatrix4x4 &model,
  54. const QVector3D &a, const QVector3D &b, float r,
  55. const QVector3D &color, Texture *white) {
  56. out.mesh(get_unit_cylinder(), model * cylinder_between(a, b, r), color, white,
  57. 1.0F);
  58. }
  59. void draw_platform(const DrawContext &p, ISubmitter &out, Mesh *unit,
  60. Texture *white, const RomanPalette &c) {
  61. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.08F, 0.0F),
  62. QVector3D(2.0F, 0.08F, 1.8F), c.limestone_dark);
  63. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.18F, 0.0F),
  64. QVector3D(1.8F, 0.02F, 1.6F), c.limestone);
  65. for (float x = -1.5F; x <= 1.5F; x += 0.35F) {
  66. for (float z = -1.3F; z <= 1.3F; z += 0.35F) {
  67. if (fabsf(x) > 0.6F || fabsf(z) > 0.5F) {
  68. draw_box(out, unit, white, p.model, QVector3D(x, 0.21F, z),
  69. QVector3D(0.15F, 0.01F, 0.15F), c.terracotta);
  70. }
  71. }
  72. }
  73. }
  74. void draw_colonnade(const DrawContext &p, ISubmitter &out, Mesh *unit,
  75. Texture *white, const RomanPalette &c,
  76. BuildingState state) {
  77. float const col_height = 1.6F;
  78. float const col_radius = 0.10F;
  79. static constexpr float FRONT_COLUMN_SPACING_RANGE = 2.5F;
  80. static constexpr float SIDE_COLUMN_SPACING_RANGE = 2.0F;
  81. float height_multiplier = 1.0F;
  82. int num_columns = 6;
  83. if (state == BuildingState::Damaged) {
  84. height_multiplier = 0.7F;
  85. num_columns = 4;
  86. } else if (state == BuildingState::Destroyed) {
  87. height_multiplier = 0.4F;
  88. num_columns = 2;
  89. }
  90. for (int i = 0; i < num_columns; ++i) {
  91. float const x =
  92. -1.25F + float(i) * (num_columns > 1 ? FRONT_COLUMN_SPACING_RANGE /
  93. (num_columns - 1)
  94. : 0.0F);
  95. float const z = 1.4F;
  96. draw_box(out, unit, white, p.model, QVector3D(x, 0.25F, z),
  97. QVector3D(col_radius * 1.2F, 0.05F, col_radius * 1.2F), c.marble);
  98. draw_cyl(out, p.model, QVector3D(x, 0.2F, z),
  99. QVector3D(x, 0.2F + col_height * height_multiplier, z), col_radius,
  100. c.limestone, white);
  101. draw_box(out, unit, white, p.model,
  102. QVector3D(x, 0.2F + col_height * height_multiplier + 0.05F, z),
  103. QVector3D(col_radius * 1.5F, 0.08F, col_radius * 1.5F), c.marble);
  104. if (state != BuildingState::Destroyed) {
  105. draw_box(out, unit, white, p.model,
  106. QVector3D(x, 0.2F + col_height * height_multiplier + 0.12F, z),
  107. QVector3D(col_radius * 1.3F, 0.04F, col_radius * 1.3F), c.gold);
  108. }
  109. }
  110. int side_columns = (state == BuildingState::Destroyed) ? 2 : 3;
  111. for (int i = 0; i < side_columns; ++i) {
  112. float const z =
  113. -1.0F + float(i) * (side_columns > 1
  114. ? SIDE_COLUMN_SPACING_RANGE / (side_columns - 1)
  115. : 0.0F);
  116. float const x_left = -1.6F;
  117. draw_box(out, unit, white, p.model, QVector3D(x_left, 0.25F, z),
  118. QVector3D(col_radius * 1.2F, 0.05F, col_radius * 1.2F), c.marble);
  119. draw_cyl(out, p.model, QVector3D(x_left, 0.2F, z),
  120. QVector3D(x_left, 0.2F + col_height * height_multiplier, z),
  121. col_radius, c.limestone, white);
  122. draw_box(
  123. out, unit, white, p.model,
  124. QVector3D(x_left, 0.2F + col_height * height_multiplier + 0.05F, z),
  125. QVector3D(col_radius * 1.5F, 0.08F, col_radius * 1.5F), c.marble);
  126. float const x_right = 1.6F;
  127. draw_box(out, unit, white, p.model, QVector3D(x_right, 0.25F, z),
  128. QVector3D(col_radius * 1.2F, 0.05F, col_radius * 1.2F), c.marble);
  129. draw_cyl(out, p.model, QVector3D(x_right, 0.2F, z),
  130. QVector3D(x_right, 0.2F + col_height * height_multiplier, z),
  131. col_radius, c.limestone, white);
  132. draw_box(
  133. out, unit, white, p.model,
  134. QVector3D(x_right, 0.2F + col_height * height_multiplier + 0.05F, z),
  135. QVector3D(col_radius * 1.5F, 0.08F, col_radius * 1.5F), c.marble);
  136. }
  137. }
  138. void draw_central_courtyard(const DrawContext &p, ISubmitter &out, Mesh *unit,
  139. Texture *white, const RomanPalette &c) {
  140. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.22F, 0.0F),
  141. QVector3D(1.3F, 0.01F, 1.1F), c.limestone_shade);
  142. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.24F, 0.0F),
  143. QVector3D(0.7F, 0.02F, 0.5F), c.blue_light);
  144. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.25F, -0.52F),
  145. QVector3D(0.72F, 0.02F, 0.02F), c.blue_accent);
  146. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.25F, 0.52F),
  147. QVector3D(0.72F, 0.02F, 0.02F), c.blue_accent);
  148. draw_cyl(out, p.model, QVector3D(0.0F, 0.25F, 0.0F),
  149. QVector3D(0.0F, 0.55F, 0.0F), 0.06F, c.marble, white);
  150. draw_box(out, unit, white, p.model, QVector3D(0.0F, 0.58F, 0.0F),
  151. QVector3D(0.08F, 0.03F, 0.08F), c.blue_accent);
  152. }
  153. void draw_chamber(const DrawContext &p, ISubmitter &out, Mesh *unit,
  154. Texture *white, const RomanPalette &c) {
  155. float const wall_h = 1.4F;
  156. draw_box(out, unit, white, p.model,
  157. QVector3D(0.0F, wall_h * 0.5F + 0.2F, -1.2F),
  158. QVector3D(1.4F, wall_h * 0.5F, 0.1F), c.limestone);
  159. draw_box(out, unit, white, p.model,
  160. QVector3D(-1.5F, wall_h * 0.5F + 0.2F, -0.5F),
  161. QVector3D(0.1F, wall_h * 0.5F, 0.6F), c.limestone);
  162. draw_box(out, unit, white, p.model,
  163. QVector3D(1.5F, wall_h * 0.5F + 0.2F, -0.5F),
  164. QVector3D(0.1F, wall_h * 0.5F, 0.6F), c.limestone);
  165. draw_box(out, unit, white, p.model, QVector3D(-0.6F, 0.65F, -1.15F),
  166. QVector3D(0.25F, 0.35F, 0.03F), c.cedar_dark);
  167. draw_box(out, unit, white, p.model, QVector3D(-0.6F, 0.98F, -1.15F),
  168. QVector3D(0.25F, 0.05F, 0.03F), c.blue_accent);
  169. draw_box(out, unit, white, p.model, QVector3D(0.6F, 0.65F, -1.15F),
  170. QVector3D(0.25F, 0.35F, 0.03F), c.cedar_dark);
  171. draw_box(out, unit, white, p.model, QVector3D(0.6F, 0.98F, -1.15F),
  172. QVector3D(0.25F, 0.05F, 0.03F), c.blue_accent);
  173. }
  174. void draw_terrace(const DrawContext &p, ISubmitter &out, Mesh *unit,
  175. Texture *white, const RomanPalette &c, BuildingState state) {
  176. if (state == BuildingState::Destroyed) {
  177. return;
  178. }
  179. draw_box(out, unit, white, p.model, QVector3D(0.0F, 2.05F, 0.0F),
  180. QVector3D(1.7F, 0.08F, 1.5F), c.marble);
  181. draw_box(out, unit, white, p.model, QVector3D(0.0F, 2.12F, 1.45F),
  182. QVector3D(1.65F, 0.05F, 0.05F), c.gold);
  183. draw_box(out, unit, white, p.model, QVector3D(0.0F, 2.18F, -0.2F),
  184. QVector3D(1.5F, 0.04F, 1.0F), c.terracotta);
  185. draw_box(out, unit, white, p.model, QVector3D(0.0F, 2.28F, -0.65F),
  186. QVector3D(1.45F, 0.06F, 0.05F), c.limestone);
  187. for (float x : {-1.4F, 1.4F}) {
  188. draw_box(out, unit, white, p.model, QVector3D(x, 2.35F, -0.65F),
  189. QVector3D(0.08F, 0.08F, 0.08F), c.gold);
  190. }
  191. }
  192. void draw_trading_goods(const DrawContext &p, ISubmitter &out, Mesh *unit,
  193. Texture *white, const RomanPalette &c) {
  194. draw_cyl(out, p.model, QVector3D(-1.2F, 0.2F, 1.1F),
  195. QVector3D(-1.2F, 0.5F, 1.1F), 0.08F, c.terracotta_dark, white);
  196. draw_cyl(out, p.model, QVector3D(-0.9F, 0.2F, 1.15F),
  197. QVector3D(-0.9F, 0.45F, 1.15F), 0.07F, c.terracotta, white);
  198. draw_cyl(out, p.model, QVector3D(1.1F, 0.2F, -0.9F),
  199. QVector3D(1.1F, 0.42F, -0.9F), 0.06F, c.blue_accent, white);
  200. }
  201. void draw_phoenician_banner(
  202. const DrawContext &p, ISubmitter &out, Mesh *unit, Texture *white,
  203. const RomanPalette &c,
  204. const BarracksFlagRenderer::ClothBannerResources *cloth) {
  205. float const pole_x = 0.0F;
  206. float const pole_z = -2.0F;
  207. float const pole_height = 3.0F;
  208. float const pole_radius = 0.045F;
  209. float const banner_width = 0.9F;
  210. float const banner_height = 0.6F;
  211. QVector3D const pole_center(pole_x, pole_height / 2.0F, pole_z);
  212. QVector3D const pole_size(pole_radius * 1.8F, pole_height / 2.0F,
  213. pole_radius * 1.8F);
  214. QMatrix4x4 pole_transform = p.model;
  215. pole_transform.translate(pole_center);
  216. pole_transform.scale(pole_size);
  217. out.mesh(unit, pole_transform, c.cedar, white, 1.0F);
  218. float const beam_length = banner_width * 0.5F;
  219. float const max_lowering = pole_height * 0.85F;
  220. auto captureColors = BarracksFlagRenderer::get_capture_colors(
  221. p, c.team, c.team_trim, max_lowering);
  222. float beam_y =
  223. pole_height - banner_height * 0.2F - captureColors.loweringOffset;
  224. float flag_y =
  225. pole_height - banner_height / 2.0F - captureColors.loweringOffset;
  226. QVector3D const beam_start(pole_x + 0.02F, beam_y, pole_z);
  227. QVector3D const beam_end(pole_x + beam_length + 0.02F, beam_y, pole_z);
  228. out.mesh(get_unit_cylinder(),
  229. p.model * Render::Geom::cylinder_between(beam_start, beam_end,
  230. pole_radius * 0.35F),
  231. c.cedar, white, 1.0F);
  232. QVector3D const connector_top(
  233. beam_end.x(), beam_end.y() - banner_height * 0.35F, beam_end.z());
  234. out.mesh(get_unit_cylinder(),
  235. p.model * Render::Geom::cylinder_between(beam_end, connector_top,
  236. pole_radius * 0.18F),
  237. c.limestone, white, 1.0F);
  238. float const panel_x = beam_end.x() + (banner_width * 0.5F - beam_length);
  239. QVector3D banner_center(panel_x, flag_y, pole_z + 0.02F);
  240. BarracksFlagRenderer::drawBannerWithTassels(
  241. p, out, unit, white, banner_center, banner_width * 0.5F,
  242. banner_height * 0.5F, 0.02F, captureColors.teamColor,
  243. captureColors.teamTrimColor, cloth);
  244. draw_box(out, unit, white, p.model,
  245. QVector3D(pole_x + 0.25F, pole_height + 0.15F, pole_z + 0.03F),
  246. QVector3D(0.35F, 0.03F, 0.015F), c.gold);
  247. for (int i = 0; i < 4; ++i) {
  248. float ring_y = 0.4F + static_cast<float>(i) * 0.5F;
  249. out.mesh(get_unit_cylinder(),
  250. p.model * Render::Geom::cylinder_between(
  251. QVector3D(pole_x, ring_y, pole_z),
  252. QVector3D(pole_x, ring_y + 0.025F, pole_z),
  253. pole_radius * 2.0F),
  254. c.gold, white, 1.0F);
  255. }
  256. }
  257. void draw_rally_flag(const DrawContext &p, ISubmitter &out, Texture *white,
  258. const RomanPalette &c) {
  259. BarracksFlagRenderer::FlagColors colors{.team = c.team,
  260. .teamTrim = c.team_trim,
  261. .timber = c.cedar,
  262. .timberLight = c.limestone,
  263. .woodDark = c.cedar_dark};
  264. BarracksFlagRenderer::draw_rally_flag_if_any(p, out, white, colors);
  265. }
  266. void draw_health_bar(const DrawContext &p, ISubmitter &out, Mesh *unit,
  267. Texture *white) {
  268. if (p.entity == nullptr) {
  269. return;
  270. }
  271. auto *u = p.entity->get_component<Engine::Core::UnitComponent>();
  272. if (u == nullptr) {
  273. return;
  274. }
  275. float const ratio =
  276. std::clamp(u->health / float(std::max(1, u->max_health)), 0.0F, 1.0F);
  277. if (ratio <= 0.0F) {
  278. return;
  279. }
  280. auto *capture = p.entity->get_component<Engine::Core::CaptureComponent>();
  281. bool under_attack = (capture != nullptr && capture->is_being_captured);
  282. if (!under_attack && u->health >= u->max_health) {
  283. return;
  284. }
  285. float const bar_width = 1.4F;
  286. float const bar_height = 0.10F;
  287. float const bar_y = 2.75F;
  288. float const border_thickness = 0.012F;
  289. if (under_attack) {
  290. float pulse = HEALTHBAR_PULSE_MIN +
  291. HEALTHBAR_PULSE_AMPLITUDE *
  292. sinf(p.animation_time * HEALTHBAR_PULSE_SPEED);
  293. draw_box(out, unit, white, p.model, QVector3D(0.0F, bar_y, 0.0F),
  294. QVector3D(bar_width * 0.5F + border_thickness * 3.0F,
  295. bar_height * 0.5F + border_thickness * 3.0F, 0.095F),
  296. HealthBarColors::GLOW_ATTACK * pulse * 0.6F);
  297. }
  298. draw_box(out, unit, white, p.model, QVector3D(0.0F, bar_y, 0.0F),
  299. QVector3D(bar_width * 0.5F + border_thickness,
  300. bar_height * 0.5F + border_thickness, 0.09F),
  301. HealthBarColors::BORDER);
  302. draw_box(out, unit, white, p.model, QVector3D(0.0F, bar_y, 0.0F),
  303. QVector3D(bar_width * 0.5F + border_thickness * 0.5F,
  304. bar_height * 0.5F + border_thickness * 0.5F, 0.088F),
  305. HealthBarColors::INNER_BORDER);
  306. draw_box(out, unit, white, p.model, QVector3D(0.0F, bar_y + 0.003F, 0.0F),
  307. QVector3D(bar_width * 0.5F, bar_height * 0.5F, 0.085F),
  308. HealthBarColors::BACKGROUND);
  309. QVector3D fg_color;
  310. QVector3D fg_dark;
  311. if (ratio >= HEALTH_THRESHOLD_NORMAL) {
  312. fg_color = HealthBarColors::NORMAL_BRIGHT;
  313. fg_dark = HealthBarColors::NORMAL_DARK;
  314. } else if (ratio >= HEALTH_THRESHOLD_DAMAGED) {
  315. float t = (ratio - HEALTH_THRESHOLD_DAMAGED) /
  316. (HEALTH_THRESHOLD_NORMAL - HEALTH_THRESHOLD_DAMAGED);
  317. fg_color = HealthBarColors::NORMAL_BRIGHT * t +
  318. HealthBarColors::DAMAGED_BRIGHT * (1.0F - t);
  319. fg_dark = HealthBarColors::NORMAL_DARK * t +
  320. HealthBarColors::DAMAGED_DARK * (1.0F - t);
  321. } else {
  322. float t = ratio / HEALTH_THRESHOLD_DAMAGED;
  323. fg_color = HealthBarColors::DAMAGED_BRIGHT * t +
  324. HealthBarColors::CRITICAL_BRIGHT * (1.0F - t);
  325. fg_dark = HealthBarColors::DAMAGED_DARK * t +
  326. HealthBarColors::CRITICAL_DARK * (1.0F - t);
  327. }
  328. draw_box(
  329. out, unit, white, p.model,
  330. QVector3D(-(bar_width * (1.0F - ratio)) * 0.5F, bar_y + 0.005F, 0.0F),
  331. QVector3D(bar_width * ratio * 0.5F, bar_height * 0.48F, 0.08F), fg_dark);
  332. draw_box(
  333. out, unit, white, p.model,
  334. QVector3D(-(bar_width * (1.0F - ratio)) * 0.5F, bar_y + 0.008F, 0.0F),
  335. QVector3D(bar_width * ratio * 0.5F, bar_height * 0.40F, 0.078F),
  336. fg_color);
  337. QVector3D const highlight = fg_color * 1.6F;
  338. draw_box(out, unit, white, p.model,
  339. QVector3D(-(bar_width * (1.0F - ratio)) * 0.5F,
  340. bar_y + bar_height * 0.35F, 0.0F),
  341. QVector3D(bar_width * ratio * 0.5F, bar_height * 0.20F, 0.075F),
  342. clamp_vec_01(highlight));
  343. draw_box(out, unit, white, p.model,
  344. QVector3D(-(bar_width * (1.0F - ratio)) * 0.5F,
  345. bar_y + bar_height * 0.48F, 0.0F),
  346. QVector3D(bar_width * ratio * 0.5F, bar_height * 0.08F, 0.073F),
  347. HealthBarColors::SHINE * 0.8F);
  348. float marker_70_x = bar_width * 0.5F * (HEALTH_THRESHOLD_NORMAL - 0.5F);
  349. draw_box(out, unit, white, p.model, QVector3D(marker_70_x, bar_y, 0.0F),
  350. QVector3D(0.015F, bar_height * 0.55F, 0.09F),
  351. HealthBarColors::SEGMENT);
  352. draw_box(out, unit, white, p.model,
  353. QVector3D(marker_70_x - 0.003F, bar_y + bar_height * 0.40F, 0.0F),
  354. QVector3D(0.008F, bar_height * 0.15F, 0.091F),
  355. HealthBarColors::SEGMENT_HIGHLIGHT);
  356. float marker_30_x = bar_width * 0.5F * (HEALTH_THRESHOLD_DAMAGED - 0.5F);
  357. draw_box(out, unit, white, p.model, QVector3D(marker_30_x, bar_y, 0.0F),
  358. QVector3D(0.015F, bar_height * 0.55F, 0.09F),
  359. HealthBarColors::SEGMENT);
  360. draw_box(out, unit, white, p.model,
  361. QVector3D(marker_30_x - 0.003F, bar_y + bar_height * 0.40F, 0.0F),
  362. QVector3D(0.008F, bar_height * 0.15F, 0.091F),
  363. HealthBarColors::SEGMENT_HIGHLIGHT);
  364. }
  365. void draw_selection(const DrawContext &p, ISubmitter &out) {
  366. QMatrix4x4 m;
  367. QVector3D const pos = p.model.column(3).toVector3D();
  368. m.translate(pos.x(), 0.0F, pos.z());
  369. m.scale(2.6F, 1.0F, 2.2F);
  370. if (p.selected) {
  371. out.selection_smoke(m, QVector3D(0.2F, 0.85F, 0.2F), 0.35F);
  372. } else if (p.hovered) {
  373. out.selection_smoke(m, QVector3D(0.95F, 0.92F, 0.25F), 0.22F);
  374. }
  375. }
  376. void draw_barracks(const DrawContext &p, ISubmitter &out) {
  377. if (!p.resources || !p.entity) {
  378. return;
  379. }
  380. auto *t = p.entity->get_component<Engine::Core::TransformComponent>();
  381. auto *r = p.entity->get_component<Engine::Core::RenderableComponent>();
  382. auto *u = p.entity->get_component<Engine::Core::UnitComponent>();
  383. if (!t || !r) {
  384. return;
  385. }
  386. BuildingState state = BuildingState::Normal;
  387. if (u != nullptr) {
  388. float const health_ratio =
  389. std::clamp(u->health / float(std::max(1, u->max_health)), 0.0F, 1.0F);
  390. state = get_building_state(health_ratio);
  391. }
  392. Mesh *unit = p.resources->unit();
  393. Texture *white = p.resources->white();
  394. QVector3D const team(r->color[0], r->color[1], r->color[2]);
  395. RomanPalette const c = make_palette(team);
  396. BarracksFlagRenderer::ClothBannerResources cloth;
  397. if (p.backend != nullptr) {
  398. cloth.clothMesh = p.backend->banner_mesh();
  399. cloth.bannerShader = p.backend->banner_shader();
  400. }
  401. draw_platform(p, out, unit, white, c);
  402. draw_colonnade(p, out, unit, white, c, state);
  403. draw_central_courtyard(p, out, unit, white, c);
  404. draw_chamber(p, out, unit, white, c);
  405. draw_terrace(p, out, unit, white, c, state);
  406. draw_trading_goods(p, out, unit, white, c);
  407. draw_phoenician_banner(p, out, unit, white, c, &cloth);
  408. draw_rally_flag(p, out, white, c);
  409. draw_health_bar(p, out, unit, white);
  410. draw_selection(p, out);
  411. }
  412. } // namespace
  413. void register_barracks_renderer(Render::GL::EntityRendererRegistry &registry) {
  414. registry.register_renderer("barracks_roman", draw_barracks);
  415. }
  416. } // namespace Render::GL::Roman