<commit_before>//#define _USE_MATH_DEFINES
//#include <cmath>
#include "core/crc32.h"
#include "core/event_manager.h"
#include "core/math_utils.h"
#include "core/matrix.h"
#include "core/quat.h"
#include "editor/gizmo.h"
#include "graphics/irender_device.h"
#include "graphics/model.h"
#include "graphics/renderer.h"
#include "universe/entity_moved_event.h"
#include "universe/universe.h"


namespace Lux
{


Gizmo::Gizmo()
{
//	m_handle = 0;
	m_selected_entity.index = -1;
}


Gizmo::~Gizmo()
{
}


void Gizmo::destroy()
{
	//h3dRemoveNode(m_handle);
}


void Gizmo::create(Renderer& renderer)
{
	m_scale = 1;
	m_renderer = &renderer;
	m_model = renderer.getModel("models/gizmo.msh");
}


void Gizmo::hide()
{
	//h3dSetNodeFlags(m_handle, h3dGetNodeFlags(m_handle) | H3DNodeFlags::Inactive, true);
}


void Gizmo::show()
{
	/*h3dSetNodeFlags(m_handle, h3dGetNodeFlags(m_handle) & ~H3DNodeFlags::Inactive, true);
	h3dSetNodeFlags(m_handle, h3dGetNodeFlags(m_handle) | H3DNodeFlags::NoCastShadow, true);	*/
}


void Gizmo::getMatrix(Matrix& mtx)
{
	m_selected_entity.getMatrix(mtx);
}


void Gizmo::updateScale(Component camera)
{
	if (m_selected_entity.isValid())
	{
		Matrix camera_mtx;
		camera.entity.getMatrix(camera_mtx);
		Matrix mtx;
		getMatrix(mtx);
		Vec3 pos = mtx.getTranslation();
		float fov;
		m_renderer->getCameraFov(camera, fov);
		float scale = tanf(fov * Math::PI / 180 * 0.5f) * (mtx.getTranslation() - camera_mtx.getTranslation()).length() * 2;
		scale /= 20 * mtx.getXVector().length();
		m_scale = scale;
	}
}


void Gizmo::setEntity(Entity entity)
{
	//h3dSetNodeFlags(m_handle, h3dGetNodeFlags(m_handle) | H3DNodeFlags::NoCastShadow, true);	
	m_selected_entity = entity;
	if(m_selected_entity.index != -1)
	{
		show();
	}
	else
	{
		hide();
	}
}


void Gizmo::setUniverse(Universe* universe)
{
	m_universe = universe;
}


RayCastModelHit Gizmo::castRay(const Vec3& origin, const Vec3& dir)
{
	if (m_selected_entity.isValid())
	{
		return m_model->castRay(origin, dir, m_selected_entity.getMatrix(), m_scale);
	}
	RayCastModelHit hit;
	hit.m_is_hit = false;
	return hit;
}


void Gizmo::render(Renderer& renderer, IRenderDevice& render_device)
{
	if(m_selected_entity.isValid())
	{
		Matrix scale_mtx = Matrix::IDENTITY;
		scale_mtx.m11 = scale_mtx.m22 = scale_mtx.m33 = m_scale;
		Matrix mtx = m_selected_entity.getMatrix() * scale_mtx;
		renderer.renderModel(*m_model, mtx, render_device.getPipeline());
	}
}


void Gizmo::startTransform(Component camera, int x, int y, TransformMode mode)
{
	m_transform_mode = mode;
	m_transform_point = getMousePlaneIntersection(camera, x, y);
	m_relx_accum = m_rely_accum = 0;
}


void Gizmo::transform(Component camera, TransformOperation operation, int x, int y, int relx, int rely, int flags)
{
	if(m_selected_entity.index != -1)
	{
		if(operation == TransformOperation::ROTATE && m_transform_mode != TransformMode::CAMERA_XZ)
		{
			Vec3 pos = m_selected_entity.getPosition();
			Matrix emtx;
			m_selected_entity.getMatrix(emtx);
			Vec3 axis;
			switch(m_transform_mode)
			{
				case TransformMode::X:
					axis = emtx.getXVector();
					break;
				case TransformMode::Y:
					axis = emtx.getYVector();
					break;
				case TransformMode::Z:
					axis = emtx.getZVector();
					break;
			}
			float angle = 0;
			if(flags & Flags::FIXED_STEP)
			{
				m_relx_accum += relx;
				m_rely_accum += rely;
				if(m_relx_accum + m_rely_accum > 50)
				{
					angle = (float)Math::PI / 4;
					m_relx_accum = m_rely_accum = 0;
				}
				else if(m_relx_accum + m_rely_accum < -50)
				{
					angle = -(float)Math::PI / 4;
					m_relx_accum = m_rely_accum = 0;
				}
				else 
				{
					angle = 0;
				}
			}
			else
			{
				angle = (relx + rely) / 100.0f;
			}
			m_selected_entity.setRotation(m_selected_entity.getRotation() * Quat(axis, angle));
			m_selected_entity.setPosition(pos);
		}
		else
		{
			Vec3 intersection = getMousePlaneIntersection(camera, x, y);
			Vec3 delta = intersection - m_transform_point;
			m_transform_point = intersection;
			Matrix mtx;
			m_selected_entity.getMatrix(mtx);
			mtx.translate(delta);
			m_selected_entity.setMatrix(mtx);
		}
	}
}


Vec3 Gizmo::getMousePlaneIntersection(Component camera, int x, int y)
{
	Vec3 origin, dir;
	m_renderer->getRay(camera, (float)x, (float)y, origin, dir);	
	dir.normalize();
	Matrix camera_mtx;
	camera.entity.getMatrix(camera_mtx);
	if(m_transform_mode == TransformMode::CAMERA_XZ)
	{
		Vec3 a = crossProduct(Vec3(0, 1, 0), camera_mtx.getXVector());
		Vec3 b = crossProduct(Vec3(0, 1, 0), camera_mtx.getZVector());
		Vec3 plane_normal = crossProduct(a, b);
		return Math::getRayPlaneIntersecion(origin, dir, m_selected_entity.getPosition(), plane_normal);
	}
	Vec3 axis;
	switch(m_transform_mode)
	{
		case TransformMode::X:
			axis = m_selected_entity.getMatrix().getXVector();
			break;
		case TransformMode::Y:<commit_msg>fixed float imprecisions when moving objects with a gizmo<commit_after>//#define _USE_MATH_DEFINES
//#include <cmath>
#include "core/crc32.h"
#include "core/event_manager.h"
#include "core/math_utils.h"
#include "core/matrix.h"
#include "core/quat.h"
#include "editor/gizmo.h"
#include "graphics/irender_device.h"
#include "graphics/model.h"
#include "graphics/renderer.h"
#include "universe/entity_moved_event.h"
#include "universe/universe.h"


namespace Lux
{


Gizmo::Gizmo()
{
//	m_handle = 0;
	m_selected_entity.index = -1;
}


Gizmo::~Gizmo()
{
}


void Gizmo::destroy()
{
	//h3dRemoveNode(m_handle);
}


void Gizmo::create(Renderer& renderer)
{
	m_scale = 1;
	m_renderer = &renderer;
	m_model = renderer.getModel("models/gizmo.msh");
}


void Gizmo::hide()
{
	//h3dSetNodeFlags(m_handle, h3dGetNodeFlags(m_handle) | H3DNodeFlags::Inactive, true);
}


void Gizmo::show()
{
	/*h3dSetNodeFlags(m_handle, h3dGetNodeFlags(m_handle) & ~H3DNodeFlags::Inactive, true);
	h3dSetNodeFlags(m_handle, h3dGetNodeFlags(m_handle) | H3DNodeFlags::NoCastShadow, true);	*/
}


void Gizmo::getMatrix(Matrix& mtx)
{
	m_selected_entity.getMatrix(mtx);
}


void Gizmo::updateScale(Component camera)
{
	if (m_selected_entity.isValid())
	{
		Matrix camera_mtx;
		camera.entity.getMatrix(camera_mtx);
		Matrix mtx;
		getMatrix(mtx);
		Vec3 pos = mtx.getTranslation();
		float fov;
		m_renderer->getCameraFov(camera, fov);
		float scale = tanf(fov * Math::PI / 180 * 0.5f) * (mtx.getTranslation() - camera_mtx.getTranslation()).length() * 2;
		scale /= 20 * mtx.getXVector().length();
		m_scale = scale;
	}
}


void Gizmo::setEntity(Entity entity)
{
	//h3dSetNodeFlags(m_handle, h3dGetNodeFlags(m_handle) | H3DNodeFlags::NoCastShadow, true);	
	m_selected_entity = entity;
	if(m_selected_entity.index != -1)
	{
		show();
	}
	else
	{
		hide();
	}
}


void Gizmo::setUniverse(Universe* universe)
{
	m_universe = universe;
}


RayCastModelHit Gizmo::castRay(const Vec3& origin, const Vec3& dir)
{
	if (m_selected_entity.isValid())
	{
		return m_model->castRay(origin, dir, m_selected_entity.getMatrix(), m_scale);
	}
	RayCastModelHit hit;
	hit.m_is_hit = false;
	return hit;
}


void Gizmo::render(Renderer& renderer, IRenderDevice& render_device)
{
	if(m_selected_entity.isValid())
	{
		Matrix scale_mtx = Matrix::IDENTITY;
		scale_mtx.m11 = scale_mtx.m22 = scale_mtx.m33 = m_scale;
		Matrix mtx = m_selected_entity.getMatrix() * scale_mtx;
		renderer.renderModel(*m_model, mtx, render_device.getPipeline());
	}
}


void Gizmo::startTransform(Component camera, int x, int y, TransformMode mode)
{
	m_transform_mode = mode;
	m_transform_point = getMousePlaneIntersection(camera, x, y);
	m_relx_accum = m_rely_accum = 0;
}


void Gizmo::transform(Component camera, TransformOperation operation, int x, int y, int relx, int rely, int flags)
{
	if(m_selected_entity.index != -1)
	{
		if(operation == TransformOperation::ROTATE && m_transform_mode != TransformMode::CAMERA_XZ)
		{
			Vec3 pos = m_selected_entity.getPosition();
			Matrix emtx;
			m_selected_entity.getMatrix(emtx);
			Vec3 axis;
			switch(m_transform_mode)
			{
				case TransformMode::X:
					axis = emtx.getXVector();
					break;
				case TransformMode::Y:
					axis = emtx.getYVector();
					break;
				case TransformMode::Z:
					axis = emtx.getZVector();
					break;
			}
			float angle = 0;
			if(flags & Flags::FIXED_STEP)
			{
				m_relx_accum += relx;
				m_rely_accum += rely;
				if(m_relx_accum + m_rely_accum > 50)
				{
					angle = (float)Math::PI / 4;
					m_relx_accum = m_rely_accum = 0;
				}
				else if(m_relx_accum + m_rely_accum < -50)
				{
					angle = -(float)Math::PI / 4;
					m_relx_accum = m_rely_accum = 0;
				}
				else 
				{
					angle = 0;
				}
			}
			else
			{
				angle = (relx + rely) / 100.0f;
			}
			m_selected_entity.setRotation(m_selected_entity.getRotation() * Quat(axis, angle));
			m_selected_entity.setPosition(pos);
		}
		else
		{
			Vec3 intersection = getMousePlaneIntersection(camera, x, y);
			Vec3 delta = intersection - m_transform_point;
			m_transform_point = intersection;
			Vec3 pos = m_selected_entity.getPosition();
			pos += delta;
			m_selected_entity.setPosition(pos);
		}
	}
}


Vec3 Gizmo::getMousePlaneIntersection(Component camera, int x, int y)
{
	Vec3 origin, dir;
	m_renderer->getRay(camera, (float)x, (float)y, origin, dir);	
	dir.normalize();
	Matrix camera_mtx;
	camera.entity.getMatrix(camera_mtx);
	if(m_transform_mode == TransformMode::CAMERA_XZ)
	{
		Vec3 a = crossProduct(Vec3(0, 1, 0), camera_mtx.getXVector());
		Vec3 b = crossProduct(Vec3(0, 1, 0), camera_mtx.getZVector());
		Vec3 plane_normal = crossProduct(a, b);
		return Math::getRayPlaneIntersecion(origin, dir, m_selected_entity.getPosition(), plane_normal);
	}
	Vec3 axis;
	switch(m_transform_mode)
	{
		case TransformMode::X:
			axis = m_selected_entity.getMatrix().getXVector();
			break;
		case TransformMode::Y:
{'fraction_non_alphanumeric': 0.13694561098023147, 'fraction_numerical': 0.014442282085424562, 'mean_word_length': 4.454748603351955, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6303729', 'n_tokens_mistral': 4298, 'n_tokens_neox': 3831, 'n_words': 666}