public void DdsDirectXCompability() { var model = new Models(1); model.AddImageFromFile(TestData.Directory + "small_scaled.png"); model.Apply(); model.Export.Quality = 100; var origTex = (TextureArray2D)model.Pipelines[0].Image; // normal colors var origColors = origTex.GetPixelColors(0, 0); // colors multiplied by 100 for integer precision formats model.Pipelines[0].Color.Formula = "I0 * 100"; model.Apply(); var integerTex = (TextureArray2D)model.Pipelines[0].Image; var origColors100 = integerTex.GetPixelColors(0, 0); Color[] newColors = null; var eFmt = model.Export.Formats.First(fmt => fmt.Extension == "dds"); string errors = ""; int numErrors = 0; foreach (var format in eFmt.Formats) { try { // export to dds var isIntegerPrecision = IsIntegerPrecisionFormat(format); var desc = new ExportDescription(ExportDir + "tmp", "dds", model.Export); desc.FileFormat = format; if (isIntegerPrecision) { desc.Multiplier = 100.0f; } model.Export.Export(origTex, desc); // load with directx dds loader DDSTextureLoader.CreateDDSTextureFromFile(Device.Get().Handle, Device.Get().ContextHandle, ExportDir + "tmp.dds", out var resource, out var resourceView, 0, out var alphaMode); // convert to obtain color data using (var newTex = model.Export.convert.ConvertFromRaw(resourceView, origTex.Size, Format.R32G32B32A32_Float, isIntegerPrecision)) { resourceView.Dispose(); resource.Dispose(); newColors = newTex.GetPixelColors(0, 0); // only compare with red channel since some formats only store red if (isIntegerPrecision) { TestData.CompareColors(origColors100, newColors, Color.Channel.R, 1.0f); } else { TestData.CompareColors(origColors, newColors, Color.Channel.R, 0.1f); } } } catch (Exception e) { errors += $"{format}: {e.Message}\n"; ++numErrors; } } if (errors.Length > 0) { throw new Exception($"directX compability failed for {numErrors}/{eFmt.Formats.Count} formats:\n" + errors); } }
public ExportViewModel(ModelsEx models, string extension, GliFormat preferredFormat, string filename, bool is3D, DefaultStatistics stats) { this.models = models; this.extension = extension; this.filename = filename; this.is3D = is3D; this.usedFormat = ExportDescription.GetExportFormat(extension); models.Display.IsExporting = true; // init layers for (var i = 0; i < models.Images.NumLayers; ++i) { AvailableLayers.Add(new ListItemViewModel <int> { Cargo = i, Name = "Layer " + i }); } models.ExportConfig.Layer = models.Display.ActiveLayer; selectedLayer = AvailableLayers[models.Display.ActiveLayer]; Debug.Assert(selectedLayer.Cargo == models.Display.ActiveLayer); // init mipmaps for (var i = 0; i < models.Images.NumMipmaps; ++i) { AvailableMipmaps.Add(new ListItemViewModel <int> { Cargo = i, Name = "Mipmap " + i }); } models.ExportConfig.Mipmap = models.Display.ActiveMipmap; selectedMipmap = AvailableMipmaps[models.Display.ActiveMipmap]; Debug.Assert(selectedMipmap.Cargo == models.Display.ActiveMipmap); // all layer option for ktx and dds if (models.Images.NumLayers > 1 && (extension == "ktx" || extension == "dds")) { AvailableLayers.Add(new ListItemViewModel <int> { Cargo = -1, Name = "All Layer" }); selectedLayer = AvailableLayers.Last(); models.ExportConfig.Layer = -1; } // all mipmaps option for ktx and dds if (models.Images.NumMipmaps > 1 && (extension == "ktx" || extension == "dds")) { AvailableMipmaps.Add(new ListItemViewModel <int> { Cargo = -1, Name = "All Mipmaps" }); selectedMipmap = AvailableMipmaps.Last(); models.ExportConfig.Mipmap = -1; } // init available pixel data types var usedPixelTypes = new SortedSet <PixelDataType>(); foreach (var format in usedFormat.Formats) { // exclude some formats for 3d export if (is3D && format.IsExcludedFrom3DExport()) { continue; } allFormats.Add(new ListItemViewModel <GliFormat> { Cargo = format, Name = format.ToString(), ToolTip = format.GetDescription() }); formatRatings.Add(stats.GetFormatRating(format, preferredFormat)); usedPixelTypes.Add(format.GetDataType()); } if (usedPixelTypes.Count > 1) { AvailableDataTypes.Add(new ListItemViewModel <PixelDataType> { Cargo = PixelDataType.Undefined, Name = "All" }); } var preferredPixelType = preferredFormat.GetDataType(); foreach (var usedPixelType in usedPixelTypes) { AvailableDataTypes.Add(new ListItemViewModel <PixelDataType> { Cargo = usedPixelType, Name = usedPixelType.ToString(), ToolTip = usedPixelType.GetDescription() }); if (usedPixelType == preferredPixelType) { SelectedDataType = AvailableDataTypes.Last(); } } if (SelectedDataType == null) { SelectedDataType = AvailableDataTypes[0]; } // assert that those were were set by SelectedDataType Debug.Assert(AvailableFormats != null); Debug.Assert(SelectedFormat != null); // enable quality if (extension == "jpg") { hasQualityValue = true; nonSrgbExportWarnings = true; } else if (extension == "bmp") { nonSrgbExportWarnings = true; } else { SetKtxDdsQuality(); } models.ExportConfig.PropertyChanged += ExportConfigOnPropertyChanged; models.Settings.PropertyChanged += SettingsOnPropertyChanged; if (models.ExportConfig.CropEnd == Float3.Zero) { // assume cropping was not set SetMaxCropping(); } }
public override async void Execute() { // make sure only one image is visible if (models.NumEnabled != 1) { models.Window.ShowErrorDialog("Exactly one image equation should be visible when exporting."); return; } // get active final image var id = models.GetFirstEnabledPipeline(); var tex = models.Pipelines[id].Image; if (tex == null) { return; // not yet computed? } float multiplier = 1.0f; // ReSharper disable once CompareOfFloatsByEqualityOperator if (models.Display.Multiplier != 1.0f) { if (models.Window.ShowYesNoDialog( $"Color multiplier is currently set to {models.Display.MultiplierString}. Do you want to include the multiplier in the export?", "Keep Color Multiplier?")) { multiplier = models.Display.Multiplier; } } if (path.InitFromEquations(models)) { // open save file dialog Debug.Assert(path.Directory != null); Debug.Assert(path.Filename != null); } // set proposed filename var firstImageId = models.Pipelines[id].Color.FirstImageId; if (exportFormat == null) { exportFormat = models.Images.Images[firstImageId].OriginalFormat; } var sfd = new SaveFileDialog { Filter = GetFilter(path.Extension, tex.Is3D), InitialDirectory = path.Directory, FileName = path.Filename }; if (sfd.ShowDialog(models.Window.TopmostWindow) != true) { return; } path.UpdateFromFilename(sfd.FileName); var viewModel = new ExportViewModel(models, path.Extension, exportFormat.Value, sfd.FileName, tex.Is3D, models.Statistics[id].Stats); var dia = new ExportDialog(viewModel); if (models.Window.ShowDialog(dia) != true) { return; } var desc = new ExportDescription(tex, path.Directory + "/" + path.Filename, path.Extension) { Multiplier = multiplier, Mipmap = models.ExportConfig.Mipmap, Layer = models.ExportConfig.Layer, UseCropping = models.ExportConfig.UseCropping, CropStart = models.ExportConfig.CropStart, CropEnd = models.ExportConfig.CropEnd, Overlay = models.Overlay.Overlay }; desc.TrySetFormat(viewModel.SelectedFormatValue); exportFormat = desc.FileFormat; models.Export.ExportAsync(desc); // export additional zoom boxes? if (viewModel.HasZoomBox && viewModel.ExportZoomBox) { for (int i = 0; i < models.ZoomBox.Boxes.Count; ++i) { var box = models.ZoomBox.Boxes[i]; var zdesc = new ExportDescription(tex, $"{path.Directory}/{path.Filename}_zoom{i}", path.Extension) { Multiplier = multiplier, Mipmap = models.ExportConfig.Mipmap, Layer = models.ExportConfig.Layer, UseCropping = true, CropStart = new Float3(box.Start, 0.0f), CropEnd = new Float3(box.End, 1.0f), Overlay = viewModel.ZoomBorders ? models.Overlay.Overlay : null, Scale = viewModel.ZoomBoxScale }; zdesc.TrySetFormat(viewModel.SelectedFormatValue); await models.Progress.WaitForTaskAsync(); models.Export.ExportAsync(zdesc); } } }
private void TryExportAllFormatsAndCompareGray(string outputExtension, bool onlySrgb = false) { var model = new Models(2); model.AddImageFromFile(TestData.Directory + "gray.png"); model.Apply(); var tex = (TextureArray2D)model.Pipelines[0].Image; var eFmt = ExportDescription.GetExportFormat(outputExtension); string errors = ""; int numErrors = 0; var lastTexel = tex.Size.Product - 1; Color[] colors = null; var i = 0; foreach (var format in eFmt.Formats) { if (onlySrgb && format.GetDataType() != PixelDataType.Srgb) { continue; } try { int numTries = 0; while (true) { try { var integerPrecision = IsIntegerPrecisionFormat(format); var desc = new ExportDescription(tex, ExportDir + "gray" + ++i, outputExtension); desc.FileFormat = format; desc.Quality = 100; if (integerPrecision) { desc.Multiplier = 100.0f; } model.Export.Export(desc); Thread.Sleep(1); // load and compare gray tone using (var newTex = new TextureArray2D(IO.LoadImage($"{ExportDir}gray{i}.{outputExtension}"))) { Assert.AreEqual(8, newTex.Size.Width); Assert.AreEqual(4, newTex.Size.Height); colors = newTex.GetPixelColors(LayerMipmapSlice.Mip0); // compare last texel var grayColor = colors[lastTexel]; float tolerance = 0.01f; if (format.IsLessThan8Bit()) { tolerance = 0.1f; } // some formats don't write to red // ReSharper disable once CompareOfFloatsByEqualityOperator //if(grayColor.Red != 0.0f) Assert.AreEqual(TestData.Gray, grayColor.Red, tolerance); if (integerPrecision) { Assert.AreEqual(TestData.Gray * 100.0f, grayColor.Red, 1.0f); } else { Assert.AreEqual(TestData.Gray, grayColor.Red, tolerance); } //else Assert.AreEqual(TestData.Gray, grayColor.Green, tolerance); break; } } catch (Exception) { ++numTries; if (numTries > 3) { throw; } } } } catch (Exception e) { errors += $"{format.ToString()}: {e.Message}\n"; ++numErrors; } } if (errors.Length > 0) { throw new Exception($"gray comparision failed for {numErrors}/{eFmt.Formats.Count} formats:\n" + errors); } }