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; }
private void WriteRange(BlockRange range, Vector3 normal, float level, Vector3 addNormal, ref Dictionary<string, DataSet> datas) { DataSet foundSet = null; BlockSide side = Block.GetSideFromNormal(normal); Block bl = Block.Blocks[range.Block.GetGlobalID()]; string tex = bl.GetTextureForSide(side, range.Block.Metadata); if (datas.ContainsKey(tex)) foundSet = datas[tex]; else { foundSet = new DataSet(); foundSet.BaseData = range.Block; foundSet.Texture = tex; datas.Add(tex, foundSet); } //BlockSide side = Block.GetSideFromNormal(normal); //Block bl = Block.Blocks[range.Block.GetGlobalID()]; //byte sideByte = 6; //DataSet foundSet = null; //sideByte = (byte)Block.GetSideInt(side); //if (bl.UsesOneTexture) //{ // side = BlockSide.AllSame; // sideByte = (byte)Block.GetSideInt(side); //} //else //{ // string tex = bl.GetTextureForSide(side, range.Block.Metadata); // int[] ids = Find(bl.GetTextures(range.Block.Metadata), tex); // DataSet[] ds = new DataSet[ids.Length]; // KeyStruct key = new KeyStruct(){ // ID = range.Block.ID, // Metadata = range.Block.Metadata, // SideByte = sideByte // }; // for (int s = 0; s < ids.Length; s++) // { // KeyStruct k = new KeyStruct() // { // ID = range.Block.ID, // Metadata = range.Block.Metadata, // SideByte = (byte)ids[s] // }; // if (datas.ContainsKey(k) && key != k) // { // ds[s] = datas[k]; // } // } // for (int e = 0; e < ds.Length; e++) // if (ds[e] != null) // { // foundSet = ds[e]; // break; // } //} PointF ch = new PointF((range.To.X - range.From.X) + 1, (range.To.Y - range.From.Y) + 1); PointF t1 = range.From; PointF t2 = new PointF(range.From.X + ch.X, range.From.Y); PointF t3 = new PointF(range.From.X + ch.X, range.From.Y + ch.Y); PointF t4 = new PointF(range.From.X, range.From.Y + ch.Y); Vector2 uv1 = new Vector2(0, 0); Vector2 uv2 = new Vector2(ch.X, 0); Vector2 uv3 = new Vector2(ch.X, ch.Y); Vector2 uv4 = new Vector2(0, ch.Y); Vector3 t3d1 = ConvertToPos(t1, normal, level) + addNormal; Vector3 t3d2 = ConvertToPos(t2, normal, level) + addNormal; Vector3 t3d3 = ConvertToPos(t3, normal, level) + addNormal; Vector3 t3d4 = ConvertToPos(t4, normal, level) + addNormal; if (foundSet == null) { //KeyStruct key = new KeyStruct() //{ // ID = range.Block.ID, // Metadata = range.Block.Metadata, // SideByte = sideByte //}; //if (!datas.ContainsKey(key)) //{ // datas.Add(key, new DataSet()); // datas[key].BaseData = range.Block; // datas[key].SideByte = sideByte; //} //WriteTriangle(datas[key], t3d1, t3d2, t3d3, uv1, uv2, uv3, normal); //WriteTriangle(datas[key], t3d3, t3d4, t3d1, uv3, uv4, uv1, normal); } else { WriteTriangle(foundSet, t3d1, t3d2, t3d3, uv1, uv2, uv3, normal); WriteTriangle(foundSet, t3d3, t3d4, t3d1, uv3, uv4, uv1, normal); } }
private void Find(ref List<BlockRange> ql, ref BlockData[,] oData, ref bool[,] proc, Point s, ref int remains, BlockData data) { //Find square int fsx = 0; int fsy = 0; bool find = true; bool b1 = false; bool b2 = false; while (find) { if (!b1 && s.X + fsx + 1 < oData.GetLength(0) && s.Y + fsy < oData.GetLength(1) && oData[s.X + fsx + 1, s.Y + fsy] != null && !proc[s.X + fsx + 1, s.Y + fsy]) { bool canAdd = true; for (int cx = s.X; cx <= s.X + fsx + 1; cx++) { for (int cy = s.Y; cy <= s.Y + fsy; cy++) { if (oData[cx, cy] == null || proc[cx, cy]) { canAdd = false; break; } } } if (canAdd) fsx++; else b1 = true; } else b1 = true; if (!b2 && s.X + fsx < oData.GetLength(0) && s.Y + fsy + 1 < oData.GetLength(1) && oData[s.X + fsx, s.Y + fsy + 1] != null && !proc[s.X + fsx, s.Y + fsy + 1]) { bool canAdd = true; for (int cy = s.Y; cy <= s.Y + fsy + 1; cy++) { for (int cx = s.X; cx <= s.X + fsx; cx++) { if (oData[cx, cy] == null || proc[cx, cy]) { canAdd = false; break; } } } if (canAdd) fsy++; else b2 = true; } else b2 = true; if (b1 && b2) { find = false; BlockRange br = new BlockRange(); br.From = s; br.To = new Point(s.X + fsx, s.Y + fsy); br.Block = data; ql.Add(br); for (int rx = s.X; rx <= br.To.X; rx++) for (int ry = s.Y; ry <= br.To.Y; ry++) { remains--; proc[rx, ry] = true; } } } }