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