#!/usr/pkg/bin/bash
# XScreenSaver, Copyright © 2026 Jamie Zawinski <jwz@jwz.org>
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation.  No representations are made about the suitability of this
# software for any purpose.  It is provided "as is" without express or 
# implied warranty.

PATH="$PATH":"$(dirname "$0")"
exec -a "selfreflect" \
xshadertoy "$@" \
 --program0 - \
<< "_XSCREENSAVER_EOF_"

// Title:  Let's self reflect
// Author: mrange
// URL:    https://www.shadertoy.com/view/XfyXRV
// Date:   11-May-2024
// Desc:   CC0: Let's self reflect
// Always enjoyed the videos of Platonic solids with inner mirrors
// I made some previous attempts but thought I make another attempt it

// CC0: Let's self reflect
//  Always enjoyed the videos of Platonic solids with inner mirrors
//  I made some previous attempts but thought I make another attempt it

// Reducing the alias effects on the inner reflections turned out to be a bit tricky. 
//  Simplest solution is just to run run fullscreen on a 4K screen ;)

// Function to generate the solid found here: https://www.shadertoy.com/view/MsKGzw

// Tinker with these parameters to create different solids
// -------------------------------------------------------


	const float rotation_speed= 0.25;
	const float poly_U        = 1.;
	const float poly_V        = 0.5;
	const float poly_W        = 1.0;
	const int   poly_type     = 3;
	const float poly_zoom     = 2.0;
	const float inner_sphere  = 1.;
	const float refr_index    = 0.9;
	#define MAX_BOUNCES2        6
	#define TIME        iTime
	#define RESOLUTION  iResolution
	#define PI          3.141592654
	#define TAU         (2.0*PI)
	const vec4 hsv2rgb_K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
	vec3 hsv2rgb(vec3 c) {
	vec3 p = abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www);
	return c.z * mix(hsv2rgb_K.xxx, clamp(p - hsv2rgb_K.xxx, 0.0, 1.0), c.y);
	}
	#define HSV2RGB(c)  (c.z * mix(hsv2rgb_K.xxx, clamp(abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www) - hsv2rgb_K.xxx, 0.0, 1.0), c.y))
	#define TOLERANCE2          0.0005
	#define MAX_RAY_MARCHES2    50
	#define NORM_OFF2           0.005
	#define BACKSTEP2
	#define TOLERANCE3          0.0005
	#define MAX_RAY_LENGTH3     10.0
	#define MAX_RAY_MARCHES3    90
	#define NORM_OFF3           0.005
	const vec3 rayOrigin    = vec3(0.0, 1., -5.);
	const vec3 sunDir       = normalize(-rayOrigin);
	const vec3 sunCol       = HSV2RGB(vec3(0.06 , 0.90, 1E-2))*1.;
	const vec3 bottomBoxCol = HSV2RGB(vec3(0.66, 0.80, 0.5))*1.;
	const vec3 topBoxCol    = HSV2RGB(vec3(0.60, 0.90, 1.))*1.;
	const vec3 glowCol0     = HSV2RGB(vec3(0.05 , 0.7, 1E-3))*1.;
	const vec3 glowCol1     = HSV2RGB(vec3(0.95, 0.7, 1E-3))*1.;
	const vec3 beerCol      = -HSV2RGB(vec3(0.15+0.5, 0.7, 2.));
	const float rrefr_index = 1./refr_index;
	const float poly_cospin   = cos(PI/float(poly_type));
	const float poly_scospin  = sqrt(0.75-poly_cospin*poly_cospin);
	const vec3  poly_nc       = vec3(-0.5, -poly_cospin, poly_scospin);
	const vec3  poly_pab      = vec3(0., 0., 1.);
	const vec3  poly_pbc_     = vec3(poly_scospin, 0., 0.5);
	const vec3  poly_pca_     = vec3(0., poly_scospin, poly_cospin);
	const vec3  poly_p        = normalize((poly_U*poly_pab+poly_V*poly_pbc_+poly_W*poly_pca_));
	const vec3  poly_pbc      = normalize(poly_pbc_);
	const vec3  poly_pca      = normalize(poly_pca_);
	mat3 g_rot;
	vec2 g_gd;
	mat3 rot(vec3 d, vec3 z) {
	vec3  v = cross( z, d );
	float c = dot( z, d );
	float k = 1.0/(1.0+c);
	return mat3( v.x*v.x*k + c,     v.y*v.x*k - v.z,    v.z*v.x*k + v.y,
	v.x*v.y*k + v.z,   v.y*v.y*k + c,      v.z*v.y*k - v.x,
	v.x*v.z*k - v.y,   v.y*v.z*k + v.x,    v.z*v.z*k + c    );
	}
	vec3 aces_approx(vec3 v) {
	v = max(v, 0.0);
	v *= 0.6;
	float a = 2.51;
	float b = 0.03;
	float c = 2.43;
	float d = 0.59;
	float e = 0.14;
	return clamp((v*(a*v+b))/(v*(c*v+d)+e), 0.0, 1.0);
	}
	float sphere(vec3 p, float r) {
	return length(p) - r;
	}
	float box(vec2 p, vec2 b) {
	vec2 d = abs(p)-b;
	return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
	}
	void poly_fold(inout vec3 pos) {
	vec3 p = pos;
	for(int i = 0; i < poly_type; ++i){
	p.xy  = abs(p.xy);
	p    -= 2.*min(0., dot(p,poly_nc)) * poly_nc;
	}
	pos = p;
	}
	float poly_plane(vec3 pos) {
	float d0 = dot(pos, poly_pab);
	float d1 = dot(pos, poly_pbc);
	float d2 = dot(pos, poly_pca);
	float d = d0;
	d = max(d, d1);
	d = max(d, d2);
	return d;
	}
	float poly_corner(vec3 pos) {
	float d = length(pos) - .0125;
	return d;
	}
	float dot2(vec3 p) {
	return dot(p, p);
	}
	float poly_edge(vec3 pos) {
	float dla = dot2(pos-min(0., pos.x)*vec3(1., 0., 0.));
	float dlb = dot2(pos-min(0., pos.y)*vec3(0., 1., 0.));
	float dlc = dot2(pos-min(0., dot(pos, poly_nc))*poly_nc);
	return sqrt(min(min(dla, dlb), dlc))-2E-3;
	}
	vec3 shape(vec3 pos) {
	pos *= g_rot;
	pos /= poly_zoom;
	poly_fold(pos);
	pos -= poly_p;
	return vec3(poly_plane(pos), poly_edge(pos), poly_corner(pos))*poly_zoom;
	}
	vec3 render0(vec3 ro, vec3 rd) {
	vec3 col = vec3(0.0);
	float srd  = sign(rd.y);
	float tp   = -(ro.y-6.)/abs(rd.y);
	if (srd < 0.) {
	col += bottomBoxCol*exp(-0.5*(length((ro + tp*rd).xz)));
	}
	if (srd > 0.0) {
	vec3 pos  = ro + tp*rd;
	vec2 pp = pos.xz;
	float db = box(pp, vec2(5.0, 9.0))-3.0;
	col += topBoxCol*rd.y*rd.y*smoothstep(0.25, 0.0, db);
	col += 0.2*topBoxCol*exp(-0.5*max(db, 0.0));
	col += 0.05*sqrt(topBoxCol)*max(-db, 0.0);
	}
	col += sunCol/(1.001-dot(sunDir, rd));
	return col;
	}
	float df2(vec3 p) {
	vec3 ds = shape(p);
	float d2 = ds.y-5E-3;
	float d0 = min(-ds.x, d2);
	float d1 = sphere(p, inner_sphere);
	g_gd = min(g_gd, vec2(d2, d1));
	float d = (min(d0, d1));
	return d;
	}
	float rayMarch2(vec3 ro, vec3 rd, float tinit) {
	float t = tinit;
	#if defined(BACKSTEP2)
	vec2 dti = vec2(1e10,0.0);
	#endif
	int i;
	for (i = 0; i < MAX_RAY_MARCHES2; ++i) {
	float d = df2(ro + rd*t);
	#if defined(BACKSTEP2)
	if (d<dti.x) { dti=vec2(d,t); }
	#endif
	if (d < TOLERANCE2) {
	break;
	}
	t += d;
	}
	#if defined(BACKSTEP2)
	if(i==MAX_RAY_MARCHES2) { t=dti.y; };
	#endif
	return t;
	}
	vec3 normal2(vec3 pos) {
	vec2  eps = vec2(NORM_OFF2,0.0);
	vec3 nor;
	nor.x = df2(pos+eps.xyy) - df2(pos-eps.xyy);
	nor.y = df2(pos+eps.yxy) - df2(pos-eps.yxy);
	nor.z = df2(pos+eps.yyx) - df2(pos-eps.yyx);
	return normalize(nor);
	}
	vec3 render2(vec3 ro, vec3 rd, float db) {
	vec3 agg = vec3(0.0);
	float ragg = 1.;
	float tagg = 0.;
	for (int bounce = 0; bounce < MAX_BOUNCES2; ++bounce) {
	if (ragg < 0.1) break;
	g_gd      = vec2(1E3);
	float t2  = rayMarch2(ro, rd, min(db+0.05, 0.3));
	vec2 gd2  = g_gd;
	tagg      += t2;
	vec3 p2   = ro+rd*t2;
	vec3 n2   = normal2(p2);
	vec3 r2   = reflect(rd, n2);
	vec3 rr2  = refract(rd, n2, rrefr_index);
	float fre2= 1.+dot(n2,rd);
	vec3 beer = ragg*exp(0.2*beerCol*tagg);
	agg += glowCol1*beer*((1.+tagg*tagg*4E-2)*6./max(gd2.x, 5E-4+tagg*tagg*2E-4/ragg));
	vec3 ocol = 0.2*beer*render0(p2, rr2);
	if (gd2.y <= TOLERANCE2) {
	ragg *= 1.-0.9*fre2;
	} else {
	agg     += ocol;
	ragg    *= 0.8;
	}
	ro        = p2;
	rd        = r2;
	db        = gd2.x;
	}
	return agg;
	}
	float df3(vec3 p) {
	vec3 ds = shape(p);
	g_gd = min(g_gd, ds.yz);
	const float sw = 0.02;
	float d1 = min(ds.y, ds.z)-sw;
	float d0 = ds.x;
	d0 = min(d0, ds.y);
	d0 = min(d0, ds.z);
	return d0;
	}
	float rayMarch3(vec3 ro, vec3 rd, float tinit, out int iter) {
	float t = tinit;
	int i;
	for (i = 0; i < MAX_RAY_MARCHES3; ++i) {
	float d = df3(ro + rd*t);
	if (d < TOLERANCE3 || t > MAX_RAY_LENGTH3) {
	break;
	}
	t += d;
	}
	iter = i;
	return t;
	}
	vec3 normal3(vec3 pos) {
	vec2  eps = vec2(NORM_OFF3,0.0);
	vec3 nor;
	nor.x = df3(pos+eps.xyy) - df3(pos-eps.xyy);
	nor.y = df3(pos+eps.yxy) - df3(pos-eps.yxy);
	nor.z = df3(pos+eps.yyx) - df3(pos-eps.yyx);
	return normalize(nor);
	}
	vec3 render3(vec3 ro, vec3 rd) {
	int iter;
	vec3 skyCol = render0(ro, rd);
	vec3 col  = skyCol;
	g_gd      = vec2(1E3);
	float t1  = rayMarch3(ro, rd, 0.1, iter);
	vec2 gd1  = g_gd;
	vec3 p1   = ro+t1*rd;
	vec3 n1   = normal3(p1);
	vec3 r1   = reflect(rd, n1);
	vec3 rr1  = refract(rd, n1, refr_index);
	float fre1= 1.+dot(rd, n1);
	fre1 *= fre1;
	float ifo = mix(0.5, 1., smoothstep(1.0, 0.9, float(iter)/float(MAX_RAY_MARCHES3)));
	if (t1 < MAX_RAY_LENGTH3) {
	col = render0(p1, r1)*(0.5+0.5*fre1)*ifo;
	vec3 icol = render2(p1, rr1, gd1.x);
	if (gd1.x > TOLERANCE3 && gd1.y > TOLERANCE3 && rr1 != vec3(0.)) {
	col += icol*(1.-0.75*fre1)*ifo;
	}
	}
	col += (glowCol0+1.*fre1*(glowCol0))/max(gd1.x, 3E-4);
	return col;
	}
	vec3 effect(vec2 p, vec2 pp) {
	const float fov = 2.0;
	const vec3 up = vec3(0., 1., 0.);
	const vec3 la   = vec3(0.0);
	const vec3 ww = normalize(normalize(la-rayOrigin));
	const vec3 uu = normalize(cross(up, ww));
	const vec3 vv = cross(ww, uu);
	vec3 rd = normalize(-p.x*uu + p.y*vv + fov*ww);
	vec3 col = vec3(0.0);
	col = render3(rayOrigin, rd);
	col -= 2E-2*vec3(2.,3.,1.)*(length(p)+0.25);
	col = aces_approx(col);
	col = sqrt(col);
	return col;
	}
	void mainImage( out vec4 fragColor, in vec2 fragCoord ) {
	vec2 q = fragCoord/RESOLUTION.xy;
	vec2 p = -1. + 2. * q;
	vec2 pp = p;
	p.x *= RESOLUTION.x/RESOLUTION.y;
	float a = TIME*rotation_speed;
	vec3 r0 = vec3(1.0, sin(vec2(sqrt(0.5), 1.0)*a));
	vec3 r1 = vec3(cos(vec2(sqrt(0.5), 1.0)*0.913*a), 1.0);
	mat3 rot = rot(normalize(r0), normalize(r1));
	g_rot = rot;
	vec3 col = effect(p, pp);
	fragColor = vec4(col, 1.0);
	}

_XSCREENSAVER_EOF_
