Example #1
0
        private IEnumerable <NtObject> CreateDirectoriesAndObject()
        {
            if (Close)
            {
                throw new ArgumentException("Can't use CreateDirectories and Close at the same time");
            }

            DisposableList <NtObject> objects = new DisposableList <NtObject>();

            string[]      path_parts = ResolvePath().Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
            StringBuilder builder    = new StringBuilder();
            bool          finished   = false;

            if (Root == null)
            {
                builder.Append(@"\");
            }

            try
            {
                for (int i = 0; i < path_parts.Length - 1; ++i)
                {
                    builder.Append(path_parts[i]);
                    NtDirectory dir = null;
                    try
                    {
                        dir = NtDirectory.Create(builder.ToString(), Root, DirectoryAccessRights.MaximumAllowed);
                    }
                    catch (NtException)
                    {
                    }

                    if (dir != null)
                    {
                        objects.Add(dir);
                    }
                    builder.Append(@"\");
                }
                objects.Add((NtObject)CreateObject(ResolvePath(), AttributeFlags, Root, SecurityQualityOfService, SecurityDescriptor));
                finished = true;
            }
            finally
            {
                if (!finished)
                {
                    objects.Dispose();
                    objects.Clear();
                }
            }
            return(objects.ToArray());
        }
Example #2
0
        static Texture CreateTextureFromImage(string path, string textureName, TextureSettings textureSettings, bool isDecalsWad)
        {
            // Load the main texture image, and any available mipmap images:
            using (var images = new DisposableList <Image <Rgba32> >(GetMipmapFilePaths(path).Prepend(path)
                                                                     .Select(imagePath => File.Exists(imagePath) ? ImageReading.ReadImage(imagePath) : null)))
            {
                // Verify image sizes:
                if (images[0].Width % 16 != 0 || images[0].Height % 16 != 0)
                {
                    throw new InvalidDataException($"Texture '{path}' width or height is not a multiple of 16.");
                }

                for (int i = 1; i < images.Count; i++)
                {
                    if (images[i] != null && (images[i].Width != images[0].Width >> i || images[i].Height != images[0].Height >> i))
                    {
                        throw new InvalidDataException($"Mipmap {i} for texture '{path}' width or height does not match texture size.");
                    }
                }

                if (isDecalsWad)
                {
                    return(CreateDecalTexture(textureName, images.ToArray(), textureSettings));
                }


                var filename             = Path.GetFileName(path);
                var isTransparentTexture = filename.StartsWith("{");
                var isAnimatedTexture    = AnimatedTextureNameRegex.IsMatch(filename);
                var isWaterTexture       = filename.StartsWith("!");

                // Create a suitable palette, taking special texture types into account:
                var transparencyThreshold = isTransparentTexture ? Clamp(textureSettings.TransparencyThreshold ?? 128, 0, 255) : 0;
                Func <Rgba32, bool> isTransparentPredicate = null;
                if (textureSettings.TransparencyColor != null)
                {
                    var transparencyColor = textureSettings.TransparencyColor.Value;
                    isTransparentPredicate = color => color.A < transparencyThreshold || (color.R == transparencyColor.R && color.G == transparencyColor.G && color.B == transparencyColor.B);
                }
                else
                {
                    isTransparentPredicate = color => color.A < transparencyThreshold;
                }

                var colorHistogram = ColorQuantization.GetColorHistogram(images.Where(image => image != null), isTransparentPredicate);
                var maxColors      = 256 - (isTransparentTexture ? 1 : 0) - (isWaterTexture ? 2 : 0);
                var colorClusters  = ColorQuantization.GetColorClusters(colorHistogram, maxColors);

                // Always make sure we've got a 256-color palette (some tools can't handle smaller palettes):
                if (colorClusters.Length < maxColors)
                {
                    colorClusters = colorClusters
                                    .Concat(Enumerable
                                            .Range(0, maxColors - colorClusters.Length)
                                            .Select(i => (new Rgba32(), new[] { new Rgba32() })))
                                    .ToArray();
                }

                // Make palette adjustments for special textures:
                if (isWaterTexture)
                {
                    var fogColor     = textureSettings.WaterFogColor ?? ColorQuantization.GetAverageColor(colorHistogram);
                    var fogIntensity = new Rgba32((byte)Clamp(textureSettings.WaterFogColor?.A ?? (int)((1f - GetBrightness(fogColor)) * 255), 0, 255), 0, 0);

                    colorClusters = colorClusters.Take(3)
                                    .Append((fogColor, new[] { fogColor }))         // Slot 3: water fog color
                                    .Append((fogIntensity, new[] { fogIntensity })) // Slot 4: fog intensity (stored in red channel)
                                    .Concat(colorClusters.Skip(3))
                                    .ToArray();
                }

                if (isTransparentTexture)
                {
                    var colorKey = new Rgba32(0, 0, 255);
                    colorClusters = colorClusters
                                    .Append((colorKey, new[] { colorKey })) // Slot 255: used for transparent pixels
                                    .ToArray();
                }

                // Create the actual palette, and a color index lookup cache:
                var palette = colorClusters
                              .Select(cluster => cluster.Item1)
                              .ToArray();
                var colorIndexMappingCache = new Dictionary <Rgba32, int>();
                for (int i = 0; i < colorClusters.Length; i++)
                {
                    (_, var colors) = colorClusters[i];
                    foreach (var color in colors)
                    {
                        colorIndexMappingCache[color] = i;
                    }
                }

                // Create any missing mipmaps:
                for (int i = 1; i < images.Count; i++)
                {
                    if (images[i] == null)
                    {
                        images[i] = images[0].Clone(context => context.Resize(images[0].Width >> i, images[0].Height >> i));
                    }
                }

                // Create texture data:
                var textureData = images
                                  .Select(image => CreateTextureData(image, palette, colorIndexMappingCache, textureSettings, isTransparentPredicate, disableDithering: isAnimatedTexture))
                                  .ToArray();

                return(Texture.CreateMipmapTexture(
                           name: textureName,
                           width: images[0].Width,
                           height: images[0].Height,
                           imageData: textureData[0],
                           palette: palette,
                           mipmap1Data: textureData[1],
                           mipmap2Data: textureData[2],
                           mipmap3Data: textureData[3]));
            }
        }