From 9c575f056ef47ef7e8da581164041985749c1676 Mon Sep 17 00:00:00 2001 From: LaG1924 <12997935+LaG1924@users.noreply.github.com> Date: Sat, 26 Jan 2019 12:58:51 +0500 Subject: Implemented new Shader class --- src/AssetManager.cpp | 32 +++++++++++++++++++ src/AssetManager.hpp | 5 +++ src/RendererWorld.cpp | 34 ++++++++++----------- src/RendererWorld.hpp | 1 - src/Shader.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/Shader.hpp | 40 ++++++++++++++++++++++++ 6 files changed, 178 insertions(+), 19 deletions(-) diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 03a672e..5f2a160 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -34,6 +34,7 @@ void ParseAsset(AssetTreeNode &node); void ParseAssetTexture(AssetTreeNode &node); void ParseAssetBlockModel(AssetTreeNode &node); void ParseAssetBlockState(AssetTreeNode &node); +void ParseAssetShader(AssetTreeNode &node); void ParseBlockModels(); @@ -132,6 +133,11 @@ void ParseAsset(AssetTreeNode &node) { ParseAssetTexture(node); return; } + + if (node.parent->name == "shaders") { + ParseAssetShader(node); + return; + } } void ParseAssetTexture(AssetTreeNode &node) { @@ -339,6 +345,32 @@ void ParseAssetBlockState(AssetTreeNode &node) { node.data.shrink_to_fit(); } +void ParseAssetShader(AssetTreeNode &node) { + try { + nlohmann::json j = nlohmann::json::parse(node.data); + + std::string vertPath = j["vert"].get(); + std::string fragPath = j["frag"].get(); + + AssetTreeNode *vertAsset = AssetManager::GetAssetByAssetName(vertPath); + AssetTreeNode *fragAsset = AssetManager::GetAssetByAssetName(fragPath); + std::string vertSource((char*)vertAsset->data.data(), (char*)vertAsset->data.data() + vertAsset->data.size()); + std::string fragSource((char*)fragAsset->data.data(), (char*)fragAsset->data.data() + fragAsset->data.size()); + + std::vector uniforms; + + for (auto &it : j["uniforms"]) { + uniforms.push_back(it.get()); + } + + node.asset = std::make_unique(); + AssetShader *asset = dynamic_cast(node.asset.get()); + asset->shader = std::make_unique(vertSource, fragSource, uniforms); + } catch (...) { + return; + } +} + void ParseBlockModels() { std::string textureName; diff --git a/src/AssetManager.hpp b/src/AssetManager.hpp index 3ecff25..3b4ad2f 100644 --- a/src/AssetManager.hpp +++ b/src/AssetManager.hpp @@ -14,6 +14,7 @@ #include "Vector.hpp" #include "Block.hpp" #include "TextureAtlas.hpp" +#include "Shader.hpp" enum FaceDirection { down, @@ -160,6 +161,10 @@ struct AssetTexture : Asset { size_t id; }; +struct AssetShader : Asset { + std::unique_ptr shader; +}; + namespace AssetManager { void InitAssetManager(); diff --git a/src/RendererWorld.cpp b/src/RendererWorld.cpp index e1dd52c..7f47a1e 100644 --- a/src/RendererWorld.cpp +++ b/src/RendererWorld.cpp @@ -265,7 +265,6 @@ RendererWorld::~RendererWorld() { workers[i].join(); delete blockShader; delete entityShader; - delete skyShader; DebugInfo::renderSections = 0; DebugInfo::readyRenderer = 0; } @@ -339,11 +338,10 @@ void RendererWorld::Render(RenderState & renderState) { //Render sky renderState.TimeOfDay = gs->TimeOfDay; - renderState.SetActiveShader(skyShader->Program); - projectionLoc = glGetUniformLocation(skyShader->Program, "projection"); - viewLoc = glGetUniformLocation(skyShader->Program, "view"); - glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); - glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); + NewShader *skyShader = AssetManager::GetAsset("/altcraft/shaders/sky")->shader.get(); + skyShader->Activate(); + skyShader->SetUniform("projection", projection); + skyShader->SetUniform("view", view); glm::mat4 model = glm::mat4(1.0); model = glm::translate(model, gs->player->pos.glm()); const float scale = 1000000.0f; @@ -353,8 +351,7 @@ void RendererWorld::Render(RenderState & renderState) { shift *= -1.0f; model = glm::rotate(model, glm::radians(90.0f), glm::vec3(0, 1.0f, 0.0f)); model = glm::rotate(model, glm::radians(360.0f * shift), glm::vec3(-1.0f, 0.0f, 0.0f)); - modelLoc = glGetUniformLocation(skyShader->Program, "model"); - glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); + skyShader->SetUniform("model", model); glCheckError(); @@ -382,7 +379,7 @@ void RendererWorld::Render(RenderState & renderState) { mixLevel = 1.0 - (timePassed / moonriseLength); } - glUniform1f(glGetUniformLocation(skyShader->Program, "DayTime"), mixLevel); + skyShader->SetUniform("DayTime", mixLevel); rendererSky.Render(renderState); glCheckError(); @@ -429,17 +426,18 @@ void RendererWorld::PrepareRender() { entityShader = new Shader("./shaders/entity.vs", "./shaders/entity.fs"); - skyShader = new Shader("./shaders/sky.vs", "./shaders/sky.fs"); - skyShader->Use(); - glUniform1i(glGetUniformLocation(skyShader->Program, "textureAtlas"), 0); TextureCoord sunTexture = AssetManager::GetTexture("/minecraft/textures/environment/sun"); - glUniform4f(glGetUniformLocation(skyShader->Program, "sunTexture"), sunTexture.x, sunTexture.y, sunTexture.w, sunTexture.h); - glUniform1f(glGetUniformLocation(skyShader->Program, "sunTextureLayer"), sunTexture.layer); TextureCoord moonTexture = AssetManager::GetTexture("/minecraft/textures/environment/moon_phases"); - moonTexture.w /= 4.0f; //First phase will be fine for now - moonTexture.h /= 2.0f; - glUniform4f(glGetUniformLocation(skyShader->Program, "moonTexture"), moonTexture.x, moonTexture.y, moonTexture.w, moonTexture.h); - glUniform1f(glGetUniformLocation(skyShader->Program, "moonTextureLayer"), moonTexture.layer); + moonTexture.w /= 4.0f; //First phase will be fine for now + moonTexture.h /= 2.0f; + + NewShader *sky = AssetManager::GetAsset("/altcraft/shaders/sky")->shader.get(); + sky->Activate(); + sky->SetUniform("textureAtlas", 0); + sky->SetUniform("sunTexture", glm::vec4(sunTexture.x, sunTexture.y, sunTexture.w, sunTexture.h)); + sky->SetUniform("sunTextureLayer", (float)sunTexture.layer); + sky->SetUniform("moonTexture", glm::vec4(moonTexture.x, moonTexture.y, moonTexture.w, moonTexture.h)); + sky->SetUniform("moonTextureLayer", (float)moonTexture.layer); } void RendererWorld::Update(double timeToUpdate) { diff --git a/src/RendererWorld.hpp b/src/RendererWorld.hpp index 2dab4f0..d8b74e6 100644 --- a/src/RendererWorld.hpp +++ b/src/RendererWorld.hpp @@ -50,7 +50,6 @@ class RendererWorld { std::vector entities; //Sky Texture *skyTexture; - Shader *skyShader; RendererSky rendererSky; public: RendererWorld(GameState* ptr); diff --git a/src/Shader.cpp b/src/Shader.cpp index d637c3b..9447131 100644 --- a/src/Shader.cpp +++ b/src/Shader.cpp @@ -111,3 +111,88 @@ void Shader::Reload() { new(this) Shader(vertexPath, fragmentPath); LOG(INFO) << "Shader is realoded!"; } + +GLuint NewShader::GetUniformLocation(const std::string &name) { + auto it = uniforms.find(name); + if (it == uniforms.end()) { + LOG(ERROR) << "Accessed not existing uniform " << name; + return 0; + } + return it->second; +} + +NewShader::NewShader(const std::string &vertSource, const std::string &fragSource, const std::vector &uniformsNames) +{ + bool vertFailed = false, fragFailed = false, linkFailed = false, uniformsFailed = false; + const GLchar *vertSourcePtr = vertSource.c_str(); + const GLchar *fragSourcePtr = fragSource.c_str(); + + GLuint vertex, fragment; + GLint success; + GLchar infoLog[512]; + + vertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertex, 1, &vertSourcePtr, NULL); + glCompileShader(vertex); + + glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(vertex, 512, NULL, infoLog); + LOG(ERROR) << "Vertex shader compilation failed: " << std::endl << infoLog; + vertFailed = true; + }; + + fragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragment, 1, &fragSourcePtr, NULL); + glCompileShader(fragment); + + glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(fragment, 512, NULL, infoLog); + LOG(ERROR) << "Fragment shader compilation failed: " << std::endl << infoLog; + fragFailed = true; + }; + + if (vertFailed || fragFailed) + throw std::runtime_error("Shaders not compiled"); + + program = glCreateProgram(); + glAttachShader(program, vertex); + glAttachShader(program, fragment); + glLinkProgram(program); + glGetProgramiv(program, GL_LINK_STATUS, &success); + if (!success) { + glGetProgramInfoLog(program, 512, NULL, infoLog); + LOG(ERROR) << "Shader program not linked: " << std::endl << infoLog; + linkFailed = true; + } + + glDeleteShader(vertex); + glDeleteShader(fragment); + + if (linkFailed) + throw std::runtime_error("Shader not linked"); + + + for (auto &it : uniformsNames) { + GLuint location = glGetUniformLocation(program, it.c_str()); + if (location == -1) { + glDeleteProgram(program); + LOG(ERROR) << "Uniform name \"" << it << "\" not found in shader"; + throw std::runtime_error("Invalid uniform"); + } + + uniforms[it] = location; + } +} + +NewShader::~NewShader() +{ + if (program) + glDeleteProgram(program); +} + +void NewShader::Activate() +{ + glUseProgram(program); +} diff --git a/src/Shader.hpp b/src/Shader.hpp index d6d59eb..b551602 100644 --- a/src/Shader.hpp +++ b/src/Shader.hpp @@ -1,6 +1,11 @@ #pragma once +#include +#include + #include +#include +#include class Shader { @@ -13,4 +18,39 @@ public: void Use(); void Reload(); +}; + +class NewShader { + std::map uniforms; + GLuint program = 0; + + GLuint GetUniformLocation(const std::string &name); + +public: + NewShader(const NewShader &) = delete; + NewShader(NewShader &&other) = delete; + NewShader &operator=(const NewShader &) = delete; + NewShader &operator=(NewShader &&other) = delete; + + NewShader(const std::string &vertSource, const std::string &fragSource, const std::vector &uniformsNames); + + ~NewShader(); + + void Activate(); + + inline void SetUniform(const std::string &name, int val) { + glUniform1i(GetUniformLocation(name), val); + } + + inline void SetUniform(const std::string &name, float val) { + glUniform1f(GetUniformLocation(name), val); + } + + inline void SetUniform(const std::string &name, glm::vec4 val) { + glUniform4f(GetUniformLocation(name), val.x, val.y, val.z, val.w); + } + + inline void SetUniform(const std::string &name, glm::mat4 val) { + glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, glm::value_ptr(val)); + } }; \ No newline at end of file -- cgit v1.2.3