246 lines
8.0 KiB
C++
246 lines
8.0 KiB
C++
#pragma once
|
|
|
|
namespace att
|
|
{
|
|
enum class kAttribute : uint8_t {
|
|
Width, MinWidth, MaxWidth,
|
|
Height, MinHeight, MaxHeight,
|
|
Divisions, InnerRadius, OuterRadius,
|
|
Grow, Shrink, FlexDir, FlexWrap,
|
|
Padding, Margin,
|
|
Color
|
|
};
|
|
|
|
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 typemap
|
|
{
|
|
const char* name;
|
|
kAttribute value;
|
|
};
|
|
static constexpr typemap map[] =
|
|
{
|
|
{ "width", kAttribute::Width },
|
|
{ "min-width", kAttribute::MinWidth },
|
|
{ "max-width", kAttribute::MaxWidth },
|
|
{ "height", kAttribute::Height },
|
|
{ "min-height", kAttribute::MinHeight },
|
|
{ "max-height", kAttribute::MaxHeight },
|
|
{ "divisions", kAttribute::Divisions },
|
|
{ "inner-radius", kAttribute::InnerRadius },
|
|
{ "outer-radius", kAttribute::OuterRadius },
|
|
{ "grow", kAttribute::Grow },
|
|
{ "shrink", kAttribute::Shrink },
|
|
{ "dir", kAttribute::FlexDir },
|
|
{ "wrap", kAttribute::FlexWrap },
|
|
{ "pad", kAttribute::Padding },
|
|
{ "margin", kAttribute::Margin },
|
|
{ "color", kAttribute::Color },
|
|
};
|
|
constexpr int map_size = sizeof(map) / sizeof(typemap) - 1;
|
|
constexpr bool same(const char* a, const char* b)
|
|
{
|
|
return (*a && *b) ? (*a == *b && same(a + 1, b + 1)) : !(*a || *b);
|
|
}
|
|
constexpr const kAttribute value(char const *name, int i = 0)
|
|
{
|
|
return ((i >= map_size) || same(map[i].name, name)) ?
|
|
map[i].value : value(name, i + 1);
|
|
}
|
|
constexpr const char* string(const kAttribute value, int i = 0)
|
|
{
|
|
return (map[i].value == value) ? map[i].name : string(value, i + 1);
|
|
}
|
|
|
|
//constexpr const char* string(kAttribute a) { return names[(int)a]; }
|
|
|
|
// template<kAttribute T, typename V>
|
|
// constexpr const char* string(const Attribute<T, V> a) { return names[(int)a.id]; }
|
|
|
|
#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
|
|
}
|
|
|
|
class Shape
|
|
{
|
|
protected:
|
|
GLuint buffers[2]{ 0 };
|
|
GLuint arrays[2]{ 0 };
|
|
GLuint count[2]{ 0 };
|
|
GLvoid* ioff[2]{ 0 };
|
|
struct vertex_t { glm::vec4 pos; glm::vec2 uvs; };
|
|
public:
|
|
YGNodeRef y_node;
|
|
glm::vec4 color;
|
|
att::AttrubutesMap attribs;
|
|
bool create_buffers(GLvoid* idx, GLvoid* vertices, int isize, int vsize);
|
|
void draw_fill() const;
|
|
void draw_stroke() const;
|
|
virtual bool create_attrib() { return true; };
|
|
~Shape()
|
|
{
|
|
glDeleteBuffers(2, buffers);
|
|
glDeleteVertexArrays(2, arrays);
|
|
}
|
|
protected:
|
|
glm::vec2 quad_mid_point(glm::vec2 a, glm::vec2 b, glm::vec2 c, glm::vec2 d)
|
|
{
|
|
float den = (a.x-c.x)*(b.y-d.y) - (a.y-c.y)*(b.x-d.x);
|
|
float numx = (a.x*c.y-a.y*c.x)*(b.x-d.x) - (a.x-c.x)*(b.x*d.y-b.y*d.x);
|
|
float numy = (a.x*c.y-a.y*c.x)*(b.y-d.y) - (a.y-c.y)*(b.x*d.y-b.y*d.x);
|
|
return glm::vec2(numx, numy) / den;
|
|
}
|
|
void adjust_quad_uvs(vertex_t& va, vertex_t& vb, vertex_t& vc, vertex_t& vd)
|
|
{
|
|
static float d[4];
|
|
static vertex_t* v[4];
|
|
v[0] = &va; v[1] = &vb; v[2] = &vc; v[3] = &vd;
|
|
auto mid = quad_mid_point(va.pos, vb.pos, vc.pos, vd.pos);
|
|
for (int i = 0; i < 4; i++)
|
|
d[i] = glm::distance(glm::vec2(v[i]->pos), mid);
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
float q = (d[i] + d[(i + 2) % 4]) / d[(i + 2) % 4];
|
|
v[i]->uvs = glm::vec2(v[i]->uvs) * q;
|
|
v[i]->pos.w = q;
|
|
}
|
|
}
|
|
};
|
|
|
|
class Plane : public Shape
|
|
{
|
|
void create_impl(float w, float h, int div, GLushort* idx, vertex_t* vertices);
|
|
public:
|
|
template<int div>
|
|
bool create(float w, float h)
|
|
{
|
|
static GLushort idx[div * div * 6 + 8];
|
|
static vertex_t vertices[(div+1)*(div+1)];
|
|
create_impl(w, h, div, idx, vertices);
|
|
return create_buffers(idx, vertices, sizeof(idx), sizeof(vertices));
|
|
}
|
|
bool create(att::Divisions divisions, att::Width w, att::Height h)
|
|
{
|
|
const int div = divisions.value;
|
|
auto idx = std::make_unique<GLushort[]>(div * div * 6 + 8);
|
|
auto vertices = std::make_unique<vertex_t[]>((div + 1)*(div + 1));
|
|
create_impl(w.value, h.value, div, idx.get(), vertices.get());
|
|
return create_buffers(idx.get(), vertices.get(), sizeof(idx), sizeof(vertices));
|
|
}
|
|
template<typename T>
|
|
T get_attribute(T def_val)
|
|
{
|
|
auto ret = attribs.find(def_val.id);
|
|
if (ret == attribs.end())
|
|
return def_val;
|
|
return *reinterpret_cast<T*>(ret->second.get());
|
|
}
|
|
bool create_attrib() override
|
|
{
|
|
const auto w = get_attribute(att::Width(0));
|
|
const auto h = get_attribute(att::Height(0));
|
|
const auto d = get_attribute(att::Divisions(1));
|
|
return create(d, w, h);
|
|
}
|
|
};
|
|
|
|
class RectShape : public Shape
|
|
{
|
|
bool create(float w, float h);
|
|
};
|
|
|
|
class Circle : public Shape
|
|
{
|
|
public:
|
|
enum class kUVMapping: uint8_t { Planar, Tube };
|
|
template<int div>
|
|
bool create(float radius)
|
|
{
|
|
static GLushort idx[div*3 + div*2];
|
|
static vertex_t vertices[div+1];
|
|
create_impl(radius, div, idx, vertices);
|
|
return create_buffers(idx, vertices, sizeof(idx), sizeof(vertices));
|
|
}
|
|
template<int div>
|
|
bool create(float radius, kUVMapping map)
|
|
{
|
|
static GLushort idx[(div+1)*3 + (div+1)*4];
|
|
static vertex_t vertices[(div+1)*2];
|
|
create_impl(radius, 0.f, (div+1), idx, vertices, map);
|
|
return create_buffers(idx, vertices, sizeof(idx), sizeof(vertices));
|
|
}
|
|
template<int div>
|
|
bool create(float radius_out, float radius_in, kUVMapping map)
|
|
{
|
|
static GLushort idx[(div+1)*6 + (div+1)*4];
|
|
static vertex_t vertices[(div+1) * 2];
|
|
create_impl(radius_out, radius_in, (div+1), idx, vertices, map);
|
|
return create_buffers(idx, vertices, sizeof(idx), sizeof(vertices));
|
|
}
|
|
private:
|
|
void create_impl(float radius, int div, GLushort* idx, vertex_t* vertices);
|
|
void create_impl(float radius_out, float radius_in, int div, GLushort* idx, vertex_t* vertices, kUVMapping map);
|
|
};
|
|
|
|
class Rounded : public Shape
|
|
{
|
|
void create_impl(float w, float h, float r, int div, GLushort* idx, GLushort* idx_tmp, vertex_t* vertices);
|
|
public:
|
|
template<int div>
|
|
bool create(float w, float h, float r)
|
|
{
|
|
static GLushort idx[(10 + div * 4) * 3 + (4 + div * 4) * 2];
|
|
static GLushort idx_tmp[div+1];
|
|
static vertex_t vertices[12 + (div-1) * 4];
|
|
create_impl(w, h, r, div, idx, idx_tmp, vertices);
|
|
return create_buffers(idx, vertices, sizeof(idx), sizeof(vertices));
|
|
}
|
|
};
|
|
|
|
class Slice9 : public Shape
|
|
{
|
|
void create_impl(float w, float h, float r, float tr, GLushort* idx, vertex_t* vertices);
|
|
public:
|
|
bool create(float w, float h, float r, float tr)
|
|
{
|
|
static GLushort idx[3 * 3 * 6 + 4 * 2];
|
|
static vertex_t vertices[4 * 4];
|
|
create_impl(w, h, r, tr, idx, vertices);
|
|
return create_buffers(idx, vertices, sizeof(idx), sizeof(vertices));
|
|
}
|
|
};
|