Files
Tower-Defense/src/render/WorldRenderer.cpp

307 lines
9.8 KiB
C++

#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 <iostream>
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() {
std::cout << "World Created !\n";
m_WorldVao = std::make_unique<GL::VertexArray>(std::move(WorldLoader::loadWorldModel(m_World)));
m_MobVao = std::make_unique<GL::VertexArray>(std::move(WorldLoader::loadMobModel()));
m_SelectTileVao = std::make_unique<GL::VertexArray>(std::move(WorldLoader::loadTileSelectModel()));
std::cout << "Vertex Count : " << m_WorldVao->getVertexCount() << std::endl;
}
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<gui::TowerPlacePopup>(m_Client->getClient());
m_MobTooltip = std::make_unique<gui::MobTooltip>(m_Client->getClient());
m_CastleTooltip = std::make_unique<gui::CastleTooltip>(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()) {
ImVec2 mouseDelta = ImGui::GetIO().MouseDelta;
const float relativeX = mouseDelta.x / (float)Display::getWindowWidth() * 2;
const float relativeY = mouseDelta.y / (float)Display::getWindowHeight() * 2;
moveCam(relativeX, relativeY, Display::getAspectRatio());
}
if (io.MouseWheel != 0) {
changeZoom(io.MouseWheel);
}
updateCursorPos();
if (ImGui::IsMouseClicked(0)) {
if (!m_PopupOpened) {
m_HoldCursorPos = { io.MousePos.x, io.MousePos.y };
} else {
m_PopupOpened = false;
}
}
if (ImGui::IsMouseDoubleClicked(1)) removeTower();
}
void WorldRenderer::removeTower() {
glm::vec2 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(), mob->getCenterY() };
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 = { (int)m_CursorPos.x, (int)m_CursorPos.y };
m_Renderer->renderModel(tileSelectModel);
}
void WorldRenderer::renderPopups() {
m_TowerPlacePopup->render();
renderTowerUpgradePopup();
}
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, float aspectRatio) {
if (m_WorldVao == nullptr)
return;
float movementX = -relativeX / m_Zoom * aspectRatio;
float movementY = relativeY / m_Zoom;
m_Renderer->setCamMovement({ movementX, movementY });
}
void WorldRenderer::changeZoom(float zoomStep) {
if (m_WorldVao == nullptr)
return;
static float sensibility = 1.5f;
if (zoomStep < 0) {
m_Zoom /= -zoomStep * sensibility;
} else {
m_Zoom *= zoomStep * sensibility;
}
m_Renderer->setZoom(m_Zoom);
m_Renderer->setCamMovement({});
}
void WorldRenderer::click() {
const game::TowerPtr tower = m_Client->getWorld().getTower(getClickWorldPos());
m_TowerPlacePopup->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->setCamPos(m_CamPos);
}
void WorldRenderer::renderTowerUpgradePopup() {
if (ImGui::BeginPopup("TowerUpgrade")) {
m_PopupOpened = true;
game::TowerPtr tower = m_Client->getWorld().getTower(getClickWorldPos());
if (tower == nullptr) {
ImGui::EndPopup();
return;
}
ImGui::Text("Tower : %s", game::TowerFactory::getTowerName(tower->getType()).c_str());
for (int y = 0; y < 3; y++) { // path: 0 -> top 1 -> middle 2 -> bottom
for (int x = 0; x < 4; x++) { // level: 1, 2, 3, 4
if (x > 0)
ImGui::SameLine();
std::uint8_t currentLevel = x + 1;
game::TowerPath currentPath = game::TowerPath(y);
const game::TowerStats* towerStats = game::getTowerStats(tower->getType(), { currentLevel, currentPath });
game::TowerPath towerPath = tower->getLevel().getPath();
bool disabled = towerStats == nullptr;
int towerLevel = tower->getLevel().getLevel();
bool alreadyUpgraded = currentLevel <= towerLevel;
bool canUpgrade = (towerLevel + 1) == currentLevel;
if (canUpgrade && towerPath != game::TowerPath::Base) {
if (currentPath != towerPath) {
canUpgrade = false;
}
}
ImGui::PushID(x * 4 + y);
if (disabled) {
ImGui::BeginDisabled();
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
ImGui::Button("", ImVec2(100, 100));
ImGui::PopStyleColor();
ImGui::EndDisabled();
} else if (alreadyUpgraded) {
ImGui::BeginDisabled();
ImGui::Button("Already", ImVec2(100, 100));
ImGui::EndDisabled();
} else if (canUpgrade) {
if (ImGui::Button("Upgrade", ImVec2(100, 100))) {
m_Client->getClient()->upgradeTower(tower->getID(), { currentLevel, currentPath });
}
} else {
ImGui::BeginDisabled();
ImGui::Button("Locked", ImVec2(100, 100));
ImGui::EndDisabled();
}
ImGui::PopID();
}
}
ImGui::EndPopup();
}
}
void WorldRenderer::detectClick() {
ImGuiIO& io = ImGui::GetIO();
if (ImGui::IsMouseReleased(0) && !ImGui::IsAnyItemHovered() && !ImGui::IsAnyItemFocused()) {
glm::vec2 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 {
glm::vec2 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 {
glm::vec2 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();
}
glm::vec2 WorldRenderer::getCursorWorldPos() const {
ImGuiIO& io = ImGui::GetIO();
return m_Renderer->getCursorWorldPos({ io.MousePos.x, io.MousePos.y }, Display::getAspectRatio(), m_Zoom, Display::getWindowWidth(), Display::getWindowHeight());
}
glm::vec2 WorldRenderer::getClickWorldPos() const {
return m_Renderer->getCursorWorldPos(m_LastClicked, Display::getAspectRatio(), m_Zoom, Display::getWindowWidth(), Display::getWindowHeight());
}
} // namespace render
} // namespace td