/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   mat4_lookat.c                                      :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: gbrochar <gbrochar@student.42.fr>          +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2020/12/23 16:14:47 by gbrochar          #+#    #+#             */
/*   Updated: 2020/12/23 17:05:21 by gbrochar         ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "mat4.h"
#include "vec3.h"
#include "scop.h"

t_mat4			mat4_lookat_make_mat(t_vec3 x, t_vec3 y, t_vec3 z, t_vec3 eye)
{
	t_mat4		ret;

	ret.data[0] = x.x;
	ret.data[1] = x.y;
	ret.data[2] = x.z;
	ret.data[3] = 0;
	ret.data[4] = y.x;
	ret.data[5] = y.y;
	ret.data[6] = y.z;
	ret.data[7] = 0;
	ret.data[8] = z.x;
	ret.data[9] = z.y;
	ret.data[10] = z.z;
	ret.data[11] = 0;
	ret.data[12] = -(x.x * eye.x + x.y * eye.y + x.z * eye.z);
	ret.data[13] = -(y.x * eye.x + y.y * eye.y + y.z * eye.z);
	ret.data[14] = -(z.x * eye.x + z.y * eye.y + z.z * eye.z);
	ret.data[15] = 1;
	return (ret);
}

t_vec3			mat4_lookat_make_y(t_vec3 x, t_vec3 z)
{
	t_vec3		y;
	double		len;

	y.x = z.y * x.z - z.z * x.y;
	y.y = z.z * x.x - z.x * x.z;
	y.z = z.x * x.y - z.y * x.x;
	len = y.x * y.x + y.y * y.y + y.z * y.z;
	if (len - EPSILON < 0 && len + EPSILON > 0)
	{
		y.x = 0;
		y.y = 0;
		y.z = 0;
	}
	else
	{
		len = 1.0 / sqrt(len);
		y.x *= len;
		y.y *= len;
		y.z *= len;
	}
	return (y);
}

t_vec3			mat4_lookat_make_x(t_vec3 z, t_vec3 up)
{
	t_vec3		x;
	double		len;

	x.x = up.y * z.z - up.z * z.y;
	x.y = up.z * z.x - up.x * z.z;
	x.z = up.x * z.y - up.y * z.x;
	len = x.x * x.x + x.y * x.y + x.z * x.z;
	if (len - EPSILON < 0 && len + EPSILON > 0)
	{
		x.x = 0;
		x.y = 0;
		x.z = 0;
	}
	else
	{
		len = 1.0 / sqrt(len);
		x.x *= len;
		x.y *= len;
		x.z *= len;
	}
	return (x);
}

t_vec3			mat4_lookat_make_z(t_vec3 eye, t_vec3 target)
{
	t_vec3		z;
	double		len;

	z.x = eye.x - target.x;
	z.y = eye.y - target.y;
	z.z = eye.z - target.z;
	len = z.x * z.x + z.y * z.y + z.z * z.z;
	if (len - EPSILON < 0 && len + EPSILON > 0)
	{
		z.x = 0;
		z.y = 0;
		z.z = 1;
	}
	else
	{
		len = 1.0 / sqrt(len);
		z.x *= len;
		z.y *= len;
		z.z *= len;
	}
	return (z);
}

t_mat4			mat4_lookat(t_vec3 eye, t_vec3 up, t_vec3 target)
{
	t_vec3		z;
	t_vec3		x;
	t_vec3		y;

	z = mat4_lookat_make_z(eye, target);
	x = mat4_lookat_make_x(z, up);
	y = mat4_lookat_make_y(x, z);
	return (mat4_lookat_make_mat(x, y, z, eye));
}
