private static PolygonOctree FindBlock(KCLModel model, PolygonOctree[] children, int x, int y, int z, int blockIdx, uint shiftR) { model.HitOctrees.Add(children[blockIdx]); if (children[blockIdx].Children != null) { shiftR--; var childBlockIdx = ((x >> (int)shiftR) & 1) | 4 * ((z >> (int)shiftR) & 1) | 2 * ((y >> (int)shiftR) & 1); return(FindBlock(model, children[blockIdx].Children, x, y, z, childBlockIdx, shiftR)); } else { return(children[blockIdx]); } }
internal static ushort[] searchBlock(KCLModel model, int x, int y, int z) { int blockIdx = 0; var shiftR = model.CoordinateShift.X; if (model.CoordinateShift.Y == ushort.MaxValue && model.CoordinateShift.Z == ushort.MaxValue) { blockIdx = 0; } else { blockIdx = ((z >> (int)shiftR) << (int)model.CoordinateShift.Z) | ((y >> (int)shiftR) << (int)model.CoordinateShift.Y) | ((x >> (int)shiftR)); } model.HitOctrees.Clear(); model.HitOctrees.Add(model.PolygonOctreeRoots[blockIdx]); var octree = FindBlock(model, model.PolygonOctreeRoots, x, y, z, blockIdx, shiftR); return(octree.TriangleIndices.ToArray()); }
private void Read(BinaryDataReader reader) { ModelOctreeRoot = new ModelOctreeNode(); ModelOctreeRoot.Children = new ModelOctreeNode[ModelOctreeNode.ChildCount]; Models = new List <KCLModel>(); reader.ByteOrder = ByteOrder.BigEndian; uint value = reader.ReadUInt32(); Version = (FileVersion)value; ByteOrder = CheckByteOrder(reader); reader.ByteOrder = this.ByteOrder; if ((FileVersion)value != FileVersion.Version2) //Assume the KCL is V1 instead { if (value == 56) //Smaller header (GCN) { Version = FileVersion.VersionGC; } else { using (reader.TemporarySeek(56, SeekOrigin.Begin)) { if (reader.ReadInt32() == 102400) { Version = FileVersion.VersionDS; } else { Version = FileVersion.VersionWII; } } } reader.Seek(-4); //Seek back and read V1 properly //V1 KCL is just a KCL model. KCLModel model = new KCLModel(); model.Read(reader, Version); Models.Add(model); //Create default model octrees that index the first model for (int i = 0; i < ModelOctreeNode.ChildCount; i++) { ModelOctreeRoot.Children[i] = new ModelOctreeNode() { ModelIndex = 0 }; } PrismCount = model.Prisms.Length; MinCoordinate = model.MinCoordinate; //Todo, auto generate the rest of V2 header data for V1 for cross conversion. } else { int octreeOffset = reader.ReadInt32(); int modelOffsetArrayOffset = reader.ReadInt32(); int modelCount = reader.ReadInt32(); MinCoordinate = reader.ReadVector3F(); MaxCoordinate = reader.ReadVector3F(); CoordinateShift = reader.ReadVector3U(); PrismCount = reader.ReadInt32(); reader.Position = octreeOffset; // Mostly unrequired, data is successive. for (int i = 0; i < ModelOctreeNode.ChildCount; i++) { ModelOctreeRoot.Children[i] = new ModelOctreeNode(reader, (uint)octreeOffset); } // Read the model offsets. reader.Position = modelOffsetArrayOffset; // Mostly unrequired, data is successive. int[] modelOffsets = reader.ReadInt32s(modelCount); Models = new List <KCLModel>(modelCount); foreach (int modelOffset in modelOffsets) { reader.Position = modelOffset; // Required as loading a model does not position reader at its end. var model = new KCLModel(); model.Read(reader, Version); Models.Add(model); } } }
internal static KCLHit CheckPoint(KCLModel model, Vector3 point, float thicknessScale, float pointDistance) { float maxDistance = model.PrismThickness * thicknessScale; int x = (int)(point.X - model.MinCoordinate.X) | 0; int y = (int)(point.Y - model.MinCoordinate.Y) | 0; int z = (int)(point.Z - model.MinCoordinate.Z) | 0; if ((x & model.CoordinateMask.X) != 0 || (y & model.CoordinateMask.Y) != 0 || (z & model.CoordinateMask.Z) != 0) { return(null); } float smallestDist = float.MaxValue; KCLHit closestHit = null; var prismIndices = searchBlock(model, x, y, z); for (int i = 0; i < prismIndices.Length; i++) { var prism = model.Prisms[prismIndices[i]]; if (prism.Length <= 0.0f) { continue; } var position = model.Positions[prism.PositionIndex]; position = point - position; //Local coordinates var edgeNormal1 = model.Normals[prism.Normal1Index]; if (Vector3.Dot(position, edgeNormal1) > 0) { continue; } var edgeNormal2 = model.Normals[prism.Normal2Index]; if (Vector3.Dot(position, edgeNormal2) > 0) { continue; } var edgeNormal3 = model.Normals[prism.Normal3Index]; if (Vector3.Dot(position, edgeNormal3) > prism.Length) { continue; } var faceNormal = model.Normals[prism.DirectionIndex]; float dist = -Vector3.Dot(faceNormal, point); // if (dist < 0.0f || dist > maxDistance) // continue; if (dist < smallestDist) { model.HitPrisms.Add(prism); smallestDist = dist; //Return with a proper hit with all checks passed. closestHit = new KCLHit() { Prism = prism, Distance = dist, }; } } return(closestHit); }