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) :