diff --git a/bazaar/GLPainter/Code.cpp b/bazaar/GLPainter/Code.cpp index 0db516a4d..12feeeb3b 100644 --- a/bazaar/GLPainter/Code.cpp +++ b/bazaar/GLPainter/Code.cpp @@ -94,4 +94,15 @@ GLCode& GLCode::Uniform(const char *id, double a, double b, double c, double d) return *this; } + +GLCode& GLCode::operator()(const char *id, Color c, double alpha) +{ + return Uniform(GetUniform(id), c, alpha); +} + +GLCode& GLCode::operator()(int i, Color c, double alpha) +{ + return Uniform(i, c.GetR() / 255.0f, c.GetG() / 255.0f, c.GetB() / 255.0f, alpha); +} + }; diff --git a/bazaar/GLPainter/Ellipse.cpp b/bazaar/GLPainter/Ellipse.cpp index 1ded969e7..6bab964df 100644 --- a/bazaar/GLPainter/Ellipse.cpp +++ b/bazaar/GLPainter/Ellipse.cpp @@ -4,42 +4,19 @@ namespace Upp { void GLDrawEllipse(const GLContext2D& dd, Pointf center, Sizef radius, Color color, double alpha) { - static GLCode program(R"( - #version 330 core - in vec2 aPos; - void main() - { - gl_Position = vec4(2 * aPos - vec2(1, 1), 0, 1); - } - )", R"( - #version 330 core - uniform vec2 center; - uniform vec2 radius1; - uniform vec4 color; - void main() - { - gl_FragColor = color; - vec2 h = radius1 * (gl_FragCoord.xy - center); - h = h * h; - if(h.x + h.y > 1) - gl_FragColor.a = 0; - } - )"); - - static int icenter = program["center"]; - static int iradius1 = program["radius1"]; - static int icolor = program["color"]; - - glEnable(GL_BLEND); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + static GLVertexData ellipse; - DDUMP(Sizef(center) * dd.vs + Sizef(-1, 1)); - - GLRectMesh().Draw( - program(icenter, center) - (iradius1, Sizef(1 / radius.cx, 1 / radius.cy)) - (icolor, color.GetR() / 255.0f, color.GetG() / 255.0f, color.GetB() / 255.0f, dd.alpha * alpha) - ); + ONCELOCK { + const int N = 200; + Vector> p; + p.Add(); + for(int i = 0; i < N; i++) { + p.Top().Add(Polar(i * M_2PI / N)); + } + GLPolygon(ellipse, p); + } + + GLDrawPolygon(dd, center, ellipse, radius, color, alpha); } -}; \ No newline at end of file +}; diff --git a/bazaar/GLPainter/GLPainter.h b/bazaar/GLPainter/GLPainter.h index 21ddfd9f6..77bc9ef33 100644 --- a/bazaar/GLPainter/GLPainter.h +++ b/bazaar/GLPainter/GLPainter.h @@ -43,6 +43,8 @@ struct GLCode : GLProgram { GLCode& operator()(int i, Pointf p) { return Uniform(i, p.x, p.y); } GLCode& operator()(const char *id, Sizef sz) { return Uniform(id, sz.cx, sz.cy); } GLCode& operator()(int i, Sizef sz) { return Uniform(i, sz.cx, sz.cy); } + GLCode& operator()(const char *id, Color c, double alpha = 1); + GLCode& operator()(int i, Color c, double alpha = 1); }; class GLTexture { @@ -78,31 +80,41 @@ void GLDrawTexture(const GLContext2D& dd, const Rect& rect, const Image& img, do void GLDrawImage(const GLContext2D& dd, const Rect& rect, const Image& img, double alpha); class GLVertexData { - GLuint VAO = 0; - GLuint EBO = 0; - int elements; - - Vector VBO; + struct Data { + int refcount = 1; + GLuint VAO = 0; + GLuint EBO = 0; + int elements = 0; + + Vector VBO; + }; - void Make(); + Data *data = NULL; + + void Do(); public: + void Clear(); + GLVertexData& Add(const void *data, int type, int ntuple, int count); - GLVertexData& Add(const float *data, int ntuple, int count) { return Add(data, GL_FLOAT, ntuple, count); } + GLVertexData& Add(const float *data, int ntuple, int count) { return Add(data, GL_FLOAT, ntuple, count); } + GLVertexData& Add(const Vector& data, int ntuple) { return Add(data, ntuple, data.GetCount() / ntuple); } GLVertexData& Add(const Vector& pt); GLVertexData& Index(const int *indices, int count); - GLVertexData& Index(const Vector& indices) { return Index(indices, indices.GetCount()); } + GLVertexData& Index(const Vector& indices) { return Index(indices, indices.GetCount()); } void Draw(int mode = GL_TRIANGLES) const; void Draw(GLCode& shaders, int mode = GL_TRIANGLES) const; - void Clear(); - - bool IsEmpty() const { return VAO == 0; } + operator bool() const { return data; } + bool IsEmpty() const { return !data; } - GLVertexData(); - ~GLVertexData(); + GLVertexData() {} + ~GLVertexData() { Clear(); } + + GLVertexData(const GLVertexData& src); + GLVertexData& operator=(const GLVertexData& src); }; const GLVertexData& GLRectMesh(); @@ -121,7 +133,9 @@ void GLDrawConvexPolygon(const GLContext2D& dd, Pointf at, const GLVertexData& m template void GLPolyline(GLVertexData& data, const Src& polygon); -void GLDrawPolyline(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, Sizef scale, Color color, double width, double alpha); +void GLDrawPolyline(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, double scale, double width, Color color, double alpha); + +void GLDrawStencil(Color color, double alpha); void GLDrawEllipse(const GLContext2D& dd, Pointf center, Sizef radius, Color color, double alpha); diff --git a/bazaar/GLPainter/GLPainter.hpp b/bazaar/GLPainter/GLPainter.hpp index a9159e2d6..35ba6505e 100644 --- a/bazaar/GLPainter/GLPainter.hpp +++ b/bazaar/GLPainter/GLPainter.hpp @@ -1,9 +1,11 @@ template void GLPolygon(GLVertexData& mesh, const Src& polygon) { - Vector vertex; // todo: Optimize! + Vector vertex; Vector ndx; + mesh.Clear(); + for(const auto& p: polygon) { int i0 = vertex.GetCount(); for(int i = 0; i < p.GetCount(); i++) { @@ -19,5 +21,40 @@ void GLPolygon(GLVertexData& mesh, const Src& polygon) template void GLPolyline(GLVertexData& data, const Src& polygon) { + Vector vertex; + Vector ndx; + + int ii = 0; + for(const auto& p: polygon) { + int i0 = vertex.GetCount(); + for(int i = 0; i < p.GetCount() - 1; i++) { + Pointf p1 = p[i]; + Pointf p2 = p[i + 1 < p.GetCount() ? i + 1 : 0]; + Pointf un = Unit(Orthogonal(p1 - p2)); + + DDUMP(p1); + DDUMP(p2); + + vertex << (float)p1.x << (float)p1.y << (float)un.x << (float)un.y; + vertex << (float)p1.x << (float)p1.y << -(float)un.x << -(float)un.y; + + vertex << (float)p2.x << (float)p2.y << (float)un.x << (float)un.y; + vertex << (float)p2.x << (float)p2.y << -(float)un.x << -(float)un.y; + + DDUMP(un); + + ndx << ii << ii + 1 << ii + 2 + << ii + 3 << ii + 2 << ii + 1; + + if(ii) + ndx << ii << ii + 1 << ii - 4 + 3 + << ii - 4 + 2 << ii - 4 + 3 << ii; + + ii += 4; + } + } + + DDUMP(vertex); + data.Add(vertex, 4).Index(ndx); } diff --git a/bazaar/GLPainter/GLPainter.upp b/bazaar/GLPainter/GLPainter.upp index 522c89273..0e6c5db9a 100644 --- a/bazaar/GLPainter/GLPainter.upp +++ b/bazaar/GLPainter/GLPainter.upp @@ -13,7 +13,7 @@ file Code.cpp, VertexData.cpp, Image.cpp, - Polygon.cpp, + TessPolygon.cpp, StencilPolygon.cpp, Line.cpp, Ellipse.cpp; diff --git a/bazaar/GLPainter/Line.cpp b/bazaar/GLPainter/Line.cpp index 69f0cda00..d7c61213f 100644 --- a/bazaar/GLPainter/Line.cpp +++ b/bazaar/GLPainter/Line.cpp @@ -1 +1,59 @@ #include "GLPainter.h" + +namespace Upp { + +void GLDrawPolyline(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, double scale, + double width, Color color, double alpha) +{ + static GLCode program(R"( + #version 330 core + in vec4 pos; + uniform vec2 offset; + uniform vec2 scale; + uniform float width; + void main() + { + gl_Position = vec4(scale * (pos.xy + width * pos.zw) + offset, 0, 1); + } + )", R"( + #version 330 core + uniform vec4 color; + void main() + { + gl_FragColor = color; + } + )"); + + static int ioffset = program["offset"]; + static int iscale = program["scale"]; + static int iwidth = program["width"]; + static int icolor = program["color"]; + + alpha *= dd.alpha; + program(ioffset, Pointf(dd.vs) * at + Sizef(-1, 1)) + (iscale, dd.vs * scale) + (iwidth, width / scale / 2) + (icolor, color, alpha) + ; + + if(alpha == 1) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + mesh.Draw(program); + } + else { + glDisable(GL_BLEND); + glDisable(GL_CULL_FACE); + + glEnable(GL_STENCIL_TEST); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glStencilFunc(GL_NEVER, 1, 1); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + + mesh.Draw(program); + + GLDrawStencil(color, dd.alpha * alpha); + } +} + +}; \ No newline at end of file diff --git a/bazaar/GLPainter/StencilPolygon.cpp b/bazaar/GLPainter/StencilPolygon.cpp index b750e07e3..f03f19adc 100644 --- a/bazaar/GLPainter/StencilPolygon.cpp +++ b/bazaar/GLPainter/StencilPolygon.cpp @@ -2,7 +2,7 @@ namespace Upp { -void GLDrawPolygon(const GLContext2D& dd, bool generic, Pointf at, const GLVertexData& mesh, Sizef scale, Color color, double alpha) +GLCode& GLSimpleCode() { static GLCode program(R"( #version 330 core @@ -21,14 +21,39 @@ void GLDrawPolygon(const GLContext2D& dd, bool generic, Pointf at, const GLVerte gl_FragColor = color; } )"); + return program; +} +void GLDrawStencil(Color color, double alpha) +{ + GLCode& program = GLSimpleCode(); + static int ioffset = program["offset"]; - static int iscale = program["iscale"]; + static int iscale = program["scale"]; static int icolor = program["color"]; - program("offset", Pointf(dd.vs) * at + Sizef(-1, 1)) - ("scale", dd.vs * scale) - ("color", color.GetR() / 255.0f, color.GetG() / 255.0f, color.GetB() / 255.0f, dd.alpha * alpha); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glStencilFunc(GL_EQUAL, 1, 1); + glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + GLRectMesh().Draw(program(ioffset, -1, -1)(iscale, 2, 2)(icolor, color, alpha)); + + glDisable(GL_STENCIL_TEST); +} + +void GLDrawPolygon(const GLContext2D& dd, bool generic, Pointf at, const GLVertexData& mesh, Sizef scale, Color color, double alpha) +{ + GLCode& program = GLSimpleCode(); + + static int ioffset = program["offset"]; + static int iscale = program["scale"]; + static int icolor = program["color"]; + + program(ioffset, Pointf(dd.vs) * at + Sizef(-1, 1)) + (iscale, dd.vs * scale); if(generic) { glDisable(GL_BLEND); @@ -40,23 +65,14 @@ void GLDrawPolygon(const GLContext2D& dd, bool generic, Pointf at, const GLVerte glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); mesh.Draw(program); - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glStencilFunc(GL_EQUAL, 1, 1); - glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); + + GLDrawStencil(color, dd.alpha * alpha); + } + else { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + mesh.Draw(program(icolor, color, dd.alpha * alpha)); } - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - program("offset", Pointf(dd.vs) * at + Sizef(-1, 1)) - ("scale", dd.vs * scale) - ("color", color.GetR() / 255.0f, color.GetG() / 255.0f, color.GetB() / 255.0f, dd.alpha * alpha); - - GLRectMesh().Draw(program("offset", -1, -1)("scale", 2, 2)); - - if(generic) - glDisable(GL_STENCIL_TEST); } void GLDrawPolygon(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, Sizef scale, Color color, double alpha) diff --git a/bazaar/GLPainter/Polygon.cpp b/bazaar/GLPainter/TessPolygon.cpp similarity index 100% rename from bazaar/GLPainter/Polygon.cpp rename to bazaar/GLPainter/TessPolygon.cpp diff --git a/bazaar/GLPainter/VertexData.cpp b/bazaar/GLPainter/VertexData.cpp index 0ad0cf403..d83aa6662 100644 --- a/bazaar/GLPainter/VertexData.cpp +++ b/bazaar/GLPainter/VertexData.cpp @@ -2,37 +2,50 @@ namespace Upp { -GLVertexData::GLVertexData() {} - -void GLVertexData::Make() +GLVertexData::GLVertexData(const GLVertexData& src) { - if(!VAO) { - glGenVertexArrays(1, &VAO); - glGenBuffers(1, &EBO); + data = src.data; + data->refcount++; +} + +GLVertexData& GLVertexData::operator=(const GLVertexData& src) +{ + if(data != src.data) { + if(data) Clear(); + data = src.data; + data->refcount++; } + return *this; } void GLVertexData::Clear() { - glDeleteVertexArrays(1, &VAO); - glDeleteBuffers(1, &EBO); - for(auto h : VBO) - glDeleteBuffers(1, &h); - VAO = EBO = 0; - VBO.Clear(); + if(data && --data->refcount == 0) { + glDeleteVertexArrays(1, &data->VAO); + glDeleteBuffers(1, &data->EBO); + for(auto h : data->VBO) + glDeleteBuffers(1, &h); + delete data; + } + data = NULL; } -GLVertexData::~GLVertexData() +void GLVertexData::Do() { - Clear(); + if(!data) { + data = new Data; + glGenVertexArrays(1, &data->VAO); + glGenBuffers(1, &data->EBO); + } + ASSERT(data->refcount == 1); // Changes are only allowed before copied } -GLVertexData& GLVertexData::Add(const void *data, int type, int ntuple, int count) +GLVertexData& GLVertexData::Add(const void *values, int type, int ntuple, int count) { - Make(); - glBindVertexArray(VAO); - int ii = VBO.GetCount(); - GLuint& vbo = VBO.Add(); + Do(); + glBindVertexArray(data->VAO); + int ii = data->VBO.GetCount(); + GLuint& vbo = data->VBO.Add(); glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); int sz = (int)decode(type, GL_FLOAT, sizeof(float), @@ -43,7 +56,7 @@ GLVertexData& GLVertexData::Add(const void *data, int type, int ntuple, int coun GL_INT, sizeof(int32), GL_UNSIGNED_INT, sizeof(uint32), sizeof(double)); - glBufferData(GL_ARRAY_BUFFER, sz * ntuple * count, data, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sz * ntuple * count, values, GL_STATIC_DRAW); glVertexAttribPointer(ii, ntuple, type, GL_FALSE, ntuple * sz, (void*)0); glEnableVertexAttribArray(ii); glBindBuffer(GL_ARRAY_BUFFER, 0); @@ -53,22 +66,23 @@ GLVertexData& GLVertexData::Add(const void *data, int type, int ntuple, int coun GLVertexData& GLVertexData::Index(const int *indices, int count) { - Make(); - glBindVertexArray(VAO); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + Do(); + glBindVertexArray(data->VAO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data->EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * count, indices, GL_STATIC_DRAW); glBindVertexArray(0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - elements = count; + data->elements = count; return *this; } void GLVertexData::Draw(int mode) const { - if(VAO) - glBindVertexArray(VAO); - glDrawElements(mode, elements, GL_UNSIGNED_INT, 0); - glBindVertexArray(0); + if(data) { + glBindVertexArray(data->VAO); + glDrawElements(mode, data->elements, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + } } void GLVertexData::Draw(GLCode& shaders, int mode) const