public TaskForm(Func<object, TaskProgressReport, bool> task, object arg)
        {
            InitializeComponent();

            _taskFunction = task;
            _arg = arg;

            _report = new TaskProgressReport(worker);
        }
        private bool ImportDataTask(object data, TaskProgressReport report)
        {
            try
            {
                report.Report(0, "Loading file");
                ImportFileSturct info = (ImportFileSturct)data;
                _sourceData = info.Reader.ReadFile(info.File, report);
            }
            catch
            {
                return false;
            }

            return true;
        }
        public bool Export(object arg, TaskProgressReport p)
        {
            int maxTotalTask = 8; //6 normals + geom build + file write
            int currentTotalTask = 0;

            PartTaskProgressReport rep = (PartTaskProgressReport)p;

            rep.SetTitle("Preparing input data");
            rep.Report();

            Dictionary<Vector4, BlockRange[]> ranges = new Dictionary<Vector4, BlockRange[]>();
            List<CustomBlockData> customData = new List<CustomBlockData>();

            Vector3[] normalsToFollow = new Vector3[] { new Vector3(1, 0, 0), new Vector3(-1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, -1, 0), new Vector3(0, 0, 1), new Vector3(0, 0, -1) };

            bool[, ,] customBuilt = new bool[_in.BlockIDs.GetLength(0), _in.BlockIDs.GetLength(1), _in.BlockIDs.GetLength(2)];
            for (int n = 0; n < normalsToFollow.Length; n++)
            {
                Vector3 normal = normalsToFollow[n];
                BlockSide normalSide = Block.GetSideFromNormal(normal);

                Vector2 xy = GetXYByNormal(normal);
                Point3 xyLength = GetLengthAxisByNormal(normal); //X:x, Y:y, Z:level

                int xs = _in.BlockIDs.GetLength(xyLength.X);
                int ys = _in.BlockIDs.GetLength(xyLength.Y);
                int zs = _in.BlockIDs.GetLength(xyLength.Z);

                rep.SetTitle("Processing side: " + TranslateNormal(normal));
                rep.Report();

                for (int lvl = 0; lvl < _in.BlockIDs.GetLength(xyLength.Z); lvl++)
                {
                    BlockData[,] lvlData = new BlockData[xs, ys];

                    int partMax = xs * ys;
                    int partProg = 0;

                    for (int a = 0; a < _in.BlockIDs.GetLength(xyLength.X); a++)
                    {
                        for (int b = 0; b < _in.BlockIDs.GetLength(xyLength.Y); b++)
                        {
                            Point3 pos = ConvertLevelAndXYToPos(a, b, lvl, xyLength);

                            if (_in.BlockIDs[pos.X, pos.Y, pos.Z] != 0)
                            {
                                BlockData bd = GetBlockDataAt(pos);
                                uint block = bd.GetGlobalID();
                                Block bl = Block.Blocks[block];
                                if (bl != null && !customBuilt[pos.X, pos.Y, pos.Z])
                                {
                                    bool canExportFace = (!_cfg.DontExportOuterFaces && !_cfg.InteriorOnly);

                                    if (_cfg.DontExportOuterFaces && CheckFace(pos, normal))
                                        canExportFace = true;
                                    else if (_cfg.InteriorOnly && CheckFaceInterior(pos, normal))
                                        canExportFace = true;

                                    if (canExportFace)
                                    {
                                        if (bl.IsFullyCustomModel())
                                        {
                                            List<CustomBlockData> dat = bl.GenerateModel(_in.BlockMetadatas[pos.X, pos.Y, pos.Z], bd, GetBlockDataAt(new Point3(pos.X + 1, pos.Y, pos.Z)), GetBlockDataAt(new Point3(pos.X - 1, pos.Y, pos.Z)), GetBlockDataAt(new Point3(pos.X, pos.Y + 1, pos.Z)), GetBlockDataAt(new Point3(pos.X, pos.Y - 1, pos.Z)), GetBlockDataAt(new Point3(pos.X, pos.Y, pos.Z + 1)), GetBlockDataAt(new Point3(pos.X, pos.Y, pos.Z - 1)), this, pos);
                                            for (int x = 0; x < dat.Count; x++)
                                            {
                                                dat[x].Vertex1 += pos.ToVector3();
                                                dat[x].Vertex2 += pos.ToVector3();
                                                dat[x].Vertex3 += pos.ToVector3();
                                                if (!dat[x].IsOneTriangle)
                                                    dat[x].Vertex4 += pos.ToVector3();
                                                dat[x].Source = bd;
                                            }
                                            customData.AddRange(dat);
                                            customBuilt[pos.X, pos.Y, pos.Z] = true;
                                        }
                                        else
                                        {
                                            if (bl.IsFullSide(normalSide))
                                            {
                                                if (CanGenerateSide(pos, normal))
                                                {
                                                    lvlData[a, b] = bd;
                                                }
                                            }
                                            else
                                            {
                                                List<CustomBlockData> dat = bl.GenerateSide(normalSide, _in.BlockMetadatas[pos.X, pos.Y, pos.Z], bd, GetBlockDataAt(new Point3(pos.X + 1, pos.Y, pos.Z)), GetBlockDataAt(new Point3(pos.X - 1, pos.Y, pos.Z)), GetBlockDataAt(new Point3(pos.X, pos.Y + 1, pos.Z)), GetBlockDataAt(new Point3(pos.X, pos.Y - 1, pos.Z)), GetBlockDataAt(new Point3(pos.X, pos.Y, pos.Z + 1)), GetBlockDataAt(new Point3(pos.X, pos.Y, pos.Z - 1)));
                                                for (int x = 0; x < dat.Count; x++)
                                                {
                                                    dat[x].Vertex1 += pos.ToVector3();
                                                    dat[x].Vertex2 += pos.ToVector3();
                                                    dat[x].Vertex3 += pos.ToVector3();
                                                    if (!dat[x].IsOneTriangle)
                                                        dat[x].Vertex4 += pos.ToVector3();
                                                    dat[x].Source = bd;
                                                }
                                                customData.AddRange(dat);
                                            }
                                        }
                                    }
                                }
                            }

                            partProg++;
                            rep.SetPartPercent((int)(((float)partProg / (float)partMax) * 100f));
                            rep.Report();
                        }
                    }

                    rep.SetTitle("Square-angulating level: " + lvl.ToString());
                    rep.Report();

                    if (_cfg.OptimizeModel)
                    {
                        List<BlockRange> sq = Squareangulate(lvlData);
                        if (sq.Count > 0)
                        {
                            ranges.Add(new Vector4(normal.X, normal.Y, normal.Z, lvl), sq.ToArray());
                        }
                    }
                    else
                    {
                        List<BlockRange> converted = new List<BlockRange>();
                        for (int x = 0; x < lvlData.GetLength(0); x++)
                        {
                            for (int y = 0; y < lvlData.GetLength(1); y++)
                            {
                                BlockData bd = lvlData[x, y];

                                if (bd == null)
                                    continue;

                                BlockRange range = new BlockRange();
                                range.Block = bd;
                                range.From = new PointF(x, y);
                                range.To = new PointF(x, y);

                                converted.Add(range);
                            }
                        }

                        ranges.Add(new Vector4(normal.X, normal.Y, normal.Z, lvl), converted.ToArray());
                    }
                }

                currentTotalTask++;
                rep.SetTotalPercent((int)(((float)currentTotalTask / (float)maxTotalTask) * 100f));
                rep.Report();
            }

            rep.SetTitle("Building geometry");
            rep.Report();

            Dictionary<string, DataSet> datas = new Dictionary<string, DataSet>();

            int pairIndex = 0;
            foreach (KeyValuePair<Vector4, BlockRange[]> pair in ranges)
            {
                Vector3 normal = new Vector3(pair.Key.X, pair.Key.Y, pair.Key.Z);
                int level = (int)pair.Key.Level;

                Vector3 addNormal = new Vector3(normal.X, normal.Y, normal.Z);
                if (addNormal.X < 0)
                    addNormal.X = 0;
                if (addNormal.Y < 0)
                    addNormal.Y = 0;
                if (addNormal.Z < 0)
                    addNormal.Z = 0;

                for (int x = 0; x < pair.Value.Length; x++)
                {
                    WriteRange(pair.Value[x], normal, level, addNormal, ref datas);
                }

                pairIndex++;
                rep.SetTotalPercent((int)(((float)pairIndex / (float)ranges.Count) * 100f));
                rep.Report();
            }

            for (int x = 0; x < customData.Count; x++)
            {
                WriteCustomData(customData[x], ref datas);
            }

            rep.SetTotalPercent(100);
            rep.Report();

            if (_cfg.CenterObject)
            {
                rep.SetTitle("Centering geometry");
                rep.Report();

                Vector3 min = new Vector3(0, 0, 0);
                Vector3 max = new Vector3(0, 0, 0);
                foreach (KeyValuePair<string, DataSet> pair2 in datas)
                {
                    foreach (Vector3 v in pair2.Value.verts)
                    {
                        min.X = Math.Min(min.X, v.X);
                        min.Y = Math.Min(min.Y, v.Y);
                        min.Z = Math.Min(min.Z, v.Z);

                        max.X = Math.Max(max.X, v.X);
                        max.Y = Math.Max(max.Y, v.Y);
                        max.Z = Math.Max(max.Z, v.Z);
                    }
                }

                Vector3 move = (max - min) / 2;
                foreach (KeyValuePair<string, DataSet> pair2 in datas)
                {
                    for (int x = 0; x < pair2.Value.verts.Count; x++)
                    {
                        pair2.Value.verts[x] -= move;
                    }
                }
            }

            currentTotalTask++;
            rep.SetTotalPercent((int)(((float)currentTotalTask / (float)maxTotalTask) * 100f));

            rep.SetTitle("Creating vertex data");
            rep.Report();

            ProcessedGeometryData geom = new ProcessedGeometryData();
            geom.ExportConfig = _cfg;
            geom.Data = datas.Values.ToList();

            //Export model file
            _outputWriter.Write(_outputFile, geom);

            //Export textures
            if (_cfg.ExportTextures)
            {
                rep.SetTitle("Exporting textures");
                rep.Report();

                List<string> failedTextures = new List<string>();

                string textureOutput = Path.Combine(Path.GetDirectoryName(_outputFile), _cfg.TextureOutputFolder);

                ResourcePack rs = new ResourcePack(_cfg.ResourcePack);
                rs.Open();

                foreach (KeyValuePair<string, DataSet> pair2 in datas)
                {
                    string tex = pair2.Value.Texture;

                    if (!rs.SaveBlockTexture(tex, textureOutput))
                        failedTextures.Add(tex);
                }

                rs.Close();
            }

            currentTotalTask++;
            rep.SetTotalPercent((int)(((float)currentTotalTask / (float)maxTotalTask) * 100f));

            return true;
        }