/// <summary>
        /// Equalizes the size of the textures by scaling to the largest known texture size
        /// </summary>
        /// <param name="texMapData">The texture map data containing the texture bytes</param>
        /// <returns>The width and height that the textures were equalized to.</returns>
        private (int Width, int Height) EqualizeTextureSizes(TexMapData texMapData)
        {
            // Normal map is chosen because almost every item has a normal map, diffuse is chosen otherwise
            var width       = 0;
            var height      = 0;
            var largestSize = 0;

            if (texMapData.Normal != null)
            {
                width       = texMapData.Normal.Width;
                height      = texMapData.Normal.Height;
                largestSize = width * height;
            }
            else if (texMapData.Diffuse != null)
            {
                width       = texMapData.Diffuse.Width;
                height      = texMapData.Diffuse.Height;
                largestSize = width * height;
            }

            var scaleDown = false;
            var scale     = 1;

            if (texMapData.Normal != null)
            {
                var size = texMapData.Normal.Width * texMapData.Normal.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Normal.Width;
                    height      = texMapData.Normal.Height;
                }
            }

            if (texMapData.Diffuse != null)
            {
                var size = texMapData.Diffuse.Width * texMapData.Diffuse.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Diffuse.Width;
                    height      = texMapData.Diffuse.Height;
                }
            }

            if (texMapData.Specular != null)
            {
                var size = texMapData.Specular.Width * texMapData.Specular.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Specular.Width;
                    height      = texMapData.Specular.Height;
                }
            }

            if (texMapData.Multi != null)
            {
                var size = texMapData.Multi.Width * texMapData.Multi.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Multi.Width;
                    height      = texMapData.Multi.Height;
                }
            }

            if (texMapData.Skin != null)
            {
                var size = texMapData.Skin.Width * texMapData.Skin.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Skin.Width;
                    height      = texMapData.Skin.Height;
                }
            }

            if (width > 4000 || height > 4000)
            {
                scale     = 4;
                scaleDown = true;
            }
            //else if (width > 2000 || height > 2000)
            //{
            //    scale = 2;
            //    scaleDown = true;
            //}

            width       = width / scale;
            height      = height / scale;
            largestSize = width * height;

            if (texMapData.Normal != null && largestSize > texMapData.Normal.Width * texMapData.Normal.Height || scaleDown)
            {
                var pixelSettings =
                    new PixelReadSettings(texMapData.Normal.Width, texMapData.Normal.Height, StorageType.Char, PixelMapping.RGBA);

                using (var image = new MagickImage(texMapData.Normal.Data, pixelSettings))
                {
                    var size = new MagickGeometry(width, height);
                    size.IgnoreAspectRatio = true;
                    image.Resize(size);

                    texMapData.Normal.Width  = width;
                    texMapData.Normal.Height = height;

                    texMapData.Normal.Data = image.ToByteArray(MagickFormat.Rgba);
                }
            }

            if (texMapData.Diffuse != null && (largestSize > texMapData.Diffuse.Width * texMapData.Diffuse.Height || scaleDown))
            {
                var pixelSettings =
                    new PixelReadSettings(texMapData.Diffuse.Width, texMapData.Diffuse.Height, StorageType.Char, PixelMapping.RGBA);

                using (var image = new MagickImage(texMapData.Diffuse.Data, pixelSettings))
                {
                    image.Alpha(AlphaOption.Off);
                    var size = new MagickGeometry(width, height);
                    size.IgnoreAspectRatio = true;
                    image.Resize(size);

                    texMapData.Diffuse.Width  = width;
                    texMapData.Diffuse.Height = height;

                    texMapData.Diffuse.Data = image.ToByteArray(MagickFormat.Rgba);
                }
            }

            if (texMapData.Specular != null && (largestSize > texMapData.Specular.Width * texMapData.Specular.Height || scaleDown))
            {
                var pixelSettings =
                    new PixelReadSettings(texMapData.Specular.Width, texMapData.Specular.Height, StorageType.Char, PixelMapping.RGBA);

                using (var image = new MagickImage(texMapData.Specular.Data, pixelSettings))
                {
                    var size = new MagickGeometry(width, height);
                    size.IgnoreAspectRatio = true;
                    image.Resize(size);

                    texMapData.Specular.Width  = width;
                    texMapData.Specular.Height = height;

                    texMapData.Specular.Data = image.ToByteArray(MagickFormat.Rgba);
                }
            }

            if (texMapData.Multi != null && (largestSize > texMapData.Multi.Width * texMapData.Multi.Height || scaleDown))
            {
                var pixelSettings =
                    new PixelReadSettings(texMapData.Multi.Width, texMapData.Multi.Height, StorageType.Char, PixelMapping.RGBA);

                using (var image = new MagickImage(texMapData.Multi.Data, pixelSettings))
                {
                    var size = new MagickGeometry(width, height);
                    size.IgnoreAspectRatio = true;
                    image.Resize(size);

                    texMapData.Multi.Width  = width;
                    texMapData.Multi.Height = height;

                    texMapData.Multi.Data = image.ToByteArray(MagickFormat.Rgba);
                }
            }

            if (texMapData.Skin != null && (largestSize > texMapData.Skin.Width * texMapData.Skin.Height || scaleDown))
            {
                var pixelSettings =
                    new PixelReadSettings(texMapData.Skin.Width, texMapData.Skin.Height, StorageType.Char, PixelMapping.RGBA);

                using (var image = new MagickImage(texMapData.Skin.Data, pixelSettings))
                {
                    var size = new MagickGeometry(width, height);
                    size.IgnoreAspectRatio = true;
                    image.Resize(size);

                    texMapData.Skin.Width  = width;
                    texMapData.Skin.Height = height;

                    texMapData.Skin.Data = image.ToByteArray(MagickFormat.Rgba);
                }
            }

            return(width, height);
        }
        /// <summary>
        /// Gets the data for the texture map
        /// </summary>
        /// <returns>The texure map data</returns>
        private TexMapData GetTexMapData()
        {
            var tex = new Tex(_gameDirectory);

            var texMapData = new TexMapData();

            foreach (var texTypePath in _mtrlData.TextureTypePathList)
            {
                if (texTypePath.Type != XivTexType.ColorSet)
                {
                    var texData = tex.GetTexData(texTypePath);

                    var imageData = tex.GetImageData(texData);

                    switch (texTypePath.Type)
                    {
                    case XivTexType.Diffuse:
                        texMapData.Diffuse = new TexInfo {
                            Width = texData.Width, Height = texData.Height, Data = imageData
                        };
                        break;

                    case XivTexType.Specular:
                        texMapData.Specular = new TexInfo {
                            Width = texData.Width, Height = texData.Height, Data = imageData
                        };;
                        break;

                    case XivTexType.Normal:
                        texMapData.Normal = new TexInfo {
                            Width = texData.Width, Height = texData.Height, Data = imageData
                        };;
                        break;

                    case XivTexType.Multi:
                        texMapData.Multi = new TexInfo {
                            Width = texData.Width, Height = texData.Height, Data = imageData
                        };;
                        break;

                    case XivTexType.Skin:
                        texMapData.Skin = new TexInfo {
                            Width = texData.Width, Height = texData.Height, Data = imageData
                        };;
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
            }

            foreach (var texPath in _mtrlData.TexturePathList)
            {
                if (texPath.Contains("dummy"))
                {
                    texMapData.HasDummyTextures = true;
                    break;
                }
            }

            if (_mtrlData.ColorSetDataSize > 0)
            {
                var colorSetData = new List <byte>();
                foreach (var half in _mtrlData.ColorSetData)
                {
                    var colorByte = (byte)(half * 255);

                    if (half > 1)
                    {
                        colorByte = 255;
                    }

                    colorSetData.Add(colorByte);
                }

                texMapData.ColorSet = new TexInfo {
                    Width = 4, Height = 16, Data = colorSetData.ToArray()
                };;
            }

            return(texMapData);
        }
Beispiel #3
0
        /// <summary>
        /// Retreives the raw pixel data for each texture, collated into a class to hold them.
        /// </summary>
        /// <returns>The texure map data</returns>
        private static async Task <TexMapData> GetTexMapData(Tex tex, XivMtrl mtrl)
        {
            var texMapData = new TexMapData();

            // Use the function that returns proper sane reuslts.
            var ttps = mtrl.GetTextureTypePathList();

            foreach (var ttp in ttps)
            {
                if (ttp.Type != XivTexType.ColorSet)
                {
                    var texData = await tex.GetTexData(ttp);

                    var imageData = await tex.GetImageData(texData);

                    switch (ttp.Type)
                    {
                    case XivTexType.Diffuse:
                        texMapData.Diffuse = new TexInfo {
                            Width = texData.Width, Height = texData.Height, Data = imageData
                        };
                        break;

                    case XivTexType.Specular:
                    case XivTexType.Multi:
                    case XivTexType.Skin:
                        texMapData.Specular = new TexInfo {
                            Width = texData.Width, Height = texData.Height, Data = imageData
                        };;
                        break;

                    case XivTexType.Normal:
                        texMapData.Normal = new TexInfo {
                            Width = texData.Width, Height = texData.Height, Data = imageData
                        };;
                        break;

                    default:
                        // Do not render textures that we do not know how to use
                        break;
                    }
                }
            }

            if (mtrl.ColorSetDataSize > 0)
            {
                var colorSetData = new List <byte>();
                foreach (var half in mtrl.ColorSetData)
                {
                    var colorByte = (byte)(half * 255);

                    if (half > 1)
                    {
                        colorByte = 255;
                    }

                    colorSetData.Add(colorByte);
                }

                texMapData.ColorSet = new TexInfo {
                    Width = 4, Height = 16, Data = colorSetData.ToArray()
                };;
            }

            return(texMapData);
        }
Beispiel #4
0
        /// <summary>
        /// Equalizes the size of the textures by scaling to the largest known texture size
        /// </summary>
        /// <param name="texMapData">The texture map data containing the texture bytes</param>
        /// <returns>The width and height that the textures were equalized to.</returns>
        private async Task <(int Width, int Height)> EqualizeTextureSizes(TexMapData texMapData)
        {
            // Normal map is chosen because almost every item has a normal map, diffuse is chosen otherwise
            var width       = 0;
            var height      = 0;
            var largestSize = 0;

            if (texMapData.Normal != null)
            {
                width       = texMapData.Normal.Width;
                height      = texMapData.Normal.Height;
                largestSize = width * height;
            }
            else if (texMapData.Diffuse != null)
            {
                width       = texMapData.Diffuse.Width;
                height      = texMapData.Diffuse.Height;
                largestSize = width * height;
            }

            var scaleDown = false;
            var scale     = 1;

            if (texMapData.Normal != null)
            {
                var size = texMapData.Normal.Width * texMapData.Normal.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Normal.Width;
                    height      = texMapData.Normal.Height;
                }
            }

            if (texMapData.Diffuse != null)
            {
                var size = texMapData.Diffuse.Width * texMapData.Diffuse.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Diffuse.Width;
                    height      = texMapData.Diffuse.Height;
                }
            }

            if (texMapData.Specular != null)
            {
                var size = texMapData.Specular.Width * texMapData.Specular.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Specular.Width;
                    height      = texMapData.Specular.Height;
                }
            }

            if (texMapData.Multi != null)
            {
                var size = texMapData.Multi.Width * texMapData.Multi.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Multi.Width;
                    height      = texMapData.Multi.Height;
                }
            }

            if (texMapData.Skin != null)
            {
                var size = texMapData.Skin.Width * texMapData.Skin.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Skin.Width;
                    height      = texMapData.Skin.Height;
                }
            }

            if (width > 4000 || height > 4000)
            {
                scale     = 4;
                scaleDown = true;
            }
            //else if (width > 2000 || height > 2000)
            //{
            //    scale = 2;
            //    scaleDown = true;
            //}

            width       = width / scale;
            height      = height / scale;
            largestSize = width * height;

            await Task.Run(() =>
            {
                if (texMapData.Normal != null && largestSize > texMapData.Normal.Width *texMapData.Normal.Height ||
                    scaleDown)
                {
                    using (var img = Image.LoadPixelData <Rgba32>(texMapData.Normal.Data, texMapData.Normal.Width,
                                                                  texMapData.Normal.Height))
                    {
                        img.Mutate(x => x.Resize(width, height));

                        texMapData.Normal.Data = MemoryMarshal.AsBytes(img.GetPixelSpan()).ToArray();
                    }
                }

                if (texMapData.Diffuse != null &&
                    (largestSize > texMapData.Diffuse.Width *texMapData.Diffuse.Height || scaleDown))
                {
                    using (var img = Image.LoadPixelData <Rgba32>(texMapData.Diffuse.Data, texMapData.Diffuse.Width,
                                                                  texMapData.Diffuse.Height))
                    {
                        for (int i = 0; i < img.Height; i++)
                        {
                            var pixelRowSpan = img.GetPixelRowSpan(i);
                            for (int j = 0; j < img.Width; j++)
                            {
                                pixelRowSpan[j] = new Rgba32(pixelRowSpan[j].R, pixelRowSpan[j].G, pixelRowSpan[j].B, 255);
                            }
                        }
                        img.Mutate(x => x.Resize(width, height));

                        texMapData.Diffuse.Data = MemoryMarshal.AsBytes(img.GetPixelSpan()).ToArray();
                    }
                }

                if (texMapData.Specular != null &&
                    (largestSize > texMapData.Specular.Width *texMapData.Specular.Height || scaleDown))
                {
                    using (var img = Image.LoadPixelData <Rgba32>(texMapData.Specular.Data, texMapData.Specular.Width,
                                                                  texMapData.Specular.Height))
                    {
                        img.Mutate(x => x.Resize(width, height));

                        texMapData.Specular.Data = MemoryMarshal.AsBytes(img.GetPixelSpan()).ToArray();
                    }
                }

                if (texMapData.Multi != null &&
                    (largestSize > texMapData.Multi.Width *texMapData.Multi.Height || scaleDown))
                {
                    using (var img = Image.LoadPixelData <Rgba32>(texMapData.Multi.Data, texMapData.Multi.Width,
                                                                  texMapData.Multi.Height))
                    {
                        img.Mutate(x => x.Resize(width, height));

                        texMapData.Multi.Data = MemoryMarshal.AsBytes(img.GetPixelSpan()).ToArray();
                    }
                }

                if (texMapData.Skin != null &&
                    (largestSize > texMapData.Skin.Width *texMapData.Skin.Height || scaleDown))
                {
                    using (var img = Image.LoadPixelData <Rgba32>(texMapData.Skin.Data, texMapData.Skin.Width,
                                                                  texMapData.Skin.Height))
                    {
                        img.Mutate(x => x.Resize(width, height));

                        texMapData.Skin.Data = MemoryMarshal.AsBytes(img.GetPixelSpan()).ToArray();
                    }
                }
            });

            return(width, height);
        }
        /// <summary>
        /// Equalizes the size of the textures by scaling to the largest known texture size
        /// </summary>
        /// <param name="texMapData">The texture map data containing the texture bytes</param>
        /// <returns>The width and height that the textures were equalized to.</returns>
        private static async Task <(int Width, int Height)> EqualizeTextureSizes(TexMapData texMapData)
        {
            // Normal map is chosen because almost every item has a normal map, diffuse is chosen otherwise
            var width       = 0;
            var height      = 0;
            var largestSize = 0;

            if (texMapData.Normal != null)
            {
                width       = texMapData.Normal.Width;
                height      = texMapData.Normal.Height;
                largestSize = width * height;
            }
            else if (texMapData.Diffuse != null)
            {
                width       = texMapData.Diffuse.Width;
                height      = texMapData.Diffuse.Height;
                largestSize = width * height;
            }

            var scaleDown = false;
            var scale     = 1;

            if (texMapData.Normal != null)
            {
                var size = texMapData.Normal.Width * texMapData.Normal.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Normal.Width;
                    height      = texMapData.Normal.Height;
                }
            }

            if (texMapData.Diffuse != null)
            {
                var size = texMapData.Diffuse.Width * texMapData.Diffuse.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Diffuse.Width;
                    height      = texMapData.Diffuse.Height;
                }
            }

            if (texMapData.Specular != null)
            {
                var size = texMapData.Specular.Width * texMapData.Specular.Height;

                if (size > largestSize)
                {
                    largestSize = size;
                    width       = texMapData.Specular.Width;
                    height      = texMapData.Specular.Height;
                }
            }

            if (width > 4000 || height > 4000)
            {
                scale     = 4;
                scaleDown = true;
            }
            //else if (width > 2000 || height > 2000)
            //{
            //    scale = 2;
            //    scaleDown = true;
            //}

            width       = width / scale;
            height      = height / scale;
            largestSize = width * height;

            await Task.Run(() =>
            {
                if (texMapData.Normal != null && largestSize > texMapData.Normal.Width *texMapData.Normal.Height ||
                    scaleDown)
                {
                    using (var img = Image.LoadPixelData <Rgba32>(texMapData.Normal.Data, texMapData.Normal.Width,
                                                                  texMapData.Normal.Height))
                    {
                        // ImageSharp pre-multiplies the RGB by the alpha component during resize, if alpha is 0 (colourset row 0)
                        // this ends up causing issues and destroying the RGB values resulting in an invisible preview model
                        // https://github.com/SixLabors/ImageSharp/issues/1498#issuecomment-757519563
                        img.Mutate(x => x.Resize(
                                       new ResizeOptions
                        {
                            Size             = new Size(width, height),
                            PremultiplyAlpha = false
                        })
                                   );

                        texMapData.Normal.Data = MemoryMarshal.AsBytes(img.GetPixelMemoryGroup()[0].Span).ToArray();
                    }
                }

                if (texMapData.Diffuse != null &&
                    (largestSize > texMapData.Diffuse.Width *texMapData.Diffuse.Height || scaleDown))
                {
                    using (var img = Image.LoadPixelData <Rgba32>(texMapData.Diffuse.Data, texMapData.Diffuse.Width,
                                                                  texMapData.Diffuse.Height))
                    {
                        for (int i = 0; i < img.Height; i++)
                        {
                            var pixelRowSpan = img.GetPixelRowSpan(i);
                            for (int j = 0; j < img.Width; j++)
                            {
                                pixelRowSpan[j] = new Rgba32(pixelRowSpan[j].R, pixelRowSpan[j].G, pixelRowSpan[j].B, 255);
                            }
                        }
                        img.Mutate(x => x.Resize(width, height));

                        texMapData.Diffuse.Data = MemoryMarshal.AsBytes(img.GetPixelMemoryGroup()[0].Span).ToArray();
                    }
                }

                if (texMapData.Specular != null &&
                    (largestSize > texMapData.Specular.Width *texMapData.Specular.Height || scaleDown))
                {
                    using (var img = Image.LoadPixelData <Rgba32>(texMapData.Specular.Data, texMapData.Specular.Width,
                                                                  texMapData.Specular.Height))
                    {
                        img.Mutate(x => x.Resize(width, height));

                        texMapData.Specular.Data = MemoryMarshal.AsBytes(img.GetPixelMemoryGroup()[0].Span).ToArray();
                    }
                }
            });

            return(width, height);
        }