diff --git a/data/layout.xml b/data/layout.xml index cc3cc77..7fd3aae 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -34,7 +34,7 @@ - + diff --git a/engine/app.cpp b/engine/app.cpp index e85beef..0a32357 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -78,10 +78,10 @@ void App::init() layout.update(width, height); sampler.create(); - shader.create(shader_v, shader_f); - shader_color.create(shader_color_v, shader_color_f); - shader_uv.create(shader_v, shader_uv_f); - plane.create<5>(1, 1); + ShaderManager::create(kShader::Texture, shader_v, shader_f); + ShaderManager::create(kShader::Color, shader_color_v, shader_color_f); + ShaderManager::create(kShader::UVs, shader_v, shader_uv_f); + WidgetBorder::m_plane.create<1>(1, 1); if (!tex.load("data/uvs.jpg")) printf("error loading image\n"); @@ -118,10 +118,8 @@ void App::update(float dt) glActiveTexture(GL_TEXTURE0); tex.bind(); sampler.bind(0); - shader.use(); - shader.u_int("tex", 0); - shader_color.use(); - shader_color.u_vec4("col", { .3f, .3f, .3f, 1 }); + ShaderManager::use(kShader::Texture); + ShaderManager::u_int(kShaderUniform::Tex, 0); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_SCISSOR_TEST); @@ -132,15 +130,7 @@ void App::update(float dt) if (n.m_widget) { - shader_color.u_vec4("col", n.color); - shader_color.use(); - shader_color.u_mat4("mvp", n.m_widget->mvp); - plane.draw_fill(); - - shader_color.u_vec4("col", { 1, 1, 1, 1 }); - shader_color.use(); - shader_color.u_mat4("mvp", n.m_widget->mvp); - plane.draw_stroke(); + n.m_widget->draw(); } } glDisable(GL_SCISSOR_TEST); diff --git a/engine/app.hpp b/engine/app.hpp index 4ff7072..487d683 100644 --- a/engine/app.hpp +++ b/engine/app.hpp @@ -8,10 +8,6 @@ class App { Sampler sampler; - Shader shader; - Shader shader_color; - Shader shader_uv; - Plane plane; Texture2D tex; Node layout; public: diff --git a/engine/layout.cpp b/engine/layout.cpp index 40f2e7a..ab3e92d 100644 --- a/engine/layout.cpp +++ b/engine/layout.cpp @@ -2,7 +2,7 @@ #include "layout.h" #include "util.hpp" -Plane* WidgetBorder::m_plane; +Plane WidgetBorder::m_plane; void Node::update(float width, float height) { @@ -34,11 +34,11 @@ void Node::update_internal(const glm::vec2& origin, const glm::mat4& proj) c.update_internal(m_pos, proj); } -void Node::parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* attr) +void Node::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { switch (ka) { - case att::kAttribute::Width: + case kAttribute::Width: if (strcmp(attr->Value(), "auto") == 0) { YGNodeStyleSetWidth(y_node, YGUndefined); @@ -52,16 +52,16 @@ void Node::parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* at YGNodeStyleSetWidth(y_node, attr->FloatValue()); } break; - case att::kAttribute::MinWidth: + case kAttribute::MinWidth: if (strchr(attr->Value(), '%')) YGNodeStyleSetMinWidthPercent(y_node, attr->FloatValue()); else YGNodeStyleSetMinWidth(y_node, attr->FloatValue()); break; - case att::kAttribute::MaxWidth: + case kAttribute::MaxWidth: YGNodeStyleSetMaxWidth(y_node, attr->FloatValue()); break; - case att::kAttribute::Height: + case kAttribute::Height: if (strcmp(attr->Value(), "auto") == 0) { YGNodeStyleSetHeight(y_node, YGUndefined); @@ -75,19 +75,19 @@ void Node::parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* at YGNodeStyleSetHeight(y_node, attr->FloatValue()); } break; - case att::kAttribute::MinHeight: + case kAttribute::MinHeight: YGNodeStyleSetMinHeight(y_node, attr->FloatValue()); break; - case att::kAttribute::MaxHeight: + case kAttribute::MaxHeight: YGNodeStyleSetMaxHeight(y_node, attr->FloatValue()); break; - case att::kAttribute::Grow: + case kAttribute::Grow: YGNodeStyleSetFlexGrow(y_node, attr->FloatValue()); break; - case att::kAttribute::Shrink: + case kAttribute::Shrink: YGNodeStyleSetFlexShrink(y_node, attr->FloatValue()); break; - case att::kAttribute::FlexDir: + case kAttribute::FlexDir: { YGFlexDirection dir = YGFlexDirectionRow; if (strcmp("col", attr->Value()) == 0) @@ -101,10 +101,10 @@ void Node::parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* at YGNodeStyleSetFlexDirection(y_node, dir); break; } - case att::kAttribute::FlexWrap: + case kAttribute::FlexWrap: YGNodeStyleSetFlexWrap(y_node, attr->IntValue() ? YGWrapWrap : YGWrapNoWrap); break; - case att::kAttribute::Padding: + case kAttribute::Padding: { glm::vec4 pad; int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); @@ -124,7 +124,7 @@ void Node::parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* at } break; } - case att::kAttribute::Margin: + case kAttribute::Margin: { glm::vec4 pad; int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); @@ -144,22 +144,9 @@ void Node::parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* at } break; } - case att::kAttribute::Color: - { - glm::vec4 pad; - int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); - if (n == 1) - { - color = glm::vec4(pad.x); - } - else - { - color = pad; - } - break; - } default: - // other_attributes_handler() + if (m_widget) + m_widget->parse_attributes(ka, attr); break; } } @@ -189,17 +176,17 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node) m_name = x_node->Name(); auto attr = x_node->FirstAttribute(); - att::kWidget widget_id = (att::kWidget)const_hash(x_node->Name()); + kWidget widget_id = (kWidget)const_hash(x_node->Name()); switch (widget_id) { - case att::kWidget::Border: + case kWidget::Border: m_widget = std::make_unique(); break; } while (attr) { - parse_attributes((att::kAttribute)const_hash(attr->Name()), attr); + parse_attributes((kAttribute)const_hash(attr->Name()), attr); attr = attr->Next(); } diff --git a/engine/layout.h b/engine/layout.h index 252ec9e..2d3cddc 100644 --- a/engine/layout.h +++ b/engine/layout.h @@ -1,104 +1,34 @@ #pragma once #include "shape.hpp" #include "util.hpp" +#include "shader.hpp" -namespace att +enum class kAttribute : uint16_t { - enum class kAttribute : uint16_t - { - Width = const_hash("width"), - MinWidth = const_hash("max-width"), - MaxWidth = const_hash("min-width"), - Height = const_hash("height"), - MinHeight = const_hash("min-height"), - MaxHeight = const_hash("max-height"), - Divisions = const_hash("divisions"), - InnerRadius = const_hash("inner-radius"), - OuterRadius = const_hash("outer-radius"), - Grow = const_hash("grow"), - Shrink = const_hash("shrink"), - FlexDir = const_hash("dir"), - FlexWrap = const_hash("wrap"), - Padding = const_hash("pad"), - Margin = const_hash("margin"), - Color = const_hash("color"), - }; + Width = const_hash("width"), + MinWidth = const_hash("max-width"), + MaxWidth = const_hash("min-width"), + Height = const_hash("height"), + MinHeight = const_hash("min-height"), + MaxHeight = const_hash("max-height"), + Divisions = const_hash("divisions"), + InnerRadius = const_hash("inner-radius"), + OuterRadius = const_hash("outer-radius"), + Grow = const_hash("grow"), + Shrink = const_hash("shrink"), + FlexDir = const_hash("dir"), + FlexWrap = const_hash("wrap"), + Padding = const_hash("pad"), + Margin = const_hash("margin"), + Color = const_hash("color"), + Thickness = const_hash("thickness"), + BorderColor = const_hash("border-color"), +}; - enum class kWidget : uint16_t - { - Border = const_hash("border"), - }; - - struct AttributeBase - { - kAttribute id; - }; - - typedef std::map> AttrubutesMap; - - template - struct Attribute : public AttributeBase - { - static const kAttribute static_id = T; - V value; - Attribute() : value{ 0 } { id = static_id; } - Attribute(V v) : value(v) { id = static_id; } - }; - - struct kAttributeMap - { - kAttribute value; - const char* name; - }; - static constexpr kAttributeMap map[] = - { - { kAttribute::Width, "width" }, - { kAttribute::MinWidth, "min-width" }, - { kAttribute::MaxWidth, "max-width" }, - { kAttribute::Height, "height" }, - { kAttribute::MinHeight, "min-height" }, - { kAttribute::MaxHeight, "max-height" }, - { kAttribute::Divisions, "divisions" }, - { kAttribute::InnerRadius, "inner-radius" }, - { kAttribute::OuterRadius, "outer-radius" }, - { kAttribute::Grow, "grow" }, - { kAttribute::Shrink, "shrink" }, - { kAttribute::FlexDir, "dir" }, - { kAttribute::FlexWrap, "wrap" }, - { kAttribute::Padding, "pad" }, - { kAttribute::Margin, "margin" }, - { kAttribute::Color, "color" }, - }; - - constexpr const char* string(const kAttribute value, int i = 0) - { - // no check on size, value MUST be found - return (map[i].value == value) ? map[i].name : string(value, i + 1); - } - -#define DECLARE_ATTRIBUTE(N,T) \ - struct N : public Attribute \ - { using Attribute::Attribute; }; - - DECLARE_ATTRIBUTE(Width, float); - DECLARE_ATTRIBUTE(MinWidth, float); - DECLARE_ATTRIBUTE(MaxWidth, float); - DECLARE_ATTRIBUTE(Height, float); - DECLARE_ATTRIBUTE(MinHeight, float); - DECLARE_ATTRIBUTE(MaxHeight, float); - DECLARE_ATTRIBUTE(Divisions, int); - DECLARE_ATTRIBUTE(InnerRadius, float); - DECLARE_ATTRIBUTE(OuterRadius, float); - DECLARE_ATTRIBUTE(Grow, float); - DECLARE_ATTRIBUTE(Shrink, float); - DECLARE_ATTRIBUTE(FlexDir, int); - DECLARE_ATTRIBUTE(FlexWrap, int); - DECLARE_ATTRIBUTE(Padding, glm::vec4); - DECLARE_ATTRIBUTE(Margin, glm::vec4); - DECLARE_ATTRIBUTE(Color, glm::vec4); - -#undef DECLARE_ATTRIBUTE -} +enum class kWidget : uint16_t +{ + Border = const_hash("border"), +}; class Widget { @@ -106,15 +36,56 @@ public: glm::mat4 mvp; glm::vec4 clip; virtual void draw() { }; + virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) { }; }; class WidgetBorder : public Widget { public: - static Plane* m_plane; + static Plane m_plane; + glm::vec4 m_color; + glm::vec4 m_border_color; + float m_thinkness{ 1 }; virtual void draw() override { - m_plane->draw_fill(); + ShaderManager::use(kShader::Color); + ShaderManager::u_mat4(kShaderUniform::MVP, mvp); + + ShaderManager::u_vec4(kShaderUniform::Col, m_color); + m_plane.draw_fill(); + + glLineWidth(m_thinkness); + ShaderManager::u_vec4(kShaderUniform::Col, m_border_color); + m_plane.draw_stroke(); + } + virtual void parse_attributes(kAttribute id, const tinyxml2::XMLAttribute* attr) + { + switch (id) + { + case kAttribute::Color: + { + glm::vec4 pad; + int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); + if (n == 1) + m_color = glm::vec4(pad.x); + else + m_color = pad; + break; + } + case kAttribute::BorderColor: + { + glm::vec4 pad; + int n = sscanf(attr->Value(), "%f %f %f %f", &pad.x, &pad.y, &pad.z, &pad.w); + if (n == 1) + m_border_color = glm::vec4(pad.x); + else + m_border_color = pad; + break; + } + case kAttribute::Thickness: + m_thinkness = attr->FloatValue(); + break; + } } }; @@ -131,7 +102,6 @@ public: glm::vec2 m_pos; glm::vec2 m_size; glm::vec4 m_clip; - glm::vec4 color; std::string m_name; Node(const Node&) = delete; Node& operator=(const Node&) = delete; @@ -143,7 +113,6 @@ public: c.parent = this; parent = o.parent; y_node = o.y_node; - color = o.color; m_pos = o.m_pos; m_size = o.m_size; m_clip = o.m_clip; @@ -189,7 +158,7 @@ public: void update(float width, float height); void update_internal(const glm::vec2& origin, const glm::mat4& proj); - void parse_attributes(att::kAttribute ka, const tinyxml2::XMLAttribute* attr); + void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr); void load(const char* path); void load_internal(const tinyxml2::XMLElement* x_node); void reload(); diff --git a/engine/shader.cpp b/engine/shader.cpp index 1664d25..a0161df 100644 --- a/engine/shader.cpp +++ b/engine/shader.cpp @@ -1,7 +1,10 @@ #include "pch.h" #include "shader.hpp" -bool Shader::create(std::string vertex, std::string fragment) +std::map ShaderManager::m_shaders; +Shader* ShaderManager::m_current; + +bool Shader::create(const char* vertex, const char* fragment) { GLint status; static char infolog[4096]; @@ -13,7 +16,7 @@ bool Shader::create(std::string vertex, std::string fragment) { return false; } - source = vertex.c_str(); + source = vertex; glShaderSource(vs, 1, &source, nullptr); glCompileShader(vs); glGetShaderiv(vs, GL_COMPILE_STATUS, &status); @@ -32,7 +35,7 @@ bool Shader::create(std::string vertex, std::string fragment) glDeleteShader(vs); return false; } - source = fragment.c_str(); + source = fragment; glShaderSource(fs, 1, &source, nullptr); glCompileShader(fs); glGetShaderiv(fs, GL_COMPILE_STATUS, &status); @@ -71,6 +74,23 @@ bool Shader::create(std::string vertex, std::string fragment) glDeleteProgram(ps); return false; } + + // Parse shader uniforms + { + GLint count; + GLint size; // size of the variable + GLenum type; // type of the variable (float, vec3 or mat4, etc) + const GLsizei bufSize = 16; // maximum name length + GLchar name[bufSize]; // variable name in GLSL + GLsizei length; // name length + glGetProgramiv(ps, GL_ACTIVE_UNIFORMS, &count); + for (int i = 0; i < count; i++) + { + glGetActiveUniform(ps, (GLuint)i, bufSize, &length, &size, &type, name); + m_umap[(kShaderUniform)const_hash(name)] = glGetUniformLocation(ps, name); + //printf("Uniform #%d Type: %u Name: %s Loc: %d\n", i, type, name, glGetUniformLocation(ps, name)); + } + } prog = ps; @@ -80,18 +100,47 @@ void Shader::use() { glUseProgram(prog); } -void Shader::u_vec4(const char* name, const glm::vec4& v) +void Shader::u_vec4(kShaderUniform id, const glm::vec4& v) { - auto loc = glGetUniformLocation(prog, name); - glUniform4fv(loc, 1, glm::value_ptr(v)); + glUniform4fv(m_umap[id], 1, glm::value_ptr(v)); } -void Shader::u_mat4(const char* name, const glm::mat4& m) +void Shader::u_mat4(kShaderUniform id, const glm::mat4& m) { - auto loc = glGetUniformLocation(prog, name); - glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(m)); + glUniformMatrix4fv(m_umap[id], 1, GL_FALSE, glm::value_ptr(m)); } -void Shader::u_int(const char* name, int i) +void Shader::u_int(kShaderUniform id, int i) { - auto loc = glGetUniformLocation(prog, name); - glUniform1i(loc, i); + glUniform1i(m_umap[id], i); +} + +bool ShaderManager::create(kShader id, const char* vertex, const char* fragment) +{ + return m_shaders[id].create(vertex, fragment); +} + +void ShaderManager::use(kShader id) +{ + m_current = &m_shaders[id]; + m_current->use(); +} + +void ShaderManager::use(const char* name) +{ + m_current = &m_shaders[(kShader)const_hash(name)]; + m_current->use(); +} + +void ShaderManager::u_vec4(kShaderUniform id, const glm::vec4& v) +{ + m_current->u_vec4(id, v); +} + +void ShaderManager::u_mat4(kShaderUniform id, const glm::mat4& m) +{ + m_current->u_mat4(id, m); +} + +void ShaderManager::u_int(kShaderUniform id, int i) +{ + m_current->u_int(id, i); } diff --git a/engine/shader.hpp b/engine/shader.hpp index db82e11..3bb97cc 100644 --- a/engine/shader.hpp +++ b/engine/shader.hpp @@ -1,25 +1,41 @@ #pragma once #include "util.hpp" +enum class kShaderUniform : uint16_t +{ + MVP = const_hash("mvp"), + Tex = const_hash("tex"), + Col = const_hash("col"), +}; + class Shader { + std::map m_umap; GLuint prog; public: - bool create(std::string vertex, std::string fragment); + bool create(const char* vertex, const char* fragment); void use(); - void u_vec4(const char* name, const glm::vec4& v); - void u_mat4(const char* name, const glm::mat4& m); - void u_int(const char* name, int i); + void u_vec4(kShaderUniform id, const glm::vec4& v); + void u_mat4(kShaderUniform id, const glm::mat4& m); + void u_int(kShaderUniform id, int i); }; enum class kShader : uint16_t { - Color = const_hash("color"), + Color = const_hash("color"), + Texture = const_hash("texture"), + UVs = const_hash("uvs"), }; class ShaderManager { + static std::map m_shaders; + static Shader* m_current; public: + static bool create(kShader id, const char* vertex, const char* fragment); static void use(kShader id); static void use(const char* name); + static void u_vec4(kShaderUniform id, const glm::vec4& v); + static void u_mat4(kShaderUniform id, const glm::mat4& m); + static void u_int(kShaderUniform id, int i); }; diff --git a/engine/util.hpp b/engine/util.hpp index 7b414d6..2fe3733 100644 --- a/engine/util.hpp +++ b/engine/util.hpp @@ -1,6 +1,6 @@ #pragma once -uint16_t constexpr const_hash(char const *input) +uint16_t constexpr const_hash(const char* input) { return *input ? static_cast(*input) + 33 * const_hash(input + 1) :