Draw: DDARasterizer, IconDes: Now using DDARasterizer

git-svn-id: svn://ultimatepp.org/upp/trunk@6058 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2013-05-12 18:54:11 +00:00
parent d7440ace2a
commit 6055936466
10 changed files with 433 additions and 3 deletions

View file

@ -0,0 +1,215 @@
#include "Draw.h"
NAMESPACE_UPP
DDARasterizer::DDARasterizer()
{
cy = 0;
p0 = p1 = Point(0, 0);
width = 1;
}
void DDARasterizer::AHorz(int x, int y, int cx)
{
if(cx)
if(cx < 0)
PutHorz(x + cx + 1, y, -cx);
else
PutHorz(x, y, cx);
}
void DDARasterizer::AVert(int x, int y, int cy)
{
if(cy)
if(cy < 0)
PutVert(x, y + cy + 1, -cy);
else
PutVert(x, y, cy);
}
void DDARasterizer::DoLine(Point p1, Point p2, bool last)
{
dirx = sgn(p2.x - p1.x);
diry = sgn(p2.y - p1.y);
int dx = abs(p2.x - p1.x);
int dy = abs(p2.y - p1.y);
int x = p1.x;
int y = p1.y;
int x0 = x;
int y0 = y;
if(dx < dy) {
int dda = dy >> 1;
int n = dy + last;
for(;;) {
if(x != x0) {
AVert(x0, y0, y - y0);
x0 = x;
y0 = y;
}
if(n-- <= 0)
break;
y += diry;
dda -= dx;
if(dda < 0) {
dda += dy;
x += dirx;
}
}
AVert(x0, y0, y - y0);
}
else {
int dda = dx >> 1;
int n = dx + last;
for(;;) {
if(y != y0) {
AHorz(x0, y0, x - x0);
x0 = x;
y0 = y;
}
if(n-- <= 0)
break;
x += dirx;
dda -= dy;
if(dda < 0) {
dda += dx;
y += diry;
}
}
AHorz(x0, y0, x - x0);
}
}
struct DDARasterizer::Segments : DDARasterizer {
int miny;
int maxy;
bool flag;
Vector< Vector< Segment > > segment;
virtual void PutHorz(int x, int y, int cx) {
if(y >= 0 && y < cy) {
Segment& m = segment.At(y).Add();
m.l = x;
m.h = x + cx;
m.flag = flag;
flag = true;
miny = min(y, miny);
maxy = max(y, maxy);
}
}
virtual void PutVert(int x, int y, int cy) {
for(int i = 0; i < cy; i++)
PutHorz(x, y + i, 1);
}
Segments() { miny = INT_MAX; maxy = 0; }
};
void DDARasterizer::FatLine(Point p1, Point p2, int n)
{
Point v = p2 - p1;
Pointf shift = n * Orthogonal(Pointf(v) / Length((Pointf(v))));
Point p = Pointf(p1) + shift / 2;
Polygon();
Move(p);
Line(p += v);
Line(p -= shift);
Line(p - v);
Fill();
}
DDARasterizer& DDARasterizer::Move(Point p)
{
Close();
p0 = p1 = p;
return *this;
}
DDARasterizer& DDARasterizer::Line(Point p)
{
if(pseg) {
Point a = p1;
Point b = p;
if(a.y > b.y)
Swap(a, b);
pseg->flag = false;
pseg->DoLine(a, b, true);
p1 = p;
}
else {
if(width <= 1)
DoLine(p1, p, false);
else
FatLine(p1, p, width);
p1 = p;
}
return *this;
}
DDARasterizer& DDARasterizer::Close()
{
if(p1 != p0)
Line(p0);
return *this;
}
DDARasterizer& DDARasterizer::Polygon()
{
pseg.Create();
pseg->Cy(cy);
return *this;
}
DDARasterizer& DDARasterizer::Fill()
{
ASSERT(pseg);
Close();
for(int y = pseg->miny; y <= pseg->maxy; y++) {
Vector<Segment>& gg = pseg->segment[y];
Sort(gg);
int i = 0;
bool flag = false;
while(i < gg.GetCount()) {
int l = gg[i].l;
int h = gg[i].h;
flag ^= gg[i++].flag;
while(i < gg.GetCount() && flag) {
h = gg[i].h;
flag ^= gg[i++].flag;
}
PutHorz(l, y, h - l);
}
}
pseg.Clear();
return *this;
}
DDARasterizer& DDARasterizer::Ellipse(const Rect& rect)
{
Size size = rect.GetSize() / 2;
int n = 16;
Buffer<Point> p(n);
for(int i = 0; i < n; i++) {
double angle = M_PI * i / (n - 1) / 2;
p[i].x = min(size.cx, int(sin(angle) * size.cx + 0.5));
p[i].y = min(size.cy, int(cos(angle) * size.cy + 0.5));
}
Point center = rect.TopLeft() + size;
Move(Point(center.x - p[0].x, center.y - p[0].y));
for(int i = 1; i < n; i++)
Line(Point(center.x - p[i].x, center.y - p[i].y));
center.y = rect.bottom - 1 - size.cy;
for(int i = n - 1; i >= 0; i--)
Line(Point(center.x - p[i].x, center.y + p[i].y));
center.x = rect.right - 1 - size.cx;
for(int i = 0; i < n; i++)
Line(Point(center.x + p[i].x, center.y + p[i].y));
center.y = rect.top + size.cy;
for(int i = n - 1; i >= 0; i--)
Line(Point(center.x + p[i].x, center.y - p[i].y));
Close();
return *this;
}
DDARasterizer::~DDARasterizer() {}
END_UPP_NAMESPACE

View file

@ -0,0 +1,46 @@
class DDARasterizer {
struct Segment : Moveable<Segment> {
int l;
int h;
bool flag;
bool operator<(const Segment& b) const { return l < b.l; }
};
struct Segments;
int cy;
int diry;
int dirx;
One<Segments> pseg;
Point p0, p1;
int width;
void AHorz(int x, int y, int cx);
void AVert(int x, int y, int cy);
void DoLine(Point p1, Point p2, bool last);
void FatLine(Point p1, Point p2, int n);
public:
virtual void PutHorz(int x, int y, int cx) = 0;
virtual void PutVert(int x, int y, int cy) = 0;
int GetDirx() const { return dirx; }
int GetDiry() const { return diry; }
DDARasterizer& Move(Point p);
DDARasterizer& Line(Point p);
DDARasterizer& Close();
DDARasterizer& Polygon();
DDARasterizer& Fill();
DDARasterizer& Ellipse(const Rect& rect);
DDARasterizer& Width(int width_) { width = width_; return *this; }
void Cy(int cy_) { cy = cy_; }
DDARasterizer();
~DDARasterizer();
};

View file

@ -884,6 +884,7 @@ DrawingToPdfFnType GetDrawingToPdfFn();
#include "Display.h"
#include "Cham.h"
#include "DDARasterizer.h"
END_UPP_NAMESPACE

View file

@ -58,6 +58,9 @@ file
iml_header.h,
iml_source.h,
DrawImg.iml,
DDA readonly separator,
DDARasterizer.h,
DDARasterizer.cpp,
Chameleon readonly separator,
Cham.h,
Cham.cpp,

View file

@ -0,0 +1,83 @@
topic "DDA Rasterizer";
[2 $$0,0#00000000000000000000000000000000:Default]
[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class]
[l288;2 $$2,2#27521748481378242620020725143825:desc]
[0 $$3,0#96390100711032703541132217272105:end]
[H6;0 $$4,0#05600065144404261032431302351956:begin]
[i448;a25;kKO9;2 $$5,0#37138531426314131252341829483370:item]
[l288;a4;*@5;1 $$6,6#70004532496200323422659154056402:requirement]
[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param]
[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam]
[b42;2 $$9,9#13035079074754324216151401829390:normal]
[{_}%EN-US
[ {{10000@(113.42.0) [s0;%- [*@2;3 DDARasterizer]]}}&]
[s3;%- &]
[s1;:DDARasterizer`:`:class:%- [@(0.0.255)3 class][3 _][*3 DDARasterizer]&]
[s2; Simple non`-antialiased rasterizer capable of drawing lines
with [^http`:`/`/en`.wikipedia`.org`/wiki`/Bresenham`%27s`_line`_algorithm^ DDA]
algorithm and polygons with even`-odd rule. Result is rendered
to pure virtual methods that draw horizontal and vertical line
segments.&]
[s3;%- &]
[ {{10000F(128)G(128)@1 [s0; [* Public Method List]]}}&]
[s3;%- &]
[s5;:DDARasterizer`:`:PutHorz`(int`,int`,int`):%- [@(0.0.255) virtual]
[@(0.0.255) void]_[* PutHorz]([@(0.0.255) int]_[*@3 x], [@(0.0.255) int]_[*@3 y],
[@(0.0.255) int]_[*@3 cx])_`=_[@3 0]&]
[s2; Pure virtual method expected to paint horizontal line at [%-*@3 x],
[%-*@3 y] with length [%-*@3 cx].&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:PutVert`(int`,int`,int`):%- [@(0.0.255) virtual]
[@(0.0.255) void]_[* PutVert]([@(0.0.255) int]_[*@3 x], [@(0.0.255) int]_[*@3 y],
[@(0.0.255) int]_[*@3 cy])_`=_[@3 0]&]
[s2; Pure virtual method expected to paint horizontal line at [%-*@3 x],
[%-*@3 y] with length [%-*@3 cy].&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:Move`(Point`):%- [_^DDARasterizer^ DDARasterizer][@(0.0.255) `&]_[* M
ove]([_^Point^ Point]_[*@3 p])&]
[s2; Moves the starting point of the next line to [%-*@3 p]. This point
is also stored as path starting point so that it can be used
in Close method.&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:Line`(Point`):%- [_^DDARasterizer^ DDARasterizer][@(0.0.255) `&]_[* L
ine]([_^Point^ Point]_[*@3 p])&]
[s2; If rasterizer is in line drawing mode, draws line from starting
point to [%-*@3 p]. [%-*@3 p] becomes a new starting point. Final
point of line is not drawn. Line thickness can be affected by
Width method. If rasterizer is in polygin drawing mode (started
by Polygon), adds the line to polygon path instead.&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:Close`(`):%- [_^DDARasterizer^ DDARasterizer][@(0.0.255) `&]_[* Close
]()&]
[s2; Draws line from starting point to the path starting point defined
by Move.&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:Polygon`(`):%- [_^DDARasterizer^ DDARasterizer][@(0.0.255) `&]_[* Pol
ygon]()&]
[s2; Starts a polygon mode.&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:Fill`(`):%- [_^DDARasterizer^ DDARasterizer][@(0.0.255) `&]_[* Fill](
)&]
[s2; Finishes polygon and fills it.&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:Ellipse`(const Rect`&`):%- [_^DDARasterizer^ DDARasterizer][@(0.0.255) `&
]_[* Ellipse]([@(0.0.255) const]_[_^Rect^ Rect][@(0.0.255) `&]_[*@3 rect])&]
[s2; Renders ellipse as serie of Move/Line commands.&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:Width`(int`):%- [_^DDARasterizer^ DDARasterizer][@(0.0.255) `&]_[* Wi
dth]([@(0.0.255) int]_[*@3 width`_])&]
[s2; [%-*@3 width`_] .&]
[s3; &]
[s4; &]
[s5;:DDARasterizer`:`:Cy`(int`):%- [@(0.0.255) void]_[* Cy]([@(0.0.255) int]_[*@3 cy])&]
[s2; Sets the total height of painting area. Rasterizer only emits
PutHorz/PutVert with y >`= 0 and y < [%-*@3 cy].&]
[s0; ]]

View file

@ -18,7 +18,6 @@ rectangular area. References to Displays are used in many widgets
as attributes affecting the rendering of widget Values. Default
implementation uses StdDisplay to perform all actions (see below
for StdDisplay description).&]
[s3; &]
[s0; &]
[s0; [* Visual style constants ]are used as `"style`" parameter bit
flags of rendering methods and provide additional information
@ -296,4 +295,4 @@ border.]
::^ [s0;:DrawingDisplay: [* DrawingDisplay]]
::= [s0; Displays Drawing scaled to fit the rectangle.]}}&]
[s3; &]
[s0; ]
[s0; ]]

View file

@ -98,9 +98,27 @@ void MirrorVert(Image& img, const Rect& rect);
String PackImlData(const Vector<Image>& image);
Image DownSample3x(const Image& src);
/*
struct IconDraw : ImagePainter {
IconDraw(Size sz) : ImagePainter(sz, MODE_NOAA) {}
};
*/
struct IconDraw : NilDraw, DDARasterizer {
RGBA docolor;
ImageBuffer image;
virtual void PutHorz(int x, int y, int cx);
virtual void PutVert(int x, int y, int cy);
virtual void DrawRectOp(int x, int y, int cx, int cy, Color color);
virtual void DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color);
virtual void DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor);
operator Image() { return image; }
IconDraw(Size sz) { image.Create(sz); Cy(sz.cy); }
};
class IconDes : public Ctrl {
public:

View file

@ -9,6 +9,7 @@ uses
file
IconDes.h,
IconDes.key,
IconDraw.cpp,
AlphaCtrl.cpp,
RGBACtrl.cpp,
ImageOp.cpp optimize_speed,

View file

@ -0,0 +1,64 @@
#include "IconDes.h"
NAMESPACE_UPP
void IconDraw::PutHorz(int x, int y, int cx)
{
if(y < 0 || y >= image.GetHeight())
return;
int r = minmax(x + cx, 0, image.GetWidth());
x = minmax(x, 0, image.GetWidth());
cx = r - x;
if(cx <= 0)
return;
Upp::Fill(image[y] + x, docolor, cx);
}
void IconDraw::PutVert(int x, int y, int cy)
{
if(x < 0 || x >= image.GetWidth())
return;
int b = minmax(y + cy, 0, image.GetHeight());
y = minmax(y, 0, image.GetHeight());
cy = b - y;
RGBA *t = image[y] + x;
while(cy-- > 0) {
*t = docolor;
t += image.GetWidth();
}
}
void IconDraw::DrawRectOp(int x, int y, int cx, int cy, Color color)
{
docolor = color;
int b = minmax(y + cy, 0, image.GetHeight());
y = minmax(y, 0, image.GetHeight());
cy = b - y;
while(cy-- > 0)
PutHorz(x, y++, cx);
}
void IconDraw::DrawLineOp(int x1, int y1, int x2, int y2, int width, Color color)
{
docolor = color;
Width(width);
Move(Point(x1, y1));
Line(Point(x2, y2));
}
void IconDraw::DrawEllipseOp(const Rect& r, Color color, int pen, Color pencolor)
{
if(!IsNull(color)) {
docolor = color;
Polygon().Ellipse(r).Fill();
}
if(!IsNull(pen) && !IsNull(pencolor)) {
docolor = pencolor;
if(pen == 1)
Ellipse(r);
else
Polygon().Ellipse(r).Ellipse(r.Deflated(pen - 1)).Fill();
}
}
END_UPP_NAMESPACE

View file

@ -566,7 +566,7 @@ void MainConfigDlg::FlagDlg()
cfg.accepts.Set(i, CC_NAME, accepts[i]);
cfg.accepts.Set(i, CC_PACKAGES, Join(pkg, ","));
}
cfg.other.SetFilter(FlagFilterM);
cfg.dll <<= cfg.gui <<= cfg.mt <<= cfg.sse2 <<= 0;
String other;