#include "render/WorldRenderer.h" #include "render/loader/WorldLoader.h" #include "render/Renderer.h" #include "render/gui/imgui/imgui.h" #include "gui/imgui/imgui_internal.h" #include "window/Display.h" #include "game/client/ClientGame.h" #include "game/client/Client.h" #include "misc/Format.h" namespace td { namespace render { ImVec4 WorldRenderer::GetImGuiTeamColor(game::TeamColor color) { switch (color) { case td::game::TeamColor::None: break; case td::game::TeamColor::Red: return ImVec4(1, 0, 0, 1); case td::game::TeamColor::Blue: return ImVec4(0, 0, 1, 1); } return ImVec4(1, 1, 1, 1); } void WorldRenderer::LoadModels() { utils::LOGD("World Created !"); m_WorldVao = std::make_unique(std::move(WorldLoader::LoadWorldModel(m_World))); m_MobVao = std::make_unique(std::move(WorldLoader::LoadMobModel())); m_SelectTileVao = std::make_unique(std::move(WorldLoader::LoadTileSelectModel())); utils::LOGD(utils::format("Vertex Count : %u", m_WorldVao->GetVertexCount())); } WorldRenderer::WorldRenderer(game::World* world, client::ClientGame* client) : m_Client(client), m_Renderer(m_Client->GetRenderer()), m_World(world), m_Zoom(0.1) { m_Renderer->SetZoom(m_Zoom); m_Renderer->SetCamMovement({}); m_TowerPlacePopup = std::make_unique(m_Client->GetClient()); m_TowerUpgradePopup = std::make_unique(m_Client->GetClient()); m_MobTooltip = std::make_unique(m_Client->GetClient()); m_CastleTooltip = std::make_unique(m_Client->GetClient()); m_Client->GetWorldClient().GetWorldNotifier().BindListener(this); } void WorldRenderer::UpdateCursorPos() { m_CursorPos = GetCursorWorldPos(); } void WorldRenderer::Update() { if (m_WorldVao == nullptr) return; ImGuiIO& io = ImGui::GetIO(); if (io.MouseDown[0] && !ImGui::IsAnyItemActive() && !ImGui::IsAnyItemHovered()) { ImVec2 mouseDelta = ImGui::GetIO().MouseDelta; m_Renderer->SetCamMovement({ mouseDelta.x, mouseDelta.y }); } if (io.MouseDown[1] && !ImGui::IsAnyItemActive() && !ImGui::IsAnyItemHovered()) { ImVec2 mouseDelta = ImGui::GetIO().MouseDelta; m_Renderer->SetCamAngularMovement({ mouseDelta.x, mouseDelta.y }); } if (io.MouseWheel != 0) { ChangeZoom(io.MouseWheel); } UpdateCursorPos(); if (ImGui::IsMouseClicked(0)) { if (!m_TowerUpgradePopup->IsPopupOpened()) { m_HoldCursorPos = { io.MousePos.x, io.MousePos.y }; } } if (ImGui::IsMouseDoubleClicked(1)) RemoveTower(); } void WorldRenderer::RemoveTower() { Vec2f cursorPos = GetCursorWorldPos(); game::TowerPtr clickedTower = m_World->GetTower(cursorPos); if (clickedTower != nullptr) { m_Client->GetClient()->RemoveTower(clickedTower->GetID()); } } void WorldRenderer::RenderWorld() const { m_Renderer->RenderVAO(*m_WorldVao); } void WorldRenderer::RenderMobs() const { for (game::MobPtr mob : m_World->GetMobList()) { Renderer::Model model; model.vao = m_MobVao.get(); model.positon = { mob->GetCenterX(), 0, mob->GetCenterY() }; model.color = mob->HasTakenDamage() ? Vec3f{ 1, 0.5, 0.5 } : Vec3f{ 1, 1, 1 }; m_Renderer->RenderModel(model); } } void WorldRenderer::RenderTowers() const { if (!m_TowersCache.IsEmpty()) m_Renderer->RenderVAO(m_TowersCache.GetVertexArray()); } void WorldRenderer::RenderTileSelect() const { if (ImGui::IsAnyItemHovered()) return; if (m_MobTooltip->IsShown() || m_CastleTooltip->IsShown()) return; Renderer::Model tileSelectModel; tileSelectModel.vao = m_SelectTileVao.get(); tileSelectModel.positon = { std::floor(m_CursorPos.x), 0, std::floor(m_CursorPos.y) }; m_Renderer->RenderModel(tileSelectModel); } void WorldRenderer::RenderPopups() { m_TowerPlacePopup->Render(); m_TowerUpgradePopup->Render(); } void WorldRenderer::Render() { if (m_WorldVao == nullptr) return; RenderWorld(); RenderMobs(); RenderTowers(); RenderTileSelect(); RenderTooltips(); RenderPopups(); DetectClick(); } WorldRenderer::~WorldRenderer() { } void WorldRenderer::RenderTooltips() const { RenderMobTooltip(); RenderCastleTooltip(); } void WorldRenderer::MoveCam(float relativeX, float relativeY) { if (m_WorldVao == nullptr) return; } void WorldRenderer::ChangeZoom(float zoomStep) { if (m_WorldVao == nullptr) return; m_Renderer->SetZoom(zoomStep); } void WorldRenderer::Click() { const game::TowerPtr tower = m_Client->GetWorld().GetTower(GetClickWorldPos()); m_TowerPlacePopup->SetClickPos(GetClickWorldPos()); m_TowerUpgradePopup->SetClickPos(GetClickWorldPos()); if (tower != nullptr) { // there is a tower here ImGui::OpenPopup("TowerUpgrade"); } else if (m_Client->GetWorld().CanPlaceLittleTower(GetClickWorldPos(), m_Client->GetPlayer()->GetID())) { ImGui::OpenPopup("TowerPlace"); } } void WorldRenderer::SetCamPos(float camX, float camY) { m_CamPos = { camX, camY }; m_Renderer->SetCamLook({ camX, camY }); } void WorldRenderer::DetectClick() { ImGuiIO& io = ImGui::GetIO(); if (ImGui::IsMouseReleased(0) && !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemFocused()) { Vec2f cursorPos = { io.MousePos.x, io.MousePos.y }; if (cursorPos == m_HoldCursorPos) { m_LastClicked = m_HoldCursorPos; Click(); } } } void WorldRenderer::RenderMobTooltip() const { if (ImGui::IsAnyItemHovered()) return; DetectMobHovering(); m_MobTooltip->Render(); } void WorldRenderer::RenderCastleTooltip() const { if (ImGui::IsAnyItemHovered()) return; DetectCastleHovering(); m_CastleTooltip->Render(); } void WorldRenderer::DetectMobHovering() const { Vec2f cursorWorldPos = GetCursorWorldPos(); for (game::MobPtr mob : m_World->GetMobList()) { if (mob->CollidesWith({ cursorWorldPos.x, cursorWorldPos.y })) { m_MobTooltip->SetMob(mob.get()); return; } } m_MobTooltip->SetMob(nullptr); } void WorldRenderer::DetectCastleHovering() const { Vec2f cursorWorldPos = GetCursorWorldPos(); for (const game::Team& team : m_World->GetTeams()) { if (team.GetCastle().CollidesWith({ cursorWorldPos.x, cursorWorldPos.y })) { m_CastleTooltip->SetCastle(&team.GetCastle()); return; } } m_CastleTooltip->SetCastle(nullptr); } void WorldRenderer::OnTowerAdd(game::TowerPtr tower) { WorldLoader::RenderData RenderData = WorldLoader::LoadTowerModel(tower); m_TowersCache.AddData(tower->GetID(), RenderData.positions, RenderData.colors); m_TowersCache.UpdateVertexArray(); } void WorldRenderer::OnTowerRemove(game::TowerPtr tower) { m_TowersCache.RemoveData(tower->GetID()); m_TowersCache.UpdateVertexArray(); } Vec2f WorldRenderer::GetCursorWorldPos() const { ImGuiIO& io = ImGui::GetIO(); return m_Renderer->GetCursorWorldPos({ io.MousePos.x, io.MousePos.y }, Display::GetWindowWidth(), Display::GetWindowHeight()); } Vec2f WorldRenderer::GetClickWorldPos() const { return m_Renderer->GetCursorWorldPos(m_LastClicked, Display::GetWindowWidth(), Display::GetWindowHeight()); } } // namespace render } // namespace td