diff --git a/include/render/Renderer.h b/include/render/Renderer.h index 4a220b1..bdfd765 100644 --- a/include/render/Renderer.h +++ b/include/render/Renderer.h @@ -29,7 +29,8 @@ public: static constexpr float m_MouseSensitivity = 200.0f; struct Model { - GL::VertexArray* vao; + std::unique_ptr vao; + std::unique_ptr texture; Vec3f positon; Vec3f color = { 1, 1, 1 }; }; diff --git a/include/render/WorldRenderer.h b/include/render/WorldRenderer.h index aed88cd..5c0e0ce 100644 --- a/include/render/WorldRenderer.h +++ b/include/render/WorldRenderer.h @@ -28,7 +28,8 @@ private: client::ClientGame* m_Client; Renderer* m_Renderer; game::World* m_World; - std::unique_ptr m_WorldVao, m_MobVao, m_SelectTileVao; + std::unique_ptr m_WorldVao; + std::unique_ptr m_MobModel, m_SelectTileModel; Vec2f m_CamPos; Vec2f m_CursorPos; Vec2f m_HoldCursorPos; diff --git a/include/render/loader/GLLoader.h b/include/render/loader/GLLoader.h index 5fe976c..1b27611 100644 --- a/include/render/loader/GLLoader.h +++ b/include/render/loader/GLLoader.h @@ -70,5 +70,24 @@ public: void Unbind() const; }; +class Texture { +private: + unsigned int m_ID; +public: + REMOVE_COPY(Texture); + + Texture(Texture&& other) { + m_ID = other.m_ID; + other.m_ID = 0; + } + + Texture(const char* textureData, int width, int height, int comp); + ~Texture(); + + unsigned int GetTextureID() const { return m_ID; } + void Bind() const; + static void Unbind(); +}; + } diff --git a/include/render/loader/MobLoader.h b/include/render/loader/MobLoader.h new file mode 100644 index 0000000..8e4fa6a --- /dev/null +++ b/include/render/loader/MobLoader.h @@ -0,0 +1,11 @@ +#pragma once + +#include "GLLoader.h" + +namespace td { +namespace MobLoader { + +GL::VertexArray LoadMobModel(); + +} // namespace loader +} // namespace td diff --git a/include/render/loader/TextureLoader.h b/include/render/loader/TextureLoader.h index 1ccfb99..7f47d23 100644 --- a/include/render/loader/TextureLoader.h +++ b/include/render/loader/TextureLoader.h @@ -8,9 +8,12 @@ #ifndef RENDER_LOADER_TEXTURELOADER_H_ #define RENDER_LOADER_TEXTURELOADER_H_ +#include "render/loader/GLLoader.h" +#include + namespace TextureLoader { -unsigned int LoadGLTexture(const char* fileName); +GL::Texture LoadTexture(const std::string& fileName); } diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b46505b..d5a64cd 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -53,7 +53,7 @@ bool Renderer::Init() { glEnable(GL_CULL_FACE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDepthFunc(GL_LESS); - glFrontFace(GL_CW); + glFrontFace(GL_CCW); InitShaders(); return true; } @@ -69,9 +69,12 @@ void Renderer::RenderModel(const Model& model) { m_EntityShader->Start(); m_EntityShader->SetModelPos(model.positon); m_EntityShader->SetColorEffect(model.color); + if (model.texture != nullptr) + model.texture->Bind(); model.vao->Bind(); glDrawArrays(GL_TRIANGLES, 0, static_cast(model.vao->GetVertexCount())); model.vao->Unbind(); + GL::Texture::Unbind(); } void Renderer::Prepare() { diff --git a/src/render/WorldRenderer.cpp b/src/render/WorldRenderer.cpp index 74b0ffc..73bca0d 100644 --- a/src/render/WorldRenderer.cpp +++ b/src/render/WorldRenderer.cpp @@ -1,5 +1,7 @@ #include "render/WorldRenderer.h" #include "render/loader/WorldLoader.h" +#include "render/loader/TextureLoader.h" +#include "render/loader/MobLoader.h" #include "render/Renderer.h" #include "render/gui/imgui/imgui.h" #include "gui/imgui/imgui_internal.h" @@ -25,9 +27,15 @@ ImVec4 WorldRenderer::GetImGuiTeamColor(game::TeamColor color) { 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())); + m_WorldVao = std::make_unique(WorldLoader::LoadWorldModel(m_World)); + + m_SelectTileModel = std::make_unique(); + m_SelectTileModel->vao = std::make_unique(WorldLoader::LoadTileSelectModel()); + + m_MobModel = std::make_unique(); + m_MobModel->texture = std::make_unique(TextureLoader::LoadTexture("Assets/zombie.png")); + m_MobModel->vao = std::make_unique(MobLoader::LoadMobModel()); + utils::LOGD(utils::format("Vertex Count : %u", m_WorldVao->GetVertexCount())); } @@ -91,11 +99,9 @@ void WorldRenderer::RenderWorld() const { 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); + m_MobModel->positon = { mob->GetCenterX(), 0, mob->GetCenterY() }; + m_MobModel->color = mob->HasTakenDamage() ? Vec3f{ 1, 0.5, 0.5 } : Vec3f{ 1, 1, 1 }; + m_Renderer->RenderModel(*m_MobModel); } } @@ -109,11 +115,9 @@ void WorldRenderer::RenderTileSelect() const { 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_SelectTileModel->positon = { std::floor(m_CursorPos.x), 0, std::floor(m_CursorPos.y) }; - m_Renderer->RenderModel(tileSelectModel); + m_Renderer->RenderModel(*m_SelectTileModel); } void WorldRenderer::RenderPopups() { diff --git a/src/render/loader/GLLoader.cpp b/src/render/loader/GLLoader.cpp index 360372e..5756090 100644 --- a/src/render/loader/GLLoader.cpp +++ b/src/render/loader/GLLoader.cpp @@ -8,6 +8,7 @@ #include "render/loader/GLLoader.h" #include "render/GL.h" +#include namespace GL { @@ -69,4 +70,37 @@ void VertexBuffer::BindVertexAttribs() const { glVertexAttribPointer(pointer.m_Index, static_cast(pointer.m_Size), GL_FLOAT, false, m_DataStride * sizeof(float), reinterpret_cast(pointer.m_Offset)); } } + +Texture::Texture(const char* textureData, int width, int height, int comp) { + glGenTextures(1, &m_ID); + + Bind(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + assert(comp == 3 || comp == 4); + + if (comp == 3) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, + GL_UNSIGNED_BYTE, textureData); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, textureData); + + Unbind(); +} + +Texture::~Texture() { + glDeleteTextures(1, &m_ID); +} + +void Texture::Bind() const { + glBindTexture(GL_TEXTURE_2D, m_ID); +} + +void Texture::Unbind() { + glBindTexture(GL_TEXTURE_2D, 0); +} + } \ No newline at end of file diff --git a/src/render/loader/MobLoader.cpp b/src/render/loader/MobLoader.cpp new file mode 100644 index 0000000..5b65260 --- /dev/null +++ b/src/render/loader/MobLoader.cpp @@ -0,0 +1,160 @@ +#include "Defines.h" +#include "render/loader/MobLoader.h" + +#include +#include +#include +#include + +namespace td { +namespace MobLoader { + +const static int POSITION_VERTEX_SIZE = 3; +const static int TEXTURE_VERTEX_SIZE = 2; + +typedef Vec3f Vertex; +typedef Vec2f TextureUV; +typedef Vec3f Normal; + +struct Index { + int vertexIndex; + int textureIndex; + int normalIndex; +}; + +enum DataType : std::uint8_t { + dt_Vertex, + dt_Texture, + dt_Normal, + dt_Index, + dt_None +}; + +static DataType GetDataType(const std::string& type) { + static const std::map Types = { + {"v", dt_Vertex}, + {"vt", dt_Texture}, + {"vn", dt_Normal}, + {"f", dt_Index} + }; + + auto it = Types.find(type); + + return it != Types.end() ? it->second : dt_None; +} + +GL::VertexArray LoadMobModel() { + std::ifstream fileStream{ "Assets/zombie.obj" }; + std::string line; + + std::vector tempVertecies; + std::vector tempTextureUvs; + std::vector tempNormals; + + std::vector vertecies; + std::vector textureUvs; + std::vector normals; + + while (getline(fileStream, line)) { + + std::replace(line.begin(), line.end(), '/', ' '); + + std::stringstream ss; + ss << line; + + std::string typeStr; + ss >> typeStr; + + DataType dataType = GetDataType(typeStr); + + switch (dataType) { + case dt_Vertex: { + Vertex vertex; + + ss >> vertex.x; + ss >> vertex.y; + ss >> vertex.z; + + tempVertecies.push_back(vertex); + break; + } + + case dt_Texture: { + TextureUV texture; + + ss >> texture.x; + ss >> texture.y; + + tempTextureUvs.push_back(texture); + break; + } + + case dt_Normal: { + Normal normal; + + ss >> normal.x; + ss >> normal.y; + ss >> normal.z; + + tempNormals.push_back(normal); + break; + } + + case dt_Index: { + + Index tempIndicies[4]; + + for (size_t i = 0; i < 4; i++){ + ss >> tempIndicies[i].vertexIndex; + ss >> tempIndicies[i].textureIndex; + ss >> tempIndicies[i].normalIndex; + } + + static const std::vector vertexOrder = {0, 1, 2, 0, 2, 3}; + + for(int i = 0; i < vertexOrder.size(); i++) { + Index& index = tempIndicies[vertexOrder[i]]; + + int vertexIndex = index.vertexIndex - 1; + int textureIndex = index.textureIndex - 1; + int normalIndex = index.normalIndex - 1; + + Vertex vertex = tempVertecies[vertexIndex]; + TextureUV texture = tempTextureUvs[textureIndex]; + Normal normal = tempNormals[normalIndex]; + + vertecies.push_back(vertex.x); + vertecies.push_back(vertex.y); + vertecies.push_back(vertex.z); + + textureUvs.push_back(texture.x); + textureUvs.push_back(1.0f - texture.y); + + normals.push_back(normal.x); + normals.push_back(normal.y); + normals.push_back(normal.z); + } + + break; + } + + case dt_None: + break; + } + } + + GL::VertexBuffer positionVBO(vertecies, POSITION_VERTEX_SIZE); + positionVBO.AddVertexAttribPointer(0, POSITION_VERTEX_SIZE, 0); + GL::VertexBuffer textureVBO(textureUvs, TEXTURE_VERTEX_SIZE); + textureVBO.AddVertexAttribPointer(1, TEXTURE_VERTEX_SIZE, 0); + + GL::VertexArray mobVao(vertecies.size() / POSITION_VERTEX_SIZE); // each pos = 1 color + mobVao.Bind(); + mobVao.BindVertexBuffer(positionVBO); + mobVao.BindVertexBuffer(textureVBO); + mobVao.Unbind(); + return mobVao; +} + +} // namespace loader +} // namespace td diff --git a/src/render/loader/TextureLoader.cpp b/src/render/loader/TextureLoader.cpp index 81dc821..fa392fc 100644 --- a/src/render/loader/TextureLoader.cpp +++ b/src/render/loader/TextureLoader.cpp @@ -10,37 +10,29 @@ #include "render/loader/stb_image.h" #include #include "render/GL.h" +#include "misc/Log.h" +#include "misc/Format.h" namespace TextureLoader { -unsigned int LoadGLTexture(const char* fileName) { +GL::Texture LoadTexture(const std::string& fileName) { int width, height, comp; - const unsigned char* image = stbi_load(fileName, &width, &height, &comp, STBI_rgb_alpha); + const unsigned char* image = stbi_load(fileName.c_str(), &width, &height, &comp, STBI_rgb_alpha); if (image == nullptr) { - std::cerr << "Erreur lors du chargement de la texture !" << std::endl; + td::utils::LOGE("Erreur lors du chargement de la texture !"); throw(std::runtime_error("Failed to load texture")); } - GLuint textureID; - glGenTextures(1, &textureID); - glBindTexture(GL_TEXTURE_2D, textureID); + GL::Texture texture {reinterpret_cast(image), width, height, comp}; - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + delete image; - if (comp == 3) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, - GL_UNSIGNED_BYTE, image); - else if (comp == 4) - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, - GL_UNSIGNED_BYTE, image); + td::utils::LOGD(td::utils::format("Texture %s chargée !", fileName.c_str())); - glBindTexture(GL_TEXTURE_2D, 0); - stbi_image_free((void*)image); - return textureID; + return texture; } } diff --git a/src/render/loader/WorldLoader.cpp b/src/render/loader/WorldLoader.cpp index 153ce74..fbafb33 100644 --- a/src/render/loader/WorldLoader.cpp +++ b/src/render/loader/WorldLoader.cpp @@ -5,50 +5,15 @@ #include "game/BaseGame.h" +#include "misc/Random.h" + namespace td { namespace render { namespace WorldLoader { -const static int VERTEX_SIZE = 3; - -GL::VertexArray LoadMobModel() { - std::vector positions = { - -0.5, 0, -0.5, - 0.5, 0, -0.5, - -0.5, 0, 0.5, - - 0.5, 0, -0.5, - -0.5, 0, 0.5, - 0.5, 0, 0.5 - }; - - float yellowFloat; - int yellow = 255 << 24 | 255 << 16 | 255; - memcpy(&yellowFloat, &yellow, sizeof(int)); - - std::vector colors = { - yellowFloat, - yellowFloat, - yellowFloat, - - yellowFloat, - yellowFloat, - yellowFloat - }; - - GL::VertexBuffer positionVBO(positions, VERTEX_SIZE); - positionVBO.AddVertexAttribPointer(0, VERTEX_SIZE, 0); - GL::VertexBuffer colorVBO(colors, 1); - colorVBO.AddVertexAttribPointer(1, 1, 0); - - GL::VertexArray mobVao(colors.size()); // each pos = 1 color - mobVao.Bind(); - mobVao.BindVertexBuffer(positionVBO); - mobVao.BindVertexBuffer(colorVBO); - mobVao.Unbind(); - return mobVao; -} +const static int POSITION_VERTEX_SIZE = 3; +const static int TEXTURE_VERTEX_SIZE = 2; GL::VertexArray LoadWorldModel(const td::game::World* world) { std::vector positions; @@ -71,12 +36,12 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) { continue; positions.insert(positions.end(), { - static_cast(chunkX + tileX), 0, static_cast(chunkY + tileY), static_cast(chunkX + tileX + 1), 0, static_cast(chunkY + tileY), + static_cast(chunkX + tileX), 0, static_cast(chunkY + tileY), static_cast(chunkX + tileX), 0, static_cast(chunkY + tileY + 1), - static_cast(chunkX + tileX), 0, static_cast(chunkY + tileY + 1), static_cast(chunkX + tileX + 1), 0, static_cast(chunkY + tileY), + static_cast(chunkX + tileX), 0, static_cast(chunkY + tileY + 1), static_cast(chunkX + tileX + 1), 0, static_cast(chunkY + tileY + 1) }); @@ -103,12 +68,12 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) { float fromY = spawn.GetTopLeft().GetY(), toY = spawn.GetBottomRight().GetY(); positions.insert(positions.end(), { - fromX, 0, toY, fromX, 0, fromY, + fromX, 0, toY, toX, 0, fromY, - toX, 0, toY, fromX, 0, toY, + toX, 0, toY, toX, 0, fromY, }); @@ -131,12 +96,12 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) { float fromY = castle.GetTopLeft().GetY(), toY = castle.GetBottomRight().GetY(); positions.insert(positions.end(), { - fromX, 0, toY, fromX, 0, fromY, + fromX, 0, toY, toX, 0, fromY, - toX, 0, toY, fromX, 0, toY, + toX, 0, toY, toX, 0, fromY, }); @@ -153,12 +118,12 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) { } } - GL::VertexBuffer positionVBO(positions, VERTEX_SIZE); - positionVBO.AddVertexAttribPointer(0, VERTEX_SIZE, 0); + GL::VertexBuffer positionVBO(positions, POSITION_VERTEX_SIZE); + positionVBO.AddVertexAttribPointer(0, POSITION_VERTEX_SIZE, 0); GL::VertexBuffer colorVBO(colors, 1); colorVBO.AddVertexAttribPointer(1, 1, 0); - GL::VertexArray worldVao(positions.size() / VERTEX_SIZE); // each pos = 3 vertecies + GL::VertexArray worldVao(positions.size() / POSITION_VERTEX_SIZE); // each pos = 3 vertecies worldVao.Bind(); worldVao.BindVertexBuffer(positionVBO); worldVao.BindVertexBuffer(colorVBO); @@ -168,12 +133,12 @@ GL::VertexArray LoadWorldModel(const td::game::World* world) { GL::VertexArray LoadTileSelectModel() { std::vector positions = { - 0, .01, 0, 1, .01, 0, + 0, .01, 0, 0, .01, 1, - 0, .01, 1, 1, .01, 0, + 0, .01, 1, 1, .01, 1 }; @@ -184,12 +149,12 @@ GL::VertexArray LoadTileSelectModel() { std::vector colors(6, colorFloat); - GL::VertexBuffer positionVBO(positions, VERTEX_SIZE); - positionVBO.AddVertexAttribPointer(0, VERTEX_SIZE, 0); + GL::VertexBuffer positionVBO(positions, POSITION_VERTEX_SIZE); + positionVBO.AddVertexAttribPointer(0, POSITION_VERTEX_SIZE, 0); GL::VertexBuffer colorVBO(colors, 1); colorVBO.AddVertexAttribPointer(1, 1, 0); - GL::VertexArray tileSelectVao(positions.size() / 2); // each pos = 2 vertecies + GL::VertexArray tileSelectVao(positions.size() / POSITION_VERTEX_SIZE); tileSelectVao.Bind(); tileSelectVao.BindVertexBuffer(positionVBO); tileSelectVao.BindVertexBuffer(colorVBO); @@ -218,13 +183,13 @@ RenderData LoadTowerModel(game::TowerPtr tower) { towerDY = tower->GetCenterY() + 2.5f; } std::vector positions = { - towerX, 0, towerY, - towerDX, 0, towerY, - towerX, 0, towerDY, + towerDX, 0.001, towerY, + towerX, 0.001, towerY, + towerX, 0.001, towerDY, - towerDX, 0, towerY, - towerX, 0, towerDY, - towerDX, 0, towerDY + towerDX, 0.001, towerY, + towerX, 0.001, towerDY, + towerDX, 0.001, towerDY }; renderData.positions = positions; diff --git a/src/render/shaders/EntityShader.cpp b/src/render/shaders/EntityShader.cpp index fd7de6a..11d50bb 100644 --- a/src/render/shaders/EntityShader.cpp +++ b/src/render/shaders/EntityShader.cpp @@ -3,6 +3,8 @@ namespace td { namespace shader { +// TODO: update ES shaders + #ifdef __ANDROID__ static const char vertexSource[] = R"(#version 300 es @@ -51,16 +53,16 @@ static const char vertexSource[] = R"( #version 330 layout(location = 0) in vec3 position; -layout(location = 1) in int color; +layout(location = 1) in vec2 textureCoords; uniform mat4 viewMatrix; uniform mat4 projectionMatrix; uniform vec3 modelPosition; -flat out int pass_color; +out vec2 pass_textureCoords; void main(void){ - pass_color = color; + pass_textureCoords = textureCoords; gl_Position = projectionMatrix * viewMatrix * vec4(position + modelPosition, 1.0); } )"; @@ -68,20 +70,21 @@ void main(void){ static const char fragmentSource[] = R"( #version 330 -flat in int pass_color; +in vec2 pass_textureCoords; out vec4 out_color; uniform vec3 ColorEffect; +uniform sampler2D textureSampler; void main(void){ - float r = float(pass_color >> 24 & 0xFF) / 255.0; - float g = float(pass_color >> 16 & 0xFF) / 255.0; - float b = float(pass_color >> 8 & 0xFF) / 255.0; - float a = float(pass_color & 0xFF) / 255.0; - vec3 intermediate_color = vec3(r, g, b) * ColorEffect; - out_color = vec4(intermediate_color, a); + vec4 color = vec4(ColorEffect, 1.0) * texture(textureSampler, pass_textureCoords); + + if (color.a <= 0.1) + discard; + + out_color = color; } )";