Skip to content

Instantly share code, notes, and snippets.

@bdero
Created November 27, 2020 11:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bdero/987a959c33b0d9dc8ab04bc5aeecb50c to your computer and use it in GitHub Desktop.
Save bdero/987a959c33b0d9dc8ab04bc5aeecb50c to your computer and use it in GitHub Desktop.
ImGui Particle Text demo
/*
* ImGui Particle Text (deobfuscated)
* ==================================
* Done as part of the "ImDrawList coding party" challenge:
* https://github.com/ocornut/imgui/issues/3606#issuecomment-734636054
* https://twitter.com/algebrandon/status/1332182010593304576
*/
#include <algorithm>
// 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
#define Rotate(u, v, r) \
{ \
float U = u; \
u = cos(r) * u - sin(r) * v; \
v = sin(r) * U + cos(r) * v; \
}
// This is a common S-curve function `1/(1+e^-t)`, but with a range of 0 to 2PI
// because this demo happens to only use it for computing rotations.
// See also: https://en.wikipedia.org/wiki/Sigmoid_function
#define Sigmoid(T) 1.f / (1 + exp(-(T))) * IM_PI * 2
// This is a just a Sine function with an exponentially decaying magnitude `sin(t)`.
// The intended domain is 0 to ~5, and the range is -1 to 1.
#define Bounce(T) sin((T) *3) * exp(-(T))
// 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 int DIAMETER = 11;
// This `unsigned int` array contains a 17x13 grid of circles (221 bits). Note that
// 7 32 bit numbers can store 224 bits, and so the least significant 3 bits of the
// first `int` are just ignored over when sampling the grid.
//
unsigned grid[] = {0xD9000080, 0x750A2B18, 0xDC2A2A17, 0x0200025D, 0x5AB1E800, 0x26EAB555, 0x01800100};
struct GridCircle {
float x, y, z;
// When the circles array is sorted by depth, the circle's position in the
// grid can no longer be determined by just looking at the index, and so the
// index is preserved in this field.
// The index is then later used when computing the color.
int gridIndex;
// Overload the < operator so that circles with higher Z values (which are
// further away from the camera) are given lower order when calling
// `std::sort`.
bool operator<(GridCircle &o) { return z > o.z; }
};
void FX(ImDrawList *drawList, ImVec2 windowPosition, ImVec2 b, ImVec2 windowSize, ImVec4 m, float time) {
float loopTime = fmod(time, 6) * 10;
GridCircle circles[221];
for (int n = 3; n < 224; n++) {
int gridIndex = n - 3;
float x = gridIndex % 17 * DIAMETER - 8.5f * DIAMETER;
float y = gridIndex / 17 * DIAMETER - 6.5f * DIAMETER;
float z = 0;
float distance = sqrt(x * x + y * y) / 32;
float rotationX = Sigmoid(loopTime - 4 - distance) + cos(time / 3) / 4;
float rotationY = Sigmoid(loopTime - 12 - distance) + cos(time / 7) / 4;
float rotationZ = Sigmoid(loopTime - 20 - distance) + cos(time / 2) / 4;
Rotate(x, y, rotationZ);// Z axis
Rotate(y, z, rotationX);// X axis
Rotate(x, z, rotationY);// Y axis
z -= loopTime - distance > 28 ? Bounce((loopTime - 28 - distance) / 2) * 50 : 0;
z = grid[n / 32] & 1 << n % 32 ? z / 100 + 1 : 0;
circles[gridIndex] = {windowPosition.x + windowSize.x * .5f + x / z,
windowPosition.y + windowSize.y * .5f + y / z, z, gridIndex};
}
std::sort(circles, &circles[221]);
for (int i = 0; i < 221; i++) {
if (circles[i].z != 0) {
drawList->AddCircleFilled(ImVec2(circles[i].x, circles[i].y), DIAMETER * .8 / circles[i].z,
ImColor(circles[i].gridIndex > 102 ? 0.f : 1.f,
circles[i].gridIndex < 102 ? 0.f : 1.f, 3.f - circles[i].z * 2.5f, 1.f));
}
}
}
@bdero
Copy link
Author

bdero commented Nov 29, 2020

test6

@ocornut
Copy link

ocornut commented Dec 24, 2020

Reworked (WIP) as ocornut/imgui@196b220

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment