<commit_before>// Copyright (C) 2015 <NAME>
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Formats/OBJParser.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Utility/Config.hpp>
#include <cctype>
#include <memory>
#include <unordered_map>
#include <Nazara/Utility/Debug.hpp>

namespace Nz
{
	bool OBJParser::Parse(Nz::Stream& stream, std::size_t reservedVertexCount)
	{
		m_currentStream = &stream;

		// Force stream in text mode, reset it at the end
		Nz::CallOnExit resetTextMode;
		if ((stream.GetStreamOptions() & StreamOption_Text) == 0)
		{
			stream.EnableTextMode(true);

			resetTextMode.Reset([&stream] ()
			{
				stream.EnableTextMode(false);
			});
		}

		String matName, meshName;
		matName = meshName = "default";
		m_keepLastLine = false;
		m_lineCount = 0;
		m_meshes.clear();
		m_mtlLib.Clear();

		m_normals.clear();
		m_positions.clear();
		m_texCoords.clear();

		// Reserve some space for incoming vertices
		m_normals.reserve(reservedVertexCount);
		m_positions.reserve(reservedVertexCount);
		m_texCoords.reserve(reservedVertexCount);

		// Sort meshes by material and group
		using MatPair = std::pair<Mesh, unsigned int>;
		std::unordered_map<String, std::unordered_map<String, MatPair>> meshesByName;

		std::size_t faceReserve = 0;
		std::size_t vertexReserve = 0;
		unsigned int matCount = 0;
		auto GetMaterial = [&] (const String& meshName, const String& matName) -> Mesh*
		{
			auto& map = meshesByName[meshName];
			auto it = map.find(matName);
			if (it == map.end())
				it = map.insert(std::make_pair(matName, MatPair(Mesh(), matCount++))).first;

			Mesh& mesh = it->second.first;

			mesh.faces.reserve(faceReserve);
			mesh.vertices.reserve(vertexReserve);
			faceReserve = 0;
			vertexReserve = 0;

			return &(it->second.first);
		};

		// On prépare le mesh par défaut
		Mesh* currentMesh = nullptr;

		while (Advance(false))
		{
			switch (std::tolower(m_currentLine[0]))
			{
				case '#': //< Comment
					// Some softwares write comments to gives the number of vertex/faces an importer can expect
					std::size_t data;
					if (std::sscanf(m_currentLine.GetConstBuffer(), "# position count: %zu", &data) == 1)
						m_positions.reserve(data);
					else if (std::sscanf(m_currentLine.GetConstBuffer(), "# normal count: %zu", &data) == 1)
						m_normals.reserve(data);
					else if (std::sscanf(m_currentLine.GetConstBuffer(), "# texcoords count: %zu", &data) == 1)
						m_texCoords.reserve(data);
					else if (std::sscanf(m_currentLine.GetConstBuffer(), "# face count: %zu", &data) == 1)
						faceReserve = data;
					else if (std::sscanf(m_currentLine.GetConstBuffer(), "# vertex count: %zu", &data) == 1)
						vertexReserve = data;

					break;

				case 'f': //< Face
				{
					if (m_currentLine.GetSize() < 7) // Since we only treat triangles, this is the minimum length of a face line (f 1 2 3)
					{
						#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
						UnrecognizedLine();
						#endif
						break;
					}

					unsigned int vertexCount = m_currentLine.Count(' ');
					if (vertexCount < 3)
					{
						#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
						UnrecognizedLine();
						#endif
						break;
					}

					if (!currentMesh)
						currentMesh = GetMaterial(meshName, matName);

					Face face;
					face.firstVertex = currentMesh->vertices.size();
					face.vertexCount = vertexCount;

					currentMesh->vertices.resize(face.firstVertex + vertexCount, FaceVertex{0, 0, 0});

					bool error = false;
					unsigned int pos = 2;
					for (unsigned int i = 0; i < vertexCount; ++i)
					{
						int offset;
						std::size_t n = 0;
						std::size_t p = 0;
						std::size_t t = 0;

						if (std::sscanf(&m_currentLine[pos], "%d/%d/%d%n", &p, &t, &n, &offset) != 3)
						{
							if (std::sscanf(&m_currentLine[pos], "%d//%d%n", &p, &n, &offset) != 2)
							{
								if (std::sscanf(&m_currentLine[pos], "%d/%d%n", &p, &t, &offset) != 2)
								{
									if (std::sscanf(&m_currentLine[pos], "%d%n", &p, &offset) != 1)
									{
										#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
										UnrecognizedLine();
										#endif
										error = true;<commit_msg>Utility/OBJParser: Fix mistake<commit_after>// Copyright (C) 2015 <NAME>
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Utility/Formats/OBJParser.hpp>
#include <Nazara/Core/CallOnExit.hpp>
#include <Nazara/Core/Log.hpp>
#include <Nazara/Utility/Config.hpp>
#include <cctype>
#include <memory>
#include <unordered_map>
#include <Nazara/Utility/Debug.hpp>

namespace Nz
{
	bool OBJParser::Parse(Nz::Stream& stream, std::size_t reservedVertexCount)
	{
		m_currentStream = &stream;

		// Force stream in text mode, reset it at the end
		Nz::CallOnExit resetTextMode;
		if ((stream.GetStreamOptions() & StreamOption_Text) == 0)
		{
			stream.EnableTextMode(true);

			resetTextMode.Reset([&stream] ()
			{
				stream.EnableTextMode(false);
			});
		}

		String matName, meshName;
		matName = meshName = "default";
		m_keepLastLine = false;
		m_lineCount = 0;
		m_meshes.clear();
		m_mtlLib.Clear();

		m_normals.clear();
		m_positions.clear();
		m_texCoords.clear();

		// Reserve some space for incoming vertices
		m_normals.reserve(reservedVertexCount);
		m_positions.reserve(reservedVertexCount);
		m_texCoords.reserve(reservedVertexCount);

		// Sort meshes by material and group
		using MatPair = std::pair<Mesh, unsigned int>;
		std::unordered_map<String, std::unordered_map<String, MatPair>> meshesByName;

		std::size_t faceReserve = 0;
		std::size_t vertexReserve = 0;
		unsigned int matCount = 0;
		auto GetMaterial = [&] (const String& meshName, const String& matName) -> Mesh*
		{
			auto& map = meshesByName[meshName];
			auto it = map.find(matName);
			if (it == map.end())
				it = map.insert(std::make_pair(matName, MatPair(Mesh(), matCount++))).first;

			Mesh& mesh = it->second.first;

			mesh.faces.reserve(faceReserve);
			mesh.vertices.reserve(vertexReserve);
			faceReserve = 0;
			vertexReserve = 0;

			return &(it->second.first);
		};

		// On prépare le mesh par défaut
		Mesh* currentMesh = nullptr;

		while (Advance(false))
		{
			switch (std::tolower(m_currentLine[0]))
			{
				case '#': //< Comment
					// Some softwares write comments to gives the number of vertex/faces an importer can expect
					std::size_t data;
					if (std::sscanf(m_currentLine.GetConstBuffer(), "# position count: %zu", &data) == 1)
						m_positions.reserve(data);
					else if (std::sscanf(m_currentLine.GetConstBuffer(), "# normal count: %zu", &data) == 1)
						m_normals.reserve(data);
					else if (std::sscanf(m_currentLine.GetConstBuffer(), "# texcoords count: %zu", &data) == 1)
						m_texCoords.reserve(data);
					else if (std::sscanf(m_currentLine.GetConstBuffer(), "# face count: %zu", &data) == 1)
						faceReserve = data;
					else if (std::sscanf(m_currentLine.GetConstBuffer(), "# vertex count: %zu", &data) == 1)
						vertexReserve = data;

					break;

				case 'f': //< Face
				{
					if (m_currentLine.GetSize() < 7) // Since we only treat triangles, this is the minimum length of a face line (f 1 2 3)
					{
						#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
						UnrecognizedLine();
						#endif
						break;
					}

					unsigned int vertexCount = m_currentLine.Count(' ');
					if (vertexCount < 3)
					{
						#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
						UnrecognizedLine();
						#endif
						break;
					}

					if (!currentMesh)
						currentMesh = GetMaterial(meshName, matName);

					Face face;
					face.firstVertex = currentMesh->vertices.size();
					face.vertexCount = vertexCount;

					currentMesh->vertices.resize(face.firstVertex + vertexCount, FaceVertex{0, 0, 0});

					bool error = false;
					unsigned int pos = 2;
					for (unsigned int i = 0; i < vertexCount; ++i)
					{
						int offset;
						int n = 0;
						int p = 0;
						int t = 0;

						if (std::sscanf(&m_currentLine[pos], "%d/%d/%d%n", &p, &t, &n, &offset) != 3)
						{
							if (std::sscanf(&m_currentLine[pos], "%d//%d%n", &p, &n, &offset) != 2)
							{
								if (std::sscanf(&m_currentLine[pos], "%d/%d%n", &p, &t, &offset) != 2)
								{
									if (std::sscanf(&m_currentLine[pos], "%d%n", &p, &offset) != 1)
									{
										#if NAZARA_UTILITY_STRICT_RESOURCE_PARSING
										UnrecognizedLine();
										#endif
										error = true;
{'fraction_non_alphanumeric': 0.1432731508444962, 'fraction_numerical': 0.007920792079207921, 'mean_word_length': 3.2758964143426295, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 37, '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': '513795', 'n_tokens_mistral': 3784, 'n_tokens_neox': 2961, 'n_words': 695}