mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
315 lines
7.1 KiB
C++
315 lines
7.1 KiB
C++
#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);
|
|
scissor = Null;
|
|
SyncScissor();
|
|
prev = Point(0, 0);
|
|
path_done = false;
|
|
}
|
|
|
|
DrawGL::~DrawGL()
|
|
{
|
|
Flush();
|
|
glDisable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
dword DrawGL::GetInfo() const
|
|
{
|
|
return DRAWTEXTLINES;
|
|
}
|
|
|
|
void DrawGL::Push()
|
|
{
|
|
auto& s = state.Add();
|
|
s.dash = clone(dash);
|
|
s.dash_start = clone(dash_start);
|
|
s.alpha = dd.alpha;
|
|
}
|
|
|
|
void DrawGL::BeginOp()
|
|
{
|
|
Flush();
|
|
Cloff c = cloff.Top();
|
|
cloff.Add(c);
|
|
Push();
|
|
}
|
|
|
|
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();
|
|
Push();
|
|
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();
|
|
Push();
|
|
return !c1.clip.IsEmpty();
|
|
}
|
|
|
|
bool DrawGL::IntersectClipOp(const Rect& r)
|
|
{
|
|
Cloff& c = cloff.Top();
|
|
c.clip = c.clip & (r + c.offset);
|
|
SyncScissor();
|
|
Push();
|
|
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;
|
|
Push();
|
|
}
|
|
|
|
void DrawGL::EndOp()
|
|
{
|
|
ASSERT(cloff.GetCount());
|
|
if(cloff.GetCount())
|
|
cloff.Drop();
|
|
if(state.GetCount()) {
|
|
auto& s = state.Top();
|
|
dash = pick(s.dash);
|
|
dash_start = s.dash_start;
|
|
dd.alpha = s.alpha;
|
|
state.Drop();
|
|
}
|
|
SyncScissor();
|
|
}
|
|
|
|
void DrawGL::SyncScissor()
|
|
{
|
|
GL_TIMING("SyncScissor");
|
|
Rect clip = cloff.Top().clip;
|
|
if(clip != scissor) {
|
|
Flush();
|
|
Size sz = clip.GetSize();
|
|
glScissor(clip.left, view_size.cy - sz.cy - clip.top, sz.cx, sz.cy);
|
|
}
|
|
}
|
|
|
|
Pointf DrawGL::Off(int x, int y)
|
|
{
|
|
Pointf o = cloff.Top().offset;
|
|
return Pointf(x + o.x, y + o.y);
|
|
}
|
|
|
|
Rectf DrawGL::Off(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::Off(int x, int y, Size sz)
|
|
{
|
|
return Off(x, y, sz.cx, sz.cy);
|
|
}
|
|
|
|
void DrawGL::DrawImageOp(int x, int y, int cx, int cy, const Image& image, const Rect& src, Color color)
|
|
{
|
|
Flush();
|
|
GLDrawImage(dd, Off(x, y, cx, cy), IsNull(color) ? image : CachedSetColorKeepAlpha(image, color),
|
|
src);
|
|
}
|
|
|
|
void DrawGL::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx)
|
|
{
|
|
Flush();
|
|
GLDrawText(dd, Off(x, y), angle * M_2PI / 3600, text, font, ink, n, dx);
|
|
}
|
|
|
|
void DrawGL::DrawRectOp(int x, int y, int cx, int cy, Color color)
|
|
{
|
|
Point off = cloff.Top().offset;
|
|
int a = Vertex(x + off.x, y + off.y, color, dd.alpha);
|
|
int b = Vertex(x + off.x + cx, y + off.y, color, dd.alpha);
|
|
int c = Vertex(x + off.x + cx, y + off.y + cy, color, dd.alpha);
|
|
int d = Vertex(x + off.x, y + off.y + cy, color, dd.alpha);
|
|
|
|
Triangle(a, b, c);
|
|
Triangle(a, c, d);
|
|
}
|
|
|
|
const Vector<double>& DrawGL::GetDash(int& width)
|
|
{
|
|
static Vector<double> nodash;
|
|
static Vector<double> dash = { 18, 6 };
|
|
static Vector<double> dot = { 3, 3 };
|
|
static Vector<double> dashdot = { 9, 6, 3, 6 };
|
|
static Vector<double> dashdotdot = { 9, 3, 3, 3, 3, 3 };
|
|
|
|
if(width == 0)
|
|
width = 1;
|
|
if(width > 0)
|
|
return nodash;
|
|
if(width == PEN_NULL || IsNull(width)) {
|
|
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<Vector<Pointf>>& polyline, int& width)
|
|
{
|
|
const Vector<double>& dash = GetDash(width);
|
|
GetDash(width);
|
|
if(dash.GetCount()) {
|
|
Vector<Vector<Pointf>> r;
|
|
for(auto& l : polyline)
|
|
DashPolyline(r, l, dash);
|
|
polyline = pick(r);
|
|
}
|
|
}
|
|
|
|
void DrawGL::DoDrawPolylines(Vector<Vector<Pointf>>& poly, int width, Color color, bool close)
|
|
{
|
|
ApplyDash(poly, width);
|
|
for(const auto& p : poly)
|
|
Polyline(*this, p, width, color, dd.alpha, close);
|
|
}
|
|
|
|
void DrawGL::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color)
|
|
{
|
|
Vector<Vector<Pointf>> poly;
|
|
poly.Add().Add(Off(x1, y1));
|
|
poly.Top().Add(Off(x2, y2));
|
|
DoDrawPolylines(poly, width, color);
|
|
}
|
|
|
|
void DrawGL::DrawArcOp(const Rect& rc, Point start, Point end, int width, Color color)
|
|
{
|
|
GL_TIMING("DrawGL::DrawArcOp");
|
|
Vector<Vector<Pointf>> poly;
|
|
GLArc(poly, rc, start, end);
|
|
DoDrawPolylines(poly, width, color);
|
|
}
|
|
|
|
void DrawGL::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor)
|
|
{
|
|
// TODO: Dash, ellipse stroke
|
|
if(!r.IsEmpty())
|
|
Upp::Ellipse(*this, Pointf(r.CenterPoint()) + cloff.Top().offset,
|
|
Sizef(r.GetSize()) / 2, color, pen, pencolor, dd.alpha);
|
|
}
|
|
|
|
void DrawGL::DoPath(Vector<Vector<Pointf>>& poly, const Point *pp, const Point *end)
|
|
{
|
|
poly.Add().Add(Off(*pp++));
|
|
while(pp < end)
|
|
poly.Top().Add(Off(*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<Vector<Pointf>> poly;
|
|
while(--count_count >= 0) {
|
|
const Point *pp = vertices;
|
|
vertices += *counts++;
|
|
DoPath(poly, pp, vertices);
|
|
}
|
|
|
|
DoDrawPolylines(poly, width, color);
|
|
}
|
|
|
|
extern int sTesselateCounter;
|
|
|
|
void DrawGL::DoDrawPolygons(const Vector<Vector<Pointf>>& path, Color color)
|
|
{
|
|
const int TESS_LIMIT = 200;
|
|
int n = 0;
|
|
for(const auto& p : path) {
|
|
n += p.GetCount();
|
|
if(n > TESS_LIMIT) {
|
|
Flush();
|
|
GLVertexData data;
|
|
GLPolygons(data, path);
|
|
GLDrawPolygons(dd, Pointf(0, 0), data, Sizef(1, 1), color);
|
|
return;
|
|
}
|
|
}
|
|
Vector<Pointf> vertex;
|
|
Vector<Tuple<int, int, int>> triangle;
|
|
sTesselateCounter++;
|
|
Tesselate(path, vertex, triangle, false);
|
|
int ii0;
|
|
for(int i = 0; i < vertex.GetCount(); i++) {
|
|
int q = Vertex(vertex[i], color, dd.alpha);
|
|
if(i == 0) ii0 = q;
|
|
}
|
|
for(const auto& t : triangle)
|
|
Triangle(t.a + ii0, t.b + ii0, t.c + ii0);
|
|
}
|
|
|
|
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<Vector<Pointf>> 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(poly.GetCount() == 0)
|
|
return;
|
|
|
|
if(!IsNull(color))
|
|
DoDrawPolygons(poly, color);
|
|
|
|
if(!IsNull(outline))
|
|
DoDrawPolylines(poly, width, outline, true);
|
|
}
|
|
|
|
|
|
void DrawGL::Flush()
|
|
{
|
|
GLTriangles::Draw(dd);
|
|
GLTriangles::Clear();
|
|
}
|
|
|
|
};
|