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
;
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
{
57 public enum LineJoin
{
65 public enum InnerJoin
{
79 public struct AGGParams
{
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
~`; }`;
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
);
137 // ////////////////////////////////////////////////////////////////////////// //
139 vertical gradient interface:
140 GxColor colorAtY (int y);
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 {
157 GxColor c
= vg
.colorAtY(y
);
161 public template AGGIsGoodGradient(SG
) {
162 enum AGGIsGoodGradient
=
163 is(typeof((inout int=0) nothrow @safe @nogc {
167 vg
.colorSpanAtXY(x
, y
, carr
[]);
172 public template AGGIsGoodSpanGen(SG
) {
173 enum AGGIsGoodSpanGen
= (AGGIsGoodSingleColor
!SG || AGGIsGoodVerticalGradient
!SG || AGGIsGoodGradient
!SG
);
179 public struct AGGVGradient3
{
182 GxColor
[3] clr
; // 0 is transparent color, what a coincidence!
184 nothrow @trusted @nogc:
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
) {
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; }
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;
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
);
238 public struct AGGHGradient
{
241 GxColor
[2] clr
; // 0 is transparent color, what a coincidence!
243 nothrow @trusted @nogc:
245 this (in int x0
, in GxColor c0
, in int x1
, in GxColor c1
) {
246 pragma(inline
, true);
250 void set (in int x0
, in GxColor c0
, in int x1
, in GxColor c1
) {
264 void colorSpanAtXY (int x
, int y
, GxColor
[] cout
) {
266 foreach (ref GxColor c
; cout
) {
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
);