public override bool Write(string file, ProcessedGeometryData data) { int tr = 0; int svt = 0; StreamWriter sw = new StreamWriter(file, false, Encoding.ASCII); StreamWriter mtlSw = null; if (data.ExportConfig.ExportMaterials) { string mtlFile = Path.Combine(Path.GetDirectoryName(file), Path.GetFileNameWithoutExtension(file)) + ".mtl"; mtlSw = new StreamWriter(mtlFile, false, Encoding.ASCII); } foreach (DataSet set in data.Data) { sw.WriteLine("o " + set.Texture); //Material name sw.WriteLine("usemtl " + set.Texture + "_mat"); sw.WriteLine(" "); sw.WriteLine("#Vertices"); for (int v = 0; v < set.verts.Count; v++) { sw.WriteLine("v " + set.verts[v].RawToString()); tr++; } if (data.ExportConfig.ExportUVs) { sw.WriteLine(" "); sw.WriteLine("#UVs"); for (int t = 0; t < set.uvs.Count; t++) { sw.WriteLine("vt " + set.uvs[t].RawToString()); } } if (data.ExportConfig.ExportNormals) { sw.WriteLine(" "); sw.WriteLine("#Normals"); for (int n = 0; n < set.normals.Count; n++) { sw.WriteLine("vn " + set.normals[n].RawToString()); } } sw.WriteLine(" "); sw.WriteLine("#Faces"); sw.WriteLine("g " + set.Texture); //Material name sw.WriteLine("s 1"); for (int f = svt; f < tr; f += 3) { int ind = f + 1; int ind2 = f + 2; int ind3 = f + 3; Vector3 normal = set.normals[f - svt]; if (normal.X > 0 || normal.Y > 0 || normal.Z < 0) { ind = f + 1; ind2 = f + 3; ind3 = f + 2; } sw.WriteLine("f " + ind.ToString() + "/" + ind.ToString() + "/" + ind.ToString() + " " + ind2.ToString() + "/" + ind2.ToString() + "/" + ind2.ToString() + " " + ind3.ToString() + "/" + ind3.ToString() + "/" + ind3.ToString()); } sw.WriteLine(" "); svt = tr; if (data.ExportConfig.ExportMaterials) { WriteMTLEntry(mtlSw, set.Texture + "_mat", set.Texture + ".png"); } } sw.Close(); if (mtlSw != null) mtlSw.Close(); return true; }
public virtual bool Write(string file, ProcessedGeometryData data) { return false; }
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; }