public KCLOctreeNode(EndianBinaryReader er, long BaseOffset) { DataOffset = er.ReadUInt32(); IsLeaf = (DataOffset >> 31) == 1; DataOffset &= 0x7FFFFFFF; long curpos = er.BaseStream.Position; er.BaseStream.Position = BaseOffset + DataOffset; if (IsLeaf) { er.BaseStream.Position += 2; //Skip starting zero var tris = new List <ushort>(); while (true) { ushort v = er.ReadUInt16(); if (v == 0) { break; } tris.Add((ushort)(v - 1)); } Triangles = tris.ToArray(); } else { SubNodes = new KCLOctreeNode[8]; for (int i = 0; i < 8; i++) { SubNodes[i] = new KCLOctreeNode(er, BaseOffset + DataOffset); } } er.BaseStream.Position = curpos; }
public KCLOctree(EndianBinaryReader er, int NrNodes) { long baseoffset = er.BaseStream.Position; RootNodes = new KCLOctreeNode[NrNodes]; for (int i = 0; i < NrNodes; i++) { RootNodes[i] = new KCLOctreeNode(er, baseoffset); } }
public KCLOctree(EndianBinaryReader er, int nrNodes) { long baseoffset = er.BaseStream.Position; RootNodes = new KCLOctreeNode[nrNodes]; for (int i = 0; i < nrNodes; i++) { RootNodes[i] = new KCLOctreeNode(er, baseoffset); } }
public KCLOctree(BinaryDataReader er, int NrNodes) { long baseoffset = er.BaseStream.Position; RootNodes = new KCLOctreeNode[NrNodes]; for (int i = 0; i < NrNodes; i++) { RootNodes[i] = new KCLOctreeNode(er, baseoffset); } }
/*public int NrUniqueTris * { * get { return GetNrUniqueTris(new List<ushort>()); } * } * * private int GetNrUniqueTris(List<ushort> tris) * { * if (IsLeaf) * { * int nr = 0; * foreach (ushort i in Triangles) * { * if (!tris.Contains(i)) { tris.Add(i); nr++; } * } * return nr; * } * int total = 0; * foreach (var v in SubNodes) * { * total += v.GetNrUniqueTris(tris); * } * return total; * } * * public int GetLeafMostTris() * { * if (IsLeaf) return Triangles.Length; * int maxnum = 0; * foreach (var v in SubNodes) * { * int num = v.GetLeafMostTris(); * if (num > maxnum) maxnum = num; * } * return maxnum; * } * * public int GetDepth() * { * if (IsLeaf) return 0; * int curdepth = 0; * foreach (var v in SubNodes) * { * int num = v.GetDepth() + 1; * if (num > curdepth) curdepth = num; * } * return curdepth; * }*/ public static KCLOctreeNode Generate(Dictionary <ushort, Triangle> Triangles, Vector3 Position, float BoxSize, int MaxTris, int MinSize) { var n = new KCLOctreeNode(); //Pump this box a little up, to prevent glitches var midpos = Position + new Vector3(BoxSize / 2f, BoxSize / 2f, BoxSize / 2f); float newsize = BoxSize + 50; // 60; var newpos = midpos - new Vector3(newsize / 2f, newsize / 2f, newsize / 2f); var t = new Dictionary <ushort, Triangle>(); foreach (var v in Triangles) { if (TriCubeOverlap(v.Value, newpos, newsize)) { t.Add(v.Key, v.Value); } } if (BoxSize > MinSize && t.Count > MaxTris) { n.IsLeaf = false; float childsize = BoxSize / 2f; n.SubNodes = new KCLOctreeNode[8]; int i = 0; for (int z = 0; z < 2; z++) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { Vector3 pos = Position + childsize * new Vector3(x, y, z); n.SubNodes[i] = Generate(t, pos, childsize, MaxTris, MinSize); i++; } } } } else { n.IsLeaf = true; n.Triangles = t.Keys.ToArray(); } return(n); }
public static KCLOctreeNode Generate(Dictionary <ushort, Triangle> Triangles, Vector3 Position, float BoxSize, int MaxTris, int MinSize, int TotOctree, int ActualOctre) { KCLOctreeNode n = new KCLOctreeNode(); //Pump this box a little up, to prevent glitches Vector3 midpos = Position + new Vector3(BoxSize / 2f, BoxSize / 2f, BoxSize / 2f); float newsize = BoxSize + 50;// 60; Vector3 newpos = midpos - new Vector3(newsize / 2f, newsize / 2f, newsize / 2f); Dictionary <ushort, Triangle> t = new Dictionary <ushort, Triangle>(); Console.Write("\r -Generating octree: " + ActualOctre.ToString() + "/" + TotOctree.ToString()); foreach (var v in Triangles) { if (tricube_overlap(v.Value, newpos, newsize)) { t.Add(v.Key, v.Value); } } if (BoxSize > MinSize && t.Count > MaxTris) { n.IsLeaf = false; float childsize = BoxSize / 2f; n.SubNodes = new KCLOctreeNode[8]; int i = 0; for (int z = 0; z < 2; z++) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { Vector3 pos = Position + childsize * new Vector3(x, y, z); n.SubNodes[i] = KCLOctreeNode.Generate(t, pos, childsize, MaxTris, MinSize, 8, i + 1); i++; } } } } else { n.IsLeaf = true; n.Triangles = t.Keys.ToArray(); } return(n); }
public static KCLOctree FromTriangles(Triangle[] Triangles, KCLHeader Header, int MaxRootSize = 2048, int MinRootSize = 128, int MinCubeSize = 32, int MaxNrTris = 10, MK7.KCL.BGArgs userarg = null, System.ComponentModel.BackgroundWorker worker = null) //35) { Header.Unknown1 = 30; Header.Unknown2 = 25; Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); Dictionary <ushort, Triangle> tt = new Dictionary <ushort, Triangle>(); ushort index = 0; foreach (var t in Triangles) { if (t.PointA.X < min.X) { min.X = t.PointA.X; } if (t.PointA.Y < min.Y) { min.Y = t.PointA.Y; } if (t.PointA.Z < min.Z) { min.Z = t.PointA.Z; } if (t.PointA.X > max.X) { max.X = t.PointA.X; } if (t.PointA.Y > max.Y) { max.Y = t.PointA.Y; } if (t.PointA.Z > max.Z) { max.Z = t.PointA.Z; } if (t.PointB.X < min.X) { min.X = t.PointB.X; } if (t.PointB.Y < min.Y) { min.Y = t.PointB.Y; } if (t.PointB.Z < min.Z) { min.Z = t.PointB.Z; } if (t.PointB.X > max.X) { max.X = t.PointB.X; } if (t.PointB.Y > max.Y) { max.Y = t.PointB.Y; } if (t.PointB.Z > max.Z) { max.Z = t.PointB.Z; } if (t.PointC.X < min.X) { min.X = t.PointC.X; } if (t.PointC.Y < min.Y) { min.Y = t.PointC.Y; } if (t.PointC.Z < min.Z) { min.Z = t.PointC.Z; } if (t.PointC.X > max.X) { max.X = t.PointC.X; } if (t.PointC.Y > max.Y) { max.Y = t.PointC.Y; } if (t.PointC.Z > max.Z) { max.Z = t.PointC.Z; } tt.Add(index, t); index++; } //in real mkds, 25 is subtracted from the min pos min -= new Vector3(25, 25, 25); //TODO: after that, from some of the components (may be more than one) 30 is subtracted aswell => How do I know from which ones I have to do that? //Assume the same is done for max: max += new Vector3(25, 25, 25); //TODO: +30 Header.OctreeOrigin = min; Vector3 size = max - min; float mincomp = Math.Min(Math.Min(size.X, size.Y), size.Z); int CoordShift = MathUtil.GetNearest2Power(mincomp); if (CoordShift > MathUtil.GetNearest2Power(MaxRootSize)) { CoordShift = MathUtil.GetNearest2Power(MaxRootSize); } //else if (CoordShift < Get2Power(MinRootSize)) CoordShift = Get2Power(MinRootSize); Header.CoordShift = (uint)CoordShift; int cubesize = 1 << CoordShift; int NrX = (1 << MathUtil.GetNearest2Power(size.X)) / cubesize; int NrY = (1 << MathUtil.GetNearest2Power(size.Y)) / cubesize; int NrZ = (1 << MathUtil.GetNearest2Power(size.Z)) / cubesize; if (NrX <= 0) { NrX = 1; } if (NrY <= 0) { NrY = 1; } if (NrZ <= 0) { NrZ = 1; } Header.YShift = (uint)(MathUtil.GetNearest2Power(size.X) - CoordShift); Header.ZShift = (uint)(MathUtil.GetNearest2Power(size.X) - CoordShift + MathUtil.GetNearest2Power(size.Y) - CoordShift); Header.XMask = 0xFFFFFFFF << MathUtil.GetNearest2Power(size.X); Header.YMask = 0xFFFFFFFF << MathUtil.GetNearest2Power(size.Y); Header.ZMask = 0xFFFFFFFF << MathUtil.GetNearest2Power(size.Z); KCLOctree k = new KCLOctree(); k.RootNodes = new KCLOctreeNode[NrX * NrY * NrZ]; int i = 0; if (userarg != null) { userarg.state = 2; userarg.totProg = k.RootNodes.Length; userarg.currProg = 0; } for (int z = 0; z < NrZ; z++) { for (int y = 0; y < NrY; y++) { for (int x = 0; x < NrX; x++) { Vector3 pos = min + ((float)cubesize) * new Vector3(x, y, z); k.RootNodes[i] = KCLOctreeNode.Generate(tt, pos, cubesize, MaxNrTris, MinCubeSize); i++; if (userarg != null) { if (worker.CancellationPending) { return(null); } userarg.currProg++; worker.ReportProgress(0, userarg); } } } } return(k); }
public void Write(EndianBinaryWriter er) { long basepos = er.BaseStream.Position; Queue <uint> NodeBaseOffsets = new Queue <uint>(); Queue <KCLOctreeNode> Nodes = new Queue <KCLOctreeNode>(); foreach (var v in RootNodes) { NodeBaseOffsets.Enqueue(0); Nodes.Enqueue(v); } uint offs = (uint)(RootNodes.Length * 4); while (Nodes.Count > 0) { KCLOctreeNode n = Nodes.Dequeue(); if (n.IsLeaf) { NodeBaseOffsets.Dequeue(); er.Write((uint)0); } else { n.DataOffset = offs - NodeBaseOffsets.Dequeue(); er.Write(n.DataOffset); foreach (var v in n.SubNodes) { NodeBaseOffsets.Enqueue(offs); Nodes.Enqueue(v); } offs += 8 * 4; } } foreach (var v in RootNodes) { NodeBaseOffsets.Enqueue(0); Nodes.Enqueue(v); } long leafstartpos = er.BaseStream.Position; uint relleafstartpos = offs; er.BaseStream.Position = basepos; offs = (uint)(RootNodes.Length * 4); while (Nodes.Count > 0) { KCLOctreeNode n = Nodes.Dequeue(); if (n.IsLeaf) { er.Write((uint)(0x80000000 | (relleafstartpos - NodeBaseOffsets.Dequeue() - 2))); long curpos = er.BaseStream.Position; er.BaseStream.Position = leafstartpos; foreach (var v in n.Triangles) { er.Write((ushort)(v + 1)); } er.Write((ushort)0); relleafstartpos += (uint)(n.Triangles.Length * 2) + 2; leafstartpos = er.BaseStream.Position; er.BaseStream.Position = curpos; } else { er.BaseStream.Position += 4; NodeBaseOffsets.Dequeue(); foreach (var v in n.SubNodes) { NodeBaseOffsets.Enqueue(offs); Nodes.Enqueue(v); } offs += 8 * 4; } } }
public static KCLOctree FromTriangles(Triangle[] Triangles, KCLHeader Header, int MaxRootSize = 2048, int MinRootSize = 128, int MinCubeSize = 32, int MaxNrTris = 10)//35) { Header.Unknown1 = 30; Header.Unknown2 = 25; Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); Dictionary <ushort, Triangle> tt = new Dictionary <ushort, Triangle>(); ushort index = 0; foreach (var t in Triangles) { if (t.PointA.X < min.X) { min.X = t.PointA.X; } if (t.PointA.Y < min.Y) { min.Y = t.PointA.Y; } if (t.PointA.Z < min.Z) { min.Z = t.PointA.Z; } if (t.PointA.X > max.X) { max.X = t.PointA.X; } if (t.PointA.Y > max.Y) { max.Y = t.PointA.Y; } if (t.PointA.Z > max.Z) { max.Z = t.PointA.Z; } if (t.PointB.X < min.X) { min.X = t.PointB.X; } if (t.PointB.Y < min.Y) { min.Y = t.PointB.Y; } if (t.PointB.Z < min.Z) { min.Z = t.PointB.Z; } if (t.PointB.X > max.X) { max.X = t.PointB.X; } if (t.PointB.Y > max.Y) { max.Y = t.PointB.Y; } if (t.PointB.Z > max.Z) { max.Z = t.PointB.Z; } if (t.PointC.X < min.X) { min.X = t.PointC.X; } if (t.PointC.Y < min.Y) { min.Y = t.PointC.Y; } if (t.PointC.Z < min.Z) { min.Z = t.PointC.Z; } if (t.PointC.X > max.X) { max.X = t.PointC.X; } if (t.PointC.Y > max.Y) { max.Y = t.PointC.Y; } if (t.PointC.Z > max.Z) { max.Z = t.PointC.Z; } tt.Add(index, t); index++; } //in real mkds, 25 is subtracted from the min pos //TODO: after that, from some of the components (may be more than one) 30 is subtracted aswell => How do I know from which ones I have to do that? min -= new Vector3(50f, 80f, 50f); max += new Vector3(50f, 50f, 50f); //TODO: +30 Header.OctreeOrigin = min; Header.OctreeMax = max; Vector3 size = max - min; float mincomp = Math.Min(Math.Min(size.X, size.Y), size.Z); int CoordShift = MathUtil.GetNearest2Power(mincomp); if (CoordShift > MathUtil.GetNearest2Power(MaxRootSize)) { CoordShift = MathUtil.GetNearest2Power(MaxRootSize); } //else if (CoordShift < Get2Power(MinRootSize)) CoordShift = Get2Power(MinRootSize); Header.CoordShift = (uint)CoordShift; int cubesize = 1 << CoordShift; int NrX = (1 << MathUtil.GetNearest2Power(size.X)) / cubesize; int NrY = (1 << MathUtil.GetNearest2Power(size.Y)) / cubesize; int NrZ = (1 << MathUtil.GetNearest2Power(size.Z)) / cubesize; if (NrX <= 0) { NrX = 1; } if (NrY <= 0) { NrY = 1; } if (NrZ <= 0) { NrZ = 1; } Header.YShift = (uint)(MathUtil.GetNearest2Power(size.X) - CoordShift); Header.ZShift = (uint)(MathUtil.GetNearest2Power(size.X) - CoordShift + MathUtil.GetNearest2Power(size.Y) - CoordShift); Header.XMask = 0xFFFFFFFF << MathUtil.GetNearest2Power(size.X); Header.YMask = 0xFFFFFFFF << MathUtil.GetNearest2Power(size.Y); Header.ZMask = 0xFFFFFFFF << MathUtil.GetNearest2Power(size.Z); Header.n_x = (float)KCLOctree.next_exponent(max.X - min.X); Header.n_y = (float)KCLOctree.next_exponent(max.Y - min.Y); Header.n_z = (float)KCLOctree.next_exponent(max.Z - min.Z); KCLOctree k = new KCLOctree(); k.RootNodes = new KCLOctreeNode[NrX * NrY * NrZ]; int i = 0; for (int z = 0; z < NrZ; z++) { for (int y = 0; y < NrY; y++) { for (int x = 0; x < NrX; x++) { Vector3 pos = min + ((float)cubesize) * new Vector3(x, y, z); k.RootNodes[i] = KCLOctreeNode.Generate(tt, pos, cubesize, MaxNrTris, MinCubeSize); i++; } } } return(k); }
/*public int NrUniqueTris { get { return GetNrUniqueTris(new List<ushort>()); } } private int GetNrUniqueTris(List<ushort> tris) { if (IsLeaf) { int nr = 0; foreach (ushort i in Triangles) { if (!tris.Contains(i)) { tris.Add(i); nr++; } } return nr; } int total = 0; foreach (var v in SubNodes) { total += v.GetNrUniqueTris(tris); } return total; } public int GetLeafMostTris() { if (IsLeaf) return Triangles.Length; int maxnum = 0; foreach (var v in SubNodes) { int num = v.GetLeafMostTris(); if (num > maxnum) maxnum = num; } return maxnum; } public int GetDepth() { if (IsLeaf) return 0; int curdepth = 0; foreach (var v in SubNodes) { int num = v.GetDepth() + 1; if (num > curdepth) curdepth = num; } return curdepth; }*/ public static KCLOctreeNode Generate(Dictionary<ushort, Triangle> Triangles, Vector3 Position, float BoxSize, int MaxTris, int MinSize) { KCLOctreeNode n = new KCLOctreeNode(); //Pump this box a little up, to prevent glitches Vector3 midpos = Position + new Vector3(BoxSize / 2f, BoxSize / 2f, BoxSize / 2f); float newsize = BoxSize + 50;// 60; Vector3 newpos = midpos - new Vector3(newsize / 2f, newsize / 2f, newsize / 2f); Dictionary<ushort, Triangle> t = new Dictionary<ushort, Triangle>(); foreach (var v in Triangles) { if (tricube_overlap(v.Value, newpos, newsize)) t.Add(v.Key, v.Value); } if (BoxSize > MinSize && t.Count > MaxTris) { n.IsLeaf = false; float childsize = BoxSize / 2f; n.SubNodes = new KCLOctreeNode[8]; int i = 0; for (int z = 0; z < 2; z++) { for (int y = 0; y < 2; y++) { for (int x = 0; x < 2; x++) { Vector3 pos = Position + childsize * new Vector3(x, y, z); n.SubNodes[i] = KCLOctreeNode.Generate(t, pos, childsize, MaxTris, MinSize); i++; } } } } else { n.IsLeaf = true; n.Triangles = t.Keys.ToArray(); } return n; }
public KCLOctreeNode(EndianBinaryReader er, long BaseOffset) { DataOffset = er.ReadUInt32(); IsLeaf = (DataOffset >> 31) == 1; DataOffset &= 0x7FFFFFFF; long curpos = er.BaseStream.Position; er.BaseStream.Position = BaseOffset + DataOffset; if (IsLeaf) { er.BaseStream.Position += 2;//Skip starting zero List<ushort> tris = new List<ushort>(); while (true) { ushort v = er.ReadUInt16(); if (v == 0) break; tris.Add((ushort)(v - 1)); } Triangles = tris.ToArray(); } else { SubNodes = new KCLOctreeNode[8]; for (int i = 0; i < 8; i++) { SubNodes[i] = new KCLOctreeNode(er, BaseOffset + DataOffset); } } er.BaseStream.Position = curpos; }
public static KCLOctree FromTriangles(Triangle[] Triangles, KCLHeader Header, int MinCubeSize = 32, int MaxNrTris = 50, uint MaxRootSize = 4096, uint MinRootSize = 128) //35) { Vector3D min = new Vector3D(float.MaxValue, float.MaxValue, float.MaxValue); Vector3D max = new Vector3D(float.MinValue, float.MinValue, float.MinValue); Dictionary <ushort, Triangle> tt = new Dictionary <ushort, Triangle>(); ushort index = 0; foreach (var t in Triangles) { if (t.PointA.X < min.X) { min.X = t.PointA.X; } if (t.PointA.Y < min.Y) { min.Y = t.PointA.Y; } if (t.PointA.Z < min.Z) { min.Z = t.PointA.Z; } if (t.PointA.X > max.X) { max.X = t.PointA.X; } if (t.PointA.Y > max.Y) { max.Y = t.PointA.Y; } if (t.PointA.Z > max.Z) { max.Z = t.PointA.Z; } if (t.PointB.X < min.X) { min.X = t.PointB.X; } if (t.PointB.Y < min.Y) { min.Y = t.PointB.Y; } if (t.PointB.Z < min.Z) { min.Z = t.PointB.Z; } if (t.PointB.X > max.X) { max.X = t.PointB.X; } if (t.PointB.Y > max.Y) { max.Y = t.PointB.Y; } if (t.PointB.Z > max.Z) { max.Z = t.PointB.Z; } if (t.PointC.X < min.X) { min.X = t.PointC.X; } if (t.PointC.Y < min.Y) { min.Y = t.PointC.Y; } if (t.PointC.Z < min.Z) { min.Z = t.PointC.Z; } if (t.PointC.X > max.X) { max.X = t.PointC.X; } if (t.PointC.Y > max.Y) { max.Y = t.PointC.Y; } if (t.PointC.Z > max.Z) { max.Z = t.PointC.Z; } tt.Add(index, t); index++; } //in real mkds, 25 is subtracted from the min pos min -= MarioKart.MK7.KCL.MinOffset; //TODO: after that, from some of the components (may be more than one) 30 is subtracted aswell => How do I know from which ones I have to do that? //Assume the same is done for max: max += MarioKart.MK7.KCL.MaxOffset; //TODO: +30 Header.OctreeOrigin = min; Header.OctreeMax = max; Vector3D size = max - min; float mincomp = (float)Math.Min(Math.Min(size.X, size.Y), size.Z); int CoordShift = next_exponent(mincomp); //if (CoordShift > MathUtil.GetNearest2Power((float)MaxRootSize)) // CoordShift = MathUtil.GetNearest2Power((float)MaxRootSize); if (CoordShift < next_exponent(MinRootSize)) { CoordShift = next_exponent(MinRootSize); } Header.CoordShift = (uint)CoordShift; int cubesize = 1 << CoordShift; int NrX = (1 << next_exponent(size.X)) / cubesize; int NrY = (1 << next_exponent(size.Y)) / cubesize; int NrZ = (1 << next_exponent(size.Z)) / cubesize; if (NrX <= 0) { NrX = 1; } if (NrY <= 0) { NrY = 1; } if (NrZ <= 0) { NrZ = 1; } Header.YShift = (uint)(next_exponent(size.X) - CoordShift); Header.ZShift = (uint)(next_exponent(size.X) - CoordShift + next_exponent(size.Y) - CoordShift); Header.XMask = 0xFFFFFFFF << next_exponent(size.X); Header.YMask = 0xFFFFFFFF << next_exponent(size.Y); Header.ZMask = 0xFFFFFFFF << next_exponent(size.Z); KCLOctree k = new KCLOctree(); k.RootNodes = new KCLOctreeNode[NrX * NrY * NrZ]; int i = 0; for (int z = 0; z < NrZ; z++) { for (int y = 0; y < NrY; y++) { for (int x = 0; x < NrX; x++) { Vector3D pos = min + ((float)cubesize) * new Vector3D(x, y, z); k.RootNodes[i] = KCLOctreeNode.Generate(tt, pos, cubesize, MaxNrTris, MinCubeSize); i++; } } } return(k); }