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()); }
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])); } }