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); }
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; } } }