// fileName of the form "d:\Temp\Image.jpg" private byte[] GetBufferFromImageFile(string fileName, TextureCompressionType compressionType) { System.Drawing.Image image = System.Drawing.Image.FromFile(fileName); MemoryStream memoryStream = new MemoryStream(); System.Drawing.Imaging.ImageFormat format = compressionType == TextureCompressionType.CompressionJPEG ? System.Drawing.Imaging.ImageFormat.Jpeg : System.Drawing.Imaging.ImageFormat.Bmp; image.Save(memoryStream, format); byte[] imageBuffer = memoryStream.ToArray(); return(imageBuffer); }
// sUri of the form "pack://application:,,,/myPack;component/Images/image.jpg" private byte[] GetBufferImage(string sUri, TextureCompressionType compressionType) { System.Drawing.Imaging.ImageFormat format = (compressionType == TextureCompressionType.CompressionJPEG) ? System.Drawing.Imaging.ImageFormat.Jpeg : System.Drawing.Imaging.ImageFormat.Bmp; Uri uri = new Uri(sUri, UriKind.RelativeOrAbsolute); StreamResourceInfo info = Application.GetResourceStream(uri); System.Drawing.Image image = System.Drawing.Image.FromStream(info.Stream); MemoryStream memoryStream = new MemoryStream(); image.Save(memoryStream, format); byte[] imageBuffer = memoryStream.ToArray(); return(imageBuffer); }
/// <summary> /// Initializes a new instance of the <see cref="Warcraft.BLP.BLP"/> class. /// This constructor creates a BLP file using the specified compression from a bitmap object. /// If the compression type specifed is DXTC, the default pixel format used is DXT1 for opaque textures and DXT3 for the rest. /// </summary> /// <param name="image">Image.</param> /// <param name="compressionType">Compression type.</param> public BLP(Image <Rgba32> image, TextureCompressionType compressionType) { // Set up the header Header = new BLPHeader { CompressionType = compressionType }; if (compressionType == TextureCompressionType.Palettized) { Header.PixelFormat = BLPPixelFormat.Palettized; // Determine best alpha bit depth if (image.HasAlpha()) { var alphaLevels = new List <byte>(); for (var y = 0; y < image.Height; ++y) { for (var x = 0; x < image.Width; ++x) { var pixel = image[x, y]; if (!alphaLevels.Contains(pixel.A)) { alphaLevels.Add(pixel.A); } if (alphaLevels.Count > 16) { break; } } } if (alphaLevels.Count > 16) { // More than 16? Use a full byte Header.AlphaBitDepth = 8; } else if (alphaLevels.Count > 2) { // More than 2, but less than or equal to 16? Use half a byte Header.AlphaBitDepth = 4; } else { // Just 2? Use a bit instead Header.AlphaBitDepth = 1; } } else { // No alpha, so a bit depth of 0. Header.AlphaBitDepth = 0; } } else if (compressionType == TextureCompressionType.DXTC) { Header.AlphaBitDepth = 8; // Determine best DXTC type (1, 3 or 5) if (image.HasAlpha()) { Header.PixelFormat = BLPPixelFormat.DXT3; } else { // DXT1 for no alpha Header.PixelFormat = BLPPixelFormat.DXT1; } } else if (compressionType == TextureCompressionType.Uncompressed) { // The alpha will be stored as a straight ARGB texture, so set it to 8 Header.AlphaBitDepth = 8; Header.PixelFormat = BLPPixelFormat.PalARGB1555DitherFloydSteinberg; } // What the mip type does is currently unknown, but it's usually set to 1. Header.MipMapType = 1; Header.Resolution = new Resolution((uint)image.Width, (uint)image.Height); // It's now time to compress the image _rawMipMaps = CompressImage(image); // Calculate the offsets and sizes var mipOffset = (uint)(Header.GetSize() + (_palette.Count * 4)); foreach (var rawMipMap in _rawMipMaps) { var mipSize = (uint)rawMipMap.Length; Header.MipMapOffsets.Add(mipOffset); Header.MipMapSizes.Add(mipSize); // Push the offset ahead for the next mipmap mipOffset += mipSize; } }
/// <summary> /// Initializes a new instance of the <see cref="Warcraft.BLP.BLPHeader"/> class. /// This constructor creates a header from input data read from a BLP file. /// Usually, this is 148 bytes. /// </summary> /// <param name="inData">ExtendedData.</param> public BLPHeader(byte[] inData) { using (MemoryStream ms = new MemoryStream(inData)) { using (BinaryReader br = new BinaryReader(ms)) { this.Signature = new string(br.ReadChars(4)); if (Enum.TryParse(this.Signature, out this.Format)) { if (this.Format == BLPFormat.BLP2) { this.Version = (uint)br.ReadInt32(); } if (this.Format == BLPFormat.BLP2) { this.CompressionType = (TextureCompressionType)br.ReadByte(); } else { this.CompressionType = (TextureCompressionType)br.ReadUInt32(); } if (this.Format == BLPFormat.BLP2) { this.AlphaBitDepth = br.ReadByte(); } else { this.AlphaBitDepth = br.ReadUInt32(); } // BLP0 & BLP1 stores the resolution here if (this.Format < BLPFormat.BLP2) { this.Resolution = new Resolution(br.ReadUInt32(), br.ReadUInt32()); } if (this.Format == BLPFormat.BLP2) { this.PixelFormat = (BLPPixelFormat)br.ReadByte(); } else { this.PixelFormat = (BLPPixelFormat)br.ReadUInt32(); } if (this.Format == BLPFormat.BLP2) { this.MipMapType = br.ReadByte(); } else { this.MipMapType = br.ReadUInt32(); } // BLP2 stores the resolution here if (this.Format == BLPFormat.BLP2) { this.Resolution = new Resolution(br.ReadUInt32(), br.ReadUInt32()); } this.MipMapOffsets = new List <uint>(); for (int i = 0; i < 16; ++i) { uint offset = br.ReadUInt32(); if (offset > 0) { this.MipMapOffsets.Add(offset); } } this.MipMapSizes = new List <uint>(); for (int i = 0; i < 16; ++i) { uint size = br.ReadUInt32(); if (size > 0) { this.MipMapSizes.Add(size); } } } else { throw new FileLoadException("The provided data did not have a BLP signature."); } } } }
protected override async void OnClick() { // make sure there's an OID from a created feature if (Module1.MultipatchOID == -1) { return; } if (MapView.Active?.Map == null) { return; } // find layer var member = MapView.Active.Map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "MultipatchWithTextureSimple") as FeatureLayer; if (member == null) { return; } // create the textures TextureCompressionType compressionType = TextureCompressionType.CompressionJPEG; byte[] brickImageBuffer = GetBufferImage("pack://application:,,,/MultipatchBuilderEx;component/Textures/Brick.jpg", compressionType); var brickTextureResource = new TextureResource(new JPEGTexture(brickImageBuffer)); BasicMaterial brickMaterialTexture = new BasicMaterial(); brickMaterialTexture.TextureResource = brickTextureResource; byte[] blocksImageBuffer = GetBufferImage("pack://application:,,,/MultipatchBuilderEx;component/Textures/Retaining_Blocks.jpg", compressionType); var blocksTextureResource = new TextureResource(new JPEGTexture(blocksImageBuffer)); BasicMaterial blockskMaterialTexture = new BasicMaterial(); blockskMaterialTexture.TextureResource = blocksTextureResource; byte[] waterImageBuffer = GetBufferImage("pack://application:,,,/MultipatchBuilderEx;component/Textures/water.jpg", compressionType); var waterTextureResource = new TextureResource(new JPEGTexture(waterImageBuffer)); BasicMaterial waterMaterialTexture = new BasicMaterial(); waterMaterialTexture.TextureResource = waterTextureResource; // set up a set of TextureCoordinates - these determine how the texture is draped over a face // In this scenario we will use the same textureCoordinates for each face var textureCoords = new List <Coordinate2D>() { new Coordinate2D(0, 0), new Coordinate2D(1, 0), new Coordinate2D(1, -1), new Coordinate2D(0, 0), new Coordinate2D(1, -1), new Coordinate2D(0, -1), }; bool result = await QueuedTask.Run(() => { // get the multipatch shape using the Inspector var insp = new Inspector(); insp.Load(member, Module1.MultipatchOID); var origMultipatch = insp.Shape as Multipatch; // create a builder var mpb = new ArcGIS.Core.Geometry.MultipatchBuilderEx(origMultipatch); // apply the texture materials to the patches var patches = mpb.Patches; patches[0].Material = brickMaterialTexture; patches[0].TextureCoords2D = textureCoords; patches[1].Material = blockskMaterialTexture; patches[1].TextureCoords2D = textureCoords; patches[2].Material = brickMaterialTexture; patches[2].TextureCoords2D = textureCoords; patches[3].Material = waterMaterialTexture; patches[3].TextureCoords2D = textureCoords; patches[4].Material = blockskMaterialTexture; patches[4].TextureCoords2D = textureCoords; patches[5].Material = waterMaterialTexture; patches[5].TextureCoords2D = textureCoords; // use this method to determine patches which contain the specified texture //var texture = mpb.QueryPatchIndicesWithTexture(brickTextureResource); // get the modified multipatch geometry var newMultipatch = mpb.ToGeometry() as Multipatch; // modify operation var modifyOp = new EditOperation(); modifyOp.Name = "Apply textures to multipatch"; modifyOp.Modify(member, Module1.MultipatchOID, newMultipatch); if (modifyOp.Execute()) { return(true); } return(false); }); }
void OnGUI() { Undo.RecordObject(this, "lb"); scrollPos = EditorGUILayout.BeginScrollView(scrollPos, false, false, GUILayout.Width(Screen.width), GUILayout.Height(Screen.height)); EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.Space(); importerType = (TexImporterType)EditorGUILayout.EnumPopup("Importer Mode", importerType, GUILayout.Width(343)); if (GUILayout.Button("Batch Import")) { if (importerType == TexImporterType.AllTextures) { var files = Directory.GetFiles("Assets", "*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".png") || s.EndsWith(".jpg") || s.EndsWith(".psd") || s.EndsWith(".gif") || s.EndsWith(".iff") || s.EndsWith(".tga") || s.EndsWith(".tiff") || s.EndsWith(".bmp") || s.EndsWith(".pict")); foreach (string s in files) { TextureImporter tImporter = AssetImporter.GetAtPath(s) as TextureImporter; tImporter.maxTextureSize = textureSize; if (comprissonMode == TextureCompressionType.None) { tImporter.textureCompression = TextureImporterCompression.Uncompressed; } if (comprissonMode == TextureCompressionType.LowQuality) { tImporter.textureCompression = TextureImporterCompression.CompressedLQ; } if (comprissonMode == TextureCompressionType.HighQuality) { tImporter.textureCompression = TextureImporterCompression.CompressedHQ; } if (advancedMode) { tImporter.textureType = textureType; tImporter.textureShape = textureShape; tImporter.sRGBTexture = textureRGB; tImporter.alphaSource = textureAlphaSource; tImporter.alphaIsTransparency = AlphaIsTransparent; tImporter.isReadable = ReadWriteEnabled; tImporter.mipmapEnabled = GenerateMipMaps; tImporter.wrapMode = wrapMode; tImporter.filterMode = filterMode; tImporter.anisoLevel = AnisoLevel; } AssetDatabase.ImportAsset(s, ImportAssetOptions.ForceUpdate); } } if (importerType == TexImporterType.CustomPath) { if (CustomPath.Length > 0) { foreach (string f in CustomPath) { var files = Directory.GetFiles(f, "*.*", SearchOption.AllDirectories) .Where(s => s.EndsWith(".png") || s.EndsWith(".jpg") || s.EndsWith(".psd") || s.EndsWith(".gif") || s.EndsWith(".iff") || s.EndsWith(".tga") || s.EndsWith(".tiff") || s.EndsWith(".bmp") || s.EndsWith(".pict")); foreach (string ss in files) { TextureImporter tImporter = AssetImporter.GetAtPath(ss) as TextureImporter; tImporter.maxTextureSize = textureSize; if (comprissonMode == TextureCompressionType.None) { tImporter.textureCompression = TextureImporterCompression.Uncompressed; } if (comprissonMode == TextureCompressionType.LowQuality) { tImporter.textureCompression = TextureImporterCompression.CompressedLQ; } if (comprissonMode == TextureCompressionType.HighQuality) { tImporter.textureCompression = TextureImporterCompression.CompressedHQ; } if (advancedMode) { tImporter.textureType = textureType; tImporter.textureShape = textureShape; tImporter.sRGBTexture = textureRGB; tImporter.alphaSource = textureAlphaSource; tImporter.alphaIsTransparency = AlphaIsTransparent; tImporter.isReadable = ReadWriteEnabled; tImporter.mipmapEnabled = GenerateMipMaps; tImporter.wrapMode = wrapMode; tImporter.filterMode = filterMode; tImporter.anisoLevel = AnisoLevel; } AssetDatabase.ImportAsset(ss, ImportAssetOptions.ForceUpdate); } } } } if (importerType == TexImporterType.CustomTextures) { if (targets.Length > 0) { foreach (Texture2D s in targets) { TextureImporter tImporter = AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(s)) as TextureImporter; tImporter.maxTextureSize = textureSize; if (comprissonMode == TextureCompressionType.None) { tImporter.textureCompression = TextureImporterCompression.Uncompressed; } if (comprissonMode == TextureCompressionType.LowQuality) { tImporter.textureCompression = TextureImporterCompression.CompressedLQ; } if (comprissonMode == TextureCompressionType.HighQuality) { tImporter.textureCompression = TextureImporterCompression.CompressedHQ; } if (advancedMode) { tImporter.textureType = textureType; tImporter.textureShape = textureShape; tImporter.sRGBTexture = textureRGB; tImporter.alphaSource = textureAlphaSource; tImporter.alphaIsTransparency = AlphaIsTransparent; tImporter.isReadable = ReadWriteEnabled; tImporter.mipmapEnabled = GenerateMipMaps; tImporter.wrapMode = wrapMode; tImporter.filterMode = filterMode; tImporter.anisoLevel = AnisoLevel; } AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(s), ImportAssetOptions.ForceUpdate); } } } } EditorGUILayout.Space(); EditorGUILayout.Space(); if (importerType == TexImporterType.CustomTextures) { ScriptableObject target = this; SerializedObject so = new SerializedObject(target); SerializedProperty stringsProperty = so.FindProperty("targets"); EditorGUILayout.PropertyField(stringsProperty, true); // True means show children so.ApplyModifiedProperties(); // Remember to apply modified properties } if (importerType == TexImporterType.CustomPath) { ScriptableObject target = this; SerializedObject so = new SerializedObject(target); SerializedProperty stringsProperty = so.FindProperty("CustomPath"); EditorGUILayout.PropertyField(stringsProperty, true); // True means show children so.ApplyModifiedProperties(); // Remember to apply modified properties } textureSize = EditorGUILayout.IntField("Texture Size", textureSize, GUILayout.Width(343)); EditorGUILayout.Space(); EditorGUILayout.Space(); comprissonMode = (TextureCompressionType)EditorGUILayout.EnumPopup("Comprisson Mode", comprissonMode, GUILayout.Width(343)); EditorGUILayout.Space(); EditorGUILayout.Space(); advancedMode = EditorGUILayout.Toggle("Show Advanced Options", advancedMode); EditorGUILayout.Space(); EditorGUILayout.Space(); if (advancedMode) { EditorGUILayout.LabelField("Recommended non-advanced mode to avoid problems"); EditorGUILayout.Space(); EditorGUILayout.Space(); textureType = (TextureImporterType)EditorGUILayout.EnumPopup("Texture Type", textureType, GUILayout.Width(343)); textureShape = (TextureImporterShape)EditorGUILayout.EnumPopup("Texture Shape", textureShape, GUILayout.Width(343)); textureRGB = EditorGUILayout.Toggle("sRGB Mode", textureRGB, GUILayout.Width(343)); textureAlphaSource = (TextureImporterAlphaSource)EditorGUILayout.EnumPopup("Alpha Source", textureAlphaSource, GUILayout.Width(343)); EditorGUILayout.Space(); EditorGUILayout.Space(); AlphaIsTransparent = EditorGUILayout.Toggle("Alpha Is Transparent", AlphaIsTransparent, GUILayout.Width(343)); ReadWriteEnabled = EditorGUILayout.Toggle("Read Write Enabled", ReadWriteEnabled, GUILayout.Width(343)); GenerateMipMaps = EditorGUILayout.Toggle("Generate Mip Maps", GenerateMipMaps, GUILayout.Width(343)); EditorGUILayout.Space(); EditorGUILayout.Space(); wrapMode = (TextureWrapMode)EditorGUILayout.EnumPopup("Wrap Mode", wrapMode, GUILayout.Width(343)); filterMode = (FilterMode)EditorGUILayout.EnumPopup("Filter Mode", filterMode, GUILayout.Width(343)); EditorGUILayout.Space(); EditorGUILayout.Space(); AnisoLevel = EditorGUILayout.IntField("Aniso Level", AnisoLevel, GUILayout.Width(343)); } EditorGUILayout.EndScrollView(); }
/// <summary> /// Initializes a new instance of the <see cref="Warcraft.BLP.BLP"/> class. /// This constructor creates a BLP file using the specified compression from a bitmap object. /// If the compression type specifed is DXTC, the default pixel format used is DXT1 for opaque textures and DXT3 for the rest. /// </summary> /// <param name="image">Image.</param> /// <param name="compressionType">Compression type.</param> public BLP(Bitmap image, TextureCompressionType compressionType) { // Set up the header this.Header = new BLPHeader { CompressionType = compressionType }; if (compressionType == TextureCompressionType.Palettized) { this.Header.PixelFormat = BLPPixelFormat.Pixel_Palettized; // Determine best alpha bit depth if (image.HasAlpha()) { List<byte> alphaLevels = new List<byte>(); for (int y = 0; y < image.Height; ++y) { for (int x = 0; x < image.Width; ++x) { Color pixel = image.GetPixel(x, y); if (!alphaLevels.Contains(pixel.A)) { alphaLevels.Add(pixel.A); } if (alphaLevels.Count > 16) { break; } } } if (alphaLevels.Count > 16) { // More than 16? Use a full byte this.Header.AlphaBitDepth = 8; } else if (alphaLevels.Count > 2) { // More than 2, but less than or equal to 16? Use half a byte this.Header.AlphaBitDepth = 4; } else { // Just 2? Use a bit instead this.Header.AlphaBitDepth = 1; } } else { // No alpha, so a bit depth of 0. this.Header.AlphaBitDepth = 0; } } else if (compressionType == TextureCompressionType.DXTC) { this.Header.AlphaBitDepth = 8; // Determine best DXTC type (1, 3 or 5) if (image.HasAlpha()) { this.Header.PixelFormat = BLPPixelFormat.Pixel_DXT3; } else { // DXT1 for no alpha this.Header.PixelFormat = BLPPixelFormat.Pixel_DXT1; } } else if (compressionType == TextureCompressionType.Uncompressed) { // The alpha will be stored as a straight ARGB texture, so set it to 8 this.Header.AlphaBitDepth = 8; this.Header.PixelFormat = BLPPixelFormat.Pixel_PalARGB1555DitherFloydSteinberg; } // What the mip type does is currently unknown, but it's usually set to 1. this.Header.MipMapType = 1; this.Header.Resolution = new Resolution((uint)image.Width, (uint)image.Height); // It's now time to compress the image this.RawMipMaps = CompressImage(image); // Calculate the offsets and sizes uint mipOffset = (uint)(this.Header.GetSize() + this.Palette.Count * 4); foreach (byte[] rawMipMap in this.RawMipMaps) { uint mipSize = (uint)rawMipMap.Length; this.Header.MipMapOffsets.Add(mipOffset); this.Header.MipMapSizes.Add(mipSize); // Push the offset ahead for the next mipmap mipOffset += mipSize; } }
/// <summary> /// Initializes a new instance of the <see cref="Warcraft.BLP.BLPHeader"/> class. /// This constructor creates a header from input data read from a BLP file. /// Usually, this is 148 bytes. /// </summary> /// <param name="InData">Data.</param> public BLPHeader(byte[] InData) { using (MemoryStream ms = new MemoryStream(InData)) { using (BinaryReader br = new BinaryReader(ms)) { this.Signature = new string(br.ReadChars(4)); if (Enum.TryParse(this.Signature, out this.Format)) { if (this.Format == BLPFormat.BLP2) { this.Version = (uint)br.ReadInt32(); } if (this.Format == BLPFormat.BLP2) { this.CompressionType = (TextureCompressionType)br.ReadByte(); } else { this.CompressionType = (TextureCompressionType)br.ReadUInt32(); } if (this.Format == BLPFormat.BLP2) { this.AlphaBitDepth = br.ReadByte(); } else { this.AlphaBitDepth = br.ReadUInt32(); } // BLP0 & BLP1 stores the resolution here if (this.Format < BLPFormat.BLP2) { this.Resolution = new Resolution(br.ReadUInt32(), br.ReadUInt32()); } if (this.Format == BLPFormat.BLP2) { this.PixelFormat = (BLPPixelFormat)br.ReadByte(); } else { this.PixelFormat = (BLPPixelFormat)br.ReadUInt32(); } if (this.Format == BLPFormat.BLP2) { this.MipMapType = br.ReadByte(); } else { this.MipMapType = br.ReadUInt32(); } // BLP2 stores the resolution here if (this.Format == BLPFormat.BLP2) { this.Resolution = new Resolution(br.ReadUInt32(), br.ReadUInt32()); } this.MipMapOffsets = new List<uint>(); for (int i = 0; i < 16; ++i) { uint offset = br.ReadUInt32(); if (offset > 0) { this.MipMapOffsets.Add(offset); } } this.MipMapSizes = new List<uint>(); for (int i = 0; i < 16; ++i) { uint size = br.ReadUInt32(); if (size > 0) { this.MipMapSizes.Add(size); } } } else { throw new FileLoadException("The provided data did not have a BLP signature."); } } } }
protected override async void OnClick() { #region Initialization // set up a set of TextureCoordinates - these determine how the texture is draped over a face // In this scenario we will use the same textureCoordinates for each face var textureCoords = new List <Coordinate2D>() { new Coordinate2D(4.67909908294678, -2.89953231811523), new Coordinate2D(-3.7085223197937, -2.89953231811523), new Coordinate2D(-3.6790623664856, 1.89953279495239), new Coordinate2D(4.67909908294678, -2.89953231811523), new Coordinate2D(-3.6790623664856, 1.89953279495239), new Coordinate2D(4.7085223197937, 1.89953327178955) }; TextureCompressionType compressionType = TextureCompressionType.CompressionJPEG; byte[] glassImageBuffer = GetBufferImage("pack://application:,,,/MultipatchBuilder;component/Textures/Glass.jpg", compressionType); var glassTextureResource = new TextureResource(new JPEGTexture(glassImageBuffer)); byte[] roofImageBuffer = GetBufferImage("pack://application:,,,/MultipatchBuilder;component/Textures/Roof.jpg", compressionType); var roofTextureResource = new TextureResource(new JPEGTexture(roofImageBuffer)); var materialGray = new BasicMaterial { Color = System.Windows.Media.Colors.Gray }; #endregion if (MapView.Active?.Map == null) { return; } // find footprint layer var footPrintLyr = MapView.Active.Map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "BuildingFootprints") as FeatureLayer; if (footPrintLyr == null) { MessageBox.Show("Can't find layer: BuildingFootprint"); return; } var buildingLyr = MapView.Active.Map.GetLayersAsFlattenedList().FirstOrDefault(l => l.Name == "BuildingStructure") as FeatureLayer; if (buildingLyr == null) { MessageBox.Show("Can't find layer: BuildingStructure"); return; } // create the multipatch var mpb = await QueuedTask.Run <MultipatchBuilderEx>(() => { // get all selected lines and use them as the building footprint var footPrintSelection = footPrintLyr.GetSelection(); Polygon footPrint = null; int floorLevels = 1; #region Get Footprint and Floor levels foreach (var footprintOid in footPrintSelection.GetObjectIDs()) { // get the multipatch shape using the Inspector var insp = new Inspector(); insp.Load(footPrintLyr, footprintOid); footPrint = GeometryEngine.Instance.ReverseOrientation(insp.Shape as Multipart) as Polygon; floorLevels = (int)insp["Floors"]; } if (footPrint == null) { MessageBox.Show("No selected building footprint found"); return(null); } #endregion // Create the MultipatchBuilder using the building footprints and the floorlevels as height return(MyMultipatchBuilder.CreateTriangleMultipatchBuilder(footPrint, floorLevels)); }); // apply texture or material // create a builder to work on the multipatch geometry switch (Module1.SelectedTexture) { case "Glass": // create the textures for walls and roof BasicMaterial glassMaterialTexture = new BasicMaterial { TextureResource = glassTextureResource }; BasicMaterial roofMaterialTexture = new BasicMaterial { TextureResource = roofTextureResource }; // apply the texture materials to the patches var patches = mpb.Patches; for (var iPatch = 0; iPatch < patches.Count; iPatch++) { if (iPatch == patches.Count - 1) { // roof patches[iPatch].Material = roofMaterialTexture; patches[iPatch].TextureCoords2D = textureCoords; } else { // walls patches[iPatch].Material = glassMaterialTexture; patches[iPatch].TextureCoords2D = textureCoords; } } break; case "Red-solid": // create some materials var materialRed = new BasicMaterial { Color = System.Windows.Media.Colors.Brown }; // apply the materials to the patches for (var iPatch = 0; iPatch < mpb.Patches.Count; iPatch++) { if (iPatch == mpb.Patches.Count - 1) { // roof mpb.Patches[iPatch].Material = materialGray; } else { // walls mpb.Patches[iPatch].Material = materialRed; } } break; case "Gray-solid": // create some materials var materialSilver = new BasicMaterial { Color = System.Windows.Media.Colors.Silver }; // apply the materials to the patches for (var iPatch = 0; iPatch < mpb.Patches.Count; iPatch++) { if (iPatch == mpb.Patches.Count - 1) { // roof mpb.Patches[iPatch].Material = materialGray; } else { // walls mpb.Patches[iPatch].Material = materialSilver; } } break; } // create a new feature using the multipatch bool result = await QueuedTask.Run(() => { var op = new EditOperation { Name = "Create multipatch feature", SelectNewFeatures = false }; Module1.NewMultipatch = mpb.ToGeometry() as Multipatch; var rowToken = op.Create(buildingLyr, Module1.NewMultipatch); if (op.Execute()) { // track the newly created objectID // save the oid in the module for other commands to use Module1.NewMultipatchOID = rowToken.ObjectID.Value; return(true); } var msg = op.ErrorMessage; return(false); }); }