<commit_before>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PPeX.Xx2
{
    public class Xx2Writer
    {
        public int Precision { get; set; }

        public bool TrimTextures { get; set; }

        public Xx2Writer()
        {
            Precision = 0;
            TrimTextures = false;
        }

        public Xx2Writer(int precision)
        {
            Precision = precision;
        }

        public void Write(Xx2File file, string filename)
        {
            using (FileStream stream = new FileStream(filename, FileMode.Create))
                Write(file, stream);
        }

        public void Write(Xx2File file, Stream stream)
        {
            using (BinaryWriter writer = new BinaryWriter(stream, Encoding.ASCII, true))
            {
                writer.Write(file.Version);


                writer.Write(file.HeaderUnknown.Length);

                writer.Write(file.HeaderUnknown);


                WriteObject(writer, file.RootObject);


                //always length of 4
                writer.Write(file.MaterialUnknown);


                writer.Write(file.Materials.Count);

                WriteMaterials(writer, file.Materials);


                if (TrimTextures)
                    file.Textures.Clear();

                writer.Write(file.Textures.Count);

                WriteTextures(writer, file.Textures);


                writer.Write(file.UnencodedData.Length);

                writer.Write(file.UnencodedData);
            }
        }

        public void WriteObject(BinaryWriter writer, xxObject obj)
        {
            writer.Write(obj.Name);

            writer.Write(obj.Unknowns.Count);

            foreach (var unknown in obj.Unknowns)
            {
                writer.Write((ushort)unknown.Length);
                writer.Write(unknown);
            }

            writer.Write(obj.Meshes.Count);

            foreach (var mesh in obj.Meshes)
                WriteMesh(writer, mesh);


            writer.Write(obj.DuplicateVerticies.Count);

            WriteVerticies(writer, obj.DuplicateVerticies);

            float[] transforms = new float[16];

            for (int x = 0; x < 4; x++)
                for (int y = 0; y < 4; y++)
                    transforms[(x * 4) + y] = obj.Transforms[x, y];


            writer.Write(FloatEncoder.Encode(transforms));

            writer.Write(obj.Bones.Count);

            WriteBones(writer, obj.Bones);

            writer.Write((short)obj.Children.Count);

            foreach (var child in obj.Children)
                WriteObject(writer, child);
        }


        public void WriteMesh(BinaryWriter writer, xxMeshInfo mesh)
        {
            writer.Write(mesh.Unknowns.Count);

            foreach (var unknown in mesh.Unknowns)
            {
                writer.Write((ushort)unknown.Length);
                writer.Write(unknown);
            }

            writer.Write(mesh.Verticies.Count);

            WriteVerticies(writer, mesh.Verticies);


            writer.Write(mesh.Faces.Count);

            for (int i = 0; i < 3; i++)
            {
                writer.Write(IntegerEncoder.Encode(mesh.Faces.Select(x => x.VertexIndicies[i]).ToArray()));
            }
        }

        public void WriteVerticies(BinaryWriter writer, List<xxVertex> verticies)
        {
            if (verticies.Count == 0)
                return;

            //encode index sizes
            for (int i = 0; i < verticies.Count; i++)
            {
                writer.Write(verticies[i].isIndexUInt16 ? (byte)1 : (byte)0);
            }

            //encode indicies
            writer.Write(IntegerEncoder.Encode(verticies.Select(x => (uint)x.Index).ToArray()));

            //encode each position collated
            for (int i = 0; i < 3; i++)
            {
                float[] data = verticies.Select(x => x.Position[i]).ToArray();

                writer.Write(FloatEncoder.Encode(data, 10f));
            }

            //encode each normal collated
            for (int i = 0; i < 3; i++)
            {
                float[] data = verticies.Select(x => x.Normal[i]).ToArray();

                writer.Write(FloatEncoder.Encode(data, 10f));
            }

            //encode each weight collated
            for (int i = 0; i < 3; i++)
            {
                float[] data = verticies.Select(x => x.Weights[i]).ToArray();

                writer.Write(FloatEncoder.Encode(data, 10f));
            }

            //encode each UV collated
            for (int i = 0; i < 2; i++)
            {
                float[] data = verticies.Select(x => x.UV[i]).ToArray();

                writer.Write(FloatEncoder.Encode(data, 10f));
            }

            //write bone indicies
            for (int i = 0; i < verticies.Count; i++)
            {
                writer.Write(verticies[i].BoneIndicies);
            }

            //write unknowns
            for (int i = 0; i < verticies.Count; i++)
            {
                writer.Write(verticies[i].Unknown);
            }
        }

        public void WriteBones(BinaryWriter writer, List<xxBone> bones)
        {
            if (bones.Count == 0)
                return;

            //encode indicies
            writer.Write(IntegerEncoder.Encode(bones.Select(x => (uint)x.Index).ToArray()));

            //encode each name<commit_msg>Added a quality setting for Xx2 encoding<commit_after>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PPeX.Xx2
{
    public class Xx2Writer
    {
        public int Precision { get; set; }

        public float Quality { get; set; }

        bool IsQualityUsed;

        public Xx2Writer() : this (0)
        {

        }

        public Xx2Writer(int precision)
        {
            Precision = precision;
            IsQualityUsed = false;
        }

        public Xx2Writer(float quality)
        {
            Quality = quality;
            IsQualityUsed = true;
        }

        public void Write(Xx2File file, string filename)
        {
            using (FileStream stream = new FileStream(filename, FileMode.Create))
                Write(file, stream);
        }

        public void Write(Xx2File file, Stream stream)
        {
            using (BinaryWriter writer = new BinaryWriter(stream, Encoding.ASCII, true))
            {
                writer.Write(file.Version);


                writer.Write(file.HeaderUnknown.Length);

                writer.Write(file.HeaderUnknown);


                WriteObject(writer, file.RootObject);


                //always length of 4
                writer.Write(file.MaterialUnknown);


                writer.Write(file.Materials.Count);

                WriteMaterials(writer, file.Materials);

                writer.Write(file.Textures.Count);

                WriteTextures(writer, file.Textures);


                writer.Write(file.UnencodedData.Length);

                writer.Write(file.UnencodedData);
            }
        }

        public void WriteObject(BinaryWriter writer, xxObject obj)
        {
            writer.Write(obj.Name);

            writer.Write(obj.Unknowns.Count);

            foreach (var unknown in obj.Unknowns)
            {
                writer.Write((ushort)unknown.Length);
                writer.Write(unknown);
            }

            writer.Write(obj.Meshes.Count);

            foreach (var mesh in obj.Meshes)
                WriteMesh(writer, mesh);


            writer.Write(obj.DuplicateVerticies.Count);

            WriteVerticies(writer, obj.DuplicateVerticies);

            float[] transforms = new float[16];

            for (int x = 0; x < 4; x++)
                for (int y = 0; y < 4; y++)
                    transforms[(x * 4) + y] = obj.Transforms[x, y];


            writer.Write(FloatEncoder.Encode(transforms));

            writer.Write(obj.Bones.Count);

            WriteBones(writer, obj.Bones);

            writer.Write((short)obj.Children.Count);

            foreach (var child in obj.Children)
                WriteObject(writer, child);
        }


        public void WriteMesh(BinaryWriter writer, xxMeshInfo mesh)
        {
            writer.Write(mesh.Unknowns.Count);

            foreach (var unknown in mesh.Unknowns)
            {
                writer.Write((ushort)unknown.Length);
                writer.Write(unknown);
            }

            writer.Write(mesh.Verticies.Count);

            WriteVerticies(writer, mesh.Verticies);


            writer.Write(mesh.Faces.Count);

            for (int i = 0; i < 3; i++)
            {
                writer.Write(IntegerEncoder.Encode(mesh.Faces.Select(x => x.VertexIndicies[i]).ToArray()));
            }
        }

        public void WriteVerticies(BinaryWriter writer, List<xxVertex> verticies)
        {
            if (verticies.Count == 0)
                return;

            //encode index sizes
            for (int i = 0; i < verticies.Count; i++)
            {
                writer.Write(verticies[i].isIndexUInt16 ? (byte)1 : (byte)0);
            }

            //encode indicies
            writer.Write(IntegerEncoder.Encode(verticies.Select(x => (uint)x.Index).ToArray()));

            //encode each position collated
            for (int i = 0; i < 3; i++)
            {
                float[] data = verticies.Select(x => x.Position[i]).ToArray();

                if (IsQualityUsed)
                    writer.Write(FloatEncoder.Encode(data, Quality));
                else
                    writer.Write(FloatEncoder.Encode(data, Precision));
            }

            //encode each normal collated
            for (int i = 0; i < 3; i++)
            {
                float[] data = verticies.Select(x => x.Normal[i]).ToArray();

                if (IsQualityUsed)
                    writer.Write(FloatEncoder.Encode(data, Quality));
                else
                    writer.Write(FloatEncoder.Encode(data, Precision));
            }

            //encode each weight collated
            for (int i = 0; i < 3; i++)
            {
                float[] data = verticies.Select(x => x.Weights[i]).ToArray();

                if (IsQualityUsed)
                    writer.Write(FloatEncoder.Encode(data, Quality));
                else
                    writer.Write(FloatEncoder.Encode(data, Precision));
            }

            //encode each UV collated
            for (int i = 0; i < 2; i++)
            {
                float[] data = verticies.Select(x => x.UV[i]).ToArray();

                if (IsQualityUsed)
                    writer.Write(FloatEncoder.Encode(data, Quality));
                else
                    writer.Write(FloatEncoder.Encode(data, Precision));
            }

            //write bone indicies
            for (int i = 0; i < verticies.Count; i++)
            {
                writer.Write(verticies[i].BoneIndicies);
            }

            //write unknowns
            for (int i = 0; i < verticies.Count; i++)
            {
                writer.Write(verticies[i].Unknown);
            }
        }

        public void WriteBones(BinaryWriter writer, List<xxBone> bones)
        {
            if (bones.Count == 0)
                return;

            //encode indicies
            writer.Write(IntegerEncoder.Encode(bones.Select(x => (uint)x.Index).ToArray()));

            //encode each name
{'fraction_non_alphanumeric': 0.10937905949597299, 'fraction_numerical': 0.006755001299038711, 'mean_word_length': 1.4424703891708968, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 21, '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': '1845970', 'n_tokens_mistral': 3256, 'n_tokens_neox': 3012, 'n_words': 645}