Files
panopainter/engine/shape.h

212 lines
6.5 KiB
C++

#pragma once
enum class kShapeType : uint16_t
{
Quad = const_hash("rect"),
Poly = const_hash("poly"),
RoundRect = const_hash("round-rect"),
Slice9 = const_hash("slice9"),
};
namespace ui {
class Shape
{
protected:
GLuint buffers[2]{ 0, 0 };
GLuint arrays[2]{ 0, 0 };
GLuint count[2]{ 0, 0 };
GLvoid* ioff[2]{ 0, 0 };
bool use_idx = true;
public:
struct vertex_t { glm::vec4 pos; glm::vec2 uvs; };
bool create_buffers(GLvoid* idx, GLvoid* vertices, int isize, int vsize);
bool create_buffers(GLvoid* vertices, int vsize);
void draw_fill() const;
void draw_stroke() const;
virtual bool create_attrib() { return true; };
~Shape()
{
glDeleteBuffers(2, buffers);
#if USE_VBO
glDeleteVertexArrays(2, arrays);
#endif // USE_VBO
}
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 LineSegment : public Shape
{
public:
bool create()
{
static vertex_t vertices[2];
count[0] = 2;
count[1] = 2;
ioff[0] = (GLvoid*)0;
ioff[1] = (GLvoid*)0;
vertices[0] = { { 0, 0, 0, 1 },{ 0, 0 } }; // A
vertices[1] = { { 0, 0, 0, 1 },{ 0, 1 } }; // B
return create_buffers(vertices, sizeof(vertices));
}
void update_vertices(const glm::vec4 data[2]);
};
class DynamicShape : public Shape
{
public:
bool create(vertex_t* vertices = nullptr, int vcount = 0)
{
count[0] = vcount;
count[1] = vcount;
ioff[0] = (GLvoid*)0;
ioff[1] = (GLvoid*)0;
return create_buffers(vertices, sizeof(vertex_t) * vcount);
}
void update_vertices(vertex_t* vertices, int vcount);
};
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));
}
void update_vertices(const glm::vec4* data);
/*
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));
}
};
class Sphere : public Shape
{
void create_impl(int rings, int sectors, float radius, GLushort* idx, vertex_t* vertices);
public:
template<int rings, int sectors>
bool create(float radius)
{
static GLushort idx[rings * sectors * 6];
static vertex_t vertices[rings * sectors];
create_impl(rings, sectors, radius, idx, vertices);
return create_buffers(idx, vertices, sizeof(idx), sizeof(vertices));
}
};
}