/// <summary> /// Can build side: Input1: Block at side, Input2: Base block /// </summary> public static List<CustomBlockData> GenerateModel(List<BoundingBox> boxes, BlockSource source, Point3 blockPos, bool removeCoveredFaces, IGeometryGeneratorSource i) { BlockData currentBlock = source.GetData(blockPos); Vector3[] norms = 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) }; Dictionary<Vector3, Dictionary<float, List<Face>>> faces = new Dictionary<Vector3, Dictionary<float, List<Face>>>(); //Vector3 key: normal //float key: value of normal component //Foreach bounding box foreach (BoundingBox bb in boxes) { //Foreach normal (Minecraft normals) foreach (Vector3 normal in norms) { //Get the face for the normal Face face = GetFace(bb, normal); face.TextureTag = bb.TextureTag; //Store it using the important Normal component float val = face.GetNormalValue(); if (float.IsNaN(val)) continue; Dictionary<float, List<Face>> dict; if (faces.ContainsKey(normal)) { dict = faces[normal]; } else { dict = new Dictionary<float, List<Face>>(); faces.Add(normal, dict); } if (dict.ContainsKey(val)) dict[val].Add(face); else dict.Add(val, new List<Face>() { face }); } } List<CustomBlockData> datas = new List<CustomBlockData>(); //Foreach normal foreach (KeyValuePair<Vector3, Dictionary<float, List<Face>>> pair in faces) { //Foreach normal component foreach (KeyValuePair<float, List<Face>> pair2 in pair.Value) { //Check if we should build the side if(pair2.Key == 0 && (pair.Key.X == -1 || pair.Key.Y == -1 || pair.Key.Z == -1)) //- sides { Point3 dir3 = pair.Key.ToPoint3(); Point3 atSide = blockPos + dir3; BlockData atSideBlock = source.GetData(atSide); if (!i.CanBuildSide(currentBlock, atSideBlock, blockPos, atSide)) { continue; } } if (pair2.Key == 1 && (pair.Key.X == 1 || pair.Key.Y == 1 || pair.Key.Z == 1)) //+ sides { Point3 dir3 = pair.Key.ToPoint3(); Point3 atSide = blockPos + dir3; BlockData atSideBlock = source.GetData(atSide); if (!i.CanBuildSide(currentBlock, atSideBlock, blockPos, atSide)) { continue; } } //pair2.Value contains the faces of the current Normal and Normal component value //Let's calculate what we can see: GpcPolygon polygon = new GpcPolygon(); foreach(Face face in pair2.Value) { GpcPolygon addPoly = new GpcPolygon(); addPoly.AddContour(new GpcVertexList(face.ConvertToPointList()), false); polygon = polygon.Clip(GpcOperation.Union, addPoly); } //Remove the invisible parts Vector3 inverseNormal = -pair.Key; if (faces.ContainsKey(inverseNormal) && removeCoveredFaces) { if (faces[inverseNormal].ContainsKey(pair2.Key)) //There are faces, which make this face invisible { GpcPolygon invisible = new GpcPolygon(); foreach (Face face2 in faces[inverseNormal][pair2.Key]) { GpcPolygon addPoly = new GpcPolygon(); addPoly.AddContour(new GpcVertexList(face2.ConvertToPointList()), false); invisible = invisible.Clip(GpcOperation.Union, addPoly); } polygon = polygon.Clip(GpcOperation.Difference, invisible); //Remove the invisible parts } } //Create the face if (polygon.NofContours == 0) continue; foreach (GpcVertexList polys in polygon.Contour) { List<PolygonPoint> points = new List<PolygonPoint>(); foreach (GpcVertex vert in polys.Vertex) { points.Add(new PolygonPoint(vert.X, vert.Y)); } Polygon triangulatorPoly = new Polygon(points); //MAGIC :D Triangulator.Triangulate(triangulatorPoly); foreach (DelaunayTriangle tri in triangulatorPoly.Triangles) { CustomBlockData bd = new CustomBlockData(); bd.IsOneTriangle = true; bd.Texture = i.GetTexture(pair2.Value[0]); bd.Vertex1 = ConvertToVertexPosition(tri.Points[0], pair.Key, pair2.Key); bd.Vertex2 = ConvertToVertexPosition(tri.Points[1], pair.Key, pair2.Key); bd.Vertex3 = ConvertToVertexPosition(tri.Points[2], pair.Key, pair2.Key); Vector2[] uvs = new Vector2[]{ new Vector2(tri.Points[0].Xf, tri.Points[0].Yf), new Vector2(tri.Points[1].Xf, tri.Points[1].Yf), new Vector2(tri.Points[2].Xf, tri.Points[2].Yf) }; uvs = i.GetUVsForTriangle(uvs, pair2.Value[0]); bd.UV1 = uvs[0]; bd.UV2 = uvs[1]; bd.UV3 = uvs[2]; bd.Normal = pair.Key; datas.Add(bd); } } } } return datas; }
private void WriteCustomData(CustomBlockData range, ref Dictionary<string, DataSet> datas) { DataSet foundSet = null; if (datas.ContainsKey(range.Texture)) foundSet = datas[range.Texture]; else { foundSet = new DataSet(); foundSet.BaseData = range.Source; foundSet.Texture = range.Texture; datas.Add(range.Texture, foundSet); } Vector3 normal = range.Normal; //BlockSide side = Block.GetSideFromNormal(normal); //Block bl = Block.Blocks[range.Source.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 = range.Texture;//bl.GetTextureForSide(side, range.Source.Metadata); // int[] ids = Find(bl.GetTextures(range.Source.Metadata), tex); // DataSet[] ds = new DataSet[ids.Length]; // KeyStruct key = new KeyStruct() // { // ID = range.Source.ID, // Metadata = range.Source.Metadata, // SideByte = sideByte, // }; // for (int s = 0; s < ids.Length; s++) // { // KeyStruct k = new KeyStruct() // { // ID = range.Source.ID, // Metadata = range.Source.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; // } //} //if (foundSet == null) //{ // KeyStruct key = new KeyStruct() // { // ID = range.Source.ID, // Metadata = range.Source.Metadata, // SideByte = sideByte // }; // if (!datas.ContainsKey(key)) // { // datas.Add(key, new DataSet()); // datas[key].BaseData = range.Source; // datas[key].SideByte = sideByte; // foundSet = datas[key]; // } // else // { // foundSet = datas[key]; // } //} //tri1: 1,2,3 //tri2: 3,4,1 //Vector3 tri1Norm = Vector3.Cross((range.Vertex2 - range.Vertex1), (range.Vertex3 - range.Vertex1)); //Vector3 tri2Norm = Vector3.Cross((range.Vertex3 - range.Vertex1), (range.Vertex4 - range.Vertex1)); Vector3 tri1Norm = normal; Vector3 tri2Norm = normal; if (range.TriFlip)// || (!range.TriFlip && (normal.X < 0 || normal.Y < 0 || normal.Z < 0))) { WriteTriangle(foundSet, range.Vertex3, range.Vertex2, range.Vertex1, range.UV3, range.UV2, range.UV1, tri1Norm); if (!range.IsOneTriangle) { WriteTriangle(foundSet, range.Vertex1, range.Vertex4, range.Vertex3, range.UV1, range.UV4, range.UV3, tri2Norm); } } else { WriteTriangle(foundSet, range.Vertex1, range.Vertex2, range.Vertex3, range.UV1, range.UV2, range.UV3, tri1Norm); if (!range.IsOneTriangle) { WriteTriangle(foundSet, range.Vertex3, range.Vertex4, range.Vertex1, range.UV3, range.UV4, range.UV1, tri2Norm); } } if (range.DoubleSided) { range.DoubleSided = false; range.Normal = -range.Normal; WriteCustomData(range, ref datas); } }