From e6b5d3129c4db7cdd41e49ceaa24bb0911cc22b6 Mon Sep 17 00:00:00 2001 From: cxl Date: Wed, 24 Oct 2018 09:07:35 +0000 Subject: [PATCH] GLDraw: DrawGL with hw accelerated polygon rendering git-svn-id: svn://ultimatepp.org/upp/trunk@12411 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/GLDraw/Arc.cpp | 23 +++ uppsrc/GLDraw/Code.cpp | 108 ++++++++++++++ uppsrc/GLDraw/DrawGL.cpp | 267 ++++++++++++++++++++++++++++++++++ uppsrc/GLDraw/DrawTexture.cpp | 114 +++++++++++++++ uppsrc/GLDraw/Ellipse.cpp | 48 ++++++ uppsrc/GLDraw/GLDraw.h | 3 + uppsrc/GLDraw/GLDraw.upp | 16 +- uppsrc/GLDraw/GLPainter.h | 246 +++++++++++++++++++++++++++++++ uppsrc/GLDraw/GLPainter.hpp | 58 ++++++++ uppsrc/GLDraw/GLTexture.cpp | 173 ++++++++++++++++++++++ uppsrc/GLDraw/Line.cpp | 88 +++++++++++ uppsrc/GLDraw/Polygon.cpp | 90 ++++++++++++ uppsrc/GLDraw/Text.cpp | 82 +++++++++++ uppsrc/GLDraw/VertexData.cpp | 107 ++++++++++++++ uppsrc/GLDraw/todo.txt | 13 ++ 15 files changed, 1435 insertions(+), 1 deletion(-) create mode 100644 uppsrc/GLDraw/Arc.cpp create mode 100644 uppsrc/GLDraw/Code.cpp create mode 100644 uppsrc/GLDraw/DrawGL.cpp create mode 100644 uppsrc/GLDraw/DrawTexture.cpp create mode 100644 uppsrc/GLDraw/Ellipse.cpp create mode 100644 uppsrc/GLDraw/GLPainter.h create mode 100644 uppsrc/GLDraw/GLPainter.hpp create mode 100644 uppsrc/GLDraw/GLTexture.cpp create mode 100644 uppsrc/GLDraw/Line.cpp create mode 100644 uppsrc/GLDraw/Polygon.cpp create mode 100644 uppsrc/GLDraw/Text.cpp create mode 100644 uppsrc/GLDraw/VertexData.cpp create mode 100644 uppsrc/GLDraw/todo.txt diff --git a/uppsrc/GLDraw/Arc.cpp b/uppsrc/GLDraw/Arc.cpp new file mode 100644 index 000000000..162d46d41 --- /dev/null +++ b/uppsrc/GLDraw/Arc.cpp @@ -0,0 +1,23 @@ +#include "GLDraw.h" + +namespace Upp { + +void GLArc(Vector>& line, const Rectf& rc, Pointf start, Pointf end) +{ + if(rc.Width() <= 0 || rc.Height() <= 0) + return; + Sizef radius = Sizef(rc.Size()) / 2.0; + Pointf center = Pointf(rc.TopLeft()) + radius; + double ang2 = Direction((Pointf(start) - center) / radius); + double ang1 = Direction((Pointf(end) - center) / radius); + if(ang1 > ang2) + ang2 += M_2PI; + if(ang1 == ang2) + ang2 += M_2PI; + + line.Add(); + for(double a = ang1; a <= ang2 + M_PI / 200; a += M_PI / 200) + line.Top().Add(radius * Polar(min(a, ang2)) + center); +} + +}; \ No newline at end of file diff --git a/uppsrc/GLDraw/Code.cpp b/uppsrc/GLDraw/Code.cpp new file mode 100644 index 000000000..38f01986a --- /dev/null +++ b/uppsrc/GLDraw/Code.cpp @@ -0,0 +1,108 @@ +#include "GLDraw.h" + +namespace Upp { + +GLCode::GLCode(const char *vertex_shader, const char *pixel_shader) +{ + Create(vertex_shader, pixel_shader); + Vector> ins; + CParser p(vertex_shader); + int ii = 0; + int ti = 0; + auto readID = [&] { + String id; + while(!p.IsEof() && !p.Char(';')) + if(p.IsId()) + id = p.ReadId(); + else + p.SkipTerm(); + return id; + }; + while(!p.IsEof() && !p.Char('{')) + if(p.Id("attribute") || p.Id("in")) { + String id = readID(); + if(id.GetCount()) + glBindAttribLocation(program, ii++, id); + } + else + p.SkipTerm(); + + p.Set(pixel_shader); + while(!p.IsEof() && !p.Char('{')) + if(p.Id("sampler2D") || p.Id("sampler3D")) { + String id = readID(); + if(id.GetCount()) + glUniform1i(GetUniform(id), ti++); + } + else + p.SkipTerm(); +} + +GLCode& GLCode::Uniform(int i, double a) +{ + Use(); + glUniform1f(i, (float)a); + return *this; +} + +GLCode& GLCode::Uniform(int i, double a, double b) +{ + Use(); + glUniform2f(i, (float)a, (float)b); + return *this; +} + +GLCode& GLCode::Uniform(int i, double a, double b, double c) +{ + Use(); + glUniform3f(i, (float)a, (float)b, (float)c); + return *this; +} + +GLCode& GLCode::Uniform(int i, double a, double b, double c, double d) +{ + Use(); + glUniform4f(i, (float)a, (float)b, (float)c, (float)d); + return *this; +} + +GLCode& GLCode::Uniform(const char *id, double a) +{ + Use(); + glUniform1f(GetUniform(id), (float)a); + return *this; +} + +GLCode& GLCode::Uniform(const char *id, double a, double b) +{ + Use(); + glUniform2f(GetUniform(id), (float)a, (float)b); + return *this; +} + +GLCode& GLCode::Uniform(const char *id, double a, double b, double c) +{ + Use(); + glUniform3f(GetUniform(id), (float)a, (float)b, (float)c); + return *this; +} + +GLCode& GLCode::Uniform(const char *id, double a, double b, double c, double d) +{ + Use(); + glUniform4f(GetUniform(id), (float)a, (float)b, (float)c, (float)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/uppsrc/GLDraw/DrawGL.cpp b/uppsrc/GLDraw/DrawGL.cpp new file mode 100644 index 000000000..0560d8320 --- /dev/null +++ b/uppsrc/GLDraw/DrawGL.cpp @@ -0,0 +1,267 @@ +#include "GLDraw.h" + +namespace Upp { + +void DrawGL::Init(Size sz, double alpha) +{ + Cloff& c = cloff.Add(); + c.clip = view_size = sz; + c.offset = Pointf(0, 0); + dd.Set(sz); + dd.alpha = alpha; + glEnable(GL_SCISSOR_TEST); + SyncScissor(); +} + +DrawGL::~DrawGL() +{ + glDisable(GL_SCISSOR_TEST); +} + +dword DrawGL::GetInfo() const +{ + return DRAWTEXTLINES; +} + +void DrawGL::BeginOp() +{ + Cloff c = cloff.Top(); + cloff.Add(c); +} + +bool DrawGL::ClipOp(const Rect& r) +{ + Cloff c = cloff.Top(); + Cloff& c1 = cloff.Add(); + c1.clip = c.clip & (r + c.offset); + c1.offset = c.offset; + SyncScissor(); + return !c1.clip.IsEmpty(); +} + +bool DrawGL::ClipoffOp(const Rect& r) +{ + Cloff c = cloff.Top(); + Cloff& c1 = cloff.Add(); + c1.clip = c.clip & (r + c.offset); + c1.offset = c.offset + (Pointf)r.TopLeft(); + SyncScissor(); + return !c1.clip.IsEmpty(); +} + +bool DrawGL::IntersectClipOp(const Rect& r) +{ + Cloff& c = cloff.Top(); + c.clip = c.clip & (r + c.offset); + SyncScissor(); + return !c.clip.IsEmpty(); +} + +bool DrawGL::ExcludeClipOp(const Rect& r) +{ + // does not work with DrawGL + return true; +} + +bool DrawGL::IsPaintingOp(const Rect& r) const +{ + return true; +} + +void DrawGL::OffsetOp(Point p) +{ + Cloff c = cloff.Top(); + Cloff& c1 = cloff.Add(); + c1.clip = c.clip; + c1.offset = c.offset + (Pointf)p; +} + +void DrawGL::EndOp() +{ + ASSERT(cloff.GetCount()); + if(cloff.GetCount()) + cloff.Drop(); + SyncScissor(); +} + +void DrawGL::SyncScissor() +{ + Rect clip = cloff.Top().clip; + Size sz = clip.GetSize(); + glScissor(clip.left, view_size.cy - sz.cy - clip.top, sz.cx, sz.cy); +} + +Pointf DrawGL::Offset(int x, int y) +{ + Pointf o = cloff.Top().offset; + return Pointf(x + o.x, y + o.y); +} + +Rectf DrawGL::Offset(int x, int y, int cx, int cy) +{ + Point o = cloff.Top().offset; + return RectfC(x + o.x, y + o.y, cx, cy); +} + +Rectf DrawGL::Offset(int x, int y, Size sz) +{ + return Offset(x, y, sz.cx, sz.cy); +} + +void DrawGL::SysDrawImageOp(int x, int y, const Image& img, Color color) +{ + GLDrawImage(dd, Offset(x, y, img.GetSize()), + IsNull(color) ? img : CachedSetColorKeepAlpha(img, color)); +} + +void DrawGL::SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color) +{ + GLDrawImage(dd, Offset(x, y, img.GetSize()), IsNull(color) ? img : CachedSetColorKeepAlpha(img, color), + src); +} + +void DrawGL::DrawRectOp(int x, int y, int cx, int cy, Color color) +{ + Vector> polygon; + polygon.Add().Add(Offset(x, y)); + polygon.Top().Add(Offset(x + cx, y)); + polygon.Top().Add(Offset(x + cx, y + cy)); + polygon.Top().Add(Offset(x, y + cy)); + + GLVertexData data; + GLPolygons(data, polygon); + + GLDrawConvexPolygons(dd, Pointf(0, 0), data, Sizef(1, 1), color); +} + +void DrawGL::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) +{ + GLDrawText(dd, Offset(x, y), angle * M_2PI / 3600, text, font, ink, n, dx); +} + +const Vector& DrawGL::GetDash(int& width) +{ + static Vector nodash; + static Vector dash = { 18, 6 }; + static Vector dot = { 3, 3 }; + static Vector dashdot = { 9, 6, 3, 6 }; + static Vector dashdotdot = { 9, 3, 3, 3, 3, 3 }; + + if(width == 0) + width = 1; + if(width > 0) + return nodash; + if(width == PEN_NULL) { + width = 0; + return nodash; + } + int w = width; + width = 1; + return *decode(w, PEN_DASH, &dash, + PEN_DOT, &dot, + PEN_DASHDOT, &dashdot, + PEN_DASHDOTDOT, &dashdotdot, + &nodash); +} + +void DrawGL::ApplyDash(Vector>& polyline, int& width) +{ + const Vector& dash = GetDash(width); + GetDash(width); + if(dash.GetCount()) { + Vector> r; + for(auto& l : polyline) + DashPolyline(r, l, dash); + polyline = pick(r); + } +} + +void DrawGL::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color) +{ + Vector> poly; + poly.Add().Add(Offset(x1, y1)); + poly.Top().Add(Offset(x2, y2)); + + ApplyDash(poly, width); + + GLVertexData data; + GLPolylines(data, poly); + + if(width > 0) + GLDrawPolylines(dd, Pointf(0, 0), data, Sizef(1, 1), width, color); +} + +void DrawGL::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color) +{ + Vector> poly; + GLArc(poly, rc, start, end); + ApplyDash(poly, width); + GLVertexData data; + GLPolylines(data, poly); + if(width > 0) + GLDrawPolylines(dd, Pointf(0, 0), data, Sizef(1, 1), width, color); +} + +void DrawGL::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor) +{ + const Vector& dash = GetDash(pen); + GLDrawEllipse(dd, Offset(r.CenterPoint()), Sizef(r.GetSize()) / 2, color, pen, pencolor, dash, 0); +} + +void DrawGL::DoPath(Vector>& poly, const Point *pp, const Point *end) +{ + poly.Add().Add(Offset(*pp++)); + while(pp < end) + poly.Top().Add(Offset(*pp++)); +} + +void DrawGL::DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, int count_count, int width, Color color, Color doxor) +{ + if(vertex_count < 2 || IsNull(color)) + return; + Vector> poly; + while(--count_count >= 0) { + const Point *pp = vertices; + vertices += *counts++; + DoPath(poly, pp, vertices); + } + + GLVertexData data; + ApplyDash(poly, width); + GLPolylines(data, poly); + if(width > 0) + GLDrawPolylines(dd, Pointf(0, 0), data, Sizef(1, 1), width, color); +} + +void DrawGL::DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, const int *subpolygon_counts, int scc, + const int *disjunct_polygon_counts, int dpcc, Color color, + int width, Color outline, uint64 pattern, Color doxor) +{ + Vector> poly; + while(--dpcc >= 0) { + const Point *sp = vertices; + vertices += *disjunct_polygon_counts++; + while(sp < vertices) { + const Point *pp = sp; + sp += *subpolygon_counts++; + DoPath(poly, pp, sp); + } + } + + if(!IsNull(color)) { + GLVertexData data; + GLPolygons(data, poly); + GLDrawPolygons(dd, Pointf(0, 0), data, Sizef(1, 1), color); + } + if(!IsNull(outline)) { + GLVertexData data; + for(auto& pl : poly) + pl.Add(pl[0]); + ApplyDash(poly, width); + GLPolylines(data, poly); + if(width > 0) + GLDrawPolylines(dd, Pointf(0, 0), data, Sizef(1, 1), width, outline); + } +} + +}; \ No newline at end of file diff --git a/uppsrc/GLDraw/DrawTexture.cpp b/uppsrc/GLDraw/DrawTexture.cpp new file mode 100644 index 000000000..9d6a46a95 --- /dev/null +++ b/uppsrc/GLDraw/DrawTexture.cpp @@ -0,0 +1,114 @@ +#include "GLDraw.h" + +namespace Upp { + +extern void (*restore_gl_viewport__)(); // in Draw/DrawUtil.cpp + +void GLTextureDraw::Clear() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glActiveTexture(GL_TEXTURE0); + if(texture) + glDeleteTextures(1, &texture); + if(rbo) + glDeleteRenderbuffers(1, &rbo); + if(framebuffer) + glDeleteFramebuffers(1, &framebuffer); + framebuffer = rbo = texture = 0; + (*restore_gl_viewport__)(); +} + +GLTexture GLTextureDraw::GetResult() +{ + ASSERT(texture); + GLTexture t; + if(msaa > 1) { + GLuint framebuffer2, texture2, rbo2; + glGenFramebuffers(1, &framebuffer2); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2); + + glGenTextures(1, &texture2); + + glBindTexture(GL_TEXTURE_2D, texture2); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sz.cx, sz.cy, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture2, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenRenderbuffers(1, &rbo2); + glBindRenderbuffer(GL_RENDERBUFFER, rbo2); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, sz.cx, sz.cy); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo2); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + NEVER_("Failed to create final texture draw framebuffer"); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer2); + glBlitFramebuffer(0, 0, sz.cx, sz.cy, 0, 0, sz.cx, sz.cy, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + t.Set(texture2, sz); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glActiveTexture(GL_TEXTURE0); + glDeleteRenderbuffers(1, &rbo2); + glDeleteFramebuffers(1, &framebuffer2); + Clear(); + } + else { + t.Set(texture, sz); + texture = 0; + Clear(); + } + return t; +} + +void GLTextureDraw::Create(Size sz_, int msaa_) +{ + sz = sz_; + msaa = msaa_; + + glGenFramebuffers(1, &framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + + glGenTextures(1, &texture); + + if(msaa > 1) { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texture); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, msaa, GL_RGBA, sz.cx, sz.cy, GL_TRUE); + glEnable(GL_MULTISAMPLE); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + } + else { + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sz.cx, sz.cy, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, msaa > 1 ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D, texture, 0); + + glGenRenderbuffers(1, &rbo); + glBindRenderbuffer(GL_RENDERBUFFER, rbo); + if(msaa > 1) + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_DEPTH24_STENCIL8, sz.cx, sz.cy); + else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, sz.cx, sz.cy); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + NEVER_("Failed to create texture draw framebuffer"); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glViewport(0, 0, sz.cx, sz.cy); +} + +}; \ No newline at end of file diff --git a/uppsrc/GLDraw/Ellipse.cpp b/uppsrc/GLDraw/Ellipse.cpp new file mode 100644 index 000000000..15e079451 --- /dev/null +++ b/uppsrc/GLDraw/Ellipse.cpp @@ -0,0 +1,48 @@ +#include "GLDraw.h" + +namespace Upp { + +void GLDrawEllipse(const GLContext2D& dd, Pointf center, Sizef radius, Color fill_color, double width, + Color line_color, const Vector& dash, double distance) +{ + static GLVertexData fill, line; + const int N = 200; + + ONCELOCK { + Vector> p; + p.Add(); + for(int i = 0; i < N; i++) + p.Top().Add(Polar(i * M_2PI / N)); + GLPolygons(fill, p); + Pointf f = p.Top()[0]; + p.Top().Add(f); + GLPolylines(line, p); + } + + Sizef r = radius - Sizef(width, width); + if(r.cx > 0 && r.cy > 0 && !IsNull(fill_color)) + GLDrawPolygons(dd, center, fill, r, fill_color); + r = radius - Sizef(width / 2, width / 2); + if(width > 0 && !IsNull(line_color)) + if(dash.GetCount()) { + Vector line; + for(int i = 0; i < N; i++) + line.Add(r * Polar(i * M_2PI / N) + center); + Vector> ll; + DashPolyline(ll, line, dash, 0); + GLVertexData data; + GLPolylines(data, ll); + GLDrawPolylines(dd, Pointf(0, 0), data, Sizef(1, 1), width, line_color); + } + else + GLDrawPolylines(dd, center, line, r, width, line_color); +} + +void GLDrawEllipse(const GLContext2D& dd, Pointf center, Sizef radius, Color fill_color, double width, + Color line_color) +{ + static Vector empty; + GLDrawEllipse(dd, center, radius, fill_color, width, line_color, empty, 0); +} + +}; diff --git a/uppsrc/GLDraw/GLDraw.h b/uppsrc/GLDraw/GLDraw.h index 8956ef0f6..cfead5897 100644 --- a/uppsrc/GLDraw/GLDraw.h +++ b/uppsrc/GLDraw/GLDraw.h @@ -2,6 +2,7 @@ #define _GlDraw_GlDraw_h_ #include +#include #include @@ -110,4 +111,6 @@ void GLOrtho(float left, float right, float bottom, float top, float near_, floa }; +#include "GLPainter.h" + #endif \ No newline at end of file diff --git a/uppsrc/GLDraw/GLDraw.upp b/uppsrc/GLDraw/GLDraw.upp index a0f24aec3..024ba5e9a 100644 --- a/uppsrc/GLDraw/GLDraw.upp +++ b/uppsrc/GLDraw/GLDraw.upp @@ -8,5 +8,19 @@ file Texture.cpp, GLDraw.cpp, GLShaders.cpp, - GLDrawS.cpp; + GLDrawS.cpp, + "HW accelerated" readonly separator, + GLPainter.h, + GLPainter.hpp, + Code.cpp, + VertexData.cpp, + GLTexture.cpp, + DrawTexture.cpp, + Polygon.cpp, + Line.cpp, + Ellipse.cpp, + Arc.cpp, + Text.cpp, + DrawGL.cpp, + todo.txt; diff --git a/uppsrc/GLDraw/GLPainter.h b/uppsrc/GLDraw/GLPainter.h new file mode 100644 index 000000000..fce1b57c1 --- /dev/null +++ b/uppsrc/GLDraw/GLPainter.h @@ -0,0 +1,246 @@ +#ifndef _GLDrawDemo_Ugl_h_ +#define _GLDrawDemo_Ugl_h_ + +namespace Upp { + +struct GL_TIMING_FINISH__ { ~GL_TIMING_FINISH__() { glFinish(); } }; + +#define GL_TIMING(x) GL_TIMING_FINISH__ COMBINE(sGlTiming, __LINE__); RTIMING(x) + +#ifdef _DEBUG +#define GLCHK(x) do { \ + x; \ + int err = glGetError(); \ + if(err) LOG("ERROR " << err << " (" << __LINE__ << "): " << #x); \ + LOG((const char *)gluErrorString(err)); \ +} while(0) +#endif + +struct GLContext2D { // TODO: This should be changed to regular matrix (later) + Sizef vs; + double alpha = 1; + + void Set(Size sz) { vs = Sizef(2.0 / sz.cx, -2.0 / sz.cy); } + + GLContext2D(Size sz) { Set(sz); } + GLContext2D() {} +}; + +struct GLCode : GLProgram { + GLCode(const char *vertex_shader, const char *pixel_shader); + + int operator[](const char *id) { return GetUniform(id); } + + GLCode& Uniform(int i, double a); + GLCode& Uniform(int i, double a, double b); + GLCode& Uniform(int i, double a, double b, double c); + GLCode& Uniform(int i, double a, double b, double c, double d); + + GLCode& Uniform(const char *id, double a); + GLCode& Uniform(const char *id, double a, double b); + GLCode& Uniform(const char *id, double a, double b, double c); + GLCode& Uniform(const char *id, double a, double b, double c, double d); + + GLCode& operator()(const char *id, double a) { return Uniform(id, a); } + GLCode& operator()(const char *id, double a, double b) { return Uniform(id, a, b); } + GLCode& operator()(const char *id, double a, double b, double c) { return Uniform(id, a, b, c); } + GLCode& operator()(const char *id, double a, double b, double c, double d) { return Uniform(id, a, b, c, d); } + + GLCode& operator()(int i, double a) { return Uniform(i, a); } + GLCode& operator()(int i, double a, double b) { return Uniform(i, a, b); } + GLCode& operator()(int i, double a, double b, double c) { return Uniform(i, a, b, c); } + GLCode& operator()(int i, double a, double b, double c, double d) { return Uniform(i, a, b, c, d); } + + GLCode& operator()(const char *id, Pointf p) { return Uniform(id, p.x, p.y); } + 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 { + struct Data { + int refcount = 1; + GLuint textureid = 0; + Point hotspot = Point(0, 0); + Size sz = Size(0, 0); + }; + + Data *data = NULL; + + void Set(GLuint texture, Size sz, Point hotspot = Point(0, 0)); + + friend class GLTextureDraw; + +public: + void Clear(); + void Set(const Image& img, dword flags = TEXTURE_LINEAR|TEXTURE_MIPMAP); + + void Bind() const { if(data) glBindTexture(GL_TEXTURE_2D, data->textureid); } + int GetID() const { return data ? data->textureid : 0; } + operator GLuint() const { return GetID(); } + Size GetSize() const { return data ? data->sz : Size(0, 0); } + Point GetHotSpot() const { return data ? data->hotspot : Point(0, 0); } + + GLTexture() {} + GLTexture(const Image& img, dword flags = TEXTURE_LINEAR|TEXTURE_MIPMAP) { Set(img, flags); } + ~GLTexture() { Clear(); } + + GLTexture(const GLTexture& src); + GLTexture& operator=(const GLTexture& src); +}; + +void GLBind(const Image& img, dword style = TEXTURE_LINEAR|TEXTURE_MIPMAP); + +void GLDrawTexture(const GLContext2D& dd, const Rectf& rect, int textureid); +void GLDrawTexture(const GLContext2D& dd, const Rectf& rect, const Image& img); +void GLDrawImage(const GLContext2D& dd, const Rectf& rect, const Image& img); + +void GLDrawTexture(const GLContext2D& dd, const Rectf& rect, int textureid, Size tsz, const Rect& src); +void GLDrawTexture(const GLContext2D& dd, const Rectf& rect, const GLTexture& img, const Rect& src); +void GLDrawImage(const GLContext2D& dd, const Rectf& rect, const Image& img, const Rect& src); + +class GLTextureDraw { + GLuint framebuffer = 0; + GLuint texture = 0; + GLuint rbo = 0; + Size sz; + int msaa = 0; + +public: + void Clear(); + void Create(Size sz, int msaa = 0); + GLTexture GetResult(); + operator GLTexture() { return GetResult(); } + + GLTextureDraw() {} + GLTextureDraw(Size sz, int msaa = 0) { Create(sz, msaa); } + ~GLTextureDraw() { Clear(); } +}; + +class GLVertexData { + struct Data { + int refcount = 1; + GLuint VAO = 0; + GLuint EBO = 0; + int elements = 0; + + Vector VBO; + }; + + 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 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()); } + + void Draw(int mode = GL_TRIANGLES) const; + + void Draw(GLCode& shaders, int mode = GL_TRIANGLES) const; + + operator bool() const { return data; } + bool IsEmpty() const { return !data; } + + GLVertexData() {} + ~GLVertexData() { Clear(); } + + GLVertexData(const GLVertexData& src); + GLVertexData& operator=(const GLVertexData& src); +}; + +const GLVertexData& GLRectMesh(); + +template +void GLPolygons(GLVertexData& mesh, const Src& polygon); + +void GLDrawPolygons(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, Sizef scale, Color color); +void GLDrawConvexPolygons(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, Sizef scale, Color color); + +template +void GLPolylines(GLVertexData& data, const Src& polygon); + +void DashPolyline(Vector>& polyline, const Vector& line, + const Vector& pattern, double distance = 0); + +void GLDrawPolylines(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, Sizef scale, double width, Color color); + +void GLDrawStencil(Color color, double alpha); + +void GLDrawEllipse(const GLContext2D& dd, Pointf center, Sizef radius, Color fill_color, + double width, Color line_color, const Vector& dash, double distance); +void GLDrawEllipse(const GLContext2D& dd, Pointf center, Sizef radius, Color fill_color, + double width, Color line_color); + +GLTexture GetGlyphGLTextureCached(double angle, int chr, Font font, Color color); + +void GLDrawText(const GLContext2D& dd, Pointf pos, double angle, const wchar *text, Font font, + Color ink, int n = -1, const int *dx = NULL); + +void GLArc(Vector>& line, const Rectf& rc, Pointf start, Pointf end); + +#include "GLPainter.hpp" + +class DrawGL : public Draw { +public: + virtual dword GetInfo() const; + + virtual void BeginOp(); + virtual bool ClipOp(const Rect& r); + virtual bool ClipoffOp(const Rect& r); + virtual bool IntersectClipOp(const Rect& r); + virtual void OffsetOp(Point p); + virtual bool ExcludeClipOp(const Rect& r); + virtual void EndOp(); + virtual bool IsPaintingOp(const Rect& r) const; + + virtual void SysDrawImageOp(int x, int y, const Image& img, Color color); + virtual void SysDrawImageOp(int x, int y, const Image& img, const Rect& src, Color color); + virtual void DrawRectOp(int x, int y, int cx, int cy, Color color); + + virtual void DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx); + + virtual void DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color); + virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor); + virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color); + virtual void DrawPolyPolyPolygonOp(const Point *vertices, int vertex_count, const int *subpolygon_counts, int scc, const int *disjunct_polygon_counts, int dpcc, Color color, int width, Color outline, uint64 pattern, Color doxor); + virtual void DrawPolyPolylineOp(const Point *vertices, int vertex_count, const int *counts, int count_count, int width, Color color, Color doxor); + +private: + struct Cloff : Moveable { + Rect clip; + Pointf offset; + }; + + Vector cloff; + GLContext2D dd; + Size view_size; + + Pointf Offset(int x, int y); + Pointf Offset(Point p) { return Offset(p.x, p.y); } + Rectf Offset(int x, int y, int cx, int cy); + Rectf Offset(int x, int y, Size sz); + void SyncScissor(); + void DoPath(Vector>& poly, const Point *pp, const Point *end); + static const Vector& GetDash(int& width); + void ApplyDash(Vector>& polyline, int& width); + +public: + void Init(Size sz, double alpha = 1); + + DrawGL() {} + DrawGL(Size sz, double alpha = 1) { Init(sz, alpha); } + ~DrawGL(); +}; + +}; + +#endif diff --git a/uppsrc/GLDraw/GLPainter.hpp b/uppsrc/GLDraw/GLPainter.hpp new file mode 100644 index 000000000..ebb54371a --- /dev/null +++ b/uppsrc/GLDraw/GLPainter.hpp @@ -0,0 +1,58 @@ +template +void GLPolygons(GLVertexData& mesh, const Src& polygon) +{ + Vector vertex; + Vector ndx; + + mesh.Clear(); + + for(const auto& p: polygon) { + int i0 = vertex.GetCount(); + for(int i = 0; i < p.GetCount(); i++) { + if(i > 1) + ndx << i0 << i0 + i - 1 << i0 + i; + vertex.Add(p[i]); + } + } + + mesh.Add(vertex).Index(ndx); +} + +template +void GLPolylines(GLVertexData& data, const Src& polygon) +{ + Vector vertex; + Vector ndx; + + int ii = 0; + for(const auto& p: polygon) { + int i0 = vertex.GetCount(); + int ii0 = ii; + 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 = p1 - 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; + + ndx << ii << ii + 1 << ii + 2 + << ii + 3 << ii + 2 << ii + 1; + + if(i) // if line is not first, draw bevel join between current and previous line + ndx << ii << ii + 1 << ii - 4 + 3 + << ii - 4 + 2 << ii - 4 + 3 << ii; + + ii += 4; + } + + if(p.GetCount() > 2 && p.Top() == p[0]) // Line loop is closed, draw bevel join + ndx << ii0 << ii0 + 1 << ii - 4 + 3 + << ii - 4 + 2 << ii - 4 + 3 << ii0; + } + + data.Add(vertex, 4).Index(ndx); +} diff --git a/uppsrc/GLDraw/GLTexture.cpp b/uppsrc/GLDraw/GLTexture.cpp new file mode 100644 index 000000000..dbfa62c07 --- /dev/null +++ b/uppsrc/GLDraw/GLTexture.cpp @@ -0,0 +1,173 @@ +#include "GLDraw.h" + +namespace Upp { + +void GLTexture::Clear() +{ + if(data && --data->refcount == 0) { + glDeleteTextures(1, &data->textureid); + delete data; + } + data = NULL; +} + +void GLTexture::Set(GLuint id, Size sz, Point hotspot) +{ + Clear(); + data = new Data; + data->sz = sz; + data->hotspot = hotspot; + data->textureid = id; +} + +void GLTexture::Set(const Image& img, dword flags) +{ + Set(CreateGLTexture(img, flags), img.GetSize(), img.GetHotSpot()); +} + +GLTexture::GLTexture(const GLTexture& src) +{ + data = src.data; + data->refcount++; +} + +GLTexture& GLTexture::operator=(const GLTexture& src) +{ + if(data != src.data) { + if(data) Clear(); + data = src.data; + data->refcount++; + } + return *this; +} + +void GLBind(const Image& img, dword style) +{ + glBindTexture(GL_TEXTURE_2D, GetTextureForImage(style, img)); +} + +const GLVertexData& GLRectMesh() +{ + static GLVertexData mesh; + ONCELOCK { + static const float box[] = { + 0, 0, // 0 + 0, 1, // 1 + 1, 0, // 2 + 1, 1, // 3 + }; + static const int ndx[] = { + 0, 1, 2, 1, 2, 3 + }; + mesh.Add(box, 2, 4).Index(ndx, 6); + } + return mesh; +} + +void GLDrawTexture(const GLContext2D& dd, const Rectf& rect, int textureid) +{ + static GLCode program(R"( + #version 330 core + uniform vec2 offset; + uniform vec2 scale; + in vec2 aPos; + out vec2 tPos; + void main() + { + gl_Position = vec4(scale * aPos + offset, 0, 1); + tPos = aPos; + } + )", R"( + #version 330 core + in vec2 tPos; + uniform float alpha; + uniform sampler2D s_texture; + void main() + { + gl_FragColor = alpha * texture2D(s_texture, tPos); + } + )"); + + static int offset = program["offset"]; + static int scale = program["scale"]; + static int ialpha = program["alpha"]; + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glBindTexture(GL_TEXTURE_2D, textureid); + GLRectMesh().Draw( + program(offset, dd.vs * rect.TopLeft() + Sizef(-1, 1)) + (scale, dd.vs * rect.GetSize()) + (ialpha, dd.alpha) + ); +} + +void GLDrawTexture(const GLContext2D& dd, const Rectf& rect, const GLTexture& img) +{ + GLDrawTexture(dd, rect, img.GetID()); +} + +void GLDrawImage(const GLContext2D& dd, const Rectf& rect, const Image& img) +{ + GLDrawTexture(dd, rect, GetTextureForImage(img)); +} + +void GLDrawTexture(const GLContext2D& dd, const Rectf& rect, int textureid, Size tsz, const Rect& src) +{ + static GLCode program(R"( + #version 330 core + uniform vec2 offset; + uniform vec2 scale; + + uniform vec2 toffset; + uniform vec2 tscale; + + in vec2 aPos; + out vec2 tPos; + void main() + { + gl_Position = vec4(scale * aPos + offset, 0, 1); + tPos = tscale * aPos + toffset; + } + )", R"( + #version 330 core + in vec2 tPos; + uniform float alpha; + uniform sampler2D s_texture; + void main() + { + gl_FragColor = alpha * texture2D(s_texture, tPos); + } + )"); + + static int ioffset = program["offset"]; + static int iscale = program["scale"]; + static int ialpha = program["alpha"]; + static int itscale = program["tscale"]; + static int itoffset = program["toffset"]; + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + glBindTexture(GL_TEXTURE_2D, textureid); + GLRectMesh().Draw( + program(ioffset, dd.vs * rect.TopLeft() + Sizef(-1, 1)) + (iscale, dd.vs * rect.GetSize()) + (ialpha, dd.alpha) + (itoffset, Sizef((float)src.left / tsz.cx, (float)src.top / tsz.cy)) + (itscale, Sizef((float)src.GetWidth() / tsz.cx, (float)src.GetHeight() / tsz.cy)) + ); +} + +void GLDrawTexture(const GLContext2D& dd, const Rectf& rect, const GLTexture& img, const Rect& src) +{ + GLDrawTexture(dd, rect, img.GetID(), img.GetSize(), src); +} + +void GLDrawImage(const GLContext2D& dd, const Rectf& rect, const Image& img, const Rect& src) +{ + GLDrawTexture(dd, rect, GetTextureForImage(img), img.GetSize(), src); +} + +}; diff --git a/uppsrc/GLDraw/Line.cpp b/uppsrc/GLDraw/Line.cpp new file mode 100644 index 000000000..4ac0ddb68 --- /dev/null +++ b/uppsrc/GLDraw/Line.cpp @@ -0,0 +1,88 @@ +#include "GLDraw.h" + +namespace Upp { + +void GLDrawPolylines(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, Sizef scale, + double width, Color color) +{ + GL_TIMING("GLDrawPolylines"); + + static GLCode program(R"( + #version 330 core + in vec4 pos; + uniform vec2 offset; + uniform vec2 scale; + uniform vec2 scale2; + uniform vec2 width; + void main() + { + vec2 v = scale2 * pos.zw; + gl_Position = vec4(scale * (scale2 * pos.xy + width * normalize(vec2(-v.y, v.x))) + 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 iscale2 = program["scale2"]; + static int iwidth = program["width"]; + static int icolor = program["color"]; + + program(ioffset, Pointf(dd.vs) * at + Sizef(-1, 1)) + (iscale, dd.vs) + (iscale2, scale) + (iwidth, Sizef(width / 2, width / 2)) + (icolor, color, dd.alpha) + ; + + if(dd.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); + } +} + +void DashPolyline(Vector>& polyline, const Vector& line, + const Vector& pattern, double distance) +{ + struct LineStore : LinearPathConsumer { + Vector>& polyline; + + void Move(const Pointf& p) override { polyline.Add().Add(p); } + void Line(const Pointf& p) override { polyline.Top().Add(p); } + + LineStore(Vector>& polyline) : polyline(polyline) {} + }; + + LineStore st(polyline); + Dasher dasher; + dasher.target = &st; + dasher.Init(pattern, distance); + for(int i = 0; i < line.GetCount(); i++) + if(i) + dasher.Line(line[i]); + else + dasher.Move(line[i]); + dasher.End(); +} + +}; \ No newline at end of file diff --git a/uppsrc/GLDraw/Polygon.cpp b/uppsrc/GLDraw/Polygon.cpp new file mode 100644 index 000000000..758d6a8ec --- /dev/null +++ b/uppsrc/GLDraw/Polygon.cpp @@ -0,0 +1,90 @@ +#include "GLDraw.h" + +namespace Upp { + +GLCode& GLSimpleCode() +{ + static GLCode program(R"( + #version 330 core + in vec2 aPos; + uniform vec2 offset; + uniform vec2 scale; + void main() + { + gl_Position = vec4(scale * aPos + offset, 0, 1); + } + )", R"( + #version 330 core + uniform vec4 color; + void main() + { + gl_FragColor = color; + } + )"); + return program; +} + +void GLDrawStencil(Color color, double alpha) +{ + GLCode& program = GLSimpleCode(); + + static int ioffset = program["offset"]; + static int iscale = program["scale"]; + static int icolor = program["color"]; + + 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 GLDrawPolygons(const GLContext2D& dd, bool generic, Pointf at, const GLVertexData& mesh, Sizef scale, Color color) +{ + GL_TIMING("GLDrawPolygons"); + + 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); + glDisable(GL_CULL_FACE); + + glEnable(GL_STENCIL_TEST); + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + glStencilFunc(GL_NEVER, 0, 1); + glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT); + + mesh.Draw(program); + + GLDrawStencil(color, dd.alpha); + } + else { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + mesh.Draw(program(icolor, color, dd.alpha)); + } +} + +void GLDrawPolygons(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, Sizef scale, Color color) +{ + GLDrawPolygons(dd, true, at, mesh, scale, color); +} + +void GLDrawConvexPolygons(const GLContext2D& dd, Pointf at, const GLVertexData& mesh, Sizef scale, Color color) +{ + GLDrawPolygons(dd, false, at, mesh, scale, color); +} + +}; \ No newline at end of file diff --git a/uppsrc/GLDraw/Text.cpp b/uppsrc/GLDraw/Text.cpp new file mode 100644 index 000000000..54be77806 --- /dev/null +++ b/uppsrc/GLDraw/Text.cpp @@ -0,0 +1,82 @@ +#include "GLDraw.h" + +namespace Upp { + +Image RenderGlyphByPainter2(Point at, double angle, int chr, Font font, Color color, Size sz) +{ + ImageBuffer ib(sz); + BufferPainter sw(ib); + sw.Clear(RGBAZero()); + sw.EvenOdd(true); + sw.Translate(at.x, at.y); + if(angle) + sw.Rotate(angle); + wchar text = chr; + sw.Text(0, 0, &text, font, 1); + sw.Fill(color); + Image h = ib; + return Premultiply(h); +} + +int texture_glyph_cache_max = 64*1024*1024; + +struct sGlyphTextureMaker : LRUCache::Maker { + double angle; + int chr; + Font font; + Color color; + + virtual String Key() const { + StringBuffer h; + RawCat(h, chr); + RawCat(h, font); + RawCat(h, angle); + RawCat(h, color); + return h; + } + virtual int Make(GLTexture& object) const { + GL_TIMING("Do glyph"); + Point at(font[chr], font.GetLineHeight()); + int n = 2 * (at.x + at.y); + at.x = max(at.x, at.y); + at.y = max(at.x, at.y); + Image img = AutoCrop(WithHotSpot(RenderGlyphByPainter2(at, angle, chr, font, color, Size(n, n)), at.x, at.y), RGBAZero()); + object = GLTexture(img, 0); + return 4 * img.GetLength(); + } +}; + +GLTexture GetGlyphGLTextureCached(double angle, int chr, Font font, Color color) +{ + GL_TIMING("GetGlyphGLTextureCached"); + static LRUCache cache; + sGlyphTextureMaker cm; + cm.angle = angle; + cm.chr = chr; + cm.font = font; + cm.color = color; + cache.Shrink(texture_glyph_cache_max, 20000); + return cache.Get(cm); +} + + +void GLDrawText(const GLContext2D& dd, Pointf pos, double angle, const wchar *text, Font font, + Color ink, int n, const int *dx) +{ + GL_TIMING("GLDrawText"); + int x = 0; + Pointf u; + if(angle) + u = Polar(-angle); + if(n < 0) + n = wstrlen(text); + for(int i = 0; i < n; i++) { + GLTexture m = GetGlyphGLTextureCached(-angle, text[i], font, ink); + Point h = m.GetHotSpot(); + Pointf p = (angle ? pos + x * u : Pointf(x + pos.x, pos.y)) - (Pointf)m.GetHotSpot(); + GLDrawTexture(dd, Rectf((Point)p, m.GetSize()), m); + x += dx ? *dx++ : font[text[i]]; + } +} + +}; diff --git a/uppsrc/GLDraw/VertexData.cpp b/uppsrc/GLDraw/VertexData.cpp new file mode 100644 index 000000000..d61738d36 --- /dev/null +++ b/uppsrc/GLDraw/VertexData.cpp @@ -0,0 +1,107 @@ +#include "GLDraw.h" + +namespace Upp { + +GLVertexData::GLVertexData(const GLVertexData& src) +{ + 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() +{ + 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; +} + +void GLVertexData::Do() +{ + 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 *values, int type, int ntuple, int count) +{ + GL_TIMING("GLVertexData::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), + GL_BYTE, sizeof(byte), + GL_UNSIGNED_BYTE, sizeof(byte), + GL_SHORT, sizeof(int16), + GL_UNSIGNED_SHORT, sizeof(uint16), + GL_INT, sizeof(int32), + GL_UNSIGNED_INT, sizeof(uint32), + sizeof(double)); + 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); + glBindVertexArray(0); + return *this; +} + +GLVertexData& GLVertexData::Index(const int *indices, int count) +{ + GL_TIMING("GLVertexData::Index"); + 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); + data->elements = count; + return *this; +} + +void GLVertexData::Draw(int mode) const +{ + if(data) { + glBindVertexArray(data->VAO); + glDrawElements(mode, data->elements, GL_UNSIGNED_INT, 0); + glBindVertexArray(0); + } +} + +void GLVertexData::Draw(GLCode& shaders, int mode) const +{ + shaders.Use(); + Draw(mode); +} + +GLVertexData& GLVertexData::Add(const Vector& pt) +{ + Buffer f(2 * pt.GetCount()); + float *t = f; + for(const Pointf& p : pt) { + *t++ = (float)p.x; + *t++ = (float)p.y; + } + return Add(f, GL_FLOAT, 2, pt.GetCount()); +} + +}; \ No newline at end of file diff --git a/uppsrc/GLDraw/todo.txt b/uppsrc/GLDraw/todo.txt new file mode 100644 index 000000000..7fa30f419 --- /dev/null +++ b/uppsrc/GLDraw/todo.txt @@ -0,0 +1,13 @@ +- make banded glyphs +- make alpha textures +- colored texture paints (optimize text) +- optimize draw rect + +DONE: + +- Texture change Rect -> Rectf +- ARC +- DASHER +- circle pen should be able to 'dash' +- arc pen should be able to 'dash' +- polygon pen should be able to 'dash'