added singleton shader manager, custom widget attribute forward, parse border thickness and color for Border widget, parse and cache uniform locations, remove unused attrubutes code

This commit is contained in:
2017-01-30 19:52:32 +00:00
parent 16c1b6481e
commit a80556f418
8 changed files with 179 additions and 172 deletions

View File

@@ -34,7 +34,7 @@
</plane>
<!-- content panel -->
<plane width="1" grow="1" height="100%" pad="30" wrap="1">
<border color=".2" height="100%"></border>
<border thickness="5" border-color="1" color=".4" height="100%"></border>
</plane>
</plane>
<!-- status bar -->

View File

@@ -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);

View File

@@ -8,10 +8,6 @@
class App
{
Sampler sampler;
Shader shader;
Shader shader_color;
Shader shader_uv;
Plane plane;
Texture2D tex;
Node layout;
public:

View File

@@ -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<WidgetBorder>();
break;
}
while (attr)
{
parse_attributes((att::kAttribute)const_hash(attr->Name()), attr);
parse_attributes((kAttribute)const_hash(attr->Name()), attr);
attr = attr->Next();
}

View File

@@ -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<att::kAttribute, std::unique_ptr<att::AttributeBase>> AttrubutesMap;
template<kAttribute T, typename V>
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<kAttribute::N,T> \
{ using Attribute<kAttribute::N,T>::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();

View File

@@ -1,7 +1,10 @@
#include "pch.h"
#include "shader.hpp"
bool Shader::create(std::string vertex, std::string fragment)
std::map<kShader, Shader> 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);
}

View File

@@ -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<kShaderUniform, GLuint> 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<kShader, Shader> 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);
};

View File

@@ -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<uint16_t>(*input) + 33 * const_hash(input + 1) :