#if UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_5_3_OR_NEWER #define UNITY #endif using System; using System.Collections.Generic; namespace LibBSP { #if UNITY using Vector2d = UnityEngine.Vector2; using Vector3d = UnityEngine.Vector3; using Plane = UnityEngine.Plane; #elif GODOT using Vector2d = Godot.Vector2; using Vector3d = Godot.Vector3; using Plane = Godot.Plane; #endif /// /// This class contains the texture scaling information for certain formats. /// Some BSP formats lack this lump (or the information is contained in a /// different lump) so their cases will be left out. /// [Serializable] public class TextureInfo { public byte[] data; public MapType type; public int version; // No BSP format uses these so they are fields. public Vector2d scale = new Vector2d(1, 1); public double rotation = 0; public Vector3d uAxis { get { return new Vector3d(BitConverter.ToSingle(data, 0), BitConverter.ToSingle(data, 4), BitConverter.ToSingle(data, 8)); } set { value.GetBytes().CopyTo(data, 0); } } public Vector3d vAxis { get { return new Vector3d(BitConverter.ToSingle(data, 16), BitConverter.ToSingle(data, 20), BitConverter.ToSingle(data, 24)); } set { value.GetBytes().CopyTo(data, 16); } } public Vector2d translation { get { return new Vector2d(BitConverter.ToSingle(data, 12), BitConverter.ToSingle(data, 28)); } set { BitConverter.GetBytes((float)value.x).CopyTo(data, 12); BitConverter.GetBytes((float)value.y).CopyTo(data, 28); } } public int flags { get { switch (type) { case MapType.Source17: case MapType.Source18: case MapType.Source19: case MapType.Source20: case MapType.Source21: case MapType.Source22: case MapType.Source23: case MapType.Source27: case MapType.L4D2: case MapType.TacticalInterventionEncrypted: case MapType.Vindictus: { return BitConverter.ToInt32(data, 64); } case MapType.DMoMaM: { return BitConverter.ToInt32(data, 88); } case MapType.Quake: { return BitConverter.ToInt32(data, 36); } default: { return -1; } } } set { byte[] bytes = BitConverter.GetBytes(value); switch (type) { case MapType.Source17: case MapType.Source18: case MapType.Source19: case MapType.Source20: case MapType.Source21: case MapType.Source22: case MapType.Source23: case MapType.Source27: case MapType.L4D2: case MapType.TacticalInterventionEncrypted: case MapType.Vindictus: { bytes.CopyTo(data, 64); break; } case MapType.DMoMaM: { bytes.CopyTo(data, 88); break; } case MapType.Quake: { bytes.CopyTo(data, 36); break; } } } } public int texture { get { switch (type) { case MapType.Source17: case MapType.Source18: case MapType.Source19: case MapType.Source20: case MapType.Source21: case MapType.Source22: case MapType.Source23: case MapType.Source27: case MapType.L4D2: case MapType.TacticalInterventionEncrypted: case MapType.Vindictus: { return BitConverter.ToInt32(data, 68); } case MapType.DMoMaM: { return BitConverter.ToInt32(data, 92); } case MapType.Quake: { return BitConverter.ToInt32(data, 32); } default: { return -1; } } } set { byte[] bytes = BitConverter.GetBytes(value); switch (type) { case MapType.Source17: case MapType.Source18: case MapType.Source19: case MapType.Source20: case MapType.Source21: case MapType.Source22: case MapType.Source23: case MapType.Source27: case MapType.L4D2: case MapType.TacticalInterventionEncrypted: case MapType.Vindictus: { bytes.CopyTo(data, 68); break; } case MapType.DMoMaM: { bytes.CopyTo(data, 92); break; } case MapType.Quake: { bytes.CopyTo(data, 32); break; } } } } /// /// Creates a new object with sensible defaults. /// public TextureInfo() { data = new byte[40]; type = MapType.Quake; version = 0; uAxis = new Vector3d(0, 0, 0); vAxis = new Vector3d(0, 0, 0); translation = new Vector2d(0, 0); flags = 0; texture = -1; scale = new Vector2d(1, 1); rotation = 0; } /// /// Creates a new object from a byte array. /// /// byte array to parse. /// The map type. /// The version of this lump. /// was null. public TextureInfo(byte[] data, MapType type, int version = 0) { if (data == null) { throw new ArgumentNullException(); } this.data = data; this.type = type; this.version = version; scale = new Vector2d(1, 1); rotation = 0; } /// /// Creates a new object using the passed data. /// /// The U texture axis. /// The V texture axis. /// Texture translation along both axes (in pixels). /// Texture scale along both axes. /// The flags for this . /// Index into the texture list for the texture this uses. /// Rotation of the texutre axes. public TextureInfo(Vector3d u, Vector3d v, Vector2d translation, Vector2d scale, int flags, int texture, double rotation) { data = new byte[40]; type = MapType.Quake; version = 0; uAxis = u; vAxis = v; this.translation = translation; this.scale = scale; this.flags = flags; this.texture = texture; this.rotation = rotation; } /// /// Given a p, return an optimal set of texture axes for it. /// /// of the surface. /// The best matching texture axes for the given . public static Vector3d[] TextureAxisFromPlane(Plane p) { int bestaxis = p.BestAxis(); Vector3d[] newAxes = new Vector3d[2]; newAxes[0] = PlaneExtensions.baseAxes[bestaxis * 3 + 1]; newAxes[1] = PlaneExtensions.baseAxes[bestaxis * 3 + 2]; return newAxes; } /// /// Factory method to parse a byte array into a List of objects. /// /// The data to parse. /// The map type. /// The version of this lump. /// A List of objects. /// was null. /// This structure is not implemented for the given maptype. public static List LumpFactory(byte[] data, MapType type, int version = 0) { if (data == null) { throw new ArgumentNullException(); } int structLength = 0; switch (type) { case MapType.Nightfire: { structLength = 32; break; } case MapType.Quake: { structLength = 40; break; } case MapType.Source17: case MapType.Source18: case MapType.Source19: case MapType.Source20: case MapType.Source21: case MapType.Source22: case MapType.Source23: case MapType.Source27: case MapType.L4D2: case MapType.TacticalInterventionEncrypted: case MapType.Vindictus: { structLength = 72; break; } case MapType.DMoMaM: { structLength = 96; break; } default: { throw new ArgumentException("Map type " + type + " isn't supported by the Leaf lump factory."); } } int numObjects = data.Length / structLength; List lump = new List(numObjects); for (int i = 0; i < numObjects; ++i) { byte[] bytes = new byte[structLength]; Array.Copy(data, (i * structLength), bytes, 0, structLength); lump.Add(new TextureInfo(bytes, type, version)); } return lump; } /// /// Gets the index for this lump in the BSP file for a specific map format. /// /// The map type. /// Index for this lump, or -1 if the format doesn't have this lump. public static int GetIndexForLump(MapType type) { switch (type) { case MapType.Quake: case MapType.Vindictus: case MapType.TacticalInterventionEncrypted: case MapType.Source17: case MapType.Source18: case MapType.Source19: case MapType.Source20: case MapType.Source21: case MapType.Source22: case MapType.Source23: case MapType.Source27: case MapType.L4D2: case MapType.DMoMaM: { return 6; } case MapType.Nightfire: { return 17; } default: { return -1; } } } } }