Example #1
0
        public void LoadBSP(String FileName)
        {
            FileStream MapFile = new FileStream(FileName, FileMode.Open);
            byte[] MapData = new byte[MapFile.Length];

            //Read in data
            MapFile.Read(MapData, 0, (int)MapFile.Length);

            //Read from in memory data
            BinaryReader InputFile = new BinaryReader( new MemoryStream(MapData) );

            //Read in header
            Header.ID = Encoding.ASCII.GetString(InputFile.ReadBytes(4), 0, 4);
            Header.Version = InputFile.ReadInt32();

            for (int i=0; i<MaxLumps; i++)
            {
                Lumps[i] = new BSPLump();
                Lumps[i].Offset = InputFile.ReadInt32();
                Lumps[i].Length = InputFile.ReadInt32();
            }

            if ( (Header.ID != "IBSP") && (Header.Version != 0x2E) )
            {
                throw new System.Exception("Wrong file type or version");
            }

            //Allocate vertices
            NumVertices = Lumps[(int)LumpType.Vertices].Length / VertexSizeInBytes;
            Vertices = new float[NumVertices * 3];
            TextureCoords = new float[NumVertices * 2];
            LightmapCoords = new float[NumVertices * 2];

            //Allocate faces
            NumFaces = Lumps[(int)LumpType.Faces].Length / BSPFace.SizeInBytes;
            Faces = new BSPFace[NumFaces];

            //Allocate textures
            NumTextures = Lumps[(int)LumpType.Textures].Length / BSPTexture.SizeInBytes;
            LoadTextures = new BSPTexture[NumTextures];
            Textures = new Texture[NumTextures];

            //Allocate lightmaps
            NumLightmaps = Lumps[(int)LumpType.Lightmaps].Length / BSPLightmap.SizeInBytes;
            Lightmaps = new Texture[NumLightmaps];

            //Allocate nodes
            NumNodes = Lumps[(int)LumpType.Nodes].Length / BSPNode.SizeInBytes;
            Nodes = new BSPNode[NumNodes];

            //Allocate leaves
            NumLeaves = Lumps[(int)LumpType.Leaves].Length / BSPLeaf.SizeInBytes;
            Leaves = new BSPLeaf[NumLeaves];

            //Allocate leaf faces
            NumLeafFaces = Lumps[(int)LumpType.LeafFaces].Length / LeafFaceSizeInBytes;
            LeafFaces = new int[NumLeafFaces];

            //Allocate planes
            NumPlanes = Lumps[(int)LumpType.Planes].Length / BSPPlane.SizeInBytes;
            Planes = new BSPPlane[NumPlanes];

            //Allocate mesh indices
            NumMeshIndices = Lumps[(int)LumpType.MeshIndices].Length / MeshIndexSizeInBytes;
            MeshIndices = new uint[NumMeshIndices];

            //Allocate models
            NumModels = Lumps[(int)LumpType.Models].Length / BSPModel.SizeInBytes;
            Models = new BSPModel[NumModels];

            //Allocate brushes
            NumBrushes = Lumps[(int)LumpType.Brushes].Length / BSPBrush.SizeInBytes;
            Brushes = new BSPBrush[NumBrushes];

            //Allocate brush sides
            NumBrushSides = Lumps[(int)LumpType.BrushSides].Length / BSPBrushSide.SizeInBytes;
            BrushSides = new BSPBrushSide[NumBrushSides];

            //Allocate leaf brushes
            NumLeafBrushes = Lumps[(int)LumpType.LeafBrushes].Length / LeafBrushSizeInBytes;
            LeafBrushes = new int[NumLeafBrushes];

            //Allocate shaders
            NumShaders = Lumps[(int)LumpType.Shaders].Length / BSPShader.SizeInBytes;
            Shaders = new BSPShader[NumShaders];

            //Allocate visibility data
            Clusters = new BSPVisData();

            //Calculate entity string length
            EntityStringLength = Lumps[(int)LumpType.Entities].Length;

            //=============
            //Entity String
            //=============
            InputFile.BaseStream.Seek(Lumps[(int)LumpType.Entities].Offset, SeekOrigin.Begin);
            byte[] EntityData = InputFile.ReadBytes(EntityStringLength);
            foreach (byte EntityByte in EntityData)
            {
                char EntityChar = Convert.ToChar(EntityByte);

                if (EntityChar != '\0')
                {
                    EntityString += EntityChar;
                }
            }

            //Generate entity collection
            Entities = new BSPEntityCollection(EntityString);

            //Seek "ambient" value of "worldspawn" entity
            String Ambient = Entities.SeekFirstEntityValue("worldspawn", "ambient");

            try
            {
                Gamma = float.Parse(Ambient);
                Gamma /= 17.0f;
            }
            catch
            {
                //Do nothing
            }

            //Seek "trigger_multiple" entities
            BSPEntity[] BSPTriggers = Entities.SeekEntitiesByClassname("trigger_multiple");

            if (BSPTriggers.Length > 0)
            {
                //Create list
                Triggers = new Trigger[BSPTriggers.Length];

                int TriggerIndex = 0;
                foreach(BSPEntity CurrentTrigger in BSPTriggers)
                {
                    try
                    {
                        Trigger NewTrigger = new Trigger();

                        //Parse name
                        NewTrigger.Name = CurrentTrigger.SeekFirstValue("trigger_name");

                        String Model = CurrentTrigger.SeekFirstValue("model");
                        Model = Model.Replace("*", String.Empty);

                        NewTrigger.ModelIndex = int.Parse(Model);

                        //Add to hash table
                        IndexTriggerHash[ NewTrigger.ModelIndex ] = NewTrigger;

                        //Add to list
                        Triggers[TriggerIndex] = NewTrigger;

                        //Next trigger
                        TriggerIndex++;
                    }
                    catch
                    {
                        //Do nothing
                    }
                }
            }

            //========
            //Vertices
            //========
            int CurrentVertex = 0;
            int CurrentTextureCoord = 0;

            int VerticesOffset = Lumps[(int)LumpType.Vertices].Offset;
            for (int i=0; i<NumVertices; i++)
            {
                InputFile.BaseStream.Seek(VerticesOffset + (i * VertexSizeInBytes), SeekOrigin.Begin);

                //Swap Y and Z values; negate Z
                Vertices[CurrentVertex] = InputFile.ReadSingle();
                Vertices[CurrentVertex + 2] = -InputFile.ReadSingle();
                Vertices[CurrentVertex + 1] = InputFile.ReadSingle();

                TextureCoords[CurrentTextureCoord] = InputFile.ReadSingle();

                //Negate V texture coordinate
                TextureCoords[CurrentTextureCoord + 1] = -InputFile.ReadSingle();

                LightmapCoords[CurrentTextureCoord] = InputFile.ReadSingle();

                //Negate V texture coordinate
                LightmapCoords[CurrentTextureCoord + 1] = -InputFile.ReadSingle();

                //Shift
                CurrentVertex += 3;
                CurrentTextureCoord += 2;
            }

            //=====
            //Faces
            //=====
            int FacesOffset = Lumps[(int)LumpType.Faces].Offset;
            for (int i=0; i<NumFaces; i++)
            {
                InputFile.BaseStream.Seek(FacesOffset + (i * BSPFace.SizeInBytes), SeekOrigin.Begin);

                Faces[i] = new BSPFace();
                Faces[i].TextureID = InputFile.ReadInt32();
                Faces[i].Effect = InputFile.ReadInt32();
                Faces[i].Type = InputFile.ReadInt32();
                Faces[i].StartVertexIndex = InputFile.ReadInt32();
                Faces[i].NumVertices = InputFile.ReadInt32();
                Faces[i].MeshVertexIndex = InputFile.ReadInt32();
                Faces[i].NumMeshVertices = InputFile.ReadInt32();
                Faces[i].LightmapID = InputFile.ReadInt32();

                Faces[i].MapCorner[0] = InputFile.ReadInt32();
                Faces[i].MapCorner[1] = InputFile.ReadInt32();

                Faces[i].MapSize[0] = InputFile.ReadInt32();
                Faces[i].MapSize[1] = InputFile.ReadInt32();

                Faces[i].MapPosition.X = InputFile.ReadSingle();
                Faces[i].MapPosition.Y = InputFile.ReadSingle();
                Faces[i].MapPosition.Z = InputFile.ReadSingle();

                Faces[i].MapVectors[0].X = InputFile.ReadSingle();
                Faces[i].MapVectors[0].Y = InputFile.ReadSingle();
                Faces[i].MapVectors[0].Z = InputFile.ReadSingle();

                Faces[i].MapVectors[1].X = InputFile.ReadSingle();
                Faces[i].MapVectors[1].Y = InputFile.ReadSingle();
                Faces[i].MapVectors[1].Z = InputFile.ReadSingle();

                Faces[i].Normal.X = InputFile.ReadSingle();
                Faces[i].Normal.Y = InputFile.ReadSingle();
                Faces[i].Normal.Z = InputFile.ReadSingle();

                Faces[i].Size[0] = InputFile.ReadInt32();
                Faces[i].Size[1] = InputFile.ReadInt32();
            }

            //========
            //Textures
            //========
            InputFile.BaseStream.Seek(Lumps[(int)LumpType.Textures].Offset, SeekOrigin.Begin);
            for(int i=0; i<NumTextures; i++)
            {
                LoadTextures[i] = new BSPTexture();

                byte[] NameBytes = InputFile.ReadBytes(64);
                for (int NameByteIndex=0; NameByteIndex<64; NameByteIndex++)
                {
                    if (NameBytes[NameByteIndex] != '\0')
                    {
                        LoadTextures[i].Name += Convert.ToChar(NameBytes[NameByteIndex]);
                    }
                }

                LoadTextures[i].Flags = InputFile.ReadInt32();
                LoadTextures[i].Contents = InputFile.ReadInt32();

                //Check for skybox texture
                if (LoadTextures[i].Name.IndexOf("bookstore/no_draw") != -1)
                {
                    NoDrawTextureIndex = i;
                }
            }

            //Load textures
            for (int i=0; i<NumTextures; i++)
            {
                String JpgFile = LoadTextures[i].Name + ".jpg";
                String TgaFile = LoadTextures[i].Name + ".tga";

                //try
                {
                    if (File.Exists(JpgFile))
                    {
                        Textures[i] = Root.Instance.ResourceManager.LoadTexture(JpgFile);
                    }
                    else if (File.Exists(TgaFile))
                    {
                        Textures[i] = Root.Instance.ResourceManager.LoadTexture(TgaFile);
                    }
                    else
                    {
                        //Mark as not loaded
                        Console.WriteLine("cant find " + JpgFile + " or " + TgaFile);
                        Textures[i] = null;
                    }
                }
                //catch
                {
                    //Mark as not loaded
                    //Textures[i] = null;
                }
            }

            //Load skybox textures
            SkyBoxTextures = new Texture[6];

            //Load depending on the time
            String SkyDir = "day";
            int Hour = DateTime.Now.Hour;

            if ( (Hour > 6) && (Hour < 8) )
            {
                SkyDir = "dawn";
            }
            else if ( (Hour >= 8) && (Hour < 18) )
            {
                SkyDir = "day";
            }
            else if ( (Hour >= 18) && (Hour < 21) )
            {
                SkyDir = "dusk";
            }
            else
            {
                SkyDir = "night";
            }
            /*
            SkyBoxTextures[0] = Root.Instance.ResourceManager.LoadTexture(@"textures\bookstore\skies\" + SkyDir + @"\negx.jpg", true);
            SkyBoxTextures[1] = Root.Instance.ResourceManager.LoadTexture(@"textures\bookstore\skies\" + SkyDir + @"\negy.jpg", true);
            SkyBoxTextures[2] = Root.Instance.ResourceManager.LoadTexture(@"textures\bookstore\skies\" + SkyDir + @"\negz.jpg", true);
            SkyBoxTextures[3] = Root.Instance.ResourceManager.LoadTexture(@"textures\bookstore\skies\" + SkyDir + @"\posx.jpg", true);
            SkyBoxTextures[4] = Root.Instance.ResourceManager.LoadTexture(@"textures\bookstore\skies\" + SkyDir + @"\posy.jpg", true);
            SkyBoxTextures[5] = Root.Instance.ResourceManager.LoadTexture(@"textures\bookstore\skies\" + SkyDir + @"\posz.jpg", true);
            */
            //=========
            //Lightmaps
            //=========
            InputFile.BaseStream.Seek(Lumps[(int)LumpType.Lightmaps].Offset, SeekOrigin.Begin);
            for (int i=0; i<NumLightmaps; i++)
            {
                byte[] InputData = InputFile.ReadBytes(BSPLightmap.SizeInBytes);
                /*Bitmap ImageData = new Bitmap(128, 128);

                int ByteIndex = 0;
                for (int y=0; y<128; y++)
                {
                    for (int x=0; x<128; x++)
                    {
                        byte R = InputData[ByteIndex];
                        byte G = InputData[ByteIndex + 1];
                        byte B = InputData[ByteIndex + 2];

                        ImageData.SetPixel( x, y, Color.FromArgb(R, G, B) );
                        ByteIndex += 3;
                    }
                }

                //Alter gamma
                ChangeGamma(ref ImageData, Gamma);*/

                //Copy back
                Lightmaps[i] = new Texture(Root.Instance.UserInterface.Renderer.CreateTexture(InputData,128,128,false));
            }

            //=====
            //Nodes
            //=====
            int NodesOffset = Lumps[(int)LumpType.Nodes].Offset;
            for (int i=0; i<NumNodes; i++)
            {
                InputFile.BaseStream.Seek(NodesOffset + (i * BSPNode.SizeInBytes), SeekOrigin.Begin);

                Nodes[i] = new BSPNode();

                Nodes[i].Plane = InputFile.ReadInt32();
                Nodes[i].Front = InputFile.ReadInt32();
                Nodes[i].Back = InputFile.ReadInt32();

                //Swap Y and Z; invert Z
                Nodes[i].Min.X = InputFile.ReadInt32();
                Nodes[i].Min.Z = -InputFile.ReadInt32();
                Nodes[i].Min.Y = InputFile.ReadInt32();

                //Swap Y and Z; invert Z
                Nodes[i].Max.X = InputFile.ReadInt32();
                Nodes[i].Max.Z = -InputFile.ReadInt32();
                Nodes[i].Max.Y = InputFile.ReadInt32();
            }

            //======
            //Leaves
            //======
            int LeavesOffset = Lumps[(int)LumpType.Leaves].Offset;
            for (int i=0; i<NumLeaves; i++)
            {
                InputFile.BaseStream.Seek(LeavesOffset + (i * BSPLeaf.SizeInBytes), SeekOrigin.Begin);

                Leaves[i] = new BSPLeaf();

                Leaves[i].Cluster = InputFile.ReadInt32();
                Leaves[i].Area = InputFile.ReadInt32();

                //Swap Y and Z; invert Z
                Leaves[i].Min.X = InputFile.ReadInt32();
                Leaves[i].Min.Z = -InputFile.ReadInt32();
                Leaves[i].Min.Y = InputFile.ReadInt32();

                //Swap Y and Z; invert Z
                Leaves[i].Max.X = InputFile.ReadInt32();
                Leaves[i].Max.Z = -InputFile.ReadInt32();
                Leaves[i].Max.Y = InputFile.ReadInt32();

                Leaves[i].LeafFace = InputFile.ReadInt32();
                Leaves[i].NumLeafFaces = InputFile.ReadInt32();
                Leaves[i].LeafBrush = InputFile.ReadInt32();
                Leaves[i].NumLeafBrushes = InputFile.ReadInt32();
            }

            //==========
            //Leaf Faces
            //==========
            InputFile.BaseStream.Seek(Lumps[(int)LumpType.LeafFaces].Offset, SeekOrigin.Begin);
            for (int i=0; i<NumLeafFaces; i++)
            {
                LeafFaces[i] = InputFile.ReadInt32();
            }

            //======
            //Planes
            //======
            int PlanesOffset = Lumps[(int)LumpType.Planes].Offset;
            for (int i=0; i<NumPlanes; i++)
            {
                InputFile.BaseStream.Seek(PlanesOffset + (i * BSPPlane.SizeInBytes), SeekOrigin.Begin);

                Planes[i] = new BSPPlane();

                //Swap Y and Z; invert Z
                Planes[i].Normal.X = InputFile.ReadSingle();
                Planes[i].Normal.Z = -InputFile.ReadSingle();
                Planes[i].Normal.Y = InputFile.ReadSingle();
                Planes[i].Distance = InputFile.ReadSingle();
            }

            //============
            //Mesh Indices
            //============
            InputFile.BaseStream.Seek(Lumps[(int)LumpType.MeshIndices].Offset, SeekOrigin.Begin);
            for (int i=0; i<NumMeshIndices; i++)
            {
                MeshIndices[i] = InputFile.ReadUInt32();
            }

            //======
            //Models
            //======
            int ModelsOffset = Lumps[(int)LumpType.Models].Offset;
            for (int i=0; i<NumModels; i++)
            {
                InputFile.BaseStream.Seek(ModelsOffset + (i * BSPModel.SizeInBytes), SeekOrigin.Begin);

                Models[i] = new BSPModel();

                //Swap Y and Z; negate Y
                Models[i].Mins[0] = InputFile.ReadSingle();
                Models[i].Maxes[2] = -InputFile.ReadSingle();
                Models[i].Mins[1] = InputFile.ReadSingle();

                //Swap Y and Z; negate Y
                Models[i].Maxes[0] = InputFile.ReadSingle();
                Models[i].Mins[2] = -InputFile.ReadSingle();
                Models[i].Maxes[1] = InputFile.ReadSingle();

                Models[i].FirstFace = InputFile.ReadInt32();
                Models[i].NumFaces = InputFile.ReadInt32();
                Models[i].FirstBrush = InputFile.ReadInt32();
                Models[i].NumBrushes = InputFile.ReadInt32();
            }

            //=======
            //Brushes
            //=======
            int BrushesOffset = Lumps[(int)LumpType.Brushes].Offset;
            for (int i=0; i<NumBrushes; i++)
            {
                InputFile.BaseStream.Seek(BrushesOffset + (i * BSPBrush.SizeInBytes), SeekOrigin.Begin);

                Brushes[i] = new BSPBrush();

                Brushes[i].FirstSide = InputFile.ReadInt32();
                Brushes[i].NumSides = InputFile.ReadInt32();
                Brushes[i].TextureIndex = InputFile.ReadInt32();
            }

            //===========
            //Brush Sides
            //===========
            int BrushSidesOffset = Lumps[(int)LumpType.BrushSides].Offset;
            for (int i=0; i<NumBrushSides; i++)
            {
                InputFile.BaseStream.Seek(BrushSidesOffset + (i * BSPBrushSide.SizeInBytes), SeekOrigin.Begin);

                BrushSides[i] = new BSPBrushSide();

                BrushSides[i].Plane = InputFile.ReadInt32();
                BrushSides[i].Texture = InputFile.ReadInt32();
            }

            //============
            //Leaf Brushes
            //============
            InputFile.BaseStream.Seek(Lumps[(int)LumpType.LeafBrushes].Offset, SeekOrigin.Begin);
            for (int i=0; i<NumLeafBrushes; i++)
            {
                LeafBrushes[i] = InputFile.ReadInt32();
            }

            //=======
            //Shaders
            //=======
            int ShadersOffset = Lumps[(int)LumpType.Shaders].Offset;
            for (int i=0; i<NumShaders; i++)
            {
                InputFile.BaseStream.Seek(ShadersOffset + (i * BSPShader.SizeInBytes), SeekOrigin.Begin);

                Shaders[i] = new BSPShader();

                byte[] NameBytes = InputFile.ReadBytes(64);
                for (int NameByteIndex=0; NameByteIndex<64; NameByteIndex++)
                {
                    if (NameBytes[NameByteIndex] != '\0')
                    {
                        Shaders[i].Name += Convert.ToChar(NameBytes[NameByteIndex]);
                    }
                }

                Shaders[i].BrushIndex = InputFile.ReadInt32();
                Shaders[i].ContentFlags = InputFile.ReadInt32();
            }

            //===============
            //Visibility Data
            //===============
            InputFile.BaseStream.Seek(Lumps[(int)LumpType.VisData].Offset, SeekOrigin.Begin);

            if (Lumps[(int)LumpType.VisData].Length > 0)
            {
                Clusters.NumClusters = InputFile.ReadInt32();
                Clusters.BytesPerCluster = InputFile.ReadInt32();

                int ClusterSize = Clusters.NumClusters * Clusters.BytesPerCluster;
                Clusters.BitSets = InputFile.ReadBytes(ClusterSize);
            }

            //Finished
            InputFile.Close();

            //=============
            //No draw faces
            //=============

            //Eliminate no draw faces
            if (NoDrawTextureIndex != -1)
            {
                for (int i=0; i<Faces.Length; i++)
                {
                    if (Faces[i].TextureID == NoDrawTextureIndex)
                    {
                        Faces[i] = null;
                    }
                }
            }

            //Create bit array
            FacesDrawn = new BitArray(NumFaces, false);
        }
Example #2
0
        private void CheckBrush(BSPBrush CurrentBrush)
        {
            float StartFraction = -1.0f;
            float EndFraction = 1.0f;
            bool StartsOut = false;
            bool EndsOut = false;
            float PlaneDistance = 0.0f;

            Vector3 CanidateNormal = new Vector3();

            //Loop through brush sides
            for (int i = 0; i < CurrentBrush.NumSides; i++)
            {
                BSPBrushSide CurrentSide = BrushSides[CurrentBrush.FirstSide + i];
                BSPPlane CurrentPlane = Planes[CurrentSide.Plane];

                //Compute distances from intitial vectors
                float StartDistance = 0.0f, EndDistance = 0.0f;

                if (CollisionType == CollisionTypes.Box)
                {
                    Vector3 VOffset = new Vector3();

                    if (CurrentPlane.Normal.X < 0)
                    {
                        VOffset.X = CollisionMax.X;
                    }
                    else
                    {
                        VOffset.X = CollisionMin.X;
                    }

                    if (CurrentPlane.Normal.Y < 0)
                    {
                        VOffset.Y = CollisionMax.Y;
                    }
                    else
                    {
                        VOffset.Y = CollisionMin.Y;
                    }

                    if (CurrentPlane.Normal.Z < 0)
                    {
                        VOffset.Z = CollisionMax.Z;
                    }
                    else
                    {
                        VOffset.Z = CollisionMin.Z;
                    }

                    StartDistance = (((CollisionStart.X + VOffset.X) * CurrentPlane.Normal.X) +
                        ((CollisionStart.Y + VOffset.Y) * CurrentPlane.Normal.Y) +
                        ((CollisionStart.Z + VOffset.Z) * CurrentPlane.Normal.Z)) - CurrentPlane.Distance;

                    EndDistance = (((CollisionEnd.X + VOffset.X) * CurrentPlane.Normal.X) +
                        ((CollisionEnd.Y + VOffset.Y) * CurrentPlane.Normal.Y) +
                        ((CollisionEnd.Z + VOffset.Z) * CurrentPlane.Normal.Z)) - CurrentPlane.Distance;
                }
                else
                {
                    //Ray and sphere
                    StartDistance = (CurrentPlane.Normal.X * CollisionStart.X) + (CurrentPlane.Normal.Y * CollisionStart.Y)
                        + (CurrentPlane.Normal.Z * CollisionStart.Z) - CurrentPlane.Distance - CollisionOffset;

                    EndDistance = (CurrentPlane.Normal.X * CollisionEnd.X) + (CurrentPlane.Normal.Y * CollisionEnd.Y)
                        + (CurrentPlane.Normal.Z * CollisionEnd.Z) - CurrentPlane.Distance - CollisionOffset;
                }

                if (StartDistance > 0)
                {
                    StartsOut = true;
                }

                if (EndDistance > 0)
                {
                    EndsOut = true;
                }

                //Outside of brush
                if ((StartDistance > 0) && (EndDistance > 0))
                {
                    return;
                }

                //Will be clipped by another side
                if ((StartDistance <= 0) && (EndDistance <= 0))
                {
                    continue;
                }

                if (StartDistance > EndDistance)
                {
                    float Fraction = (StartDistance - QuakeEpsilon) / (StartDistance - EndDistance);
                    if (Fraction > StartFraction)
                    {
                        StartFraction = Fraction;
                        CanidateNormal = CurrentPlane.Normal;
                        PlaneDistance = CurrentPlane.Distance;
                    }
                }
                else
                {
                    float Fraction = (StartDistance + QuakeEpsilon) / (StartDistance - EndDistance);
                    if (Fraction < EndFraction)
                    {
                        EndFraction = Fraction;
                    }
                }
            }

            //Done checking sides
            if (StartsOut == false)
            {
                CollisionInfo.StartsOut = false;

                if (EndsOut == false)
                {
                    CollisionInfo.AllSolid = true;
                }

                return;
            }

            if (StartFraction < EndFraction)
            {
                if ((StartFraction > -1) && (StartFraction < CollisionInfo.Fraction))
                {
                    if (StartFraction < 0)
                    {
                        StartFraction = 0;
                    }

                    CollisionInfo.Fraction = StartFraction;
                    CollisionInfo.Normal = CanidateNormal;
                    CollisionInfo.PlaneDistance = PlaneDistance;
                }
            }
        }