egra: prepare agg mini before calling `onPaint()` (and cleanup afterwards)
[iv.d.git] / egra / gfx / aggmini / enums.d
blob35a3dbcc003c090d615fac29d3faac488172ab9b
1 /*
2 * Simple Framebuffer Gfx/GUI lib
4 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
5 * Understanding is not required. Only obedience.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 3 of the License ONLY.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 module iv.egra.gfx.aggmini.enums;
20 private:
21 nothrow @safe @nogc:
23 private import iv.egra.gfx.lowlevel : gxInterpolateColorI;
24 private import iv.egra.gfx.base : GxColor, gxTransparent, gxUnknown;
27 /* Bezier curve rasterizer.
29 * De Casteljau Bezier rasterizer is faster, but currently rasterizing curves with cusps sligtly wrong.
30 * It doesn't really matter in practice.
32 * AFD tesselator is somewhat slower, but does cusps better.
34 * McSeem rasterizer should have the best quality, bit it is the slowest method. Basically, you will
35 * never notice any visial difference. But it can render something... ahem... sensible with very low
36 * recursion levels (as low as 1), while standard De Casteljau produces garbage if its built-in
37 * "flatness limit" is not reached. so McSeem tesselator is the default here.
38 * On Baphomet test It is slower than De Casteljau by about 100 *micro*seconds. I'm ok with that.
40 public enum AGGTesselation {
41 DeCasteljauMcSeem, // standard well-known tesselation algorithm, with improvements from Maxim Shemanarev; slowest one, but should give best results
42 DeCasteljau, // standard well-known tesselation algorithm
43 AFD, // adaptive forward differencing (experimental)
46 public enum FillRule {
47 NonZero,
48 EvenOdd,
51 public enum LineCap {
52 Butt,
53 Square,
54 Round,
57 public enum LineJoin {
58 Miter,
59 MiterRevert,
60 Round,
61 Bevel,
62 MiterRound,
65 public enum InnerJoin {
66 Bevel,
67 Miter,
68 Jag,
69 Round,
72 public enum Winding {
73 CW,
74 CCW,
78 // drawer params
79 public struct AGGParams {
80 private:
81 float mWidth = 1.5f;
82 float mMiterLimit = 4.0f;
83 float mInnerMiterLimit = 1.01f;
84 float mApproxScale = 1.0f;
85 float mShorten = 0.0f;
86 LineCap mLineCap = LineCap.Butt;
87 LineJoin mLineJoin = LineJoin.Miter;
88 InnerJoin mInnerJoin = InnerJoin.Miter;
89 FillRule mFillRule = FillRule.NonZero;
90 bool mChanged = false;
92 enum PropMixin(string pname, string fldname) =
93 `@property void `~pname~` (in typeof(`~fldname~`) v) { pragma(inline, true); mChanged = (mChanged || `~fldname~` != v); `~fldname~` = v; }
94 @property typeof(`~fldname~`) `~pname~` () const pure { pragma(inline, true); return `~fldname~`; }`;
96 nothrow @safe @nogc:
97 public:
98 this() (in auto ref AGGParams other) { pragma(inline, true); opAssign(other); mChanged = true; }
100 void opAssign() (in auto ref AGGParams other) @trusted {
101 if (&other is &this) return;
102 foreach (string mname; __traits(allMembers, typeof(this))) {
103 static if (mname != "mChanged" && mname.length > 3 && mname[0] == 'm' && mname[1] >= 'A' && mname[1] <= 'Z') {
104 //pragma(msg, mname);
105 mixin("if ("~mname~" != other."~mname~") { mChanged = true; "~mname~" = other."~mname~"; }");
110 @property bool isDirty () const pure { pragma(inline, true); return mChanged; }
111 void setDirty () { pragma(inline, true); mChanged = true; }
112 void resetDirty () { pragma(inline, true); mChanged = false; }
114 mixin(PropMixin!("lineCap", "mLineCap"));
115 mixin(PropMixin!("lineJoin", "mLineJoin"));
116 mixin(PropMixin!("innerJoin", "mInnerJoin"));
117 mixin(PropMixin!("fillRule", "mFillRule"));
119 mixin(PropMixin!("width", "mWidth"));
120 mixin(PropMixin!("miterLimit", "mMiterLimit"));
121 mixin(PropMixin!("innerMiterLimit", "mInnerMiterLimit"));
123 mixin(PropMixin!("approximationScale", "mApproxScale"));
125 mixin(PropMixin!("shorten", "mShorten"));
127 @property void miterLimitTheta (in float t) {
128 pragma(inline, true);
129 import core.stdc.math : sinf;
130 immutable float v = 1.0f/sinf(t*0.5f);
131 mChanged = (mChanged || mMiterLimit != v);
132 mMiterLimit = v;
137 // ////////////////////////////////////////////////////////////////////////// //
139 vertical gradient interface:
140 GxColor colorAtY (int y);
142 graident interface:
143 // should fill all `cout`
144 // `cout` is never of zero length
145 void colorSpanAtXY (int x, int y, GxColor[] cout);
148 public template AGGIsGoodSingleColor(SG) {
149 enum AGGIsGoodSingleColor = (__traits(isIntegral, SG) && SG.sizeof == 4);
152 public template AGGIsGoodVerticalGradient(SG) {
153 enum AGGIsGoodVerticalGradient =
154 is(typeof((inout int=0) nothrow @safe @nogc {
155 SG vg = void;
156 int y;
157 GxColor c = vg.colorAtY(y);
158 }));
161 public template AGGIsGoodGradient(SG) {
162 enum AGGIsGoodGradient =
163 is(typeof((inout int=0) nothrow @safe @nogc {
164 SG vg = void;
165 int x, y;
166 GxColor[2] carr;
167 vg.colorSpanAtXY(x, y, carr[]);
168 }));
172 public template AGGIsGoodSpanGen(SG) {
173 enum AGGIsGoodSpanGen = (AGGIsGoodSingleColor!SG || AGGIsGoodVerticalGradient!SG || AGGIsGoodGradient!SG);
177 // 2 or 3 colors
178 // 2 if clr[2] is 0
179 public struct AGGVGradient3 {
180 private:
181 int[3] yp;
182 GxColor[3] clr; // 0 is transparent color, what a coincidence!
184 nothrow @trusted @nogc:
185 public:
186 this (in int y0, in GxColor c0, in int y1, in GxColor c1, in int midpercent=-1, in GxColor midc=gxTransparent) {
187 pragma(inline, true);
188 set(y0, c0, y1, c1, midpercent, midc);
191 int getY (int idx) const pure { return (idx >= 0 && idx < yp.length ? yp[idx] : -666); }
192 GxColor getColor (int idx) const pure { return (idx >= 0 && idx < clr.length ? clr[idx] : gxUnknown); }
194 void set (in int y0, in GxColor c0, in int y1, in GxColor c1, in int midpercent=-1, in GxColor midc=gxTransparent) {
195 if (y0 < y1) {
196 yp.ptr[0] = y0;
197 clr.ptr[0] = c0;
198 yp.ptr[1] = y1;
199 clr.ptr[1] = c1;
200 } else {
201 yp.ptr[0] = y1;
202 clr.ptr[0] = c1;
203 yp.ptr[1] = y0;
204 clr.ptr[1] = c0;
206 // no third point yet (i.e. max)
207 yp.ptr[2] = yp.ptr[1];
208 clr.ptr[2] = clr.ptr[1];
209 // check for valid midpoint
210 if (midpercent < 0 || midpercent > 100) return;
211 // check for min or max midpoint
212 if (midpercent == 0) { clr.ptr[0] = midc; return; }
213 if (midpercent == 100) { clr.ptr[1] = clr.ptr[2] = midc; return; }
214 // add midpoint
215 yp.ptr[2] = yp.ptr[1];
216 clr.ptr[2] = clr.ptr[1];
217 yp.ptr[1] = yp.ptr[0]+(yp.ptr[1]-yp.ptr[0])*midpercent/100;
218 clr.ptr[1] = midc;
221 GxColor colorAtY (int y) const pure {
222 if (y <= yp.ptr[0]) return clr.ptr[0];
223 if (y < yp.ptr[1] && yp.ptr[0] != yp.ptr[1]) {
224 // scale to [0..65535]
225 immutable int t = ((y-yp.ptr[0])<<16)/(yp.ptr[1]-yp.ptr[0]);
226 return gxInterpolateColorI(clr.ptr[0], clr.ptr[1], t);
228 if (clr.ptr[1] != clr.ptr[2] && y < yp.ptr[2] && yp.ptr[1] != yp.ptr[2]) {
229 // scale to [0..65535]
230 immutable int t = ((y-yp.ptr[1])<<16)/(yp.ptr[2]-yp.ptr[1]);
231 return gxInterpolateColorI(clr.ptr[1], clr.ptr[2], t);
233 return clr.ptr[2];
238 public struct AGGHGradient {
239 private:
240 int[2] xp;
241 GxColor[2] clr; // 0 is transparent color, what a coincidence!
243 nothrow @trusted @nogc:
244 public:
245 this (in int x0, in GxColor c0, in int x1, in GxColor c1) {
246 pragma(inline, true);
247 set(x0, c0, x1, c1);
250 void set (in int x0, in GxColor c0, in int x1, in GxColor c1) {
251 if (x0 < x1) {
252 xp.ptr[0] = x0;
253 clr.ptr[0] = c0;
254 xp.ptr[1] = x1;
255 clr.ptr[1] = c1;
256 } else {
257 xp.ptr[0] = x1;
258 clr.ptr[0] = c1;
259 xp.ptr[1] = x0;
260 clr.ptr[1] = c0;
264 void colorSpanAtXY (int x, int y, GxColor[] cout) {
265 --x;
266 foreach (ref GxColor c; cout) {
267 ++x;
268 if (x <= xp.ptr[0]) { c = clr.ptr[0]; continue; }
269 if (x >= xp.ptr[1]) { c = clr.ptr[1]; continue; }
270 // scale to [0..65535]
271 immutable int t = ((x-xp.ptr[0])<<16)/(xp.ptr[1]-xp.ptr[0]);
272 c = gxInterpolateColorI(clr.ptr[0], clr.ptr[1], t);