Esempio n. 1
0
        public void Save(Stream output, DdsSaveConfig saveConfig)
        {
            BinaryWriter writer = new BinaryWriter(output);

            header = new DdsHeader(saveConfig, Width, Height);
            header.Write(writer);

            if (saveConfig.GenerateMipMaps)
            {
                GenerateMipMaps();
            }

            foreach (DdsMipMap mipMap in MipMaps.OrderByDescending(mip => mip.Width))
            {
                byte[] outputData = WriteMipMap(mipMap, saveConfig);

                output.Write(outputData, 0, outputData.Length);
            }

            output.Flush();
        }
Esempio n. 2
0
    private async Task exportFileObjects(List<DomainUpkFile> files) {
      LoadProgressMessage message = new LoadProgressMessage { Text = "Exporting...", Total = files.Count };

      int compressor = menuViewModel.IsCompressorClusterFit ? 0 : menuViewModel.IsCompressorRangeFit ? 1 : 2;

      int errorMetric = menuViewModel.IsErrorMetricPerceptual ? 0 : 1;

      DdsSaveConfig config = new DdsSaveConfig(FileFormat.Unknown, compressor, errorMetric, menuViewModel.IsWeightColorByAlpha, false);

      foreach(DomainUpkFile file in files) {
        FileViewEntity fileEntity = viewModel.Files.Single(fe => fe.Id == file.Id);

        string directory = Path.Combine(settings.ExportPath, Path.GetDirectoryName(file.GameFilename), Path.GetFileNameWithoutExtension(file.GameFilename));

        if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);

        DomainHeader header = file.Header;

        if (header == null) {
          try {
            header = await repository.LoadUpkFile(Path.Combine(settings.PathToGame, file.GameFilename));

            await Task.Run(() => header.ReadHeaderAsync(null));
          }
          catch(Exception ex) {
            messenger.Send(new ApplicationErrorMessage { HeaderText = "Error Loading UPK File", ErrorMessage = $"Filename: {file.GameFilename}", Exception = ex });

            fileEntity.IsErrored = true;

            continue;
          }
        }

        message.Current++;

        foreach(DomainExportTableEntry export in header.ExportTable) {
          if (export.DomainObject == null) {
            try {
              await export.ParseDomainObject(header, false, false);
            }
            catch(Exception ex) {
              messenger.Send(new ApplicationErrorMessage { HeaderText = "Error Parsing Object", ErrorMessage = $"Filename: {header.Filename}\nExport Name: {export.NameTableIndex.Name}\nType: {export.TypeReferenceNameIndex.Name}", Exception = ex });

              fileEntity.IsErrored = true;

              continue;
            }
          }

          if (!export.DomainObject.IsExportable) continue;

          string filename = Path.Combine(directory, $"{export.NameTableIndex.Name}{export.DomainObject.FileExtension}");

          message.StatusText = filename;

          messenger.Send(message);

          await export.DomainObject.SaveObject(filename, config);
        }

        file.Header = null;
      }

      message.IsComplete = true;
      message.StatusText = null;

      messenger.Send(message);
    }
Esempio n. 3
0
        public DdsHeader(DdsSaveConfig config, int width, int height)
        {
            PixelFormat = new DdsPixelFormat(config.FileFormat);

            bool isCompressed = config.FileFormat == FileFormat.DXT1 ||
                                config.FileFormat == FileFormat.DXT3 ||
                                config.FileFormat == FileFormat.DXT5;
            //
            // Compute mip map count..
            //
            int mipCount = config.GenerateMipMaps ? CountMipMaps(width, height) : 1;

            Size = 18 * 4 + PixelFormat.Size + 5 * 4;

            Width  = (uint)width;
            Height = (uint)height;

            MipMapCount = mipCount == 1 ? 0 : (uint)mipCount;

            HeaderFlags = (uint)(Constants.HeaderFlags.Texture | (isCompressed ? Constants.HeaderFlags.LinearSize : Constants.HeaderFlags.Pitch)
                                 | (mipCount > 1 ? Constants.HeaderFlags.MipMap     : Constants.HeaderFlags.None));

            SurfaceFlags = (uint)(Constants.SurfaceFlags.Texture | (mipCount > 1 ? Constants.SurfaceFlags.MipMap : Constants.SurfaceFlags.None));

            if (isCompressed)
            {
                //
                // Compresssed textures have the linear flag set.  So pitchOrLinearSize
                // needs to contain the entire size of the DXT block.
                //
                int blockCount = (width + 3) / 4 * ((height + 3) / 4);

                int blockSize = config.FileFormat == FileFormat.Unknown ? 8 : 16;

                PitchOrLinearSize = (uint)(blockCount * blockSize);
            }
            else
            {
                //
                // Non-compressed textures have the pitch flag set. So pitchOrLinearSize
                // needs to contain the row pitch of the main image.
                //
                int pixelWidth = 0;

                switch (config.FileFormat)
                {
                case FileFormat.A8R8G8B8:
                case FileFormat.X8R8G8B8:
                case FileFormat.A8B8G8R8:
                case FileFormat.X8B8G8R8: {
                    pixelWidth = 4;

                    break;
                }

                case FileFormat.R8G8B8: {
                    pixelWidth = 3;

                    break;
                }

                case FileFormat.A1R5G5B5:
                case FileFormat.A4R4G4B4:
                case FileFormat.R5G6B5: {
                    pixelWidth = 2;

                    break;
                }

                case FileFormat.G8: {
                    pixelWidth = 1;

                    break;
                }
                }

                PitchOrLinearSize = (uint)(width * pixelWidth);
            }
        }
Esempio n. 4
0
        public byte[] WriteMipMap(DdsMipMap mipMap, DdsSaveConfig saveConfig)
        {
            byte[] outputData;

            if (saveConfig.FileFormat >= FileFormat.DXT1 && saveConfig.FileFormat <= FileFormat.DXT5)
            {
                outputData = DdsSquish.CompressImage(mipMap.MipMap, mipMap.Width, mipMap.Height, saveConfig.GetSquishFlags(), null);
            }
            else
            {
                int pixelWidth = (int)header.PitchOrLinearSize / Width;

                int mipPitch = pixelWidth * mipMap.Width;

                outputData = new byte[mipPitch * mipMap.Height];

                outputData.Initialize();

                for (int i = 0; i < mipMap.MipMap.Length; i += 4)
                {
                    uint pixelData = 0;

                    byte R = mipMap.MipMap[i + 0];
                    byte G = mipMap.MipMap[i + 1];
                    byte B = mipMap.MipMap[i + 2];
                    byte A = mipMap.MipMap[i + 3];

                    switch (saveConfig.FileFormat)
                    {
                    case FileFormat.A8R8G8B8: {
                        pixelData = ((uint)A << 24) |
                                    ((uint)R << 16) |
                                    ((uint)G << 8) |
                                    ((uint)B << 0);
                        break;
                    }

                    case FileFormat.X8R8G8B8: {
                        pixelData = ((uint)R << 16) |
                                    ((uint)G << 8) |
                                    ((uint)B << 0);
                        break;
                    }

                    case FileFormat.A8B8G8R8: {
                        pixelData = ((uint)A << 24) |
                                    ((uint)B << 16) |
                                    ((uint)G << 8) |
                                    ((uint)R << 0);
                        break;
                    }

                    case FileFormat.X8B8G8R8: {
                        pixelData = ((uint)B << 16) |
                                    ((uint)G << 8) |
                                    ((uint)R << 0);
                        break;
                    }

                    case FileFormat.A1R5G5B5: {
                        pixelData = ((uint)(A != 0 ? 1 : 0) << 15) |
                                    ((uint)(R >> 3) << 10) |
                                    ((uint)(G >> 3) << 5) |
                                    ((uint)(B >> 3) << 0);
                        break;
                    }

                    case FileFormat.A4R4G4B4: {
                        pixelData = ((uint)(A >> 4) << 12) |
                                    ((uint)(R >> 4) << 8) |
                                    ((uint)(G >> 4) << 4) |
                                    ((uint)(B >> 4) << 0);
                        break;
                    }

                    case FileFormat.R8G8B8: {
                        pixelData = ((uint)R << 16) |
                                    ((uint)G << 8) |
                                    ((uint)B << 0);
                        break;
                    }

                    case FileFormat.R5G6B5: {
                        pixelData = ((uint)(R >> 3) << 11) |
                                    ((uint)(G >> 2) << 5) |
                                    ((uint)(B >> 3) << 0);
                        break;
                    }

                    case FileFormat.G8: {
                        pixelData = (uint)((R + G + B) / 3.0 + 0.5);

                        break;
                    }
                    }

                    int pixelOffset = i / 4 * pixelWidth;

                    for (int j = 0; j < pixelWidth; j++)
                    {
                        outputData[pixelOffset + j] = (byte)((pixelData >> (8 * j)) & 0xff);
                    }
                }
            }

            return(outputData);
        }
Esempio n. 5
0
    public byte[] WriteMipMap(DdsMipMap mipMap , DdsSaveConfig saveConfig) {
      byte[] outputData;

      if (saveConfig.FileFormat >= FileFormat.DXT1 && saveConfig.FileFormat <= FileFormat.DXT5) {
        outputData = DdsSquish.CompressImage(mipMap.MipMap, mipMap.Width, mipMap.Height, saveConfig.GetSquishFlags(), null);
      }
      else {
        int pixelWidth = (int)header.PitchOrLinearSize / Width;

        int mipPitch = pixelWidth * mipMap.Width;

        outputData = new byte[mipPitch * mipMap.Height];

        outputData.Initialize();

        for(int i = 0; i < mipMap.MipMap.Length; i += 4) {
          uint pixelData = 0;

          byte R = mipMap.MipMap[i + 0];
          byte G = mipMap.MipMap[i + 1];
          byte B = mipMap.MipMap[i + 2];
          byte A = mipMap.MipMap[i + 3];

          switch(saveConfig.FileFormat) {
            case FileFormat.A8R8G8B8: {
              pixelData = ((uint)A << 24) |
                          ((uint)R << 16) |
                          ((uint)G <<  8) |
                          ((uint)B <<  0);
              break;
            }
            case FileFormat.X8R8G8B8: {
              pixelData = ((uint)R << 16) |
                          ((uint)G <<  8) |
                          ((uint)B <<  0);
              break;
            }
            case FileFormat.A8B8G8R8: {
              pixelData = ((uint)A << 24) |
                          ((uint)B << 16) |
                          ((uint)G <<  8) |
                          ((uint)R <<  0);
              break;
            }
            case FileFormat.X8B8G8R8: {
              pixelData = ((uint)B << 16) |
                          ((uint)G <<  8) |
                          ((uint)R <<  0);
              break;
            }
            case FileFormat.A1R5G5B5: {
              pixelData = ((uint)(A != 0 ? 1 : 0) << 15) |
                          ((uint)(R >> 3) << 10) |
                          ((uint)(G >> 3) <<  5) |
                          ((uint)(B >> 3) <<  0);
              break;
            }
            case FileFormat.A4R4G4B4: {
              pixelData = ((uint)(A >> 4) << 12) |
                          ((uint)(R >> 4) <<  8) |
                          ((uint)(G >> 4) <<  4) |
                          ((uint)(B >> 4) <<  0);
              break;
            }
            case FileFormat.R8G8B8: {
              pixelData = ((uint)R << 16) |
                          ((uint)G <<  8) |
                          ((uint)B <<  0);
              break;
            }
            case FileFormat.R5G6B5: {
              pixelData = ((uint)(R >> 3) << 11) |
                          ((uint)(G >> 2) <<  5) |
                          ((uint)(B >> 3) <<  0);
              break;
            }
            case FileFormat.G8: {
              pixelData = (uint)((R + G + B) / 3.0 + 0.5);

              break;
            }
          }

          int pixelOffset = i / 4 * pixelWidth;

          for(int j = 0; j < pixelWidth; j++) outputData[pixelOffset + j] = (byte)((pixelData >> (8 * j)) & 0xff);
        }
      }

      return outputData;
    }
Esempio n. 6
0
    public void Save(Stream output, DdsSaveConfig saveConfig) {
      BinaryWriter writer = new BinaryWriter(output);

      header = new DdsHeader(saveConfig, Width, Height);

      header.Write(writer);

      if (saveConfig.GenerateMipMaps) GenerateMipMaps();

      foreach(DdsMipMap mipMap in MipMaps.OrderByDescending(mip => mip.Width)) {
        byte[] outputData = WriteMipMap(mipMap, saveConfig);

        output.Write(outputData, 0, outputData.Length);
      }

      output.Flush();
    }
Esempio n. 7
0
    private async Task rebuildExports() {
      Dictionary<ExportedObjectViewEntity, List<ExportedObjectViewEntity>> filesToMod = viewModel.ExportsTree?.Traverse(e => Path.HasExtension(e.Filename) && e.IsChecked)
                                                                                                              .GroupBy(e => e.Parent)
                                                                                                              .ToDictionary(g => g.Key, g => g.ToList());

      if (filesToMod == null || !filesToMod.Any()) return;

      LoadProgressMessage message = new LoadProgressMessage { Text = "Rebuilding...", Total = filesToMod.Count };

      foreach(KeyValuePair<ExportedObjectViewEntity, List<ExportedObjectViewEntity>> pair in filesToMod) {
        string gameFilename = $"{pair.Key.Filename.Replace(settings.ExportPath, null)}.upk";

        DomainUpkFile file = allFiles.SingleOrDefault(f => f.GameFilename.Equals(gameFilename));

        if (file == null) continue;

        DomainHeader header = await repository.LoadUpkFile(Path.Combine(settings.PathToGame, file.GameFilename));

        await header.ReadHeaderAsync(null);

        message.Current++;

        foreach(ExportedObjectViewEntity entity in pair.Value) {
          DomainExportTableEntry export = header.ExportTable.SingleOrDefault(ex => ex.NameTableIndex.Name.Equals(Path.GetFileNameWithoutExtension(entity.Filename), StringComparison.CurrentCultureIgnoreCase));

          if (export == null) continue;

          await export.ParseDomainObject(header, false, false);

          int compressor = menuViewModel.IsCompressorClusterFit ? 0 : menuViewModel.IsCompressorRangeFit ? 1 : 2;

          int errorMetric = menuViewModel.IsErrorMetricPerceptual ? 0 : 1;

          DdsSaveConfig config = new DdsSaveConfig(FileFormat.Unknown, compressor, errorMetric, menuViewModel.IsWeightColorByAlpha, false);

          await export.DomainObject.SetObject(entity.Filename, header.NameTable, config);

          message.StatusText = entity.Filename;

          messenger.Send(message);
        }

        string directory = Path.Combine(settings.PathToGame, Path.GetDirectoryName(file.GameFilename), "mod");

        string filename = Path.Combine(directory, Path.GetFileName(file.GameFilename));

        if (!Directory.Exists(directory)) Directory.CreateDirectory(directory);

        await repository.SaveUpkFile(header, filename);

        DomainUpkFile upkFile = new DomainUpkFile { GameFilename = filename.Replace(settings.PathToGame, null), FileSize = new FileInfo(filename).Length };

        messenger.Send(new ModFileBuiltMessage { UpkFile = upkFile });
      }

      message.IsComplete = true;
      message.StatusText = null;

      messenger.Send(message);
    }
Esempio n. 8
0
    public DdsHeader(DdsSaveConfig config, int width, int height) {
      PixelFormat = new DdsPixelFormat(config.FileFormat);

      bool isCompressed = config.FileFormat == FileFormat.DXT1
                       || config.FileFormat == FileFormat.DXT3
                       || config.FileFormat == FileFormat.DXT5;
      //
      // Compute mip map count..
      //
      int mipCount = config.GenerateMipMaps ? CountMipMaps(width, height) : 1;

      Size = 18 * 4 + PixelFormat.Size + 5 * 4;

      Width  = (uint)width;
      Height = (uint)height;

      MipMapCount = mipCount == 1 ? 0 : (uint)mipCount;

      HeaderFlags = (uint)(Constants.HeaderFlags.Texture | (isCompressed ? Constants.HeaderFlags.LinearSize : Constants.HeaderFlags.Pitch)
                                                         | (mipCount > 1 ? Constants.HeaderFlags.MipMap     : Constants.HeaderFlags.None));

      SurfaceFlags = (uint)(Constants.SurfaceFlags.Texture | (mipCount > 1 ? Constants.SurfaceFlags.MipMap : Constants.SurfaceFlags.None));

      if (isCompressed) {
        //
        // Compresssed textures have the linear flag set.  So pitchOrLinearSize
        // needs to contain the entire size of the DXT block.
        //
        int blockCount = (width + 3) / 4 * ((height + 3) / 4);

        int blockSize = config.FileFormat == FileFormat.Unknown ? 8 : 16;

        PitchOrLinearSize = (uint)(blockCount * blockSize);
      }
      else {
        //
        // Non-compressed textures have the pitch flag set. So pitchOrLinearSize
        // needs to contain the row pitch of the main image.
        //
        int pixelWidth = 0;

        switch(config.FileFormat) {
          case FileFormat.A8R8G8B8:
          case FileFormat.X8R8G8B8:
          case FileFormat.A8B8G8R8:
          case FileFormat.X8B8G8R8: {
            pixelWidth = 4;

            break;
          }
          case FileFormat.R8G8B8: {
            pixelWidth = 3;

            break;
          }
          case FileFormat.A1R5G5B5:
          case FileFormat.A4R4G4B4:
          case FileFormat.R5G6B5: {
            pixelWidth = 2;

            break;
          }
          case FileFormat.G8: {
            pixelWidth = 1;

            break;
          }
        }

        PitchOrLinearSize = (uint)(width * pixelWidth);
      }
    }
Esempio n. 9
0
    private async Task onSaveObjectAsExecute() {
      VistaSaveFileDialog sfd = new VistaSaveFileDialog {
        FileName   = export.NameTableIndex.Name,
        DefaultExt = export.DomainObject.FileExtension,
        Filter     = $"{export.DomainObject.FileTypeDesc}|*{export.DomainObject.FileExtension}",
        Title      = "Save Object As..."
      };

      bool? result = sfd.ShowDialog();

      if (!result.HasValue || !result.Value) return;

      int compressor = menuViewModel.IsCompressorClusterFit ? 0 : menuViewModel.IsCompressorRangeFit ? 1 : 2;

      int errorMetric = menuViewModel.IsErrorMetricPerceptual ? 0 : 1;

      DdsSaveConfig config = new DdsSaveConfig(FileFormat.Unknown, compressor, errorMetric, menuViewModel.IsWeightColorByAlpha, false);

      await export.DomainObject.SaveObject(sfd.FileName, config);
    }