Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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();
        }