private void ReadMipTexture(DirectoryEntry directoryEntry) { var wadTexture = _textures.SingleOrDefault(t => t.Name == Encoding.ASCII.GetString(directoryEntry.Name).TrimEnd('\0')); if (wadTexture == null) { return; } _binaryReader.BaseStream.Seek(directoryEntry.FileOffset, SeekOrigin.Begin); var newMipTexture = new MipTexture(); newMipTexture.Name = _binaryReader.ReadBytes(MipTexture.TEXTURE_NAME_MAX_LENGTH); newMipTexture.Width = _binaryReader.ReadUInt32(); newMipTexture.Height = _binaryReader.ReadUInt32(); newMipTexture.DataOffsets = new UInt32[MipTexture.MIPMAP_LEVEL_COUNT]; newMipTexture.MipData = new byte[MipTexture.MIPMAP_LEVEL_COUNT][]; newMipTexture.Palette = new Color[MipTexture.PALETTE_ENTRY_COUNT]; for (int j = 0; j < MipTexture.MIPMAP_LEVEL_COUNT; j++) { newMipTexture.DataOffsets[j] = _binaryReader.ReadUInt32(); } var mipDataSize = (int)(newMipTexture.Width * newMipTexture.Height); for (int j = 0; j < MipTexture.MIPMAP_LEVEL_COUNT; j++) { _binaryReader.BaseStream.Seek(directoryEntry.FileOffset + newMipTexture.DataOffsets[j], SeekOrigin.Begin); newMipTexture.MipData[j] = _binaryReader.ReadBytes(mipDataSize); mipDataSize /= 4; } newMipTexture._dummy = _binaryReader.ReadInt16(); for (int j = 0; j < MipTexture.PALETTE_ENTRY_COUNT; j++) { var colorData = _binaryReader.ReadBytes(3); newMipTexture.Palette[j] = Color.FromArgb(0xFF, colorData[0], colorData[1], colorData[2]); } wadTexture.InitializeFromMipTexture(newMipTexture); }
internal void InitializeFromMipTexture(MipTexture mipTexture) { Width = mipTexture.Width; Height = mipTexture.Height; Mipmaps = new byte[mipTexture.MipData.Length][]; for (int i = 0; i < mipTexture.MipData.Length; i++) { Mipmaps[i] = new byte[mipTexture.MipData[i].Length]; mipTexture.MipData[i].CopyTo(Mipmaps[i], 0); } Palette = new Color[mipTexture.Palette.Length]; mipTexture.Palette.CopyTo(Palette, 0); IsInitialized = true; }
/// <summary> /// Builds the vertices and indices buffers for the given faces /// </summary> /// <param name="bspFile"></param> /// <param name="faces"></param> /// <param name="texture"></param> /// <param name="textureResourceSet"></param> /// <param name="defaultLightmapTexture"></param> /// <param name="lightmapBuilders"></param> /// <param name="vertices"></param> /// <param name="indices"></param> public static void BuildFacesBuffer( BSPFile bspFile, IReadOnlyList <Face> faces, MipTexture texture, ResourceSet textureResourceSet, Image <Rgba32> defaultLightmapTexture, List <LightmapBuilder> lightmapBuilders, List <BSPSurfaceData> vertices, List <uint> indices) { if (bspFile == null) { throw new ArgumentNullException(nameof(bspFile)); } if (faces == null) { throw new ArgumentNullException(nameof(faces)); } if (texture == null) { throw new ArgumentNullException(nameof(texture)); } if (textureResourceSet == null) { throw new ArgumentNullException(nameof(textureResourceSet)); } if (defaultLightmapTexture == null) { throw new ArgumentNullException(nameof(defaultLightmapTexture)); } if (lightmapBuilders == null) { throw new ArgumentNullException(nameof(lightmapBuilders)); } if (vertices == null) { throw new ArgumentNullException(nameof(vertices)); } if (indices == null) { throw new ArgumentNullException(nameof(indices)); } if (faces.Count == 0) { throw new ArgumentException("Cannot create a face buffer when no faces are provided", nameof(faces)); } if (lightmapBuilders.Count == 0) { throw new ArgumentException("You must provide at least one lightmap builder", nameof(lightmapBuilders)); } var lightmapBuilder = lightmapBuilders[lightmapBuilders.Count - 1]; var firstVertex = vertices.Count; var firstIndex = indices.Count; void AddTextureData() { lightmapBuilder.AddTextureData(new SingleTextureData { Texture = textureResourceSet, FirstIndex = (uint)firstIndex, IndicesCount = (uint)(indices.Count - firstIndex) }); } foreach (var face in faces) { var smax = (face.Extents[0] / 16) + 1; var tmax = (face.Extents[1] / 16) + 1; var numLightmaps = face.Styles.Count(style => style != BSPConstants.NoLightStyle); using (var lightmapTexture = CreateLightmapTexture(bspFile, face, numLightmaps, smax, tmax)) { var lightmap = lightmapTexture ?? defaultLightmapTexture; var coordinates = lightmapBuilder.TryAllocate(lightmap); if (!coordinates.HasValue) { //Lightmap is full //Add the current vertices to the full one AddTextureData(); //New starting point firstIndex = indices.Count; //Create a new one lightmapBuilder = new LightmapBuilder(lightmapBuilder.Width, lightmapBuilder.Height); lightmapBuilders.Add(lightmapBuilder); //This can't fail without throwing an exception coordinates = lightmapBuilder.TryAllocate(lightmap); } //Create triangles out of the face foreach (var i in Enumerable.Range(vertices.Count + 1, face.Points.Count - 2)) { indices.Add((uint)vertices.Count); indices.Add((uint)i); indices.Add((uint)i + 1); } var textureInfo = face.TextureInfo; foreach (var point in face.Points) { var s = Vector3.Dot(point, textureInfo.SNormal) + textureInfo.SValue; s /= texture.Width; var t = Vector3.Dot(point, textureInfo.TNormal) + textureInfo.TValue; t /= texture.Height; var lightmapS = Vector3.Dot(point, textureInfo.SNormal) + textureInfo.SValue; lightmapS -= face.TextureMins[0]; lightmapS += coordinates.Value.X * BSPConstants.LightmapScale; lightmapS += 8; lightmapS /= lightmapBuilder.Width * BSPConstants.LightmapScale; //lightmapS /= numLightmaps != 0 ? numLightmaps : 1; //Rescale X so it covers one lightmap in the texture var lightmapT = Vector3.Dot(point, textureInfo.TNormal) + textureInfo.TValue; lightmapT -= face.TextureMins[1]; lightmapT += coordinates.Value.Y * BSPConstants.LightmapScale; lightmapT += 8; lightmapT /= lightmapBuilder.Height * BSPConstants.LightmapScale; vertices.Add(new BSPSurfaceData { WorldTexture = new WorldTextureCoordinate { Vertex = point, Texture = new Vector2(s, t) }, Lightmap = new Vector2(lightmapS, lightmapT), LightmapXOffset = smax / (float)lightmapBuilder.Width, Style0 = face.Styles[0], Style1 = face.Styles[1], Style2 = face.Styles[2], Style3 = face.Styles[3] }); } } } AddTextureData(); }