Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Anzeigen von DDS Dateien (https://www.delphipraxis.net/194484-anzeigen-von-dds-dateien.html)

creehawk 28. Nov 2017 16:34

Anzeigen von DDS Dateien
 
Moin Moin.

Ich möchte (muss) für ein Programm Grafik(Textur) Dateien vom Typ DDS anzeigen. Mit D7 kein Problem.

Mit Delphi 10.2 schon, weil alle angebotenen Hilfsmittel wie Devil, Vampyre, Andorra, glBitmap und weiß ich was in Delphi 10.2 nicht laufen, zumeist gibt es massig Typprobleme. Liegt wohl daran das die aktuellsten Ausgaben der genannten so um das Jahr 2009 datieren - aber auch Modelle aus 2015 gehen nicht.

Gibt es irgendwas Neueres, eine andere Möglichkeit?

creehawk

TiGü 28. Nov 2017 16:48

AW: Anzeigen von DDS Dateien
 
Da wirst du um das Laden per Stream und dann händisch auseinander basteln wohl nicht drum rum kommen.
Außer natürlich, jemand hat noch irgendwo eine fertige Unit parat.

Bist du mit dem Programm ILSpy und Paint.Net vertraut?
Mit dem Ersten kannst du im Zweiten nachschauen, wie im Namespace PaintDotNet.Data.Dds -> DdsFile diese Texturen geladen werden.

Beispiel:
Code:
      public void Load(Stream input)
      {
         uint ddsTag = (uint)input.ReadUInt32();
         if (ddsTag != 542327876u)
         {
            throw new FormatException("File does not appear to be a DDS image");
         }
         this.m_header.Read(input);
         if (this.m_header.m_pixelFormat.m_flags == 0u || (this.m_header.m_pixelFormat.m_flags & 4u) != 0u)
         {
            uint fourCC = this.m_header.m_pixelFormat.m_fourCC;
            int squishFlags;
            if (fourCC != 827611204u)
            {
               if (fourCC != 861165636u)
               {
                  if (fourCC != 894720068u)
                  {
                     throw new FormatException("File is not a supported DDS format");
                  }
                  squishFlags = 4;
               }
               else
               {
                  squishFlags = 2;
               }
            }
            else
            {
               squishFlags = 1;
            }
            int blockCount = (this.GetWidth() + 3) / 4 * ((this.GetHeight() + 3) / 4);
            int blockSize = ((squishFlags & 1) != 0) ? 8 : 16;
            byte[] compressedBlocks = new byte[blockCount * blockSize];
            input.Read(compressedBlocks, 0, compressedBlocks.GetLength(0));
            this.m_pixelData = DdsSquish.DecompressImage(compressedBlocks, this.GetWidth(), this.GetHeight(), squishFlags);
            return;
         }
         DdsFileFormat fileFormat;
         if (this.m_header.m_pixelFormat.m_flags == 65u && this.m_header.m_pixelFormat.m_rgbBitCount == 32u && this.m_header.m_pixelFormat.m_rBitMask == 16711680u && this.m_header.m_pixelFormat.m_gBitMask == 65280u && this.m_header.m_pixelFormat.m_bBitMask == 255u && this.m_header.m_pixelFormat.m_aBitMask == 4278190080u)
         {
            fileFormat = DdsFileFormat.DDS_FORMAT_A8R8G8B8;
         }
         else if (this.m_header.m_pixelFormat.m_flags == 64u && this.m_header.m_pixelFormat.m_rgbBitCount == 32u && this.m_header.m_pixelFormat.m_rBitMask == 16711680u && this.m_header.m_pixelFormat.m_gBitMask == 65280u && this.m_header.m_pixelFormat.m_bBitMask == 255u && this.m_header.m_pixelFormat.m_aBitMask == 0u)
         {
            fileFormat = DdsFileFormat.DDS_FORMAT_X8R8G8B8;
         }
         else if (this.m_header.m_pixelFormat.m_flags == 65u && this.m_header.m_pixelFormat.m_rgbBitCount == 32u && this.m_header.m_pixelFormat.m_rBitMask == 255u && this.m_header.m_pixelFormat.m_gBitMask == 65280u && this.m_header.m_pixelFormat.m_bBitMask == 16711680u && this.m_header.m_pixelFormat.m_aBitMask == 4278190080u)
         {
            fileFormat = DdsFileFormat.DDS_FORMAT_A8B8G8R8;
         }
         else if (this.m_header.m_pixelFormat.m_flags == 64u && this.m_header.m_pixelFormat.m_rgbBitCount == 32u && this.m_header.m_pixelFormat.m_rBitMask == 255u && this.m_header.m_pixelFormat.m_gBitMask == 65280u && this.m_header.m_pixelFormat.m_bBitMask == 16711680u && this.m_header.m_pixelFormat.m_aBitMask == 0u)
         {
            fileFormat = DdsFileFormat.DDS_FORMAT_X8B8G8R8;
         }
         else if (this.m_header.m_pixelFormat.m_flags == 65u && this.m_header.m_pixelFormat.m_rgbBitCount == 16u && this.m_header.m_pixelFormat.m_rBitMask == 31744u && this.m_header.m_pixelFormat.m_gBitMask == 992u && this.m_header.m_pixelFormat.m_bBitMask == 31u && this.m_header.m_pixelFormat.m_aBitMask == 32768u)
         {
            fileFormat = DdsFileFormat.DDS_FORMAT_A1R5G5B5;
         }
         else if (this.m_header.m_pixelFormat.m_flags == 65u && this.m_header.m_pixelFormat.m_rgbBitCount == 16u && this.m_header.m_pixelFormat.m_rBitMask == 3840u && this.m_header.m_pixelFormat.m_gBitMask == 240u && this.m_header.m_pixelFormat.m_bBitMask == 15u && this.m_header.m_pixelFormat.m_aBitMask == 61440u)
         {
            fileFormat = DdsFileFormat.DDS_FORMAT_A4R4G4B4;
         }
         else if (this.m_header.m_pixelFormat.m_flags == 64u && this.m_header.m_pixelFormat.m_rgbBitCount == 24u && this.m_header.m_pixelFormat.m_rBitMask == 16711680u && this.m_header.m_pixelFormat.m_gBitMask == 65280u && this.m_header.m_pixelFormat.m_bBitMask == 255u && this.m_header.m_pixelFormat.m_aBitMask == 0u)
         {
            fileFormat = DdsFileFormat.DDS_FORMAT_R8G8B8;
         }
         else
         {
            if (this.m_header.m_pixelFormat.m_flags != 64u || this.m_header.m_pixelFormat.m_rgbBitCount != 16u || this.m_header.m_pixelFormat.m_rBitMask != 63488u || this.m_header.m_pixelFormat.m_gBitMask != 2016u || this.m_header.m_pixelFormat.m_bBitMask != 31u || this.m_header.m_pixelFormat.m_aBitMask != 0u)
            {
               throw new FormatException("File is not a supported DDS format");
            }
            fileFormat = DdsFileFormat.DDS_FORMAT_R5G6B5;
         }
         int srcPixelSize = (int)(this.m_header.m_pixelFormat.m_rgbBitCount / 8u);
         int rowPitch;
         if ((this.m_header.m_headerFlags & 8u) != 0u)
         {
            rowPitch = (int)this.m_header.m_pitchOrLinearSize;
         }
         else if ((this.m_header.m_headerFlags & 524288u) != 0u)
         {
            rowPitch = (int)(this.m_header.m_pitchOrLinearSize / this.m_header.m_height);
         }
         else
         {
            rowPitch = (int)(this.m_header.m_width * (uint)srcPixelSize);
         }
         byte[] readPixelData = new byte[(long)rowPitch * (long)((ulong)this.m_header.m_height)];
         input.Read(readPixelData, 0, readPixelData.GetLength(0));
         this.m_pixelData = new byte[this.m_header.m_width * this.m_header.m_height * 4u];
         for (int destY = 0; destY < (int)this.m_header.m_height; destY++)
         {
            for (int destX = 0; destX < (int)this.m_header.m_width; destX++)
            {
               int srcPixelOffset = destY * rowPitch + destX * srcPixelSize;
               uint pixelColour = 0u;
               uint pixelRed = 0u;
               uint pixelGreen = 0u;
               uint pixelBlue = 0u;
               uint pixelAlpha = 0u;
               for (int loop = 0; loop < srcPixelSize; loop++)
               {
                  pixelColour |= (uint)((uint)readPixelData[srcPixelOffset + loop] << 8 * loop);
               }
               if (fileFormat == DdsFileFormat.DDS_FORMAT_A8R8G8B8)
               {
                  pixelAlpha = (pixelColour >> 24 & 255u);
                  pixelRed = (pixelColour >> 16 & 255u);
                  pixelGreen = (pixelColour >> 8 & 255u);
                  pixelBlue = (pixelColour & 255u);
               }
               else if (fileFormat == DdsFileFormat.DDS_FORMAT_X8R8G8B8)
               {
                  pixelAlpha = 255u;
                  pixelRed = (pixelColour >> 16 & 255u);
                  pixelGreen = (pixelColour >> 8 & 255u);
                  pixelBlue = (pixelColour & 255u);
               }
               else if (fileFormat == DdsFileFormat.DDS_FORMAT_A8B8G8R8)
               {
                  pixelAlpha = (pixelColour >> 24 & 255u);
                  pixelRed = (pixelColour & 255u);
                  pixelGreen = (pixelColour >> 8 & 255u);
                  pixelBlue = (pixelColour >> 16 & 255u);
               }
               else if (fileFormat == DdsFileFormat.DDS_FORMAT_X8B8G8R8)
               {
                  pixelAlpha = 255u;
                  pixelRed = (pixelColour & 255u);
                  pixelGreen = (pixelColour >> 8 & 255u);
                  pixelBlue = (pixelColour >> 16 & 255u);
               }
               else if (fileFormat == DdsFileFormat.DDS_FORMAT_A1R5G5B5)
               {
                  pixelAlpha = (pixelColour >> 15) * 255u;
                  pixelRed = (pixelColour >> 10 & 31u);
                  pixelGreen = (pixelColour >> 5 & 31u);
                  pixelBlue = (pixelColour & 31u);
                  pixelRed = (pixelRed << 3 | pixelRed >> 2);
                  pixelGreen = (pixelGreen << 3 | pixelGreen >> 2);
                  pixelBlue = (pixelBlue << 3 | pixelBlue >> 2);
               }
               else if (fileFormat == DdsFileFormat.DDS_FORMAT_A4R4G4B4)
               {
                  pixelAlpha = (pixelColour >> 12 & 255u);
                  pixelRed = (pixelColour >> 8 & 15u);
                  pixelGreen = (pixelColour >> 4 & 15u);
                  pixelBlue = (pixelColour & 15u);
                  pixelAlpha = (pixelAlpha << 4 | pixelAlpha);
                  pixelRed = (pixelRed << 4 | pixelRed);
                  pixelGreen = (pixelGreen << 4 | pixelGreen);
                  pixelBlue = (pixelBlue << 4 | pixelBlue);
               }
               else if (fileFormat == DdsFileFormat.DDS_FORMAT_R8G8B8)
               {
                  pixelAlpha = 255u;
                  pixelRed = (pixelColour >> 16 & 255u);
                  pixelGreen = (pixelColour >> 8 & 255u);
                  pixelBlue = (pixelColour & 255u);
               }
               else if (fileFormat == DdsFileFormat.DDS_FORMAT_R5G6B5)
               {
                  pixelAlpha = 255u;
                  pixelRed = (pixelColour >> 11 & 31u);
                  pixelGreen = (pixelColour >> 5 & 63u);
                  pixelBlue = (pixelColour & 31u);
                  pixelRed = (pixelRed << 3 | pixelRed >> 2);
                  pixelGreen = (pixelGreen << 2 | pixelGreen >> 4);
                  pixelBlue = (pixelBlue << 3 | pixelBlue >> 2);
               }
               int destPixelOffset = destY * (int)this.m_header.m_width * 4 + destX * 4;
               this.m_pixelData[destPixelOffset] = (byte)pixelRed;
               this.m_pixelData[destPixelOffset + 1] = (byte)pixelGreen;
               this.m_pixelData[destPixelOffset + 2] = (byte)pixelBlue;
               this.m_pixelData[destPixelOffset + 3] = (byte)pixelAlpha;
            }
         }
      }

creehawk 28. Nov 2017 17:12

AW: Anzeigen von DDS Dateien
 
Selber basteln......

Hab' ich schon geahnt. Schaun' mer ma.

Vielen Dank für die Antwort.

Creehawk

Jens01 28. Nov 2017 17:14

AW: Anzeigen von DDS Dateien
 
Hast Du wirklich die "aktuelle" Datei von glBitmap?
http://git.delphigl.com/?p=glBitmap..../master;sf=tgz
Forum https://delphigl.com/forum/viewtopic.php?p=62127#p62127

Was geht denn da nicht?

Vielleicht auch mal Herrn Bergmann fragen, der verwaltet das gerade.
http://www.delphigl.com/forum/viewtopic.php?t=7457
https://bergmann89.de/de/

Jens01 28. Nov 2017 17:19

AW: Anzeigen von DDS Dateien
 
in der "glBitmapConf.default.inc" müssen Kompilerdirektiven für Delphi eingestellt werden!

creehawk 29. Nov 2017 07:30

AW: Anzeigen von DDS Dateien
 
Moin Moin.

glBitmap habe ich samt Zubehör installiert. Mangels Dokumentation habe ich folgendes ausprobiert:


Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  TGLBMPTyp:Tglbitmapdata;
  BMPTyp:TBitmap;
begin
   BMPTyp := TBitmap.Create; TGLBMPTyp := Tglbitmapdata.Create;
   TGLBMPTyp.LoadFromFile('E:\Games\maps\Attuwe_Color.dds');
   // TGLBMPTyp.AssignToBitmap(BitmapTyp);
   TGLBMPTyp.AssignToBitmap(Form1.Image1.Picture.Bitmap);
end;

// Fehlermeldung aus UNIT GLBitmap : "Fehlerhafters Pixelformat"


procedure TForm1.Button2Click(Sender: TObject);
var
  TGLBMPTyp:Tglbitmapdata;
begin
   TGLBMPTyp := tglbitmapdata.Create;
   TGLBMPTyp.LoadFromFile('E:\Games\maps\Attuwe_Color.dds');
   TGLBMPTyp.SaveToFile('E:\Games\maps\Attuwe_Color.bmp',ftbmp);
end;

// Fehlermeldung aus UNIT GLBitmap : Unsupported Format : tf23tcDtx1rgba
Letzteres - die Formatdefinition - steht auch nicht in der Liste der unterstützten Formate. Geht also wohl nicht, es sei denn ich mache etwas falsch.

Blöderweise ist das Programm das ich da erarbeite eigentlich eine Übertragung von Delphi7 nach Delphi 10.2. Die Delphi 7 Variante arbeitet problemlos.

In Delphi7 wird die DevIL Variante verwendet (2005), die, kompiliert mit Delphi 10.2, auch problemlos arbeitet, aber nichts anzeigt. Die DevIL Variante in neuerer Version wurde überarbeitet, aber ohne Dokumentation - jedenfalls habe ich keine gefunden - veröffentlicht. Die Befehle der Version 2005 funktionieren nicht mehr.

Wat mach' ich nu?

creehawk

Redeemer 29. Nov 2017 07:57

AW: Anzeigen von DDS Dateien
 
Liste der Anhänge anzeigen (Anzahl: 1)
Lag hier rum, ist von 2012 aber sollte immer noch laufen. Methoden sind LoadDXT1, LoadDXT3 und LoadDXT5, such dir eins aus oder schreib eine Methode, das das erkennt. Index, Heights und Widths sind wegen des Programms, das sie verwendet hat, da, weil es die als vertikale ImageStrips benutzt hat und so ein wahlfreier Zugriff möglich ist. Daten werden in einen MemoryStream kopiert, weil das byteweise Lesen von FileStreams sehr langsam ist.

TiGü 29. Nov 2017 08:51

AW: Anzeigen von DDS Dateien
 
Zitat:

Zitat von Redeemer (Beitrag 1387440)
Lag hier rum, ist von 2012 aber sollte immer noch laufen. Methoden sind LoadDXT1, LoadDXT3 und LoadDXT5, such dir eins aus oder schreib eine Methode, das das erkennt. Index, Heights und Widths sind wegen des Programms, das sie verwendet hat, da, weil es die als vertikale ImageStrips benutzt hat und so ein wahlfreier Zugriff möglich ist. Daten werden in einen MemoryStream kopiert, weil das byteweise Lesen von FileStreams sehr langsam ist.

Funktioniert gut für die drei Formatvarianten (nachdem ich den Filestream-Parameter angepasst habe)!
Mit der Vorlage sollte der TE ggf. auch die anderen Formate implementieren können, wenn er sie denn braucht.

Jens01 29. Nov 2017 11:41

AW: Anzeigen von DDS Dateien
 
@creehawk
Dann würde ich sagen, glBitmap macht Dein Format nicht ....

TiGü 29. Nov 2017 13:20

AW: Anzeigen von DDS Dateien
 
Mir ist noch was eingefallen. Du könntest es auch per DirectX an sich laden.
Mit folgenden Codeschnipsel hast du zumindest die geladene DDS-Datei als IDirect3DTexture9 und IDirect3DSurface9 vorliegen.

Es würde noch die Möglichkeit geben das in eine IDirectDrawSurface7 umzukopieren und die dann wiederum zu verwenden, um ein Winapi.GDIOBJ.TGPBitmap zu erzeugen. Vom TGPBitmap aus kann man ja weitermachen...
Sag Bescheid, wenn du das dann brauchst.

Delphi-Quellcode:
uses
  Winapi.GDIPOBJ,
  Winapi.Windows,
  Winapi.Direct3D9,
  // Winapi.DirectDraw,
  Winapi.D3DX9;

procedure LoadPerDirectX(const Filename: string);
var
  HR: HRESULT;
  Direct3D: IDirect3D9Ex;
  Device: IDirect3DDevice9;
  Texture: IDirect3DTexture9;
  Params: TD3DPresentParameters;
  DisplayMode: TD3DDisplayMode;
  D3DSurface: IDirect3DSurface9;
  // DDSurface: IDirectDrawSurface7;
begin
  HR := Direct3DCreate9Ex(D3D_SDK_VERSION, Direct3D);
  if Failed(HR) then
    Exit;

  HR := Direct3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, DisplayMode);
  if Failed(HR) then
    Exit;

  FillChar(Params, SizeOf(Params), 0);
  Params.SwapEffect := D3DSWAPEFFECT_DISCARD;
  Params.BackBufferCount := 1;
  Params.BackBufferWidth := DisplayMode.Width;
  Params.BackBufferHeight := DisplayMode.Height;
  Params.BackBufferFormat := DisplayMode.Format;

  HR := Direct3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, 0, D3DCREATE_SOFTWARE_VERTEXPROCESSING, @Params, Device);
  if Failed(HR) then
    Exit;

  HR := Winapi.D3DX9.D3DXCreateTextureFromFile(Device, PWideChar(Filename), Texture);
  if Failed(HR) then
    Exit;

  HR := Texture.GetSurfaceLevel(0, D3DSurface);
  if Failed(HR) then
    Exit;
end;

creehawk 29. Nov 2017 14:37

AW: Anzeigen von DDS Dateien
 
@redeemer

Herunterladen : 5 Sekunden - Einbauen : 120 Sekunden - Ausprobieren : 360 Sekunden - Erfolg: 100% !

Perfekt.

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
Var
PNGTyp:TPngImage;
begin
PNGTyp:= TPNGIMAGE.Create;
PNGTyp := LoadDXT1('aaaaa');
Image1.Picture.Assign(PngTyp);
end;
Das ist alles. LoadDXT1 ist alles was ich brauche, die DDS Dateien stammen aus den PC Spielen CaesarIV, Anno1404 und Age of Empires 3.

@an alle die geantwortet haben
Ich bin nicht der Experte für PC Grafik. Vieles davon muss und musste ich mir empirisch zusammenbasteln, "basteln" wörtlich genommen. Und die o.g. LoadDXT1 ist mir in ihrer Ausführung auch ziemlich schleierhaft.
Wir hier bauen für einige ältere Spiele - siehe oben - Karten, Missionen und Hilfstools. Das spielt sich eher in dem Bereich Datenbank oder auch schlichter Textbearbeitung ab.

Ich bedanke mich bei allen für die Antworten und Hilfestellungen! :thumb:

creehawk

TiGü 29. Nov 2017 14:41

AW: Anzeigen von DDS Dateien
 
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
Var
  PNGTyp:TPngImage;
begin
  PNGTyp := LoadDXT1('aaaaa');
  Image1.Picture.Assign(PngTyp);
  PNGTyp.Free;
end;
Sonst hast du Speicherlecks!

creehawk 29. Nov 2017 17:06

AW: Anzeigen von DDS Dateien
 
Ups, alles klar, danke!

haentschman 30. Nov 2017 05:34

AW: Anzeigen von DDS Dateien
 
Moin...:P
Ich will ja nicht meckern...aber TRY FINALLY ist ein indisches Gewürz oder? :roll:
Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var
  PNGTyp:TPngImage;
begin
  PNGTyp := LoadDXT1('aaaaa');
  try
    Image1.Picture.Assign(PngTyp);
  finally
    PNGTyp.Free;
  end;
end;

haluter 13. Sep 2020 13:44

AW: Anzeigen von DDS Dateien
 
Hi, apologies for using English but I am desperate for some help.

I need to load a DDS file and display it in a TImage32 (or TImage/TBitmap) component, but I have been unable to do so.

Could I please ask you for an example on how to do this (if possible?)

Thank you!

TurboMagic 13. Sep 2020 14:57

AW: Anzeigen von DDS Dateien
 
Hello,

download the attachment attached to this post from 2017 in this thread:

Zitat:

Zitat von Redeemer (Beitrag 1387440)
Lag hier rum, ist von 2012 aber sollte immer noch laufen.

Then use the sample code in the answer directly preceeding your post.
That should work.

Best regards
TurboMagic

himitsu 13. Sep 2020 16:03

AW: Anzeigen von DDS Dateien
 
Zitat:

Zitat von creehawk (Beitrag 1387507)
Herunterladen : 5 Sekunden - Einbauen : 120 Sekunden - Ausprobieren : 360 Sekunden - Erfolg: 100% !

Perfekt.

Speicherleck 200%.

Einmal die Instanz vom Create, dann nochmal aus LoadDXT1, und am Ende wird Keine davon wieder freigegeben.

Zitat:

Sonst hast du Speicherlecks!
Und ja, nach einem Fehler kann Aufräumen auch nie schaden.

TurboMagic 13. Sep 2020 19:24

AW: Anzeigen von DDS Dateien
 
Wieso? Der Code im Post direkt vor seinem = "preceding" gibt doch das png image frei! Oder was hab' ich übersehen?

himitsu 13. Sep 2020 22:14

AW: Anzeigen von DDS Dateien
 
Zitat:

Zitat von TurboMagic (Beitrag 1473516)
Oder was hab' ich übersehen?

Posts #6 und #11, da hast bestimmt zuviel gesehn.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:58 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz