1 module creator.widgets.shadow;
2 import bindbc.imgui;
3 import std.stdio : writeln;
4 
5 /**
6     Creates drawlist
7 */
8 ImDrawList* incCreateWindowDrawList() {
9     return ImDrawList_ImDrawList(igGetDrawListSharedData());
10 }
11 
12 /**
13     destroys drawlist
14 */
15 void incDestroyWindowDrawList(ImDrawList* drawList) {
16     ImDrawList_destroy(drawList);
17 }
18 
19 private {
20     T* prepend(T)(ref ImVector!T vec, ref ImVector!T other) {
21         import core.stdc.string : memcpy;
22         if (other.Size == 0) return &vec.Data[vec.Size];
23 
24         // First reserve space to make sure the data will fit.
25         // NOTE: We need to *reserve* space, not resize
26         // If we used resize, vec.Size would be wrong and we would
27         // Get garbage data likely to crash the app.
28         int newSize = vec.Size+other.Size;
29         if (newSize > vec.Capacity) vec.reserve(vec._grow_capacity(newSize));
30 
31         memcpy(vec.Data+other.Size,     vec.Data,   vec.Size*T.sizeof);
32         memcpy(vec.Data,                other.Data, other.Size*T.sizeof);
33 
34         // Apply the new size based on the previous sizes.
35         vec.Size = newSize;
36         return &vec.Data[vec.Size];
37     }
38 
39     void prepend(ImDrawList* self, ImDrawList* other) {
40 
41         // Offset draw buffer
42         ImDrawCmd* cmd = &self.CmdBuffer.Data[0];
43         cmd.VtxOffset += other.VtxBuffer.size;
44         cmd.IdxOffset += other.IdxBuffer.size;
45 
46         // Copy state from origin
47         ImDrawCmd* ocmd = &other.CmdBuffer.Data[0];
48         ocmd.TextureId = cmd.TextureId;
49         ocmd.ClipRect = cmd.ClipRect;
50 
51         // Prepend
52         self.CmdBuffer.prepend(other.CmdBuffer);
53         self._VtxWritePtr = self.VtxBuffer.prepend(other.VtxBuffer);
54         self._IdxWritePtr = self.IdxBuffer.prepend(other.IdxBuffer);
55         self._VtxCurrentIdx = other.VtxBuffer.Size;
56         self._Path.prepend(other._Path);
57         self._TextureIdStack.prepend(other._TextureIdStack);
58         self._ClipRectStack.prepend(other._ClipRectStack);
59     }
60 }
61 
62 /**
63     Renders a shadow at the specified spot
64 */
65 void incRenderWindowShadow(ImDrawList* drawList, ImRect area, float falloff=16, float startShade=0.25) {
66     ImDrawList__ResetForNewFrame(drawList);
67     auto outDrawList = igGetWindowDrawList();
68     auto style = igGetStyle();
69 
70     float inset = style.WindowRounding;
71     uint iColor = igGetColorU32(ImVec4(0, 0, 0, startShade));
72     uint oColor = igGetColorU32(ImVec4(0, 0, 0, 0));
73 
74     ImVec2 shadowInnerMin = ImVec2(area.Min.x-inset, area.Min.y-inset);
75     ImVec2 shadowInnerMax = ImVec2(area.Max.x+inset, area.Max.y+inset);
76     ImVec2 realMin = ImVec2(shadowInnerMin.x+falloff, shadowInnerMin.y+falloff);
77     ImVec2 realMax = ImVec2(shadowInnerMax.x-falloff, shadowInnerMax.y-falloff);
78 
79     igPushClipRect(realMin, realMax, false);
80 
81         // CENTER
82         ImDrawList_AddRectFilled(
83             drawList,
84             shadowInnerMin,
85             shadowInnerMax,
86             iColor
87         );
88 
89         // CORNERS
90 
91         // LEFT TOP
92         // XX
93         // XO
94         ImDrawList_AddRectFilledMultiColor(
95             drawList,
96             ImVec2(realMax.x, realMax.y),
97             ImVec2(shadowInnerMax.x, shadowInnerMax.y),
98             oColor,
99             oColor,
100             iColor,
101             oColor,
102         );
103 
104         // RIGHT TOP
105         // XX
106         // OX
107         ImDrawList_AddRectFilledMultiColor(
108             drawList,
109             ImVec2(realMin.x, realMax.y),
110             ImVec2(shadowInnerMin.x, shadowInnerMax.y),
111             oColor,
112             oColor,
113             iColor,
114             oColor,
115         );
116 
117         // LEFT BOTTOM
118         // XO
119         // XX
120         ImDrawList_AddRectFilledMultiColor(
121             drawList,
122             ImVec2(realMax.x, realMin.y),
123             ImVec2(shadowInnerMax.x, shadowInnerMin.y),
124             oColor,
125             oColor,
126             iColor,
127             oColor,
128         );
129 
130         // RIGHT BOTTOM
131         // OX
132         // XX
133         ImDrawList_AddRectFilledMultiColor(
134             drawList,
135             ImVec2(realMin.x, realMin.y),
136             ImVec2(shadowInnerMin.x, shadowInnerMin.y),
137             oColor,
138             oColor,
139             iColor,
140             oColor,
141         );
142 
143 
144         // CAPS
145 
146         // LEFT
147         // XO
148         // XO
149         ImDrawList_AddRectFilledMultiColor(
150             drawList,
151             ImVec2(realMax.x, shadowInnerMin.y),
152             ImVec2(shadowInnerMax.x, shadowInnerMax.y),
153             oColor,
154             iColor,
155             iColor,
156             oColor,
157         );
158 
159         // RIGHT
160         // OX
161         // OX
162         ImDrawList_AddRectFilledMultiColor(
163             drawList,
164             ImVec2(shadowInnerMin.x, shadowInnerMin.y),
165             ImVec2(realMin.x, shadowInnerMax.y),
166             iColor,
167             oColor,
168             oColor,
169             iColor,
170         );
171 
172         // TOP
173         // XX
174         // OO
175         ImDrawList_AddRectFilledMultiColor(
176             drawList,
177             ImVec2(shadowInnerMin.x, realMax.y),
178             ImVec2(shadowInnerMax.x, shadowInnerMax.y),
179             oColor,
180             oColor,
181             iColor,
182             iColor,
183         );
184 
185         // BOTTOM
186         // OO
187         // XX
188         ImDrawList_AddRectFilledMultiColor(
189             drawList,
190             ImVec2(shadowInnerMin.x, shadowInnerMin.y),
191             ImVec2(shadowInnerMax.x, realMin.y),
192             iColor,
193             iColor,
194             oColor,
195             oColor,
196         );
197 
198     igPopClipRect();
199 
200     outDrawList.prepend(drawList);
201 }