#pragma once

// Płaszczyzna wraz z użytecznymi metodami.
class CCollisionPlane {
public:

	// Jednoznaczna definicja płaszczyzny: Ax + By + Cz + D = 0
	vec3 N; // Wektor normalny (ABC).
	float Cp; // D (-N*P0, gdzie P0 jest punktem na płaszczyźnie a * oznacza iloczyn skalarny)

	CCollisionPlane() {
		N.Set(0.0f, 0.0f, -1.0f);
		Cp = 0.0f;
	}

	// Konstruktor - budowa z zestawu punktów.
	CCollisionPlane(vec3 v[]) {
		FromPoints(v);
	}

	// Konstruktor - budowa z wektora normalnego i punktu leżącego na płaszczyźnie.
	CCollisionPlane(vec3 nN, vec3 pO) {
		FromNormalAndPoint(nN, pO);
	}

	// Budowa płaszczyzny z trzech punktów na niej leżących.
	void FromPoints(vec3 v[]) {
		vec3::Cross(v[2] - v[1], v[0] - v[1], N);
		N.Normalize();
		Cp = -N.Dot(v[0]);
	}

	// Budowa płaszczyzny z wektora normalnego i punktu na tej płaszczyźnie.
	void FromNormalAndPoint(vec3 nN, vec3 pO) {
		N = nN;
		N.Normalize();
		Cp = -N.Dot(pO);
	}

	// Czy dany wektor jest skierowany w stronę przedniej strony płaszczyzny, lub jest do niej równoległy?
	bool IsFrontFacingTo(vec3 v) {
		return N.Dot(v) <= 0.0f;
	}

	// Najkrótsza odległość zadanego punktu do płaszczyzny (ze znakiem).
	float SDistanceTo(vec3 p) {
		return p.Dot(N) + Cp;
	}
	
	// Najkrótsza odległość zadanego punktu do płaszczyzny (bez znaku).
	float DistanceTo(vec3 p) {
		return abs(p.Dot(N) + Cp);
	}

	// Projekcja punktu na płaszczyznę.
	vec3 Project(vec3 p) {
		return p - N * N.Dot(p);
	}
};
