Demo: integrated a reworked demo from @bdero (TODO: default parent window size missing)

https://gist.github.com/bdero/987a959c33b0d9dc8ab04bc5aeecb50c
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt
index 234daec..f145d51 100644
--- a/docs/CHANGELOG.txt
+++ b/docs/CHANGELOG.txt
@@ -1660,6 +1660,9 @@
 - Style: Changed default style.WindowRounding value to 0.0f (matches default for multi-viewports).
 - Style: Reduced the size of the resizing grip, made alpha less prominent.
 - Style: Classic: Increase the default alpha value of WindowBg to be closer to other styles.
+- Demo: Added a fancy "particle text" demo in Examples->Custom Rendering. [@bdero]
+  Originally done as a 1024 bytes source, as part of the "ImDrawList coding party" challenge:
+    https://github.com/ocornut/imgui/issues/3606
 - Demo: Clarify usage of right-aligned items in Demo>Layout>Widgets Width.
 - Backends: OpenGL3: Use glGetString(GL_VERSION) query instead of glGetIntegerv(GL_MAJOR_VERSION, ...)
   when the later returns zero (e.g. Desktop GL 2.x). (#3530) [@xndcn]
diff --git a/imgui_demo.cpp b/imgui_demo.cpp
index 431cd4c..7a0c3c4 100644
--- a/imgui_demo.cpp
+++ b/imgui_demo.cpp
@@ -7593,6 +7593,79 @@
 // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
 //-----------------------------------------------------------------------------
 
+// Mini "Particle Text" demo by Brandon DeRosier
+// Originally done as a 1024 bytes source, as part of the "ImDrawList coding party" challenge:
+// - https://github.com/ocornut/imgui/issues/3606#issuecomment-734636054
+// - https://twitter.com/algebrandon/status/1332182010593304576
+// This is a fun thing to inspire people to see the potential of using ImDrawList for custom drawing.
+// However, the very dense coding-style is not something to be inspired of :) don't do this at home!
+static void ShowFxParticleText(ImDrawList* draw_list, ImVec2 p0, ImVec2 p1, float time)
+{
+    // The base diameter (and distance apart) all of the circles should be on the grid.
+    // The actual diameter is inflated a bit from this value so that the circles smoosh together.
+    const float diameter = 11.0f;
+    const float scale = (p1.x - p0.x) / 400.0f;
+
+    // This packed array contains a 17x13 grid (221-bit) spelling the word "DEAR IMGUI". Last 3 bits are unused (hence the -3 in the loop below).
+    const unsigned int GRID[] = { 0xD9000080, 0x750A2B18, 0xDC2A2A17, 0x0200025D, 0x5AB1E800, 0x26EAB555, 0x01800100 };
+
+    // Storage for a rotating circle (we use the index for sorting and for computing the color)
+    struct GridCircle { float x, y, z; int index; };
+    GridCircle circles[221];
+
+    // Helper functions
+    struct f
+    {
+        // This is a S-curve function `1/(1+e^-t)`, but with a range of 0 to 2 PI
+        // because this demo happens to only use it for computing rotations.
+        // See also: https://en.wikipedia.org/wiki/Sigmoid_function
+        static float Sigmoid(float T)                       { return 1.f / (1 + expf(-(T))) * 3.141592f * 2.0f; }
+
+        // This is a Sine function with an exponentially decaying magnitude `sin(t)`.
+        // The intended domain is 0 to ~5, and the range is -1 to 1.
+        static float Bounce(float T)                        { return sinf((T) * 3.0f) * expf(-(T)); }
+
+        // 2D rotation formula. This demo uses Euler angles, and so this formula is used
+        // three times (once for each basis axis) when computing the position of each circle.
+        // See also: https://en.wikipedia.org/wiki/Rotation_matrix
+        static void  Rotate(float& u, float& v, float r)    { float U = u; u = cosf(r) * u - sinf(r) * v; v = sinf(r) * U + cosf(r) * v; }
+
+        // Sorting function so that circles with higher Z values (which are further away from the camera) are given lower order
+        static int IMGUI_CDECL GridCircleCompareByZ(const void* a, const void* b) { return (((const GridCircle*)b)->z - ((const GridCircle*)a)->z > 0.0f) ? 1 : -1; }
+    };
+
+    // For each circle in the grid: rotate, calculate z and calculate x
+    const float loop_time = fmodf(time, 6.0f) * 10.0f;
+    for (int n = 3; n < 224; n++)
+    {
+        int index = (n - 3);
+        float x = (float)(index % 17) * diameter - 9.0f * diameter;
+        float y = (float)(index / 17) * diameter - 6.0f * diameter;
+        float z = 0.0f;
+        float distance = sqrtf(x * x + y * y) / 32.0f;
+        f::Rotate(x, y, f::Sigmoid(loop_time - 20 - distance) + cosf(time / 2) / 4); // Rotate on Z axis
+        f::Rotate(y, z, f::Sigmoid(loop_time -  4 - distance) + cosf(time / 3) / 4); // Rotate on X axis
+        f::Rotate(x, z, f::Sigmoid(loop_time - 12 - distance) + cosf(time / 7) / 4); // Rotate on Y axis
+
+        z -= (loop_time - distance > 28) ? f::Bounce((loop_time - 28 - distance) / 2) * 50 : 0;
+        z = (GRID[n / 32] & (1 << (n % 32))) ? z / 100.f + 1.f : 0.0f;
+
+        circles[index].x = p0.x + (p1.x - p0.x) * 0.5f + scale * x / z;
+        circles[index].y = p0.y + (p1.y - p0.y) * 0.5f + scale * y / z;
+        circles[index].z = z;
+        circles[index].index = index;
+    }
+
+    // Sort back-to-front, then draw
+    qsort(&circles[0], 221, sizeof(GridCircle), f::GridCircleCompareByZ);
+    for (GridCircle& c : circles)
+        if (c.z != 0.0f)
+        {
+            ImU32 col = IM_COL32(c.index > 102 ? 0 : 255, c.index < 102 ? 0 : 255, IM_CLAMP((int)(765 - c.z * 637), 0, 255), 255);
+            draw_list->AddCircleFilled(ImVec2(c.x, c.y), (diameter * 0.8f / c.z) * scale, col);
+        }
+}
+
 // Demonstrate using the low-level ImDrawList to draw custom shapes.
 static void ShowExampleAppCustomRendering(bool* p_open)
 {
@@ -7610,6 +7683,26 @@
 
     if (ImGui::BeginTabBar("##TabBar"))
     {
+        if (ImGui::BeginTabItem("Fancy demo"))
+        {
+            // Mini "Particle Text" demo by Brandon DeRosier
+            // See ShowFxParticleText() for details!
+            static float time = 0.0f;
+            time = ImGui::IsWindowAppearing() ? 0.0f : time + ImGui::GetIO().DeltaTime;
+            float w = ImGui::GetContentRegionAvail().x;
+            float h = (float)(int)(w / 1.777f);
+            ImDrawList* draw_list = ImGui::GetWindowDrawList();
+            ImGui::InvisibleButton("canvas", ImVec2(w, h));
+            ImVec2 p0 = ImGui::GetItemRectMin();
+            ImVec2 p1 = ImGui::GetItemRectMax();
+            draw_list->PushClipRect(p0, p1, true);
+            draw_list->AddRectFilled(p0, p1, IM_COL32(0, 0, 0, 100));
+            ShowFxParticleText(draw_list, p0, p1, time);
+            draw_list->AddRect(p0, p1, IM_COL32(100, 100, 100, 100));
+            draw_list->PopClipRect();
+            ImGui::EndTabItem();
+        }
+
         if (ImGui::BeginTabItem("Primitives"))
         {
             ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);