imgui icon indicating copy to clipboard operation
imgui copied to clipboard

ImDrawList coding party - deadline Nov 30, 2020!

Open ocornut opened this issue 4 years ago • 82 comments

ImDrawList coding party!

  • create small visual effects
  • 1024 bytes of source code
  • 320x180 output
  • only use dear imgui's crappy low-level shape drawing api

Two days ago I thought: "It'd be fun to organize a contest for writing special effects using the ImDrawList api, with a constraint on source code size. May be fun to see what people can come up with using shape/vector-based api (quite different from a pixel-shading function). Would you participate?"

It's by no mean a great api but it has served many well, to draw custom widgets etc, let's get it some extra love..

Here's a testbed imdrawlist_party.cpp which you can paste in your application or any dear imgui example: https://gist.github.com/ocornut/51367cc7dfd2c41d607bb0acfa6caf66

Rules:

  • Your source file fx.inl must be <= 1024 bytes.
  • Effect should be reasonably portable (not relying on specific render backend callback)
  • OK to use preprocessor define or other tricks as long as they are reasonably portable.
  • Included are: math.h, imgui.h, imgui_internal.h with ImVec2 maths operators
  • The effect should not use ImGui:: functions, only use ImDrawList facilities.
  • Canvas ratio is expected to be 16/9, canvas size expected to be 320 by 180.
  • For simplicity we assume you can encode a color as 0xAAGGBBRR instead of using the IM_COL32() macro, therefore IMGUI_USE_BGRA_PACKED_COLOR config option is not supported!

Prizes:

  • This is mostly for fun so please feel free to make multiple submissions or tweak them as you feel. No pressure. Mostly, I'm supposed to work and ship tables this or next week so hey why I am doing this?!
  • We could possibly include some of them in imgui_demo if they strike a good balance of cool and educational. If we end up doing that we'll rework code to be neat and proper for a demo (aka not densely packed into 1024 characters).

Function signature:

void FX(ImDrawList* d, ImVec2 a, ImVec2 b, ImVec2 sz, ImVec4 mouse, float t);
     d : draw list
     a : upper-left corner
     b : lower-right corner
    sz : size (== b - a)
 mouse : x,y = mouse position (normalized so 0,0 over 'a'; 1,1 is over 'b', not clamped)
         z,w = left/right button held. <-1.0f not pressed, 0.0f just pressed, >0.0f time held.
    t  : time

If not using a given parameter, you can omit its name in your function to save a few characters.

To record gif files you can use ShareX https://getsharex.com or ScreenToGif https://www.screentogif.com/

Let's get started! You can post on this thread, on discord or on twitter!

Known issues

  • ImDrawList polygon stroking with thick lines looks broken on acute angle, good luck!!

ocornut avatar Nov 19 '20 21:11 ocornut

Here are some examples I made to get you started:

Circles

#define V2 ImVec2
void FX(ImDrawList* d, V2 a, V2 b, V2 sz, ImVec4 mouse, float t)
{
    for (int n = 0; n < (1.0f + sinf(t * 5.7f)) * 40.0f; n++)
        d->AddCircle(V2(a.x + sz.x * 0.5f, a.y + sz.y * 0.5f), sz.y * (0.01f + n * 0.03f), 
            IM_COL32(255, 140 - n * 4, n * 3, 255));
}

drawlist fx 03

Squares

#define V2 ImVec2
void FX(ImDrawList* d, V2 a, V2 b, V2 sz, ImVec4, float t)
{
    float sx = 1.f / 16.f;
    float sy = 1.f / 9.f;
    for (float ty = 0.0f; ty < 1.0f; ty += sy)
        for (float tx = 0.0f; tx < 1.0f; tx += sx)
        {
            V2 c((tx + 0.5f * sx), (ty + 0.5f * sy));
            float k = 0.45f;
            d->AddRectFilled(
                V2(a.x + (c.x - k * sx) * sz.x, a.y + (c.y - k * sy) * sz.y),
                V2(a.x + (c.x + k * sx) * sz.x, a.y + (c.y + k * sy) * sz.y),
                IM_COL32(ty * 200, tx * 255, 100, 255));
        }
}

unknown

Curves

#define V2 ImVec2
void FX(ImDrawList* d, V2 a, V2 b, V2 sz, ImVec4, float t0)
{
    for (float t = t0; t < t0 + 1.0f; t += 1.0f / 100.0f)
    {
        V2 cp0(a.x, b.y);
        V2 cp1(b);
        float ts = t - t0;
        cp0.x += (0.4f + sin(t) * 0.3f) * sz.x;
        cp0.y -= (0.5f + cos(ts * ts) * 0.4f) * sz.y;
        cp1.x -= (0.4f + cos(t) * 0.4f) * sz.x;
        cp1.y -= (0.5f + sin(ts * t) * 0.3f) * sz.y;
        d->AddBezierCurve(V2(a.x, b.y), cp0, cp1, b, IM_COL32(100 + ts*150, 255 - ts*150, 60, ts * 200), 5.0f);
    }
}

drawlist fx 04b

Waves

#define V2 ImVec2
#define ARFM d->AddRectFilledMultiColor
#define ACF d->AddCircleFilled
#define CH s.SetCurrentChannel
void FX(ImDrawList* d, V2 a, V2 b, V2 sz, ImVec4, float t)
{
    ARFM(a, b, 0xFF1E1E1E, 0xFF1E281E, 0xFF1E1E5A, 0xFF321E78);
    ARFM(a, V2(b.x, a.y + sz.y*0.4f), 0x1EFFDCFF, 0x14FFFFDC, 0x001E1E5A, 0x00321E78);
    auto s = d->_Splitter;
    s.Split(d, 2);
    for (int n = 0; n < 256; n++)
    {
        V2 c(a.x + n / 256.f * sz.x, b.y + 20 - cos(t - 0.1f * n / 2) * 10 + cos(t) * 5);
        float r(40 + sin(t + n / 2) * 40);
        CH(d, 0);
        ACF(c, r + 1, 0x80FFFFFF);
        CH(d, 1);
        ACF(c, r, IM_COL32(255, n / 2, n / 8, 255));
    }
    s.Merge(d);
    d->AddRect(a, b, IM_COL32(128, 128, 128, 100));
}

drawlist fx 02

ocornut avatar Nov 19 '20 21:11 ocornut

Thunder Storm

#define min(x,y) ((x)<(y)?x:y)
#define wh(a) ImColor(1.f,1.f,1.f,a)
void FX(ImDrawList* d, ImVec2 a, ImVec2 b, ImVec2 sz, ImVec2, float t)
{
    static float fl;
    if ((rand() % 500) == 0) fl = t;
    if ((t-fl) > 0)
    {
        auto ft = 0.25f;
        d->AddRectFilled(a, b, wh((ft - (t - fl)) / ft));
    }

    for (int i = 0; i < 2000; ++i) {
        unsigned h = ImGui::GetID(d+i + int(t/4));
        auto f = fmodf(t + fmodf(h / 777.f, 99), 99);
        auto tx = h % (int)sz.x;
        auto ty = h % (int)sz.y;
        if (f < 1) {
            auto py = ty - 1000 * (1 - f);
            d->AddLine({ a.x + tx, a.y + py }, { a.x + tx, a.y + min(py + 10,ty) }, (ImU32)-1);
        }
        else if (f < 1.2f)
            d->AddCircle({ a.x + tx, a.y + ty }, (f - 1) * 10 + h % 5, wh(1-(f-1)*5.f));
    }
}

imgui_storm

kudaba avatar Nov 19 '20 22:11 kudaba

The Matrix effect, slowly been shaving off spaces and making the code uglier and uglier

//v1.1
#define V2 ImVec2
void FX(ImDrawList*d,V2 a,V2,V2 sz,ImVec4,float t)
{
  static struct{int y,h,c; float t,s;} m[40]={0};
  static int S=0x1234;
  static float t0=t;
  float ZI=t*.07f,Z=ZI+1.f;
  for(int x=0;x<40;x++)
  {
    auto& M=m[x];
    int i=x>=15&&x<25;
    if(M.s==0.f||M.y>16)
    {
      M.h = (t<7.f||i)*((int)(2+t*.5f) + S%(int)(6+(t*0.3f)));
      M.y = (M.s==0.f)*-(S%15)-M.h;
      M.c += S;
      M.s = (5+(S%14))*(.01f-t*.001f);
      if(t>5.f&&i)
      {
        M.c = (340003872375972UL>>(x*5-75))&31;
        M.h = i?(x!=19):0;
      }
    }
    if((M.t-=t-t0)<0.f)
    {
      if(t<6.f||!i||M.y!=6)
        M.y++;
      M.t += M.s;
    }
    char c=64|M.c%42;
    for(int j=0; j<M.h; j++,c=64|(c^M.c+M.h^j)%42)
      for(int f=(j+1==M.h)?13:4+(M.c&1);f--;)
        d->AddText(0, 13*(i?Z:-Z), V2(a.x-(sz.x*.5f*ZI)+x*8*Z+sin(j+t*f), a.y-(sz.y*.5f*ZI)+(M.y+j)*13*Z+cos(x*f-t)), 0x3c68bb5b, &c, &c+1);
    S|=((S&1)^((S&8)>>2))<<16;
    S>>=1;
  }
  t0 = t;
}

fx matrix 2

ocornut avatar Nov 19 '20 22:11 ocornut

Tiny Loading Screen!

Had a bunch of fun trying to get this as small I could, managed to get it just under 600 bytes for now.

b0bapW4Ez9

#define V ImVec2
#define R d->AddRectFilled
#define C(x) IM_COL32((sin(x) + 1) * 255 / 2, (cos(x) + 1) * 255 / 2, 99, 255)
#include <set>
void FX(ImDrawList* d, V a, V b, V s, ImVec4, float t) {
  static auto z = 0.f;
  if (t > z + 2) z += 2;
  auto c = C(z + 2);
  R(a, b, C(z));
  for (auto B = b.x, i = 0.f, o = s.y / 8; i < 8; ++i, B = b.x) {
    if (auto w = (i / 7) * .2f, x = std::max(t - z - w, 0.f); t - z < w + 1)
      B = a.x + (x < .5 ? 8 * x * x * x * x : std::min(1 - pow(-2 * x + 2, 4.f) / 2, 1.f)) * s.x;
    R(V(a.x, a.y + o * i), V(B, a.y + o * i + o), c);
  }
}

Fuzznip avatar Nov 19 '20 22:11 Fuzznip

Quicksort visualization.

#define V2 ImVec2
#include <vector>
#include <array>
using namespace std;
int N = 64, S, J;
#define V vector<int>
V v = [] {
	V r;
	for (; J < N; J++) r.push_back(rand() % 180);
	return r;
}();
vector<array<int,4>> st { { 0, N-1, 0, 0} };
#define A st.back()[0]
#define B st.back()[1]
#define I st.back()[2]
void FX(ImDrawList* d,V2 a,V2 b,V2 s,ImVec4,float t)
{
	float bs = s.x / N, y, c;
	for (int i = 0; i < N; i++) {
		y=a.y+v[i];
		c=70+v[i];
		d->AddRectFilled(V2(a.x+bs*i,y),V2(a.x+bs*(i+1),b.y),IM_COL32(c,255-c,255,255));
	}
	d->AddText(a, -1u, "Quicksort");
	if (st.empty()) return;
	d->AddRect(V2(a.x+bs*A,a.y),V2(a.x+bs*(B+1),b.y),0xFF00FF00,8,ImDrawCornerFlags_Top,2);
	switch (S) {
	case 0:case 5: if(A>=B)st.pop_back(),S+=3;else I=J=A,S++;break;
	case 1:case 6:
		if(v[J]>v[B])swap(v[I],v[J]),I++;
		if(++J>B)swap(v[I],v[B]),S++;
		break;
	case 2:case 7:st.push_back({A,I-1,A,3});S=0;break;
	case 3:st.push_back({I+1,B,A,8});S=5;break;
	case 8:S = st.back()[3]; st.pop_back();
	}
}

sort Blobs.

#define V2 ImVec2
void FX (ImDrawList* d, V2 a, V2 b, V2 s, ImVec4 m, float t)
{
	int N = 25;
	float sp = s.y / N, y, st = sin(t) * 0.5 + 0.5,
	      r[3] = { 1500, 1087 + 200 * st, 1650 },
	      ctr[3][2] = { { 150, 140 }, { s.x * m.x, s.y * m.y },
		      { 40 + 200 * st, 73 + 20*sin(st * 5) } };
	for (int i = 0; i < N; i++) {
		y = a.y + sp*(i+.5);
		for (int x = a.x; x <= b.x; x += 2) {
			float D = 0, o = 255;
			for (int k = 0; k < 3; k++)
				D += r[k]/(pow(x-a.x-ctr[k][0], 2) + pow(y-a.y-ctr[k][1], 2));
			if (D < 1) continue;
			if (D>2.5) D = 2.5;
			if (D < 1.15) o /= 2;
			d->AddLine(V2(x, y), V2(x+2, y), IM_COL32(239, 129, 19, o), D + sin(2.3 * t + 0.3 * i));
		}
	}
}

o 3D cube.

#define V2 ImVec2
void FX (ImDrawList* d, V2 a, V2 b, V2 s, ImVec4 m, float t)
{
	a.x += s.x/2, a.y += s.y / 2;
	float S = sin(m.x), C = cos(m.x), x = 50, y, z = (m.y * 2 - 1) * x;
	float v[8][3] { { x, x, z+x }, { x, -x, z+x }, { -x, -x, z+x }, { -x, x, z+x },
			{ x, x, z-x }, { x, -x, z-x }, { -x, -x, z-x }, { -x, x, z-x } };
	for (int i = 0; i < 8; i++) {
		x = v[i][0] * C - v[i][1] * S;
		y = v[i][0] * S + v[i][1] * C + 120;
		z = v[i][2];
		v[i][0] = x / y * 50;
		v[i][1] = z / y * 50;
		v[i][2] = y;
	}
#define L(A,B) z = 500 / (v[A][2] + v[B][2]); \
	d->AddLine(V2(a.x+v[A][0],a.y+v[A][1]),V2(a.x+v[B][0],a.y+v[B][1]),-1u,z);
	L(0, 1) L(1, 2) L(2, 3) L(0, 3)
	L(4, 5) L(5, 6) L(6, 7) L(4, 7)
	L(0, 4) L(1, 5) L(2, 6) L(3, 7)
}

cubes Real-time visualization of the interweb blogosphere.

#define V2 ImVec2
#include <vector>
int N = 300;
auto v = [] {
	std::vector<std::pair<V2,V2>>r(N);
	for (auto&p:r)
		p.second = p.first = V2(rand() % 320, rand() % 180);
	return r;
}();
float l2 (V2 x) { return x.x*x.x + x.y*x.y; }
void FX(ImDrawList* d,V2 a,V2 b,V2 s,ImVec4,float t)
{
	float D, T;
	for (auto&p:v) {
		D = sqrt(l2(p.first - p.second));
		if (D > 0) p.first += (p.second - p.first) / D;
		if (D < 4) p.second = V2(rand() % 320, rand() % 180);
	}
	for (int i = 0; i < N; i++) {
		for (int j = i+1; j < N; j++) {
			D = l2(v[i].first - v[j].first);
			T = l2((v[i].first + v[j].first) - s) / 200;
			if (T > 255) T = 255;
			if (D < 400) d->AddLine(a+v[i].first, a+v[j].first, IM_COL32(T, 255-T, 255, 70), 2);
		}
	}
}

interwebs

sugrob9000 avatar Nov 19 '20 23:11 sugrob9000

Here's my attempt at some abstract fireworks... with about four bytes to spare. The code has ended up pretty unreadable as a result, sadly.

#define V ImVec2
#define R rand()
#define I int
#define F float
#define S ((F)R/32767)
#define T(d,b,e)p[j].d=(b*(j&1^j>>1?1:-1))+(e*((j>1)?1:-1))+c.d+a.d;
#define X(a)I a=128+(R&127);
struct P {F x,y,vx,vy,a;I l,s,f,d;};P p[8192]={0};
void A(V o, I f){P t;t.x=o.x;t.y=o.y;t.vx=S*3-1.5;t.vy=S*2.5-(f?4:1);t.l=R%(f?50:99);t.s=R;t.f=f;for(I j=0;j<9;j++){t.d=j;t.a=1-(F)j/9;for(I i=0;i<8192;i++)if(!p[i].l){p[i]=t;break;}}}
void FX(ImDrawList*d,V a,V b,V sz,V mn,F t0){I g=R;for(I i=200;i;--i)d->AddLine(V(a.x,a.y+i),V(b.x,a.y+i),IM_COL32(0,0,i,255));I e=0;for(I i=0;i<8192;i++){P&c=p[i];if(c.l){if(c.d)c.d--;else{srand(c.s);c.x+=c.vx;c.y+=c.vy;c.vy+=.04;c.l-=(c.vy>0)?1:0;F s=(S*3+.1)*(c.f+1);F n=(t0*(c.l<0?0:1))+(i*S*2.5-1.5);F sa=sin(n)*s;F ca=cos(n)*s;V p[4];for(I j=0;j<4;j++){T(x,sa,ca);T(y,ca,-sa);}X(r)X(g)X(b)d->AddConvexPolyFilled(p,c.f?4:3,IM_COL32(r,g,b,(c.f?255:c.l)*c.a));if(!c.l&&c.f&&c.a==1){I l=R%40+15;for(I j=0;j<l;j++)A(V(c.x,c.y),0);}}if(c.f)e++;}}
srand(g);if(e<512)A(V(S*420-50,200),1);}

Fireworks

ShironekoBen avatar Nov 20 '20 02:11 ShironekoBen

Old school plasma.

ImDrawList_Party_Plasma

#define V2 ImVec2
#define S sinf
#define C cosf
#define I int
#define F float
#define CL(x,l,h) (((x)>(h))?(h):(((x)<(l))?(l):(x)))
#define PI 3.1415926535
#define CO(c,b) (int(c*255)<<b)
void FX(ImDrawList* d, V2 a, V2 b, V2 s, ImVec4 m, float t)
{
    t*=3;
    F ix=s.x/320;
    F iy=s.y/180;
    F sz=s.x / 15;
    for (F x=a.x;x<b.x;x+=ix)
        for (F y=a.y;y<b.y;y+=iy){
            F v=0;
            v+=S((x/sz+t));
            v+=S((y/sz+t)/2.0f);
            v+=S((x/sz+y/sz+t)/2.0f);
            F cx=x/sz/10+0.3*S(t/3.0);
            F cy=y/sz/10+0.3f*C(t/2.0);
            v+=S(sqrt(100*(cx*cx+cy*cy+1))+t);
            v=CL(v/2, 0, 1);
            F r=S(v*PI)*.5f+.5f;
            F g=S(v*PI+PI/3)*.5f+.5f;
            F b=S(v*PI+PI)*.5f+.5f;
            d->AddQuadFilled({x,y},{x+ix,y},{x+ix,y+iy},{x,y+iy},0xff000000|CO(b,16)|CO(g,8)|CO(r,0));
        }
}

heretique avatar Nov 20 '20 12:11 heretique

Guitar for strumming. ~~Unfortunately, requires that ImGuiWindowFlags_NoMove be set for the window in the testbed to work correctly.~~ Using InvisibleButton instead of Dummy also works.

#define V2 ImVec2
#define C1 0xA7A830FF
#define C2 0x775839FF
float amp[6], ml;
int pk;
void FX(ImDrawList* d, V2 a, V2 b, V2 s, ImVec4 m, float t)
{
	if (m.z > -1)
		pk |= 2;
	m.y *= s.y; m.x *= s.x;
	m.y += a.y; m.x += a.x;
	float st = sin(10*t), th, y, w;
	d->AddRectFilledMultiColor(V2(a.x, a.y+40), V2(b.x, b.y-40), C1, C1, C2, C2);
	for (float i = a.x + 10, j = 20; i < b.x; i += (j += 10))
		d->AddRectFilled(V2(i, a.y+38), V2(i + 8, b.y-38), 0xFF888888, 8);
	for (int i = 0; i < 6; i++) {
		y = a.y + 48 + i * 16.6; th = 4-i*.5f; w = 1;
		int N = 10;
		for (int j = 0; j < N; j++) {
			float x = a.x + j * s.x / N, k = (w *= -1) * amp[i] * st;
			d->AddBezierCurve(V2(x,y+k),V2(x+10,y+k),V2(x+s.x/N-10,y-k),V2(x+s.x/N,y-k),-1u,th);
		}
		amp[i] *= 0.9;
		if (pk == 3) {
			float A=ml, B=m.y;
			if((A<=y&&B>y)||(A>=y&&B<y))amp[i]+=A-B;
		}
	}
	ml = m.y;
	if (pk >>= 1) d->AddTriangleFilled(V2(m.x, m.y), V2(m.x-15, m.y-15), V2(m.x+10, m.y-25), 0xFF0000FF);
}

guitar

sugrob9000 avatar Nov 20 '20 15:11 sugrob9000

Complementary colors I guess? I have to optimize the hell out of it to get it under 1K, the code looks so ugly now :'( But it's quite fun!

#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define fract(x) (abs(x-floor(x)))
#define rand(x,se) (fract(sin(x)*se))
#define eps 1e-3
#define V2 ImVec2
#define C 10000.0f
float mix(float a,float b,float v) {return a+(b-a)*v;}float ss(float a,float b,float v) {return mix(a,b,3.0f*v*v-2.0f*v*v*v);}float perlin(float v,float se) {v=v*0.7f+eps;float f=floor(v);float s=fract(v);float a=rand(f,se);float b=rand(f+1.0f,se);return ss(a,b,s);}float perlin_d(float v,float se) {v *= 2.0f;float f=floor(v);float s=fract(v);float a=rand(f,se);float b=rand(f+1.0f,se);return ss(a,b,s);}void FX(ImDrawList* d,ImVec2 a,ImVec2 b,ImVec2 sz,ImVec4 mouse,float t) {t *= 0.3f;float sa[]={255.0f,0.0f};float sb[]={125.0f,130.0f};float sc[]={0.0f,255.0f};for(int i=0;i<2;i++) {for(int x=0;x<sz.x;x++) {float p=0.5f+rand(1.0f,(C-sa[i]));float bt=perlin(x/sz.x+t*p,C-sa[i])*sz.y;float tp=perlin(x/sz.x+t*p,C-sb[i])*sz.y;float h=tp-bt;d->AddRectFilled(V2(a.x+x,a.y+bt),V2(a.x+x+1,a.y+bt+h),IM_COL32(sa[i],sb[i],sc[i],200));}}}

result

42yeah avatar Nov 20 '20 16:11 42yeah

Unfortunately, requires that ImGuiWindowFlags_NoMove be set for the window in the testbed to work correctly.

I updated the test bed today (to 0.22) to use InvisibleButton() instead of Dummy() for the canvas, so it catches inputs.

Beautiful submissions everyone!

ocornut avatar Nov 20 '20 16:11 ocornut

Snake Game (781 bytes)

#define v2 ImVec2
#define px(v,c) d->AddRectFilled(a+v*2,a+v*2+v2(2,2),c);
#define fr(v,x) for(int v=0;v<x;++v)
#define eq(l,r) l.x==r.x&l.y==r.y
#define kd(k) ImGui::IsKeyDown(ImGui::GetKeyIndex(k))
v2 sn[160*90]={{20,20}};
int ln=0,tg=4;
float lf;
v2 dr(1,0);
v2 fd(99,45);
void FX(ImDrawList* d, v2 a, v2 b, v2 sz, v2, float t)
{
	if (t-lf>0.033f){
		lf=t;
		if (ln<tg){ln++;sn[ln]=sn[ln-1];}
		else fr(x,ln)sn[x]=sn[x+1];
		sn[ln]+=dr;
		bool e=sn[ln].x<0|sn[ln].x>159|sn[ln].y<0|sn[ln].y>89;
		fr(x,ln-1)e|=eq(sn[x],sn[ln]);
		if(e)ln=0,tg=4,sn[0]={20,20};
		if(eq(sn[ln],fd))tg+=4,fd={rand()%150+5.f,rand()%80+5.f};
		if(kd(1))dr={-1,0};
		if(kd(2))dr={1,0};
		if(kd(3))dr={0,-1};
		if(kd(4))dr={0,1};
	}

	fr(x,ln+1)px(sn[x],-1);
	px(fd,-256);
}

imgui_snake

kudaba avatar Nov 20 '20 18:11 kudaba

Mosaic. It wasn't what I was trying to do, but ended up in a neat place.

#define v2 ImVec2
#define wh(a) ImColor(1.f,1.f,1.f,a)
#define px(v,c) d->AddRectFilled(a+v*2,a+v*2+v2(2,2),c);
#define fr(v,x) for(int v=0;v<x;++v)
#define frc(x) ((x)-int(x))
#define hash(x) (srand(x),ImLerp(rand()/32767.f,rand()/32767.f,0.5f))
#define noise(x) ImLerp(hash(x),hash(x+1),frc(x))
void FX(ImDrawList* d, v2 a, v2 b, v2 sz, v2 mm, float t)
{
	fr(x,160)fr(y,90){
		auto rx=x-80;
		auto ry=y-45;
		auto an=ImAtan2(rx,ry);an=an<0?M_PI*2+an:an;
		auto len=(rx*rx+ry*ry+0.1f)+t*4;
		auto n0 = noise(an);
		auto n1 = noise(len);
		auto al= n0+n1;
		px(v2(x,y),wh(al));
	}
}

imgui_noise

kudaba avatar Nov 20 '20 20:11 kudaba

Hershey vectorial font! 3.8 KiB. I have not stripped the ASCII chars in the font to make the code fit under 1KiB, bc I wanted to make something useful as well. Sorry for breaking the rules! :D

void Hershey(ImDrawList* d, ImVec2 pos, ImVec2 sca, ImVec2 old, char *s) {
 static const char *fnt[] = {
 "AQ","IKFVFH@@FCEBFAGBFC","FQEVEO@@MVMO","LVLZE:@@RZK:@@EMSM@@DGRG","[UIZI=@@MZ"
 "M=@@RSPUMVIVFUDSDQEOFNHMNKPJQIRGRDPBMAIAFBDD","`YVVDA@@IVKTKRJPHOFODQDSEUGVIVK"
 "UNTQTTUVV@@RHPGOEOCQASAUBVDVFTHRH","c[XMXNWOVOUNTLRGPDNBLAHAFBECDEDGEIFJMNNOOQ"
 "OSNULVJUISIQJNLKQDSBUAWAXBXC","HKFTEUFVGUGSFQEP","KOLZJXHUFQELEHFCH?J<L:","KOD"
 "ZFXHUJQKLKHJCH?F<D:","IQIVIJ@@DSNM@@NSDM","F[NSNA@@EJWJ","IKGBFAEBFCGBG@F>E=",\
 "C[EJWJ","FKFCEBFAGBFC","CWUZC:","RUJVGUERDMDJEEGBJALAOBQERJRMQROULVJV","EUGRIS"
 "LVLA","OUEQERFTGUIVMVOUPTQRQPPNNKDARA","PUFVQVKNNNPMQLRIRGQDOBLAIAFBECDE","GUN"
 "VDHSH@@NVNA","RUPVFVEMFNIOLOONQLRIRGQDOBLAIAFBECDE","XUQSPUMVKVHUFREMEHFDHBKAL"
 "AOBQDRGRHQKOMLNKNHMFKEH","FURVHA@@DVRV","^UIVFUESEQFOHNLMOLQJRHREQCPBMAIAFBECD"
 "EDHEJGLJMNNPOQQQSPUMVIV","XUQOPLNJKIJIGJELDODPESGUJVKVNUPSQOQJPENBKAIAFBED","L"
 "KFOENFMGNFO@@FCEBFAGBFC","OKFOENFMGNFO@@GBFAEBFCGBG@F>E=","DYUSEJUA","F[EMWM@@"
 "EGWG","DYESUJEA","USDQDRETFUHVLVNUOTPRPPONNMJKJH@@JCIBJAKBJC","x\\SNRPPQMQKPJO"
 "ILIIJGLFOFQGRI@@MQKOJLJIKGLF@@SQRIRGTFVFXHYKYMXPWRUTSUPVMVJUHTFREPDMDJEGFEHCJB"
 "MAPASBUCVD@@TQSISGTF","ISJVBA@@JVRA@@EHOH","XVEVEA@@EVNVQURTSRSPRNQMNL@@ELNLQK"
 "RJSHSERCQBNAEA","SVSQRSPUNVJVHUFSEQDNDIEFFDHBJANAPBRDSF","PVEVEA@@EVLVOUQSRQSN"
 "SIRFQDOBLAEA","LTEVEA@@EVRV@@ELML@@EARA","ISEVEA@@EVRV@@ELML","WVSQRSPUNVJVHUF"
 "SEQDNDIEFFDHBJANAPBRDSFSI@@NISI","IWEVEA@@SVSA@@ELSL","CIEVEA","KQMVMFLCKBIAGA"
 "EBDCCFCH","IVEVEA@@SVEH@@JMSA","FREVEA@@EAQA","LYEVEA@@EVMA@@UVMA@@UVUA","IWEV"
 "EA@@EVSA@@SVSA","VWJVHUFSEQDNDIEFFDHBJANAPBRDSFTITNSQRSPUNVJV","NVEVEA@@EVNVQU"
 "RTSRSORMQLNKEK","YWJVHUFSEQDNDIEFFDHBJANAPBRDSFTITNSQRSPUNVJV@@MES?","QVEVEA@@"
 "EVNVQURTSRSPRNQMNLEL@@LLSA","UURSPUMVIVFUDSDQEOFNHMNKPJQIRGRDPBMAIAFBDD","FQIV"
 "IA@@BVPV","KWEVEGFDHBKAMAPBRDSGSV","FSBVJA@@RVJA","LYCVHA@@MVHA@@MVRA@@WVRA",""
 "FUDVRA@@RVDA","GSBVJLJA@@RVJL","IURVDA@@DVRV@@DARA","LOEZE:@@FZF:@@EZLZ@@E:L:",
 "COAVO>","LOJZJ:@@KZK:@@DZKZ@@D:K:","KQGPISKP@@DMIRNM@@IRIA","CQA?Q?","HKGVFUES"
 "EQFPGQFR","RTPOPA@@PLNNLOIOGNELDIDGEDGBIALANBPD","RTEVEA@@ELGNIOLONNPLQIQGPDNB"
 "LAIAGBED","OSPLNNLOIOGNELDIDGEDGBIALANBPD","RTPVPA@@PLNNLOIOGNELDIDGEDGBIALANB"
 "PD","RSDIPIPKOMNNLOIOGNELDIDGEDGBIALANBPD","IMKVIVGUFRFA@@COJO","WTPOP?O<N;L:I"
 ":G;@@PLNNLOIOGNELDIDGEDGBIALANBPD","KTEVEA@@EKHNJOMOONPKPA","IIDVEUFVEWDV@@EOE"
 "A","LKFVGUHVGWFV@@GOG>F;D:B:","IREVEA@@OOEE@@IIPA","CIEVEA","S_EOEA@@EKHNJOMOO"
 "NPKPA@@PKSNUOXOZN[K[A","KTEOEA@@EKHNJOMOONPKPA","RTIOGNELDIDGEDGBIALANBPDQGQIP"
 "LNNLOIO","RTEOE:@@ELGNIOLONNPLQIQGPDNBLAIAGBED","RTPOP:@@PLNNLOIOGNELDIDGEDGBI"
 "ALANBPD","INEOEA@@EIFLHNJOMO","RROLNNKOHOENDLEJGILHNGOEODNBKAHAEBDD","IMFVFEGB"
 "IAKA@@COJO","KTEOEEFBHAKAMBPE@@POPA","FQCOIA@@OOIA","LWDOHA@@LOHA@@LOPA@@TOPA",
 "FRDOOA@@OODA","JQCOIA@@OOIAG=E;C:B:","IROODA@@DOOO@@DAOA","hOJZHYGXFVFTGRHQIOI"
 "MGK@@HYGWGUHSIRJPJNILEJIHJFJDIBHAG?G=H;@@GIIGIEHCGBF@F>G<H;J:","CIEZE:","hOFZH"
 "YIXJVJTIRHQGOGMIK@@HYIWIUHSGRFPFNGLKJGHFFFDGBHAI?I=H;@@IIGGGEHCIBJ@J>I<H;F:",""
 "XYDGDIELGMIMKLOIQHSHUIVK@@DIEKGLILKKOHQGSGUHVKVM" };
 for( char c, *glyph; (c = *s++, glyph = (char*)fnt[c - 32], c > 0 && c < 127); ) {
  if( c != '\n' && c != '\r' ) {
   if( c > 32 ) for( int pen = 0, i = 0; i < (glyph[0] - 65); i++ ) {
    int x = glyph[2 + i*2 + 0] - 65, y = glyph[2 + i*2 + 1] - 65;
    if( x == -1 && y == -1 ) pen = 0; else {
     ImVec2 next = ImVec2(pos.x+sca.x*x, pos.y-sca.y*y);
     if( !pen ) pen = 1; else d->AddLine(old, next, 0.9*(ImU32)-1);
     old = next;
    }
   }
   pos.x += sca.x * (glyph[1] - 65);
  }
 }
}
void FX(ImDrawList* d, ImVec2 a, ImVec2 b, ImVec2 sz, ImVec4 mouse, float t) {
 ImVec2 pos(a.x,((a+b)/2).y), sca(1,sin(t*5)+1+0.5f);
 char str[128]; sprintf(str, "Hello imgui! %5.2fs", t);
 Hershey(d, pos, sca, ImVec2(), str);
}

GIF 11-20-2020 10-58-19 PM

r-lyeh avatar Nov 20 '20 22:11 r-lyeh

Ugly Doom Fire doomfire

#define V2 ImVec2
#define W 64
#define H 48
#define S 0x07
#define T 0x1F
#define U 0x0F
#define I int
#define F float
I w=0,P[]={S,S,S,T,S,S,0x2F,U,S,0x47,U,S,0x57,0x17,S,0x67,T,S,0x77,T,S,0x8F,0x27,S,0x9F,0x2F,S,0xAF,0x3F,S,0xBF,0x47,S,0xC7,0x47,S,0xDF,0x4F,S,0xDF,0x57,S,0xDF,0x57,S,0xD7,0x5F,S,0xD7,0x5F,S,0xD7,0x67,U,0xCF,0x6F,U,0xCF,0x77,U,0xCF,0x7F,U,0xCF,0x87,0x17,0xC7,0x87,0x17,0xC7,0x8F,0x17,0xC7,0x97,T,0xBF,0x9F,T,0xBF,0x9F,T,0xFF,0xFF,0xFF};
char i[W*H];
void FX(ImDrawList *d,V2 a,V2 b,V2 sz,ImVec4,F t){if(!w){memset(i,0,W*H);memset(i+(H-1)*W,27,W);w=1;}for(I x=0;x<W;x++){for(I y=1;y<H;y++){I j=y*W+x,p=i[j];if(!p)i[j-W]=0;else{I r=I(3.f*rand()/RAND_MAX),d=j-r+1;i[d-W]=p-(r&1);}}};I j=0;F sx=1.f/W,sy=1.f/H,k=0.45f,ty=0;for(I y=0;y<H;y++,ty+=sy){F tx=0;for(I x=0;x<W;x++,tx+=sx){V2 c((tx+.5f*sx),(ty+.5f*sy));I *z=P+i[j++]*3;d->AddRectFilled(V2(a.x+(c.x-k*sx)*sz.x,a.y+(c.y-k*sy)*sz.y),V2(a.x+(c.x+k*sx)*sz.x,a.y+(c.y+k*sy)*sz.y),IM_COL32(z[0],z[1],z[2],255));}}}

scemino avatar Nov 20 '20 22:11 scemino

This one (The Business Card Raytracer from Paul Heckbert) is too big 1 510 bytes 😢 but still fun aek

#define V2 ImVec2
#define op operator
#define rt return
typedef int i;typedef float f;struct v{f x,y,z;v op+(v r){rt v(x+r.x,y+r.y,z+r.z);}v op*(f r){rt v(x*r,y*r,z*r);}f op%(v r){rt x*r.x+y*r.y+z*r.z;}v(){}v op^(v r){rt v(y*r.z-z*r.y,z*r.x-x*r.z,x*r.y-y*r.x);}v(f a,f b,f c){x=a;y=b;z=c;}v op!(){rt*this*(1/sqrt(*this%*this));}};i G[]={247570,280596,280600,249748,18578,18577,231184,16,16};f R(){rt(f)rand()/RAND_MAX;}i T(v o,v d,f&t,v&n){t=1e9;i m=0;f p=-o.z/d.z;if(.01<p)t=p,n=v(0,0,1),m=1;for(i k=19;k--;)for(i j=9;j--;)if(G[j]&1<<k){v p=o+v(-k,0,-j-4);f b=p%d,c=p%p-1,q=b*b-c;if(q>0){f s=-b-sqrt(q);if(s<t&&s>.01)t=s,n=!(p+d*t),m=2;}}rt m;}v S(v o,v d){f t;v n;i m=T(o,d,t,n);if(!m)rt v(.7,.6,1)*pow(1-d.z,4);v h=o+d*t,l=!(v(9+R(),9+R(),16)+h*-1),r=d+n*(n%d*-2);f b=l%n;if(b<0||T(h,l,t,n))b=0;f p=pow(l%r*(b>0),99);if(m&1){h=h*.2;rt((i)(ceil(h.x)+ceil(h.y))&1?v(3,1,1):v(3,3,3))*(b*.2+.1);}rt v(p,p,p)+S(h,r)*.5;}
v img[512*512];i y=512;void FX(ImDrawList*d,V2 z,V2,V2 sz,ImVec4,f){v g=!v(-6,-16,0),a=!(v(0,0,1)^g)*.002,b=!(g^a)*.002,c=(a+b)*-256+g;f sx=1.f/512.f;f sy=1.f/512.f;if(y){y--;for(i x=512;x--;){v p(13,13,13);for(i r=64;r--;){v t=a*(R()-.5)*99+b*(R()-.5)*99;p=S(v(17,16,8)+t,!(t*-1+(a*(R()+x)+b*(y+R())+c)*16))*3.5+p;}img[y*512+x]=p;}}v*img2=img;f k=0.45f;for(f ty=1.0f;ty;ty-=sy)for(f tx=1.0f;tx;tx-=sx){V2 u((tx+0.5f*sx),(ty+0.5f*sy));v q=*img2++;d->AddRectFilled(V2(z.x+(u.x-k*sx)*sz.x,z.y+(u.y-k*sy)*sz.y),V2(z.x+(u.x+k*sx)*sz.x,z.y+(u.y+k*sy)*sz.y),IM_COL32((i)q.x,(i)q.y,(i)q.z,255));}}

scemino avatar Nov 21 '20 10:11 scemino

tribute to https://tixy.land/ 473 bytes ezgif com-gif-maker

#define V2 ImVec2
void FX(ImDrawList* d, V2 a, V2 b, V2 sz, ImVec4, float t)
{
   int i =0;
   for (int y = 0;y <= sz.y *0.2;y++)
   {
      for (int x = 0;x<=sz.x * 0.2;x++, i++)
      {
         //float v = cos(t * cos(i * 2)) * cos(i * cos(x * 2));
         float v = tan(t * cos(i * 2))* sin(i * cos(x * 2));
         v = ImClamp(v, -1.f, 1.f);
         d->AddCircleFilled(V2(x * 10 + a.x,y * 10 + a.x), 5 * fabsf(v), (v>0.f)?0xFFFFFFFF:0xFF0000FF, 12);
      }
   }
}

CedricGuillemet avatar Nov 21 '20 10:11 CedricGuillemet

Yet another entry because it's a lot of fun! I tried to emulate DOF with alpha and bigger disks. ezgif com-gif-maker (1)

800 bytes

#define V2 ImVec2
#define F float
F k;
int i{};
F r() { return F(rand() / 32768.f) * 2.f - 1.f; };
struct P {F x,y,z,a,b,c;void A(){x+=a*k;y+=b*k;z+=c*k;
F ng{0.008f};z-=5.f;F xp=x*cosf(ng)-z*sinf(ng);F zp=x*sinf(ng)+z*cosf(ng);
x=xp;z=zp+5.f;a-=x*k+r()*k;b-=y*k+r()*k;c-=(z-5.0f)*k+r()*k;}};
P p[64];
void FX(ImDrawList* d, V2 o, V2 b, V2 sz, ImVec4, F t)
{int j{};
if (!i) {i=1;for (P&a:p){a={r(),r(),r()+5.f,r(),r(),r() };}}
for (P&a:p){
if (a.z<0.001) continue;
V2 s((a.x/a.z)*sz.x*2.f+sz.x*0.5f+o.x,(a.y/a.z)*sz.y*2.f+sz.y*0.5f+o.y);
int x=(j++)%16;
k=cosf((j/64.f)*3.14592f)*0.002f+0.002f;
F dist=fabsf(a.z-5.f)/2.5f,sc=(10.f+dist*100.f)/a.z;
int tr=int(ImMin(dist*128.f,128.f)+127)<<24;
ImColor col=ImColor::HSV(k*9.f+0.06f,0.8f,1.f,1.f-sqrtf(dist));
d->AddCircleFilled(s,sc,col,12);a.A();
}}

CedricGuillemet avatar Nov 21 '20 11:11 CedricGuillemet

A Breakout/Arkanoid type of game implementation in 1014 bytes. (Control paddle with mouse, use right-click to reset)

ImDrawList_Party_Breakout

#define V2 ImVec2
#define I int
#define F float
#define B bool
#define T static
#define W 320
#define H 180
#define FR(i,m) for(I i=0;i<m;++i)
#define C 0xffffffff
struct B2{V2 l,h;B a=1;B in(V2 p){return(p.x>l.x&&p.x<h.x)&&(p.y>l.y&&p.y<h.y);}};
void FX(ImDrawList* d,V2 a,V2 b,V2 s,ImVec4 m,float t)
{T B re=1;T F cx,cy,r,vx,vy;T F lt=t;T F dt=0;T F bw=W/10;T F bh=H/12;T B2 br[60];T B2 p{{0,b.y-5},{0,b.y}};if(re){cx=a.x+W/2;cy=a.y+H-8;r=3;vx=-1;vy=-3;FR(i,6)FR(j,10){B2& b=br[j+i*10];b.a=1;b.l={a.x+j*bw,a.y+i*bh};b.h={a.x+(j+1)*bw,a.y+(i+1)*bh};}re=0;}FR(i,60){B2& b=br[i];if(!b.a)continue;if(!b.in({cx,cy}))continue;b.a=0;F ol=cx-b.l.x;F or=b.h.x-cx;F ot=cy-b.l.y;F ob=b.h.y-cy;F ox=min(ol,or);F oy=min(ot,ob);B lo=ol<ob;B to=ot<ob;ox<oy?vx=-vx:vy=-vy;}dt=t-lt;lt=t;p.l.x=a.x+m.x*s.x-20;p.h.x=p.l.x+40;if(p.in({cx,cy}))vy=-vy;FR(i,60){if(br[i].a)d->AddRect(br[i].l,br[i].h,C);}d->AddRect(p.l,p.h,C);d->AddCircle({cx,cy},r,C);cx+=vx*dt*30;cy+=vy*dt*30;if(cx<a.x||cx>b.x)vx=-vx;if(cy<a.y)vy=-vy;if (!m.w)re=1;}

Update: @ocornut 's suggestion on Twitter made we want to push it a little further and here it is in 1024 bytes with colors

ImDrawList_Party_Breakout2

using V=ImVec2;using I=int;using F=float;using B=bool;
#define T static
#define W 320
#define H 180
#define FR(i,m) for(I i=0;i<m;++i)
#define A d->AddRectFilled
struct B2{V l,h;B a=1;I c=~0;B in(V p){return(p.x>l.x&&p.x<h.x)&&(p.y>l.y&&p.y<h.y);}};
void FX(ImDrawList* d,V a,V b,V s,ImVec4 m,float t){T B re=1;T F cx,cy,r,vx,vy;T F lt=t;T F dt=0;T F bw=W/10;T F bh=H/12;T B2 br[60];T B2 p{{0,b.y-5},{0,b.y}};if(re){cx=a.x+W/2;cy=a.y+H-8;r=3;vx=-1;vy=-3;FR(i,6)FR(j,10){B2& b=br[j+i*10];b.a=1;b.l={a.x+j*bw,a.y+i*bh};b.h={a.x+(j+1)*bw,a.y+(i+1)*bh};b.c=255<<24|rand();}re=0;}FR(i,60){B2& b=br[i];if(!b.a)continue;if(!b.in({cx,cy}))continue;b.a=0;F ol=cx-b.l.x;F or=b.h.x-cx;F ot=cy-b.l.y;F ob=b.h.y-cy;F ox=min(ol,or);F oy=min(ot,ob);B lo=ol<ob;B to=ot<ob;ox<oy?vx=-vx:vy=-vy;}dt=t-lt;lt=t;p.l.x=a.x+m.x*s.x-20;p.h.x=p.l.x+40;if(p.in({cx,cy}))vy=-vy;FR(i,60){B2& b=br[i];if(b.a)A(b.l,b.h,b.c);}A(p.l,p.h,~0);d->AddCircleFilled({cx,cy},r,~0);cx+=vx*dt*30;cy+=vy*dt*30;if(cx<a.x||cx>b.x)vx=-vx;if(cy<a.y)vy=-vy;if (!m.w)re=1;}

heretique avatar Nov 21 '20 13:11 heretique

Came across this by accident. I think it looks quite cool.

imdrawlist-party-1

521 bytes

#define V ImVec2
#define CF d->AddCircleFilled
#define RAND(a) (float)rand()/(float)(RAND_MAX/a)
void FX(ImDrawList*d,V a,V b,V s,ImVec4 m,float t) {
 static bool o = true;
 static V bs[1000];
 if(o){
  o=false;
  for(int i=0;i<1000;++i){
   float g=RAND(IM_PI/2)+(IM_PI/4);
   float r=RAND(50)+5;
   bs[i]=V(g,r);
  }
 }
 for(int i=0;i<1000;++i){
  float
   g=bs[i].x,
   r=bs[i].y;
  r+=sin(t+i)*100;
  CF(V(r*cos(g),r*sin(g))+(s/2+a)+V(r*cos(t),0),i%2+1,IM_COL32(r+100,50,fabs(r)+100,200));
 }
}

PossiblyAShrub avatar Nov 21 '20 17:11 PossiblyAShrub

I did a poor man’s tetris I’d like top put some more features (~~like, detection for when the game is lost, for example~~ [mostly done]), but I’m at ~~1021~~ ~~994~~ 1024 bytes, so I can’t really add more

By the way, I also took the liberty to change from mouse_data.y = (io.MousePos.y - p1.y) / size.y; to mouse_data.y = (io.MousePos.y - p0.y) / size.y; in the gist, so that it corresponds to the specs on the OP

In case anyone wonders about the controls : the piece follows the mouse’s y coordinate, mouse left click rotates it, and right click accelerates it.

tetris disclaimer: colors were modified to squeeze some space for end-game detection

source code (1024 bytes)
#define F(a,b)for(I a=b;a--;)
#define S(a,b)s(c[a],c[b]);
#define I int
#define V ImVec2
#define L(w,z) d->AddLine(a+V(p,y)*8,a+V(p+w,y+z)*8,g-1^~0);
#define P(x,y) a+V(x,y)*8,a+V(x+1,y+1)*8
#define R(x,y,c) d->AddRectFilled(P(x,y),c);
I g=1;I pc[][9]={{1,1,1},{1,1,0,1,1},{1,1,1,0,1},{1,1,1,1},{1,1,1,0,0,1},{1,1,0,0,1,1},{0,1,1,1,1}};I*c=0;I p=0;I f=0;I T[41][21];void s(I&a,I&b){I d=a;a=b;b=d;}void FX(ImDrawList * d,V a,V,V,ImVec4 m,float t){F(i,21)T[40][i]=1;if(!p)F(i,40){c=pc[(I)t%7];I s=-21;F(j,21)s+=T[i][j];if(!s){F(j,i)F(k,21)T[j+1][k]=T[j][k];++i;}}if(!m.z){S(0,6)S(1,5)S(2,8)S(3,7)S(3,5)S(0,8)}I y=m.y*23-1.;if(y<0){if(!(c[0]|c[1]|c[2]))F(i,3){c[i]=c[i+3];c[i+3]=c[i+6];c[i+6]=0;}y=0;}if(y>18){if(!(c[6]|c[7]|c[8]))F(i,3){c[i+6]=c[i+3];c[i+3]=c[i];c[i]=0;}y=18;}p+=m.w>0|!(++f%8);F(i,3)F(j,3)if(c[j*3+i]&T[p+i+1][y+j]){F(k,3)F(l,3)T[p+k][y+l]|=g&c[l*3+k];p=0;}F(i,21)g&=!T[0][i];F(i,40)F(j,21)if(T[i][j])R(i,j,g?~0xFDA:~0)if(g)F(i,3)F(j,3)if(c[j*3+i])R(i+p,j+y,~0xFF14)L(3,0)L(0,3)p+=3;y+=3;L(0,-3)L(-3,0)p-=3;}
expanded source code (3409 bytes)
#include <algorithm>
#include <numeric>

static int board[41][21];
static int pieces_list[][9] = {
		{1, 1, 1,
		 0, 0, 0,
		 0, 0, 0},
		{0, 1, 1,
		 0, 1, 1,
		 0, 0, 0},
		{1, 1, 1,
		 0, 1, 0,
		 0, 0, 0},
		{1, 1, 1,
		 1, 0, 0,
		 0, 0, 0},
		{1, 1, 1,
		 0, 0, 1,
		 0, 0, 0},
		{1, 1, 0,
		 0, 1, 1,
		 0, 0, 0},
		{0, 1, 1,
		 1, 1, 0,
		 0, 0, 0}};

static int * current_piece = nullptr;
static int piece_pos = 0;
static int frame_count = 0;
static int game_ongoing = 1;

void FX(ImDrawList * d, ImVec2 a, ImVec2, ImVec2, ImVec4 mouse, float t) {
	++frame_count;

	std::fill_n(board[40], 21, 1);// could be done only once

	if (piece_pos == 0) {
		for (int i = 39; i >= 0; --i) {
			current_piece = pieces_list[static_cast<int>(t) % 7];// selecting new piece (such randomness)

			if (std::accumulate(board[i], board[i] + 21, 0) == 21) {// checking for full line
				for (int j = i; j > 0; --j) {
					for (int k = 0; k < 21; ++k) {
						board[j + 1][k] = board[j][k];
					}
				}
				++i;// rollback
			}
		}
	}

	if (mouse.z == 0.f) {// rotating piece
		int copy[9]{};
		std::copy(current_piece, current_piece + 9, copy);
		current_piece[0] = copy[2];
		current_piece[1] = copy[5];
		current_piece[2] = copy[8];
		current_piece[3] = copy[1];
		current_piece[5] = copy[7];
		current_piece[6] = copy[0];
		current_piece[7] = copy[3];
		current_piece[8] = copy[6];
	}

	int y = mouse.y * 23 - 1.;// piece y coord
	if (y < 0) {
		if (!current_piece[0] && !current_piece[1] && !current_piece[2]) {
			for (int i = 0; i < 3; ++i) {
				current_piece[i] = current_piece[i + 3];
				current_piece[i + 3] = current_piece[i + 6];
				current_piece[i + 6] = 0;
			}
		}
		y = 0;

	} else if (y > 18) {
		if (!current_piece[6] && !current_piece[7] && !current_piece[8]) {
			for (int i = 0; i < 3; ++i) {
				current_piece[i + 6] = current_piece[i + 3];
				current_piece[i + 3] = current_piece[i];
				current_piece[i] = 0;
			}
		}
		y = 18;
	}

	if (mouse.w > 0 || frame_count % 8 == 0) {
		++piece_pos;
	}

	bool collided = false;
	for (int i = 0; i < 3; ++i) {
		for (int j = 0; j < 3; ++j) {

			if (current_piece[j * 3 + i] && board[piece_pos + i + 1][y + j]) {
				collided = true;
			}
		}
	}

	if (collided) {
		for (int i = 0; i < 3; ++i) {
			for (int j = 0; j < 3; ++j) {
				if (game_ongoing && current_piece[j * 3 + i]) {
					board[piece_pos + i][y + j] = 1;
				}
			}
		}
		piece_pos = 0;
	}

	if (std::accumulate(board[0], board[0] + 21, 0) != 0) {
		// game lost
		game_ongoing = 0;
	}


	for (int i = 0; i < 40; ++i) {
		for (int j = 0; j < 21; ++j) {
			if (board[i][j]) {
				d->AddRectFilled(a + ImVec2(i, j) * 8, a + ImVec2(i + 1, j + 1) * 8, game_ongoing ? IM_COL32(37,240,255,255) : IM_COL32_WHITE);
			}
		}
	}

	if (game_ongoing) {
		for (int i = 0; i < 3; ++i) {
			for (int j = 0; j < 3; ++j) {
				if (current_piece[j * 3 + i]) {
					d->AddRectFilled(a + ImVec2(i + piece_pos, j + y) * 8, a + ImVec2(i + piece_pos + 1, j + y + 1) * 8, IM_COL32(235,0,255,255));
				}
			}
		}

		d->AddLine(a + ImVec2(piece_pos, y) * 8, a + ImVec2(piece_pos + 3, y) * 8, IM_COL32_WHITE);
		d->AddLine(a + ImVec2(piece_pos, y) * 8, a + ImVec2(piece_pos, y + 3) * 8, IM_COL32_WHITE);
		d->AddLine(a + ImVec2(piece_pos + 3, y + 3) * 8, a + ImVec2(piece_pos + 3, y) * 8, IM_COL32_WHITE);
		d->AddLine(a + ImVec2(piece_pos + 3, y + 3) * 8, a + ImVec2(piece_pos, y + 3) * 8, IM_COL32_WHITE);
	}
}

Organic-Code avatar Nov 21 '20 19:11 Organic-Code

I made a Mandelbrot set visualization with mouse-centered zoom/de-zoom:

Mandelbrot

I also took the liberty to change from mouse_data.y = (io.MousePos.y - p1.y) / size.y; to mouse_data.y = (io.MousePos.y - p0.y) / size.y; in the gist, so that it corresponds to the specs on the OP

Source code (1024 bytes)
#include <complex>

ImVec2 shift(-2.12,-0.9);
float scale = 0.01;
float zoom_factor = 0.9;
size_t max_iter = 32;

void FX(ImDrawList* d, ImVec2 a, ImVec2, ImVec2 sz, ImVec4 m, float)
{
	if((m.x >= 0 && m.x <= 1 && m.y >= 0 && m.y <= 1) && (m.z > 0 || m.w > 0))
	{
		float zf = m.z > 0 ? zoom_factor : 1 / zoom_factor;
		shift.x -= (m.x * sz.x * scale * (zf - 1));
		shift.y -= (m.y * sz.y * scale * (zf - 1));
		scale *= zf;
	}

	for(size_t x = 0; x < sz.x; ++x)
	{
		for (size_t y = 0; y < sz.y; ++y)
		{
			std::complex<double> c(shift.x + x /(sz.x-1.0)*(sz.x * scale), shift.y + y /(sz.y-1.0)*(sz.y * scale)), z;

			size_t iter;
			for (iter = 0; iter < max_iter && std::abs(z) < 2.0; ++iter)
				z = z * z + c;

			double v = std::log(iter) / std::log(max_iter - 1);
			if(iter < max_iter)
				d->AddRectFilled(ImVec2(a.x+ x,a.y+ y), ImVec2(a.x+ x +1,a.y+ y +1), IM_COL32((v*255), 255-(v*255), 255, 255));
			else
				d->AddRectFilled(ImVec2(a.x+ x,a.y+ y), ImVec2(a.x+ x +1,a.y+ y +1), IM_COL32(0, 0,0, 255));
		}
	}
}

pinam45 avatar Nov 21 '20 20:11 pinam45

Mandatory tunnel 971 bytes

#define V2 ImVec2
#define F float
V2 conv(V2 v, F z, V2 sz, V2 o){return V2((v.x/z)*sz.x*5.f+sz.x*0.5f,(v.y/z)*sz.y*5.f+sz.y*0.5f)+o;}
V2 R(V2 v, F ng){ng*=0.1f;return V2(v.x*cosf(ng)-v.y*sinf(ng),v.x*sinf(ng)+v.y*cosf(ng));}
void FX(ImDrawList* d, V2 o, V2 b, V2 sz, ImVec4, F t){d->AddRectFilled(o,b,0xFF000000,0);t*=4;
for (int i = 0; i < 20; i++){
F z=21.-i-(t-floorf(t))*2.,ng=-t*2.1+z,ot0=-t+z*0.2,ot1=-t+(z+1.)*0.2,os=0.3;
V2 s[]={V2(cosf((t+z)*0.1)*0.2+1.,sinf((t+z)*0.1)*0.2+1.),V2(cosf((t+z+1.)*0.1)*0.2+1.,sinf((t+z+1.)*0.1)*0.2+1.)};
V2 of[]={V2(cosf(ot0)*os,sinf(ot0)*os),V2(cosf(ot1)*os,sinf(ot1)*os)};
V2 p[]={V2(-1,-1),V2(1,-1),V2(1,1),V2(-1,1)};
ImVec2 pts[8];int j;
for (j=0;j<8;j++){int n = (j/4);pts[j]=conv(R(p[j%4]*s[n]+of[n],ng+n),(z+n)*2.,sz,o);}
for (j=0;j<4;j++){V2 q[4]={pts[j],pts[(j+1)%4],pts[((j+1)%4)+4],pts[j+4]};
F it=(((i&1)?0.5:0.6)+j*0.05)*((21.-z)/21.);
d->AddConvexPolyFilled(q,4,ImColor::HSV(0.6+sinf(t*0.03)*0.5,1,sqrtf(it)));
}}}

ezgif com-gif-maker (2)

CedricGuillemet avatar Nov 22 '20 10:11 CedricGuillemet

Awesome stuff so far.

I started by looking at some of the first entries, and decided to play with circles. So I went on googling for something to find some inspiration, and I though it would be cool to replicate this: Black and White Minimal Circles by Colin Saunders.

Anyway, while playing with the drawing algorithm something went wrong and I ended up with an out of control Death Star laser-shooting randomly onto the galaxy!

Death Star - 926 bytes

#define V2 ImVec2
#define CR(o,r,c) d->AddCircle(o,r,c)
#define LN(a,b,c) d->AddLine(a,b,c)
#define FORI(n) for(int i=0;i<n;++i)
void FX(ImDrawList*d,V2 a,V2 b,V2 sz,ImVec4,float t){
	static float pr{t}, tm{};
	static auto st=[](){ImVector<V2> v; v.resize(512); FORI(512) v[i]=V2(rand()%480,rand()%270); return v;}();
	V2 hsz{sz/2}, o{a+hsz}, dir{sinf(tm),cosf(tm)}, c, sf;
	float dt{}, rad{hsz.y*0.7}, r;
	int cnt{rad/2}, sh{!(int(t)%2)}, inc;
	FORI(512) CR(st[i],1,0xFF333333);
	if(!sh) dt=t-pr,tm+=dt;
	pr=t;
	ImU32 BL{0xFF000000}, WH{0xFFFFFFFF}, G{0xFF00FF00};
	FORI(cnt){r=rad-i,inc=i; c={o.x+inc*dir.x,o.y+inc*dir.y}; CR(c,r,WH);}
	V2 la{o.x-rad,o.y}, lb{o.x+rad,o.y};
	LN(la,lb,BL);
	FORI(cnt){r=rad-(cnt+i), inc=(cnt-i); c={o.x+inc*dir.x,o.y+inc*dir.y}; CR(c,r,WH);}
	if(sh){la=o+dir*rad/8; lb=o+dir*hsz.x*2; sf={3*sinf(t*1024),3*cosf(t*1024)}; LN(la,lb,G); LN(la+sf,lb+sf,G); LN(la-sf,lb-sf,G);}
}

death-star

Fahien avatar Nov 22 '20 15:11 Fahien

Following the Mandelbrot set visualization, this time I made a Julia sets visualization:

Julia

Inspired by this Wikipedia gif, the Julia sets represented are generated by

z^{2} + 0.7885 e^{ia}

where a ranges from 0 to 2π.

Source code (1024 bytes)
#include <complex>
#define C(r,g,b) IM_COL32(255*(r), 255*(g), 255*(b), 255)
size_t max_iter = 256;
float color_f = 48.0;
float speed_f = 2.0;

ImU32 to_color(float v)
{
	v = 1.f - std::log(v * color_f+1) / std::log(color_f+1);
	size_t p = v * 5.0;
	double g = (v * 5.0 - p);
	ImU32 colors[] = {C(1, 0, 1-g),C(1, g, 0),C(1-g, 1, 0),C(0, 1, g),C(0, 1-g, 1),C(0, 0, 1),};
	return colors[p];
}
void FX(ImDrawList* d, ImVec2 a, ImVec2, ImVec2 sz, ImVec4, float t)
{
	for (size_t x = 0; x < sz.x; ++x)
		for (size_t y = 0; y < sz.y; ++y)
		{
			std::complex<double> z(-2.1+x/(sz.x-1.0)*(sz.x*0.013), -1.15+y/(sz.y-1.0)*(sz.y*0.013));
			std::complex<double> c(0.7885*std::cos(t/speed_f),0.7885*std::sin(t/speed_f));

			size_t iter;
			for (iter = 0; iter < max_iter && std::abs(z) < 2.0; ++iter)
				z=z*z+c;

			if(iter < max_iter)
				d->AddRectFilled(ImVec2(a.x+x,a.y+y), ImVec2(a.x+x+1,a.y+y+1), to_color((float)iter / max_iter));
			else
				d->AddRectFilled(ImVec2(a.x+x,a.y+y), ImVec2(a.x+x+1,a.y+y+1), 0XFF000000);
		}
}

pinam45 avatar Nov 22 '20 15:11 pinam45

A little driving game. Use the mouse buttons to move left and right.

drive

#define V2 ImVec2
#define R d->AddRectFilled
#define RED 0xff0000ff

void FX(ImDrawList* d, V2 a, V2 b, V2 sz, ImVec4 m, float t)
{
    static float mx = a.x + 160;
    float dy = 36, dt = 8;
    int i = fmodf(dt * t, 2) < 1 ? 1 : 0;
    auto v = fmodf(dt * t, 1), y = a.y - dy + v * dy;
    for (int s = 1 + sz.y / dy; s > 0; --s, y += dy) {
        float c = sinf(t + v / dy - s / dy) * 40;
        V2 tl = { c + a.x + sz.x / 2 - 64, y };
        V2 br = { c + a.x + sz.x / 2 + 64, y + dy };
        R(tl, br, (++i & 1) ? 0xffffffff : RED);
        tl.x += 8;
        br.x -= 8;
        R(tl, br, 0xff3f3f3f);
    }
    if (m.z >= 0) mx--; if (m.w >= 0) mx++;
    R({ mx - 8, b.y - sz.y / 4 - 15 }, { mx + 8, b.y - sz.y / 4 + 15 }, 0xff00ff00, 4);
    R({ mx - 7, b.y - sz.y / 4 - 8 }, { mx + 7, b.y - sz.y / 4 + 12 }, 0xff007f00, 4);
    R({ mx - 6, b.y - sz.y / 4 + 12 }, { mx - 2, b.y - sz.y / 4 + 14 }, RED);
    R({ mx + 2, b.y - sz.y / 4 + 12 }, { mx + 6, b.y - sz.y / 4 + 14 }, RED);
}

badlydrawnrod avatar Nov 22 '20 16:11 badlydrawnrod

Inspired by this party, my entry is a Game of Life pulsar oscillator (see Wikipedia)

GoL

Uses left mouse button clicks to process next generation.

My algorithm is probably not efficient, and I need quite a big data input, so had to make the code ugly to get to 994 bytes:

#define V2 ImVec2
#define S 17
#define L 16
#define I int
#define F float

I h[S][S],g[S][S]={{0},{0},{0,0,0,0,1,1,1,0,0,0,1,1,1},{0},{0,0,1,0,0,0,0,1,0,1,0,0,0,0,1},{0,0,1,0,0,0,0,1,0,1,0,0,0,0,1},{0,0,1,0,0,0,0,1,0,1,0,0,0,0,1},{0,0,0,0,1,1,1,0,0,0,1,1,1},{0},{0,0,0,0,1,1,1,0,0,0,1,1,1},{0,0,1,0,0,0,0,1,0,1,0,0,0,0,1},{0,0,1,0,0,0,0,1,0,1,0,0,0,0,1},{0,0,1,0,0,0,0,1,0,1,0,0,0,0,1},{0},{0,0,0,0,1,1,1,0,0,0,1,1,1}};

void FX(ImDrawList* d,V2 a,V2 b,V2 sz,ImVec4 m,F t)
{
if (!m.z)
{
for(I i=1;i<L;i++)
for(I j=1;j<L;j++)
{
I c=g[i-1][j-1]+g[i-1][j]+g[i-1][j+1]+g[i][j-1]+g[i][j+1]+g[i+1][j-1]+g[i+1][j]+g[i+1][j+1];
h[i][j]=(g[i][j]&&c==2)||c==3;
}
for(I i=1;i<L;i++)
for(I j=1;j<L;j++)
g[i][j]=h[i][j];
}
F s=1.f/S; I i=0,j=0;
for(F y=0.f;y<1.f;y+=s,j++,i=0)
for(F x=0.f;x<1.f;x+=s,i++)
{
V2 c((x+.5f*s),(y+.5f*s));
F k = .45f;
d->AddRectFilled(
V2(a.x+(c.x-k*s)*sz.x,a.y+(c.y-k*s)*sz.y),
V2(a.x+(c.x+k*s)*sz.x,a.y+(c.y+k*s)*sz.y),
g[i][j]*0xFFFF0000);
}
}

jv42 avatar Nov 22 '20 19:11 jv42

Non competing (I mean it’s not really my idea ; and truthfully it’s not really an effect), inspired by the previous comment, Conway’s Game of Life conways conways2

Use left click to place/remove a cell, and right click to start/stop.

Source code (1024 bytes)
#define V ImVec2
#define R(c)d->AddRectFilled(a+V(1,1)+V(i-1,j-1)*8, a-V(1,1)+V(i,j)*8,c)
int board[42][24]{};
int r = 0;
int f = 0;
void FX(ImDrawList * d,V a,V,V,ImVec4 m, float t) {
	if (r && ++f%10==1) {
		int n[42][22] = {};
		for (int i = 41; --i;) {
			for (int j = 23; --j;) {
				int s = -board[i][j];
				for (int k = 3; k--;) {
					for (int l = 3; l--;) {
						s += board[i + k - 1][j + l - 1];
					}
				}
				if (s == 3)
					n[i][j] = board[i][j]?1:2;
				if (s == 2)
					n[i][j] = board[i][j];
			}
		}
		for (int i = 41; --i;)
			for (int j = 23; --j;)
				board[i][j] = n[i][j];
	}
	int x = int(m.x * 40);
	int y = int(m.y * 22.5f);
	if (m.z == 0.f && !r)
		if (x >= 0 && x < 41 && y >= 0 && y < 23)
			board[x+1][y+1] = !board[x+1][y+1];

	if (m.w == 0.f)
		r = !r;

	for (int i = 41; --i;)
		for (int j = 23; --j;) {
			if (board[i][j] == 2) {
				board[i][j] = 1+!!(f%10);
				R(0xFF55AAAA);
			}
			if (board[i][j] == 1)
				R(0xFFFF8855);
		}

	d->AddRect(a + V(x,y) * 8, a + V(x+1,y+1) * 8, ~0);
}

Organic-Code avatar Nov 22 '20 22:11 Organic-Code

A kind of 2D version of the old electropaint effect using translucent circles. Works well against either a light or dark background.

fx_ec_23 fx_ec_17

Source Code (1021 bytes)
typedef float F;
struct G { F v0, v1; int mc, w; F ms, ma; int c; F v, d, a; };

F x(G& g){
g.c++;
if (g.c > g.mc){
g.a = (drand48() - 0.5) * 2 * g.ma;
g.c = 0;
}
g.d += g.a;
g.d = fmin(g.ms, fmax(-g.ms, g.d));
g.v += g.d;
if (g.w)
g.v = g.v0 + fmodf(g.v - g.v0, g.v1 - g.v0);
else
g.v = fmin(g.v1, fmax(g.v0, g.v));
return g.v;
}

int mx=999;
G rc={-15, 15, 150, 0, 0.05, 0.005, mx};
G ac={0, 360, 120, 1, 1, 0.025, mx};
G da={0, 360, 80, 1, 0.1, 0.01, mx};
G rm={0, 255, 95, 0, 5, 1.275, mx};
G gm={0, 255, 40, 0, 5, 1.275, mx};

struct Elt{F r;F a;F da;F cr;F cg;};
Elt ne() {return {x(rc),x(ac),x(da),x(rm),x(gm)};}
#include <deque>
std::deque<Elt> es(80);

void FX(ImDrawList* d, V2 a, V2 b, V2 sz, ImVec4, F){
es.pop_back();
es.push_front(ne());
V2 o = a + sz * 0.5;
for (Elt& e : es){
F ar=e.a*M_PI/180;
V2 p(sinf(ar), cosf(ar));
p *= sz.y*e.r/37.5;
F cr = sz.y/10 * (0.25 + fabs(e.r/20));
d->AddCircleFilled(o+p, cr, IM_COL32(e.cr, e.cg, (255-e.cr*e.cg/255), 48));
d->AddCircle(o+p, cr, 64<<24);
e.a += e.da;
}
}

andrewwillmott avatar Nov 23 '20 00:11 andrewwillmott

Simple DFS Maze Generation, I had a rough time getting it under 1024 bytes

9iN3byNyCq

Source Code (989 bytes)

#include <random>
#include <functional>
#define arf q->AddRectFilled
#define al q->AddLine
#define V ImVec2
#define I(p,o) V(a.x+j*5+p,a.y+i*5+o)
#define J I(0,0)
#define K I(5,5)
#define wh 0xFFFFFFFF
#define bl 0xFF000000
#define fr(x,y) for(int x=0;x<y;++x)
#define P int p,int&c,int m,int&f
int u=1,d=2,r=4,l=8;auto S=std::random_device()();float W=0,I=.002;void FX(ImDrawList*q,V a,V,V s,ImVec4,float t){if(t>W+I)W=t;int w=64,h=36,C=0,F=-1;std::vector<int>G(w*h,15);std::mt19937 N(S);std::function<void(P)>fn=[&](P){if(c==m){f=p;return;}int n[]={-w,w,1,-1};int T[]={0,1,2,3};std::shuffle(T,T+4,N);fr(i,4){if(c==m)return;int L=p+n[T[i]];if(L<0||L>w*h-1||(L<p&&!(p%w))||(L>p&&!((p+1)%w)))continue;if(G[L]==15){auto v=1<<T[i];G[p]^=v;G[L]^=(v==u||v==r)?v*2:v/2;fn(L,++c,m,f);}}};fn(0,C,W/I,F);fr(i,h)fr(j,w){int e=G[i*w+j];if(i*w+j==F)arf(J,K,0xFF00FF00);else if(e!=15)arf(J,K,wh);if(e&u)al(J,I(5,0),bl);if(e&d)al(I(0,5),K,bl);if(e&l)al(I(0,5),J,bl);if(e&r)al(K,I(5,0),bl);}}

Fuzznip avatar Nov 23 '20 08:11 Fuzznip

Non competing (I mean it’s not really my idea ; and truthfully it’s not really an effect), inspired by the previous comment, Conway’s Game of Life conways conways2

Use left click to place/remove a cell, and right click to start/stop. Source code (1024 bytes)

That's a nice improvement over my attempt! And it can double as a paint program :-D

jv42 avatar Nov 23 '20 09:11 jv42