<commit_before>#include "core/lux.h"
#include "graphics/model.h"

#include "core/fs/file_system.h"
#include "core/fs/ifile.h"
#include "core/log.h"
#include "core/array.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "core/vec3.h"
#include "graphics/geometry.h"
#include "graphics/material.h"
#include "graphics/pose.h"
#include "graphics/renderer.h"


namespace Lux
{

	
Model::~Model()
{
	ASSERT(isEmpty());
}


RayCastModelHit Model::castRay(const Vec3& origin, const Vec3& dir, const Matrix& model_transform, float scale)
{
	RayCastModelHit hit;
	hit.m_is_hit = false;
	if(!m_geometry)
	{
		return hit;
	}
	
	Matrix inv = model_transform;
	inv.multiply3x3(scale);
	inv.inverse();
	Vec3 local_origin = inv.mutliplyPosition(origin);
	Vec3 local_dir = static_cast<Vec3>(inv * Vec4(dir.x, dir.y, dir.z, 0));

	const Array<Vec3>& vertices = m_geometry->getVertices();

	int32_t last_hit_index = -1;
	for(int i = 0; i < vertices.size(); i += 3)
	{
		Vec3 p0 = vertices[i];
		Vec3 p1 = vertices[i+1];
		Vec3 p2 = vertices[i+2];
		Vec3 normal = crossProduct(p1 - p0, p2 - p0);
		float q = dotProduct(normal, local_dir);
		if(q == 0)
		{
			continue;
		}
		float d = -dotProduct(normal, p0);
		float t = -(dotProduct(normal, local_origin) + d) / q;
		if(t < 0)
		{
			continue;
		}
		Vec3 hit_point = local_origin + local_dir * t;

		Vec3 edge0 = p1 - p0;
		Vec3 VP0 = hit_point - p0;
		if (dotProduct(normal, crossProduct(edge0, VP0)) < 0)
		{
			continue;
		}

		Vec3 edge1 = p2 - p1;
		Vec3 VP1 = hit_point - p1;
		if (dotProduct(normal, crossProduct(edge1, VP1)) < 0)
		{
			continue;
		}
 
		Vec3 edge2 = p0 - p2;
		Vec3 VP2 = hit_point - p2;
		if (dotProduct(normal, crossProduct(edge2, VP2)) < 0)
		{
			continue;
		}

		if(!hit.m_is_hit || hit.m_t > t)
		{
			hit.m_is_hit = true;
			hit.m_t = t;
			last_hit_index = i;
		}
	}

	if(last_hit_index != -1)
	{
		for(int i = 0; i < m_meshes.size(); ++i)
		{
			if(last_hit_index < m_meshes[i].getStart() + m_meshes[i].getCount())
			{
				hit.m_mesh = &m_meshes[i];
				break;
			}
		}
	}
	hit.m_origin = origin;
	hit.m_dir = dir;
	return hit;
}

void Model::getPose(Pose& pose)
{
	ASSERT(pose.getCount() == getBoneCount());
	Vec3* pos =	pose.getPositions();
	Quat* rot = pose.getRotations();
	Matrix mtx;
	for(int i = 0, c = getBoneCount(); i < c; ++i) 
	{
		mtx = m_bones[i].inv_bind_matrix;
		mtx.fastInverse();
		mtx.getTranslation(pos[i]);
		mtx.getRotation(rot[i]);
	}
}


bool Model::parseVertexDef(FS::IFile* file, VertexDef* vertex_definition)
{
	ASSERT(vertex_definition);
	int vertex_def_size = 0;
	file->read(&vertex_def_size, sizeof(vertex_def_size));
	char tmp[16];
	ASSERT(vertex_def_size < 16);
	if (vertex_def_size >= 16)
	{
		g_log_error.log("renderer", "Model file corrupted %s", getPath());
		return false;
	}
	file->read(tmp, vertex_def_size);
	vertex_definition->parse(tmp, vertex_def_size);
	return true;
}

bool Model::parseGeometry(FS::IFile* file, const VertexDef& vertex_definition)
{
	int tri_count = 0;
	file->read(&tri_count, sizeof(tri_count));
	if (tri_count <= 0)
	{
		return false;
	}
	Array<uint8_t> data;
	int data_size = vertex_definition.getVertexSize() * tri_count * 3;
	data.resize(data_size);
	if (!file->read(&data[0], data_size))
	{
		return false;
	}
	m_geometry = LUX_NEW(Geometry);
	m_geometry->copy(&data[0], data_size, vertex_definition);
	return true;
}

bool Model::parseBones(FS::IFile* file)
{
	int bone_count;
	file->read(&bone_count, sizeof(bone_count));
	if (bone_count < 0)
	{
		return false;
	}
	m_bones.reserve(bone_count);
	for (int i = 0; i < bone_count; ++i)
	{
		Model::Bone& b = m_bones.pushEmpty();
		int len;
		file->read(&len, sizeof(len));
		char tmp[MAX_PATH];
		if (len >= MAX_PATH)
		{
			return false;
		}
		file->read(tmp, len);
		tmp[len] = 0;
		b.name = tmp;
		file->read(&len, sizeof(len));
		if (len >= MAX_PATH)
		{
			return false;
		}<commit_msg>new mesh file format loader<commit_after>#include "core/lux.h"
#include "graphics/model.h"

#include "core/fs/file_system.h"
#include "core/fs/ifile.h"
#include "core/log.h"
#include "core/array.h"
#include "core/resource_manager.h"
#include "core/resource_manager_base.h"
#include "core/vec3.h"
#include "graphics/geometry.h"
#include "graphics/material.h"
#include "graphics/pose.h"
#include "graphics/renderer.h"


namespace Lux
{

	
Model::~Model()
{
	ASSERT(isEmpty());
}


RayCastModelHit Model::castRay(const Vec3& origin, const Vec3& dir, const Matrix& model_transform, float scale)
{
	RayCastModelHit hit;
	hit.m_is_hit = false;
	if(!m_geometry)
	{
		return hit;
	}
	
	Matrix inv = model_transform;
	inv.multiply3x3(scale);
	inv.inverse();
	Vec3 local_origin = inv.mutliplyPosition(origin);
	Vec3 local_dir = static_cast<Vec3>(inv * Vec4(dir.x, dir.y, dir.z, 0));

	const Array<Vec3>& vertices = m_geometry->getVertices();

	int32_t last_hit_index = -1;
	for(int i = 0; i < vertices.size(); i += 3)
	{
		Vec3 p0 = vertices[i];
		Vec3 p1 = vertices[i+1];
		Vec3 p2 = vertices[i+2];
		Vec3 normal = crossProduct(p1 - p0, p2 - p0);
		float q = dotProduct(normal, local_dir);
		if(q == 0)
		{
			continue;
		}
		float d = -dotProduct(normal, p0);
		float t = -(dotProduct(normal, local_origin) + d) / q;
		if(t < 0)
		{
			continue;
		}
		Vec3 hit_point = local_origin + local_dir * t;

		Vec3 edge0 = p1 - p0;
		Vec3 VP0 = hit_point - p0;
		if (dotProduct(normal, crossProduct(edge0, VP0)) < 0)
		{
			continue;
		}

		Vec3 edge1 = p2 - p1;
		Vec3 VP1 = hit_point - p1;
		if (dotProduct(normal, crossProduct(edge1, VP1)) < 0)
		{
			continue;
		}
 
		Vec3 edge2 = p0 - p2;
		Vec3 VP2 = hit_point - p2;
		if (dotProduct(normal, crossProduct(edge2, VP2)) < 0)
		{
			continue;
		}

		if(!hit.m_is_hit || hit.m_t > t)
		{
			hit.m_is_hit = true;
			hit.m_t = t;
			last_hit_index = i;
		}
	}

	if(last_hit_index != -1)
	{
		for(int i = 0; i < m_meshes.size(); ++i)
		{
			if(last_hit_index < m_meshes[i].getStart() + m_meshes[i].getCount())
			{
				hit.m_mesh = &m_meshes[i];
				break;
			}
		}
	}
	hit.m_origin = origin;
	hit.m_dir = dir;
	return hit;
}

void Model::getPose(Pose& pose)
{
	ASSERT(pose.getCount() == getBoneCount());
	Vec3* pos =	pose.getPositions();
	Quat* rot = pose.getRotations();
	Matrix mtx;
	for(int i = 0, c = getBoneCount(); i < c; ++i) 
	{
		mtx = m_bones[i].inv_bind_matrix;
		mtx.fastInverse();
		mtx.getTranslation(pos[i]);
		mtx.getRotation(rot[i]);
	}
}


bool Model::parseVertexDef(FS::IFile* file, VertexDef* vertex_definition)
{
	ASSERT(vertex_definition);
	int vertex_def_size = 0;
	file->read(&vertex_def_size, sizeof(vertex_def_size));
	char tmp[16];
	ASSERT(vertex_def_size < 16);
	if (vertex_def_size >= 16)
	{
		g_log_error.log("renderer", "Model file corrupted %s", getPath());
		return false;
	}
	file->read(tmp, vertex_def_size);
	vertex_definition->parse(tmp, vertex_def_size);
	return true;
}

bool Model::parseGeometry(FS::IFile* file, const VertexDef& vertex_definition)
{
	struct Vertex
	{
		Vec3 pos;
		Vec3 normal;
		float u, v;
	};

	int32_t indices_count = 0;
	file->read(&indices_count, sizeof(indices_count));
	if (indices_count <= 0)
	{
		return false;
	}
	Array<int32_t> indices;
	indices.resize(indices_count);
	file->read(&indices[0], sizeof(indices[0]) * indices_count);
	
	int32_t vertices_count = 0;
	file->read(&vertices_count, sizeof(vertices_count));
	if (vertices_count <= 0)
	{
		return false;
	}
	Array<Vertex> vertices;
	vertices.resize(vertices_count);
	file->read(&vertices[0], sizeof(vertices[0]) * vertices_count);
	
	Array<Vertex> data;
	data.resize(indices_count);
	for(int i = 0; i < indices_count; ++i)
	{
		data[i].pos.x = vertices[indices[i]].pos.x;
		data[i].pos.y = vertices[indices[i]].pos.y;
		data[i].pos.z = vertices[indices[i]].pos.z;
		data[i].normal.x = vertices[indices[i]].normal.x;
		data[i].normal.y = vertices[indices[i]].normal.y;
		data[i].normal.z = vertices[indices[i]].normal.z;
		data[i].u = vertices[indices[i]].u;
		data[i].v = vertices[indices[i]].v;
	}
	m_geometry = LUX_NEW(Geometry);
	m_geometry->copy((uint8_t*)&data[0], sizeof(Vertex) * data.size(), vertex_definition);
	return true;
}

bool Model::parseBones(FS::IFile* file)
{
	int bone_count;
	file->read(&bone_count, sizeof(bone_count));
	if (bone_count < 0)
	{
		return false;
	}
	m_bones.reserve(bone_count);
	for (int i = 0; i < bone_count; ++i)
	{
		Model::Bone& b = m_bones.pushEmpty();
		int len;
		file->read(&len, sizeof(len));
		char tmp[MAX_PATH];
		if (len >= MAX_PATH)
		{
			return false;
		}
		file->read(tmp, len);
		tmp[len] = 0;
		b.name = tmp;
		file->read(&len, sizeof(len));
		if (len >= MAX_PATH)
		{
			return false;
		}
{'fraction_non_alphanumeric': 0.16599002435912308, 'fraction_numerical': 0.020763252522909174, 'mean_word_length': 4.021549213744904, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 43, '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': '5411916', 'n_tokens_mistral': 3865, 'n_tokens_neox': 3562, 'n_words': 708}