diff --git a/src/graphics/core/material.h b/src/graphics/core/material.h index 03f9ea18..a112674a 100644 --- a/src/graphics/core/material.h +++ b/src/graphics/core/material.h @@ -74,6 +74,8 @@ struct Material CullFace cullFace = CullFace::BACK; // Special tag std::string tag = ""; + // Recolor reference color + Color recolorReference = { 0.0f, 0.0f, 0.0f, 0.0f }; // Legacy functionality //! Variable detail texture @@ -95,6 +97,7 @@ struct Material && alphaThreshold == other.alphaThreshold && cullFace == other.cullFace && tag == other.tag + && recolorReference == other.recolorReference && variableDetail == other.variableDetail && detailTexture == other.detailTexture; } diff --git a/src/graphics/core/renderers.h b/src/graphics/core/renderers.h index 3d0e0cbc..a1b9d60d 100644 --- a/src/graphics/core/renderers.h +++ b/src/graphics/core/renderers.h @@ -198,6 +198,9 @@ public: //! Sets alpha scissor virtual void SetAlphaScissor(float alpha) = 0; + //! Sets recolor parameters + virtual void SetRecolor(bool enabled, const glm::vec3& from = {}, const glm::vec3& to = {}, float threshold = {}) = 0; + //! Sets depth test virtual void SetDepthTest(bool enabled) = 0; //! Sets depth mask diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 4b1828cc..c89ef5cf 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -2374,11 +2374,6 @@ void CEngine::SetOverColor(const Color& color, TransparencyMode mode) m_overMode = mode; } -void CEngine::SetTeamColor(int team, const Color& color) -{ - m_teamColors[team] = color; -} - void CEngine::SetParticleDensity(float value) { if (value < 0.0f) value = 0.0f; @@ -2946,9 +2941,54 @@ void CEngine::Draw3DScene() Color color = data.material.albedoColor; + bool recolor = false; + Color recolorFrom = {}; + Color recolorTo = {}; + float recolorTreshold = 0.0; + if (data.material.tag == "team") { - color = m_teamColors[m_objects[objRank].team]; + color = CRobotMain::GetInstance().GetTeamColor(m_objects[objRank].team); + } + else if (data.material.tag == "vehicle") + { + color = CRobotMain::GetInstance().GetVehicleColor(); + } + else if (data.material.tag == "plant") + { + color = CRobotMain::GetInstance().GetGreeneryColor(); + } + else if (data.material.tag == "alien") + { + color = CRobotMain::GetInstance().GetAlienColor(); + } + else if (data.material.tag == "recolor_team") + { + recolor = true; + recolorFrom = data.material.recolorReference; + recolorTo = CRobotMain::GetInstance().GetTeamColor(m_objects[objRank].team); + recolorTreshold = 0.1; + } + else if (data.material.tag == "recolor_vehicle") + { + recolor = true; + recolorFrom = data.material.recolorReference; + recolorTo = CRobotMain::GetInstance().GetVehicleColor(); + recolorTreshold = 0.1; + } + else if (data.material.tag == "recolor_plant") + { + recolor = true; + recolorFrom = data.material.recolorReference; + recolorTo = CRobotMain::GetInstance().GetGreeneryColor(); + recolorTreshold = 0.1; + } + else if (data.material.tag == "recolor_alien") + { + recolor = true; + recolorFrom = data.material.recolorReference; + recolorTo = CRobotMain::GetInstance().GetAlienColor(); + recolorTreshold = 0.1; } objectRenderer->SetAlbedoColor(color); @@ -2961,6 +3001,8 @@ void CEngine::Draw3DScene() objectRenderer->SetMaterialParams(data.material.roughness, data.material.metalness, data.material.aoStrength); objectRenderer->SetMaterialTexture(data.materialTexture); + objectRenderer->SetRecolor(recolor, recolorFrom, recolorTo, recolorTreshold); + objectRenderer->SetCullFace(data.material.cullFace); objectRenderer->SetUVTransform(data.uvOffset, data.uvScale); objectRenderer->DrawObject(data.buffer); diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 015473b9..40cb8016 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -827,8 +827,6 @@ public: void SetOverFront(bool front); //! Sets the foreground overlay color void SetOverColor(const Color& color, TransparencyMode mode); - //! Sets color for a team - void SetTeamColor(int team, const Color& color); //@{ //! Management of the particle density diff --git a/src/graphics/model/model_gltf.cpp b/src/graphics/model/model_gltf.cpp index 817a3dfb..bc893818 100644 --- a/src/graphics/model/model_gltf.cpp +++ b/src/graphics/model/model_gltf.cpp @@ -209,6 +209,17 @@ void GLTFLoader::ReadMaterials() mat.tag = extras["tag"].get(); } + if (extras.contains("recolor_ref")) + { + const auto& color = extras["recolor_ref"]; + + float r = color[0]; + float g = color[1]; + float b = color[2]; + + mat.recolorReference = Color(r, g, b); + } + if (extras.contains("energy")) { if (extras["energy"].get() != 0) diff --git a/src/graphics/opengl33/gl33_object_renderer.cpp b/src/graphics/opengl33/gl33_object_renderer.cpp index a5a41e2a..55323104 100644 --- a/src/graphics/opengl33/gl33_object_renderer.cpp +++ b/src/graphics/opengl33/gl33_object_renderer.cpp @@ -97,6 +97,12 @@ CGL33ObjectRenderer::CGL33ObjectRenderer(CGL33Device* device) m_triplanarMode = glGetUniformLocation(m_program, "uni_TriplanarMode"); m_triplanarScale = glGetUniformLocation(m_program, "uni_TriplanarScale"); m_alphaScissor = glGetUniformLocation(m_program, "uni_AlphaScissor"); + + m_recolor = glGetUniformLocation(m_program, "uni_Recolor"); + m_recolorFrom = glGetUniformLocation(m_program, "uni_RecolorFrom"); + m_recolorTo = glGetUniformLocation(m_program, "uni_RecolorTo"); + m_recolorThreshold = glGetUniformLocation(m_program, "uni_RecolorThreshold"); + m_uvOffset = glGetUniformLocation(m_program, "uni_UVOffset"); m_uvScale = glGetUniformLocation(m_program, "uni_UVScale"); @@ -211,6 +217,7 @@ void CGL33ObjectRenderer::CGL33ObjectRenderer::Begin() SetEmissiveColor({ 0, 0, 0, 0 }); SetAlbedoColor({ 1, 1, 1, 1 }); SetMaterialParams(1.0, 0.0, 0.0); + SetRecolor(false); } void CGL33ObjectRenderer::CGL33ObjectRenderer::End() @@ -427,6 +434,21 @@ void CGL33ObjectRenderer::SetAlphaScissor(float alpha) glUniform1f(m_alphaScissor, alpha); } +void CGL33ObjectRenderer::SetRecolor(bool enabled, const glm::vec3& from, const glm::vec3& to, float threshold) +{ + glUniform1i(m_recolor, enabled ? 1 : 0); + + if (enabled) + { + auto fromHSV = RGB2HSV(Color(from.r, from.g, from.b, 1.0)); + auto toHSV = RGB2HSV(Color(to.r, to.g, to.b, 1.0)); + + glUniform3f(m_recolorFrom, fromHSV.h, fromHSV.s, fromHSV.v); + glUniform3f(m_recolorTo, toHSV.h, toHSV.s, toHSV.v); + glUniform1f(m_recolorThreshold, threshold); + } +} + void CGL33ObjectRenderer::DrawObject(const CVertexBuffer* buffer) { auto b = dynamic_cast(buffer); diff --git a/src/graphics/opengl33/gl33_object_renderer.h b/src/graphics/opengl33/gl33_object_renderer.h index 0a3c4c53..206c9ecb 100644 --- a/src/graphics/opengl33/gl33_object_renderer.h +++ b/src/graphics/opengl33/gl33_object_renderer.h @@ -86,6 +86,9 @@ public: //! Sets alpha scissor virtual void SetAlphaScissor(float alpha) override; + //! Sets recolor parameters + virtual void SetRecolor(bool enabled, const glm::vec3& from = {}, const glm::vec3& to = {}, float threshold = {}) override; + virtual void SetDepthTest(bool enabled) override; virtual void SetDepthMask(bool enabled) override; @@ -141,6 +144,11 @@ private: GLint m_triplanarScale = -1; GLint m_alphaScissor = -1; + GLint m_recolor = -1; + GLint m_recolorFrom = -1; + GLint m_recolorTo = -1; + GLint m_recolorThreshold = -1; + GLint m_uvOffset = -1; GLint m_uvScale = -1; diff --git a/src/graphics/opengl33/shaders/gl33/object_fs.glsl b/src/graphics/opengl33/shaders/gl33/object_fs.glsl index ee184b84..b7a666e8 100644 --- a/src/graphics/opengl33/shaders/gl33/object_fs.glsl +++ b/src/graphics/opengl33/shaders/gl33/object_fs.glsl @@ -17,7 +17,7 @@ * along with this program. If not, see http://gnu.org/licenses */ -// FRAGMENT SHADER - TERRAIN RENDERER +// FRAGMENT SHADER - OBJECT RENDERER uniform vec2 uni_FogRange; uniform vec3 uni_FogColor; @@ -39,6 +39,11 @@ uniform float uni_TriplanarScale; uniform float uni_AlphaScissor; +uniform bool uni_Recolor; +uniform vec3 uni_RecolorFrom; +uniform vec3 uni_RecolorTo; +uniform float uni_RecolorThreshold; + in VertexData { vec4 Color; @@ -64,11 +69,48 @@ vec3 Triplanar(vec3 position, vec3 normal) return sum; } +// All components are in the range [0...1], including hue. +vec3 rgb2hsv(vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +// All components are in the range [0...1], including hue. +vec3 hsv2rgb(vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + void main() { vec4 albedo = data.Color * uni_AlbedoColor; - albedo *= texture(uni_AlbedoTexture, data.TexCoord0); + vec4 texColor = texture(uni_AlbedoTexture, data.TexCoord0); + + if (uni_Recolor) + { + vec3 hsv = rgb2hsv(texColor.rgb); + + if (abs(hsv.x - uni_RecolorFrom.x) < uni_RecolorThreshold) + { + hsv += (uni_RecolorTo - uni_RecolorFrom); + + if (hsv.x < 0.0) hsv.x += 1.0; + if (hsv.x > 1.0) hsv.x -= 1.0; + } + + texColor.rgb = hsv2rgb(hsv); + } + + albedo *= texColor; vec3 dirty = vec3(0.0); diff --git a/src/graphics/opengl33/shaders/gl33/object_vs.glsl b/src/graphics/opengl33/shaders/gl33/object_vs.glsl index 949167c3..dce9998e 100644 --- a/src/graphics/opengl33/shaders/gl33/object_vs.glsl +++ b/src/graphics/opengl33/shaders/gl33/object_vs.glsl @@ -17,7 +17,7 @@ * along with this program. If not, see http://gnu.org/licenses */ -// VERTEX SHADER - TERRAIN RENDERER +// VERTEX SHADER - OBJECT RENDERER uniform mat4 uni_ProjectionMatrix; uniform mat4 uni_ViewMatrix; diff --git a/src/level/robotmain.cpp b/src/level/robotmain.cpp index 11362395..7df641b8 100644 --- a/src/level/robotmain.cpp +++ b/src/level/robotmain.cpp @@ -4036,10 +4036,6 @@ void CRobotMain::ChangeColor() { int team = it.first; Gfx::Color newColor = it.second; - std::string teamStr = StrUtils::ToString(team); - if(team == 0) teamStr = ""; - - m_engine->SetTeamColor(team, newColor); //m_engine->ChangeTextureColor("textures/objects/base1.png"+teamStr, "textures/objects/base1.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); //m_engine->ChangeTextureColor("textures/objects/convert.png"+teamStr, "textures/objects/convert.png", COLOR_REF_BOT, newColor, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, nullptr, 0, true); @@ -6000,6 +5996,34 @@ void CRobotMain::MarkResearchDone(ResearchType type, int team) } } +const Gfx::Color& CRobotMain::GetTeamColor(int team) +{ + if (m_colorNewBot.count(team) > 0) + return m_colorNewBot.at(team); + else + return m_colorNewBot.at(0); +} + +const Gfx::Color& CRobotMain::GetVehicleColor() +{ + return m_colorNewBot.at(0); +} + +const Gfx::Color& CRobotMain::GetAlienColor() +{ + return m_colorNewAlien; +} + +const Gfx::Color& CRobotMain::GetGreeneryColor() +{ + return m_colorNewGreen; +} + +const Gfx::Color& CRobotMain::GetWaterColor() +{ + return m_colorNewWater; +} + Error CRobotMain::CanBuildError(ObjectType type, int team) { if(!IsBuildingEnabled(type)) return ERR_BUILD_DISABLED; diff --git a/src/level/robotmain.h b/src/level/robotmain.h index a7ca4fae..c5378679 100644 --- a/src/level/robotmain.h +++ b/src/level/robotmain.h @@ -440,6 +440,17 @@ public: //! \brief Mark given research as done void MarkResearchDone(ResearchType type, int team); + //! \brief Returns a color associated with a team or vehicle color if none defined + const Gfx::Color& GetTeamColor(int team); + //! \brief Returns vehicle color + const Gfx::Color& GetVehicleColor(); + //! \brief Returns alien color + const Gfx::Color& GetAlienColor(); + //! \brief Returns plant color + const Gfx::Color& GetGreeneryColor(); + //! \brief Returns water color + const Gfx::Color& GetWaterColor(); + /** * \brief Check if all requirements to build this object are met (EnableBuild + DoneResearch) * \return true if the building can be built, false otherwise