1 /**
2 * PBR widget: clickable logo.
3 * Copyright: Copyright Auburn Sounds 2015 and later.
4 * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
5 * Authors:   Guillaume Piolat
6 */
7 module dplug.pbrwidgets.logo;
8 
9 import std.math;
10 import dplug.gui.element;
11 import dplug.core.math;
12 
13 class UILogo : UIElement
14 {
15 public:
16 nothrow:
17 @nogc:
18 
19     /// Change this to point to your website
20     string targetURL = "http://example.com";
21     float animationTimeConstant = 30.0f;
22     ubyte defaultEmissive = 0; // emissive where the logo isn't
23 
24     // these are offset on top of defaultEmissive
25     ubyte emissiveOn = 40;
26     ubyte emissiveOff = 0;
27 
28     /// Note: once called, the logo now own the diffuse image, and will destroy it.
29     this(UIContext context, OwnedImage!RGBA diffuseImage)
30     {
31         super(context);
32         _diffuseImage = diffuseImage;
33         _animation = 0;
34     }
35 
36     ~this()
37     {
38         _diffuseImage.destroyNoGC();
39     }
40 
41     override void onAnimate(double dt, double time) nothrow @nogc
42     {
43         float target = ( isDragged() || isMouseOver() ) ? 1 : 0;
44 
45         float newAnimation = lerp(_animation, target, 1.0 - exp(-dt * animationTimeConstant));
46 
47         if (abs(newAnimation - _animation) > 0.001f)
48         {
49             _animation = newAnimation;
50             setDirtyWhole();
51         }
52     }
53 
54     override void onDraw(ImageRef!RGBA diffuseMap, ImageRef!L16 depthMap, ImageRef!RGBA materialMap, box2i[] dirtyRects) nothrow @nogc
55     {
56         foreach(dirtyRect; dirtyRects)
57         {
58             auto croppedDiffuseIn = _diffuseImage.crop(dirtyRect);
59             auto croppedDiffuseOut = diffuseMap.crop(dirtyRect);
60 
61             int w = dirtyRect.width;
62             int h = dirtyRect.height;
63 
64             ubyte emissive = cast(ubyte)(0.5f + lerp!float(emissiveOff, emissiveOn, _animation));
65 
66             for(int j = 0; j < h; ++j)
67             {
68                 RGBA[] input = croppedDiffuseIn.scanline(j);
69                 RGBA[] output = croppedDiffuseOut.scanline(j);
70 
71                 for(int i = 0; i < w; ++i)
72                 {
73                     ubyte alpha = input[i].a;
74                     RGBA color = RGBA.op!q{.blend(a, b, c)}(input[i], output[i], alpha);
75 
76                     // emissive has to be multiplied by alpha, and added to the default background emissive
77                     color.a = cast(ubyte)( (128 + defaultEmissive * 256 + (emissive * color.a) ) >> 8);
78                     output[i] = color;
79                 }
80             }
81         }
82     }
83 
84     override bool onMouseClick(int x, int y, int button, bool isDoubleClick, MouseState mstate)
85     {
86         browseNoGC(targetURL);
87         return true;
88     }
89 
90 private:
91     float _animation;
92     OwnedImage!RGBA _diffuseImage;
93 }