#pragma kernel WaveKernel
#pragma kernel WaveToMultiWaveKernel
#pragma kernel WaveToRippleKernel
#pragma kernel WaveToSphereKernel
#pragma kernel WaveToTorusKernel

#pragma kernel MultiWaveToWaveKernel
#pragma kernel MultiWaveKernel
#pragma kernel MultiWaveToRippleKernel
#pragma kernel MultiWaveToSphereKernel
#pragma kernel MultiWaveToTorusKernel

#pragma kernel RippleToWaveKernel
#pragma kernel RippleToMultiWaveKernel
#pragma kernel RippleKernel
#pragma kernel RippleToSphereKernel
#pragma kernel RippleToTorusKernel

#pragma kernel SphereToWaveKernel
#pragma kernel SphereToMultiWaveKernel
#pragma kernel SphereToRippleKernel
#pragma kernel SphereKernel
#pragma kernel SphereToTorusKernel

#pragma kernel TorusToWaveKernel
#pragma kernel TorusToMultiWaveKernel
#pragma kernel TorusToRippleKernel
#pragma kernel TorusToSphereKernel
#pragma kernel TorusKernel

RWStructuredBuffer<float3> _Positions;

uint _Resolution;

float _Step;
float _Time;
float _TransitionProgress;

float2 GetUV(uint3 id)
{
	return (id.xy + 0.5) * _Step - 1.0;
}

void SetPositions(uint3 id, float3 positions)
{
	if (id.x < _Resolution && id.y < _Resolution) 
	{
		_Positions[id.x + id.y * _Resolution] = positions;
	}
}

#define PI 3.14159265358979323846

float3 Wave(float u, float v, float t)
{
    float3 p;
    p.x = u;
    p.y = sin(PI * (u + v + t));
    p.z = v;
    return p;
}

float3 MultiWave(float u, float v, float t)
{
    float3 p;
    p.x = u;
    p.y = sin(PI * (u + 0.5 * t));
    p.y += 0.5 * sin(2.0 * PI * (v + t));
    p.y += sin(PI * (u + v + 0.25 * t));
    p.y *= 1.0 / 2.5;
    p.z = v;
    return p;
}

float3 Ripple(float u, float v, float t)
{
    float d = sqrt(u * u + v * v);
    float3 p;
    p.x = u;
    p.y = sin(PI * (4.0 * d - t));
    p.y /= 1.0 + 10.0 * d;
    p.z = v;
    return p;
}

float3 Sphere(float u, float v, float t)
{
    float r = 0.9 + 0.1 * sin(PI * (6.0 * u + 4.0 * v + t));
    float s = r * cos(0.5 * PI * v);
    float3 p;
    p.x = s * sin(PI * u);
    p.y = r * sin(0.5 * PI * v);
    p.z = s * cos(PI * u);
    return p;
}

float3 Torus(float u, float v, float t)
{
    float r1 = 0.7 + 0.1 * sin(PI * (6.0 * u + 0.5 * t));
    float r2 = 0.15 + 0.05 * sin(PI * (8.0 * u + 4.0 * v + 2.0 * t));
    float s = r1 + r2 * cos(PI * v);
    float3 p;
    p.x = s * sin(PI * u);
    p.y = r2 * sin(PI * v);
    p.z = s * cos(PI * u);
    return p;
}

#define KERNEL_FUNCTION(function) \
	[numthreads(8, 8, 1)] \
	void function##Kernel(uint3 id : SV_DISPATCHTHREADID) \
	{ \
		float2 uv = GetUV(id); \
		SetPositions(id, function(uv.x, uv.y, _Time)); \
	}

KERNEL_FUNCTION(Wave)
KERNEL_FUNCTION(MultiWave)
KERNEL_FUNCTION(Ripple)
KERNEL_FUNCTION(Sphere)
KERNEL_FUNCTION(Torus)

#define KERNEL_MOPH_FUNCTION(functionA, functionB) \
	[numthreads(8, 8, 1)] \
	void functionA##To##functionB##Kernel(uint3 id : SV_DISPATCHTHREADID) \
	{ \
		float2 uv = GetUV(id); \
		float3 position = lerp(functionA(uv.x, uv.y, _Time), functionB(uv.x, uv.y, _Time), _TransitionProgress); \
		SetPositions(id, position); \
	}

KERNEL_MOPH_FUNCTION(Wave, MultiWave)
KERNEL_MOPH_FUNCTION(Wave, Ripple)
KERNEL_MOPH_FUNCTION(Wave, Sphere)
KERNEL_MOPH_FUNCTION(Wave, Torus)

KERNEL_MOPH_FUNCTION(MultiWave, Wave)
KERNEL_MOPH_FUNCTION(MultiWave, Ripple)
KERNEL_MOPH_FUNCTION(MultiWave, Sphere)
KERNEL_MOPH_FUNCTION(MultiWave, Torus)

KERNEL_MOPH_FUNCTION(Ripple, Wave)
KERNEL_MOPH_FUNCTION(Ripple, MultiWave)
KERNEL_MOPH_FUNCTION(Ripple, Sphere)
KERNEL_MOPH_FUNCTION(Ripple, Torus)

KERNEL_MOPH_FUNCTION(Sphere, Wave)
KERNEL_MOPH_FUNCTION(Sphere, MultiWave)
KERNEL_MOPH_FUNCTION(Sphere, Ripple)
KERNEL_MOPH_FUNCTION(Sphere, Torus)

KERNEL_MOPH_FUNCTION(Torus, Wave)
KERNEL_MOPH_FUNCTION(Torus, MultiWave)
KERNEL_MOPH_FUNCTION(Torus, Ripple)
KERNEL_MOPH_FUNCTION(Torus, Sphere)
