mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 22:02:49 -06:00
Painter improvements: Multithreaded rendering improved, new image filter (like Lanczos 3) option, image mapping is now more precise
229 lines
4.4 KiB
C++
229 lines
4.4 KiB
C++
#include "Painter.h"
|
|
|
|
namespace Upp {
|
|
|
|
void BufferPainter::BeginOp()
|
|
{
|
|
attr.onpath = false;
|
|
attrstack.Add(attr);
|
|
attr.hasclip = false;
|
|
}
|
|
|
|
void BufferPainter::EndOp()
|
|
{
|
|
if(attrstack.GetCount() == 0) {
|
|
NEVER_("Painter::End: attribute stack is empty");
|
|
return;
|
|
}
|
|
pathattr = attr = attrstack.Top();
|
|
attrstack.Drop();
|
|
if(clip.GetCount() != attr.cliplevel || attr.mask)
|
|
Finish();
|
|
clip.SetCount(attr.cliplevel);
|
|
if(attr.mask)
|
|
FinishMask();
|
|
if(attr.onpath) {
|
|
attr.onpath = false;
|
|
onpath = pick(onpathstack.Top());
|
|
onpathstack.Drop();
|
|
pathlen = pathlenstack.Pop();
|
|
}
|
|
}
|
|
|
|
void BufferPainter::TransformOp(const Xform2D& m)
|
|
{
|
|
ASSERT_(IsNull(current), "Cannot change transformation during path definition");
|
|
pathattr.mtx = attr.mtx = m * attr.mtx;
|
|
pathattr.mtx_serial = attr.mtx_serial = ++mtx_serial;
|
|
}
|
|
|
|
void BufferPainter::OpacityOp(double o)
|
|
{
|
|
pathattr.opacity *= o;
|
|
if(IsNull(current))
|
|
attr.opacity *= o;
|
|
}
|
|
|
|
void BufferPainter::LineCapOp(int linecap)
|
|
{
|
|
pathattr.cap = linecap;
|
|
if(IsNull(current))
|
|
attr.cap = linecap;
|
|
}
|
|
|
|
void BufferPainter::LineJoinOp(int linejoin)
|
|
{
|
|
pathattr.join = linejoin;
|
|
if(IsNull(current))
|
|
attr.join = linejoin;
|
|
}
|
|
|
|
void BufferPainter::MiterLimitOp(double l)
|
|
{
|
|
pathattr.miter_limit = l;
|
|
if(IsNull(current))
|
|
attr.miter_limit = l;
|
|
}
|
|
|
|
void BufferPainter::EvenOddOp(bool evenodd)
|
|
{
|
|
pathattr.evenodd = evenodd;
|
|
if(IsNull(current))
|
|
attr.evenodd = evenodd;
|
|
}
|
|
|
|
void BufferPainter::InvertOp(bool invert)
|
|
{
|
|
pathattr.invert = invert;
|
|
if(IsNull(current))
|
|
attr.invert = invert;
|
|
}
|
|
|
|
void BufferPainter::ImageFilterOp(int filter)
|
|
{
|
|
pathattr.filter = filter;
|
|
if(IsNull(current))
|
|
attr.invert = filter;
|
|
}
|
|
|
|
Vector<double> StringToDash(const String& dash, double& start);
|
|
|
|
void BufferPainter::DashOp(const String& dash, double start)
|
|
{
|
|
String key;
|
|
if(start) {
|
|
key.Cat(1);
|
|
RawCat(key, start);
|
|
}
|
|
else
|
|
key.Cat(2);
|
|
RawCat(key, dash);
|
|
const DashInfo *d = dashes.FindPtr(key);
|
|
if(!d) {
|
|
DashInfo& h = dashes.Add(key);
|
|
h.dash = StringToDash(dash, start);
|
|
h.start = start;
|
|
d = &h;
|
|
}
|
|
pathattr.dash = d;
|
|
if(IsNull(current))
|
|
attr.dash = d;
|
|
}
|
|
|
|
void BufferPainter::DashOp(const Vector<double>& dash, double start)
|
|
{
|
|
String key;
|
|
RawCat(key, 0);
|
|
RawCat(key, start);
|
|
for(double h : dash)
|
|
RawCat(key, h);
|
|
const DashInfo *d = dashes.FindPtr(key);
|
|
if(!d) {
|
|
DashInfo& h = dashes.Add(key);
|
|
h.start = start;
|
|
h.dash = clone(dash);
|
|
d = &h;
|
|
}
|
|
pathattr.dash = d;
|
|
if(IsNull(current))
|
|
attr.dash = d;
|
|
}
|
|
|
|
void BufferPainter::ColorStop0(Attr& a, double pos, const RGBA& color)
|
|
{
|
|
pos = minmax(pos, 0.0, 1.0);
|
|
ColorStop c;
|
|
c.color = color;
|
|
c.stop = pos;
|
|
int i = FindLowerBound(a.color_stop, c);
|
|
a.color_stop.Insert(i, c);
|
|
}
|
|
|
|
void BufferPainter::ColorStopOp(double pos, const RGBA& color)
|
|
{
|
|
ColorStop0(pathattr, pos, color);
|
|
if(IsNull(current))
|
|
ColorStop0(attr, pos, color);
|
|
}
|
|
|
|
void BufferPainter::ClearStopsOp()
|
|
{
|
|
pathattr.color_stop.Clear();
|
|
if(IsNull(current))
|
|
attr.color_stop.Clear();
|
|
}
|
|
|
|
void BufferPainter::Create(ImageBuffer& ib, int mode_)
|
|
{
|
|
ip = &ib;
|
|
ip->SetKind(IMAGE_ALPHA);
|
|
|
|
if(mode_ != mode || (Size)size != ib.GetSize()) {
|
|
mode = mode_;
|
|
|
|
rasterizer.Create(ib.GetWidth(), ib.GetHeight(), mode == MODE_SUBPIXEL);
|
|
cojob.Clear();
|
|
cofill.Clear();
|
|
|
|
render_cx = ib.GetWidth();
|
|
if(mode == MODE_SUBPIXEL) {
|
|
render_cx *= 3;
|
|
subpixel.Alloc(render_cx + 30);
|
|
}
|
|
else
|
|
subpixel.Clear();
|
|
size = ib.GetSize();
|
|
|
|
co_subpixel.Clear();
|
|
co_span.Clear();
|
|
span.Clear();
|
|
|
|
co_clear.Clear();
|
|
}
|
|
|
|
SyncCo();
|
|
|
|
if(!paths)
|
|
paths.Alloc(BATCH_SIZE);
|
|
|
|
path_info = paths;
|
|
|
|
attr.mtx = Xform2D::Identity();
|
|
attr.cap = LINECAP_BUTT;
|
|
attr.join = LINEJOIN_MITER;
|
|
attr.miter_limit = 4;
|
|
attr.evenodd = false;
|
|
attr.hasclip = false;
|
|
attr.cliplevel = 0;
|
|
attr.opacity = 1;
|
|
attr.dash = NULL;
|
|
attr.mask = false;
|
|
attr.invert = false;
|
|
attr.mtx_serial = 0;
|
|
|
|
pathattr = attr;
|
|
|
|
ClearPath();
|
|
|
|
jobcount = fillcount = emptycount = 0;
|
|
|
|
attrstack.Clear();
|
|
clip.Clear();
|
|
mask.Clear();
|
|
onpathstack.Clear();
|
|
pathlenstack.Clear();
|
|
onpath.Clear();
|
|
|
|
preclip_mtx_serial = -1;
|
|
path_index = 0;
|
|
}
|
|
|
|
BufferPainter::BufferPainter(PainterTarget& t, double tolerance)
|
|
: BufferPainter(dummy, MODE_ANTIALIASED)
|
|
{
|
|
alt = &t;
|
|
alt_tolerance = tolerance;
|
|
dummy.Create(1, 1);
|
|
}
|
|
|
|
}
|