#ifndef PARTICLE_INC
#define PARTICLE_INC

#define EPSILON 0.00000001f

struct ParticleMinimal {
    vec3 position;
    float size;
    vec3 velocity;
    float mass;
	
	vec3 pad;
	float weight_sum;
};

struct Particle {
    ParticleMinimal minimal;
    mat4 deformation;
	mat4 mls;
};

const float PI = 3.1415926535897932384626433832795;

float sphere_volume(float radius) {
	return 4.0f * (radius * radius * radius) * PI / 3.0f;
}

float sphere_radius(float volume) {
	return pow(volume * 3.0f / 4.0f / PI, 1.0f / 3.0f);
}

float weight_A(float x) {
	return max(1.0f - x, 0.0f);
}

float weight_B(float x) {
	if (x < 0.5f) {
		return 0.75f - x * x;
	} else
	if (x < 1.5f) {
		float y = (1.5f - x);
		return 0.5f * y * y;
	} else {
		return 0.0f;
	}
}

float weight_C(float x) {
	if (x < 1.0f) {
		return (0.5f * x - 1.0f) * x*x + 2.0f / 3.0f;
	} else
	if (x < 2.0f) {
		float y = (2.0f - x);
		return 0.5f / 3.0f * y * y * y;
	} else {
		return 0.0f;
	}
}

float voxel_particle_weight(vec3 voxel, ParticleMinimal particle) {
	vec3 delta = abs(particle.position - voxel) / particle.size;
	
	if (any(isnan(delta)) || any(isinf(delta))) {
		return 0.0f;
	}
	
	vec3 weight = vec3(
		weight_C(delta.x),
		weight_C(delta.y),
		weight_C(delta.z)
	);
	
	float result = (
		weight.x * weight.y * weight.z
	) / particle.weight_sum;
	
	if ((isnan(result)) || (isinf(result))) {
		return 0.0f;
	} else {
		return result;
	}
}

#endif // PARTICLE_INC