* Bitfield support for LoadDDS
[LazOpenGLCore.git] / glBitmap.pas
index 68d9cde..e1e591d 100644 (file)
@@ -591,7 +591,7 @@ type
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
   TglBitmapFormat = (
-    tfEmpty = 0,
+    tfEmpty = 0, //must be smallest value!
 
     tfAlpha4,
     tfAlpha8,
@@ -645,7 +645,11 @@ type
 
     tfDepth16,
     tfDepth24,
-    tfDepth32
+    tfDepth32,
+
+    tfS3tcDtx1RGBA,
+    tfS3tcDtx3RGBA,
+    tfS3tcDtx5RGBA
   );
 
   TglBitmapFileType = (
@@ -1004,6 +1008,7 @@ procedure glBitmapGetDefaultTextureWrap(var S, T, R: Cardinal);
 
 function glBitmapPosition(X: Integer = -1; Y: Integer = -1): TglBitmapPixelPosition;
 function glBitmapColorRec(const r, g, b, a: Cardinal): TglBitmapColorRec;
+function glBitmapColorRecCmp(const r1, r2: TglBitmapColorRec): Boolean;
 
 var
   glBitmapDefaultDeleteTextureOnFree: Boolean;
@@ -1052,7 +1057,10 @@ type
     fFormat: TglBitmapFormat;
     fWithAlpha: TglBitmapFormat;
     fWithoutAlpha: TglBitmapFormat;
+    fRGBInverted: TglBitmapFormat;
+    fUncompressed: TglBitmapFormat;
     fPixelSize: Single;
+    fIsCompressed: Boolean;
 
     fRange: TglBitmapColorRec;
     fShift: TShiftRec;
@@ -1066,8 +1074,10 @@ type
     property Format:       TglBitmapFormat read fFormat;
     property WithAlpha:    TglBitmapFormat read fWithAlpha;
     property WithoutAlpha: TglBitmapFormat read fWithoutAlpha;
+    property RGBInverted:  TglBitmapFormat read fRGBInverted;
     property Components:   Integer         read GetComponents;
     property PixelSize:    Single          read fPixelSize;
+    property IsCompressed: Boolean         read fIsCompressed;
 
     property glFormat:         Cardinal read fglFormat;
     property glInternalFormat: Cardinal read fglInternalFormat;
@@ -1410,6 +1420,24 @@ type
     constructor Create; override;
   end;
 
+  TfdS3tcDtx1RGBA = class(TFormatDescriptor)
+    procedure Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); override;
+    procedure Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); override;
+    constructor Create; override;
+  end;
+
+  TfdS3tcDtx3RGBA = class(TFormatDescriptor)
+    procedure Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); override;
+    procedure Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); override;
+    constructor Create; override;
+  end;
+
+  TfdS3tcDtx5RGBA = class(TFormatDescriptor)
+    procedure Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer); override;
+    procedure Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer); override;
+    constructor Create; override;
+  end;
+
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   TbmpBitfieldFormat = class(TFormatDescriptor)
   private
@@ -1523,7 +1551,11 @@ const
 
     TfdDepth16,
     TfdDepth24,
-    TfdDepth32
+    TfdDepth32,
+
+    TfdS3tcDtx1RGBA,
+    TfdS3tcDtx3RGBA,
+    TfdS3tcDtx5RGBA
   );
 
 var
@@ -1554,6 +1586,18 @@ begin
 end;
 
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function glBitmapColorRecCmp(const r1, r2: TglBitmapColorRec): Boolean;
+var
+  i: Integer;
+begin
+  result := false;
+  for i := 0 to high(r1.arr) do
+    if (r1.arr[i] <> r2.arr[i]) then
+      exit;
+  result := true;
+end;
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 function glBitmapShiftRec(const r, g, b, a: Byte): TShiftRec;
 begin
   result.r := r;
@@ -1565,8 +1609,6 @@ end;
 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 function FormatGetSupportedFiles(const aFormat: TglBitmapFormat): TglBitmapFileTypes;
 begin
-  result := [ftDDS, ftTGA];
-
   if (aFormat in [
         //4 bbp
         tfLuminance4,
@@ -1586,9 +1628,45 @@ begin
         tfBGR10, tfBGR10A2, tfBGRA8]) then
     result := result + [ftBMP];
 
-  //TODO Supported File Formats!
+  if (aFormat in [
+        //8 bpp
+        tfLuminance8, tfAlpha8,
+
+        //16 bpp
+        tfLuminance16, tfLuminance8Alpha8,
+        tfRGB5, tfRGB5A1, tfRGBA4,
+        tfBGR5, tfBGR5A1, tfBGRA4,
+
+        //24 bpp
+        tfRGB8, tfBGR8,
+
+        //32 bpp
+        tfRGB10A2, tfRGBA8, tfBGR10A2, tfBGRA8]) then
+    result := result + [ftTGA];
+
+  if (aFormat in [
+        //8 bpp
+        tfAlpha8, tfLuminance8, tfLuminance4Alpha4, tfLuminance6Alpha2,
+        tfR3G3B2, tfRGBA2, tfBGRA2,
+
+        //16 bpp
+        tfAlpha16, tfLuminance16, tfLuminance8Alpha8, tfLuminance12Alpha4,
+        tfRGB4, tfR5G6B5, tfRGB5, tfRGBA4, tfRGB5A1,
+        tfBGR4, tfB5G6R5, tfBGR5, tfBGRA4, tfBGR5A1,
+
+        //24 bpp
+        tfRGB8, tfBGR8,
+
+        //32 bbp
+        tfLuminance16Alpha16,
+        tfRGBA8, tfRGB10A2,
+        tfBGRA8, tfBGR10A2,
 
-  (*
+        //compressed
+        tfS3tcDtx1RGBA, tfS3tcDtx3RGBA, tfS3tcDtx5RGBA]) then
+    result := result + [ftDDS];
+
+  (* TODO
   {$IFDEF GLB_SUPPORT_PNG_WRITE}
   if aFormat in [
     tfAlpha4, tfAlpha8, tfAlpha12, tfAlpha16,
@@ -2204,7 +2282,10 @@ begin
   fFormat       := tfEmpty;
   fWithAlpha    := tfEmpty;
   fWithoutAlpha := tfEmpty;
+  fRGBInverted  := tfEmpty;
+  fUncompressed := tfEmpty;
   fPixelSize    := 0.0;
+  fIsCompressed := false;
 
   fglFormat         := 0;
   fglInternalFormat := 0;
@@ -2932,6 +3013,7 @@ begin
   fFormat           := tfRGB4;
   fWithAlpha        := tfRGBA4;
   fWithoutAlpha     := tfRGB4;
+  fRGBInverted      := tfBGR4;
   fRange.r          := $F;
   fRange.g          := $F;
   fRange.b          := $F;
@@ -2949,6 +3031,7 @@ begin
   fFormat           := tfR5G6B5;
   fWithAlpha        := tfRGBA4;
   fWithoutAlpha     := tfR5G6B5;
+  fRGBInverted      := tfB5G6R5;
   fRange.r          := $1F;
   fRange.g          := $3F;
   fRange.b          := $1F;
@@ -2966,6 +3049,7 @@ begin
   fFormat           := tfRGB5;
   fWithAlpha        := tfRGB5A1;
   fWithoutAlpha     := tfRGB5;
+  fRGBInverted      := tfBGR5;
   fRange.r          := $1F;
   fRange.g          := $1F;
   fRange.b          := $1F;
@@ -2983,6 +3067,7 @@ begin
   fFormat           := tfRGB8;
   fWithAlpha        := tfRGBA8;
   fWithoutAlpha     := tfRGB8;
+  fRGBInverted      := tfBGR8;
   fglInternalFormat := GL_RGB8;
 end;
 
@@ -2992,6 +3077,7 @@ begin
   fFormat           := tfRGB10;
   fWithAlpha        := tfRGB10A2;
   fWithoutAlpha     := tfRGB10;
+  fRGBInverted      := tfBGR10;
   fRange.r          := $3FF;
   fRange.g          := $3FF;
   fRange.b          := $3FF;
@@ -3009,6 +3095,7 @@ begin
   fFormat           := tfRGB12;
   fWithAlpha        := tfRGBA12;
   fWithoutAlpha     := tfRGB12;
+  fRGBInverted      := tfBGR12;
   fglInternalFormat := GL_RGB12;
 end;
 
@@ -3018,6 +3105,7 @@ begin
   fFormat           := tfRGB16;
   fWithAlpha        := tfRGBA16;
   fWithoutAlpha     := tfRGB16;
+  fRGBInverted      := tfBGR16;
   fglInternalFormat := GL_RGB16;
 end;
 
@@ -3027,6 +3115,7 @@ begin
   fFormat           := tfRGBA2;
   fWithAlpha        := tfRGBA2;
   fWithoutAlpha     := tfR3G3B2;
+  fRGBInverted      := tfBGRA2;
   fglInternalFormat := GL_RGBA2;
 end;
 
@@ -3036,6 +3125,7 @@ begin
   fFormat           := tfRGBA4;
   fWithAlpha        := tfRGBA4;
   fWithoutAlpha     := tfRGB4;
+  fRGBInverted      := tfBGRA4;
   fRange.r          := $F;
   fRange.g          := $F;
   fRange.b          := $F;
@@ -3055,6 +3145,7 @@ begin
   fFormat           := tfRGB5A1;
   fWithAlpha        := tfRGB5A1;
   fWithoutAlpha     := tfRGB5;
+  fRGBInverted      := tfBGR5A1;
   fRange.r          := $1F;
   fRange.g          := $1F;
   fRange.b          := $1F;
@@ -3074,6 +3165,7 @@ begin
   fFormat           := tfRGBA8;
   fWithAlpha        := tfRGBA8;
   fWithoutAlpha     := tfRGB8;
+  fRGBInverted      := tfBGRA8;
   fglInternalFormat := GL_RGBA8;
 end;
 
@@ -3083,6 +3175,7 @@ begin
   fFormat           := tfRGB10A2;
   fWithAlpha        := tfRGB10A2;
   fWithoutAlpha     := tfRGB10;
+  fRGBInverted      := tfBGR10A2;
   fRange.r          := $3FF;
   fRange.g          := $3FF;
   fRange.b          := $3FF;
@@ -3102,6 +3195,7 @@ begin
   fFormat           := tfRGBA12;
   fWithAlpha        := tfRGBA12;
   fWithoutAlpha     := tfRGB12;
+  fRGBInverted      := tfBGRA12;
   fglInternalFormat := GL_RGBA12;
 end;
 
@@ -3111,6 +3205,7 @@ begin
   fFormat           := tfRGBA16;
   fWithAlpha        := tfRGBA16;
   fWithoutAlpha     := tfRGB16;
+  fRGBInverted      := tfBGRA16;
   fglInternalFormat := GL_RGBA16;
 end;
 
@@ -3121,6 +3216,7 @@ begin
   fFormat           := tfBGR4;
   fWithAlpha        := tfBGRA4;
   fWithoutAlpha     := tfBGR4;
+  fRGBInverted      := tfRGB4;
   fRange.r          := $F;
   fRange.g          := $F;
   fRange.b          := $F;
@@ -3143,6 +3239,7 @@ begin
   fFormat           := tfB5G6R5;
   fWithAlpha        := tfBGRA4;
   fWithoutAlpha     := tfB5G6R5;
+  fRGBInverted      := tfR5G6B5;
   fRange.r          := $1F;
   fRange.g          := $3F;
   fRange.b          := $1F;
@@ -3154,9 +3251,6 @@ begin
   fglDataFormat     := GL_UNSIGNED_SHORT_5_6_5;
 end;
 
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 constructor TfdBGR5.Create;
 begin
   inherited Create;
@@ -3164,6 +3258,7 @@ begin
   fFormat           := tfBGR5;
   fWithAlpha        := tfBGR5A1;
   fWithoutAlpha     := tfBGR5;
+  fRGBInverted      := tfRGB5;
   fRange.r          := $1F;
   fRange.g          := $1F;
   fRange.b          := $1F;
@@ -3183,6 +3278,7 @@ begin
   fFormat           := tfBGR8;
   fWithAlpha        := tfBGRA8;
   fWithoutAlpha     := tfBGR8;
+  fRGBInverted      := tfRGB8;
   fglInternalFormat := GL_RGB8;
 end;
 
@@ -3192,6 +3288,7 @@ begin
   fFormat           := tfBGR10;
   fWithAlpha        := tfBGR10A2;
   fWithoutAlpha     := tfBGR10;
+  fRGBInverted      := tfRGB10;
   fRange.r          := $3FF;
   fRange.g          := $3FF;
   fRange.b          := $3FF;
@@ -3211,6 +3308,7 @@ begin
   fFormat           := tfBGR12;
   fWithAlpha        := tfBGRA12;
   fWithoutAlpha     := tfBGR12;
+  fRGBInverted      := tfRGB12;
   fglInternalFormat := GL_RGB12;
 end;
 
@@ -3220,6 +3318,7 @@ begin
   fFormat           := tfBGR16;
   fWithAlpha        := tfBGRA16;
   fWithoutAlpha     := tfBGR16;
+  fRGBInverted      := tfRGB16;
   fglInternalFormat := GL_RGB16;
 end;
 
@@ -3229,6 +3328,7 @@ begin
   fFormat           := tfBGRA2;
   fWithAlpha        := tfBGRA4;
   fWithoutAlpha     := tfBGR4;
+  fRGBInverted      := tfRGBA2;
   fglInternalFormat := GL_RGBA2;
 end;
 
@@ -3238,6 +3338,7 @@ begin
   fFormat           := tfBGRA4;
   fWithAlpha        := tfBGRA4;
   fWithoutAlpha     := tfBGR4;
+  fRGBInverted      := tfRGBA4;
   fRange.r          := $F;
   fRange.g          := $F;
   fRange.b          := $F;
@@ -3257,6 +3358,7 @@ begin
   fFormat           := tfBGR5A1;
   fWithAlpha        := tfBGR5A1;
   fWithoutAlpha     := tfBGR5;
+  fRGBInverted      := tfRGB5A1;
   fRange.r          := $1F;
   fRange.g          := $1F;
   fRange.b          := $1F;
@@ -3276,6 +3378,7 @@ begin
   fFormat           := tfBGRA8;
   fWithAlpha        := tfBGRA8;
   fWithoutAlpha     := tfBGR8;
+  fRGBInverted      := tfRGBA8;
   fglInternalFormat := GL_RGBA8;
 end;
 
@@ -3285,6 +3388,7 @@ begin
   fFormat           := tfBGR10A2;
   fWithAlpha        := tfBGR10A2;
   fWithoutAlpha     := tfBGR10;
+  fRGBInverted      := tfRGB10A2;
   fRange.r          := $3FF;
   fRange.g          := $3FF;
   fRange.b          := $3FF;
@@ -3304,6 +3408,7 @@ begin
   fFormat           := tfBGRA12;
   fWithAlpha        := tfBGRA12;
   fWithoutAlpha     := tfBGR12;
+  fRGBInverted      := tfRGBA12;
   fglInternalFormat := GL_RGBA12;
 end;
 
@@ -3313,6 +3418,7 @@ begin
   fFormat           := tfBGRA16;
   fWithAlpha        := tfBGRA16;
   fWithoutAlpha     := tfBGR16;
+  fRGBInverted      := tfRGBA16;
   fglInternalFormat := GL_RGBA16;
 end;
 
@@ -3344,6 +3450,84 @@ begin
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//TfdS3tcDtx1RGBA/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TfdS3tcDtx1RGBA.Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer);
+begin
+  raise EglBitmapException.Create('mapping for compressed formats is not supported');
+end;
+
+procedure TfdS3tcDtx1RGBA.Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer);
+begin
+  raise EglBitmapException.Create('mapping for compressed formats is not supported');
+end;
+
+constructor TfdS3tcDtx1RGBA.Create;
+begin
+  inherited Create;
+  fFormat           := tfS3tcDtx1RGBA;
+  fWithAlpha        := tfS3tcDtx1RGBA;
+  fUncompressed     := tfRGB5A1;
+  fPixelSize        := 0.5;
+  fIsCompressed     := true;
+  fglFormat         := GL_COMPRESSED_RGBA;
+  fglInternalFormat := GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+  fglDataFormat     := GL_UNSIGNED_BYTE;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//TfdS3tcDtx3RGBA/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TfdS3tcDtx3RGBA.Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer);
+begin
+  raise EglBitmapException.Create('mapping for compressed formats is not supported');
+end;
+
+procedure TfdS3tcDtx3RGBA.Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer);
+begin
+  raise EglBitmapException.Create('mapping for compressed formats is not supported');
+end;
+
+constructor TfdS3tcDtx3RGBA.Create;
+begin
+  inherited Create;
+  fFormat           := tfS3tcDtx3RGBA;
+  fWithAlpha        := tfS3tcDtx3RGBA;
+  fUncompressed     := tfRGBA8;
+  fPixelSize        := 1.0;
+  fIsCompressed     := true;
+  fglFormat         := GL_COMPRESSED_RGBA;
+  fglInternalFormat := GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+  fglDataFormat     := GL_UNSIGNED_BYTE;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//TfdS3tcDtx5RGBA/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TfdS3tcDtx5RGBA.Map(const aPixel: TglBitmapPixelData; var aData: PByte; var aMapData: Pointer);
+begin
+  raise EglBitmapException.Create('mapping for compressed formats is not supported');
+end;
+
+procedure TfdS3tcDtx5RGBA.Unmap(var aData: PByte; var aPixel: TglBitmapPixelData; var aMapData: Pointer);
+begin
+  raise EglBitmapException.Create('mapping for compressed formats is not supported');
+end;
+
+constructor TfdS3tcDtx5RGBA.Create;
+begin
+  inherited Create;
+  fFormat           := tfS3tcDtx3RGBA;
+  fWithAlpha        := tfS3tcDtx3RGBA;
+  fUncompressed     := tfRGBA8;
+  fPixelSize        := 1.0;
+  fIsCompressed     := true;
+  fglFormat         := GL_COMPRESSED_RGBA;
+  fglInternalFormat := GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+  fglDataFormat     := GL_UNSIGNED_BYTE;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //TFormatDescriptor///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 class procedure TFormatDescriptor.Init;
@@ -3531,9 +3715,6 @@ begin
         fColorTable[i].g := Round(((i shr Shift.g) and Range.g) / Range.g * 255);
         fColorTable[i].b := Round(((i shr Shift.b) and Range.b) / Range.b * 255);
         fColorTable[i].a := 0;
-
-        s := SysUtils.Format('%.2X%.2X%.2X' + sLineBreak, [fColorTable[i].r, fColorTable[i].g, fColorTable[i].b]);
-        fs.Write(s[1], Length(s));
       end;
     end;
   end;
@@ -4004,6 +4185,8 @@ procedure TglBitmap.LoadFromFile(const aFilename: String);
 var
   fs: TFileStream;
 begin
+  if not FileExists(aFilename) then
+    raise EglBitmapException.Create('file does not exist: ' + aFilename);
   fFilename := aFilename;
   fs := TFileStream.Create(fFilename, fmOpenRead);
   try
@@ -6422,29 +6605,43 @@ type
     ImageID: Byte;
     ColorMapType: Byte;
     ImageType: Byte;
-    ColorMapSpec: Array[0..4] of Byte;
+    //ColorMapSpec: Array[0..4] of Byte;
+    ColorMapStart: Word;
+    ColorMapLength: Word;
+    ColorMapEntrySize: Byte;
     OrigX: Word;
     OrigY: Word;
     Width: Word;
     Height: Word;
     Bpp: Byte;
-    ImageDes: Byte;
+    ImageDesc: Byte;
   end;
 
 const
-  TGA_UNCOMPRESSED_RGB = 2;
-  TGA_UNCOMPRESSED_GRAY = 3;
-  TGA_COMPRESSED_RGB = 10;
-  TGA_COMPRESSED_GRAY = 11;
+  TGA_UNCOMPRESSED_COLOR_TABLE =  1;
+  TGA_UNCOMPRESSED_RGB         =  2;
+  TGA_UNCOMPRESSED_GRAY        =  3;
+  TGA_COMPRESSED_COLOR_TABLE   =  9;
+  TGA_COMPRESSED_RGB           = 10;
+  TGA_COMPRESSED_GRAY          = 11;
+
+  TGA_NONE_COLOR_TABLE = 0;
+  TGA_COLOR_TABLE      = 1;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 function TglBitmap.LoadTGA(const aStream: TStream): Boolean;
 var
   Header: TTGAHeader;
-  NewImage, pData: PByte;
-  StreamPos: Int64;
-  PixelSize, LineSize, YStart, YEnd, YInc: Integer;
-  Format: TglBitmapFormat;
+  ImageData: PByte;
+  StartPosition: Int64;
+  PixelSize, LineSize: Integer;
+  tgaFormat: TglBitmapFormat;
+  FormatDesc: TFormatDescriptor;
+  Counter: packed record
+    X, Y: packed record
+      low, high, dir: Integer;
+    end;
+  end;
 
 const
   CACHE_SIZE = $4000;
@@ -6452,195 +6649,233 @@ const
   ////////////////////////////////////////////////////////////////////////////////////////
   procedure ReadUncompressed;
   var
-    RowSize: Integer;
+    i, j: Integer;
+    buf, tmp1, tmp2: PByte;
   begin
-    RowSize := Header.Width * PixelSize;
-    // copy line by line
-    while YStart <> YEnd + YInc do begin
-      pData := NewImage;
-      Inc(pData, YStart * LineSize);
-      aStream.Read(pData^, RowSize);
-      Inc(YStart, YInc);
+    buf := nil;
+    if (Counter.X.dir < 0) then
+      buf := GetMem(LineSize);
+    try
+      while (Counter.Y.low <> Counter.Y.high + counter.Y.dir) do begin
+        tmp1 := ImageData + (Counter.Y.low * LineSize); //pointer to LineStart
+        if (Counter.X.dir < 0) then begin               //flip X
+          aStream.Read(buf^, LineSize);
+          tmp2 := buf + LineSize - PixelSize;           //pointer to last pixel in line
+          for i := 0 to Header.Width-1 do begin         //for all pixels in line
+            for j := 0 to PixelSize-1 do begin          //for all bytes in pixel
+              tmp1^ := tmp2^;
+              inc(tmp1);
+              inc(tmp2);
+            end;
+            dec(tmp2, 2*PixelSize);                     //move 2 backwards, because j-loop moved 1 forward
+          end;
+        end else
+          aStream.Read(tmp1^, LineSize);
+        inc(Counter.Y.low, Counter.Y.dir);              //move to next line index
+      end;
+    finally
+      if Assigned(buf) then
+        FreeMem(buf);
     end;
   end;
 
   ////////////////////////////////////////////////////////////////////////////////////////
   procedure ReadCompressed;
-  var
-    HeaderWidth, HeaderHeight: Integer;
-    LinePixelsRead, ImgPixelsRead, ImgPixelsToRead: Integer;
-
-    Cache: PByte;
-    CacheSize, CachePos: Integer;
-
-    Temp: Byte;
-    TempBuf: Array [0..15] of Byte;
-
-    PixelRepeat: Boolean;
-    PixelToRead, TempPixels: Integer;
 
     /////////////////////////////////////////////////////////////////
+    var
+      TmpData: PByte;
+      LinePixelsRead: Integer;
     procedure CheckLine;
     begin
-      if LinePixelsRead >= HeaderWidth then begin
+      if (LinePixelsRead >= Header.Width) then begin
         LinePixelsRead := 0;
-        pData := NewImage;
-        Inc(YStart, YInc);
-        Inc(pData, YStart * LineSize);
+        inc(Counter.Y.low, Counter.Y.dir);                //next line index
+        TmpData := ImageData + Counter.Y.low * LineSize;  //set line
+        if (Counter.X.dir < 0) then                       //if x flipped then
+          TmpData := TmpData + LineSize - PixelSize;      //set last pixel
       end;
     end;
 
     /////////////////////////////////////////////////////////////////
+    var
+      Cache: PByte;
+      CacheSize, CachePos: Integer;
     procedure CachedRead(out Buffer; Count: Integer);
     var
       BytesRead: Integer;
     begin
-      if (CachePos + Count) > CacheSize then begin
+      if (CachePos + Count > CacheSize) then begin
+        //if buffer overflow save non read bytes
         BytesRead := 0;
-
-        // Read Data
-        if CacheSize - CachePos > 0 then begin
+        if (CacheSize - CachePos > 0) then begin
           BytesRead := CacheSize - CachePos;
-          Move(pByteArray(Cache)^[CachePos], Buffer, BytesRead);
-          Inc(CachePos, BytesRead);
+          Move(PByteArray(Cache)^[CachePos], Buffer, BytesRead);
+          inc(CachePos, BytesRead);
         end;
 
-        // Reload Data
+        //load cache from file
         CacheSize := Min(CACHE_SIZE, aStream.Size - aStream.Position);
         aStream.Read(Cache^, CacheSize);
         CachePos := 0;
 
-        // Read else
-        if Count - BytesRead > 0 then begin
-          Move(pByteArray(Cache)^[CachePos], TByteArray(Buffer)[BytesRead], Count - BytesRead);
-          Inc(CachePos, Count - BytesRead);
+        //read rest of requested bytes
+        if (Count - BytesRead > 0) then begin
+          Move(PByteArray(Cache)^[CachePos], TByteArray(Buffer)[BytesRead], Count - BytesRead);
+          inc(CachePos, Count - BytesRead);
         end;
       end else begin
-        Move(pByteArray(Cache)^[CachePos], Buffer, Count);
-        Inc(CachePos, Count);
+        //if no buffer overflow just read the data
+        Move(PByteArray(Cache)^[CachePos], Buffer, Count);
+        inc(CachePos, Count);
+      end;
+    end;
+
+    procedure PixelToBuffer(const aData: PByte; var aBuffer: PByte);
+    begin
+      case PixelSize of
+        1: begin
+          aBuffer^ := aData^;
+          inc(aBuffer, Counter.X.dir);
+        end;
+        2: begin
+          PWord(aBuffer)^ := PWord(aData)^;
+          inc(aBuffer, 2 * Counter.X.dir);
+        end;
+        3: begin
+          PByteArray(aBuffer)^[0] := PByteArray(aData)^[0];
+          PByteArray(aBuffer)^[1] := PByteArray(aData)^[1];
+          PByteArray(aBuffer)^[2] := PByteArray(aData)^[2];
+          inc(aBuffer, 3 * Counter.X.dir);
+        end;
+        4: begin
+          PCardinal(aBuffer)^ := PCardinal(aData)^;
+          inc(aBuffer, 4 * Counter.X.dir);
+        end;
       end;
     end;
 
+  var
+    TotalPixelsToRead, TotalPixelsRead: Integer;
+    Temp: Byte;
+    buf: array [0..3] of Byte; //1 pixel is max 32bit long
+    PixelRepeat: Boolean;
+    PixelsToRead, PixelCount: Integer;
   begin
     CacheSize := 0;
-    CachePos := 0;
+    CachePos  := 0;
 
-    HeaderWidth := Header.Width;
-    HeaderHeight := Header.Height;
+    TotalPixelsToRead := Header.Width * Header.Height;
+    TotalPixelsRead   := 0;
+    LinePixelsRead    := 0;
 
-    GetMem(Cache, CACHE_SIZE); // 16K Buffer
+    GetMem(Cache, CACHE_SIZE);
     try
-      ImgPixelsToRead := HeaderWidth * HeaderHeight;
-      ImgPixelsRead := 0;
-      LinePixelsRead := 0;
+      TmpData := ImageData + Counter.Y.low * LineSize;  //set line
+      if (Counter.X.dir < 0) then                       //if x flipped then
+        TmpData := TmpData + LineSize - PixelSize;      //set last pixel
 
-      pData := NewImage;
-      Inc(pData, YStart * LineSize);
-
-      // Read until all Pixels
       repeat
+        //read CommandByte
         CachedRead(Temp, 1);
-
-        PixelRepeat := Temp and $80 > 0;
-        PixelToRead := (Temp and $7F) + 1;
-
-        Inc(ImgPixelsRead, PixelToRead);
-
-        if PixelRepeat then begin
-          // repeat one pixel x times
-          CachedRead(TempBuf[0], PixelSize);
-
-          // repeat Pixel
-          while PixelToRead > 0 do begin
-            CheckLine;
-
-            TempPixels := HeaderWidth - LinePixelsRead;
-            if PixelToRead < TempPixels then
-              TempPixels := PixelToRead;
-
-            Inc(LinePixelsRead, TempPixels);
-            Dec(PixelToRead, TempPixels);
-
-            while TempPixels > 0 do begin
-              case PixelSize of
-                1: begin
-                  pData^ := TempBuf[0];
-                  Inc(pData);
-                end;
-                2: begin
-                  pWord(pData)^ := pWord(@TempBuf[0])^;
-                  Inc(pData, 2);
-                end;
-                3: begin
-                  pWord(pData)^ := pWord(@TempBuf[0])^;
-                  Inc(pData, 2);
-                  pData^ := TempBuf[2];
-                  Inc(pData);
-                end;
-                4: begin
-                  pDWord(pData)^ := pDWord(@TempBuf[0])^;
-                  Inc(pData, 4);
-                end;
-              end;
-              Dec(TempPixels);
-            end;
-          end;
-        end else begin
-          // copy x pixels
-          while PixelToRead > 0 do begin
-            CheckLine;
-            TempPixels := HeaderWidth - LinePixelsRead;
-            if PixelToRead < TempPixels then
-              TempPixels := PixelToRead;
-            CachedRead(pData^, PixelSize * TempPixels);
-            Inc(pData, PixelSize * TempPixels);
-            Inc(LinePixelsRead, TempPixels);
-            Dec(PixelToRead, TempPixels);
+        PixelRepeat  := (Temp and $80) > 0;
+        PixelsToRead := (Temp and $7F) + 1;
+        inc(TotalPixelsRead, PixelsToRead);
+
+        if PixelRepeat then
+          CachedRead(buf[0], PixelSize);
+        while (PixelsToRead > 0) do begin
+          CheckLine;
+          PixelCount := Min(Header.Width - LinePixelsRead, PixelsToRead); //max read to EOL or EOF
+          while (PixelCount > 0) do begin
+            if not PixelRepeat then
+              CachedRead(buf[0], PixelSize);
+            PixelToBuffer(@buf[0], TmpData);
+            inc(LinePixelsRead);
+            dec(PixelsToRead);
+            dec(PixelCount);
           end;
         end;
-      until ImgPixelsRead >= ImgPixelsToRead;
+      until (TotalPixelsRead >= TotalPixelsToRead);
     finally
-      FreeMem(Cache)
+      FreeMem(Cache);
     end;
   end;
 
+  function IsGrayFormat: Boolean;
+  begin
+    result := Header.ImageType in [TGA_UNCOMPRESSED_GRAY, TGA_COMPRESSED_GRAY];
+  end;
+
 begin
   result := false;
 
   // reading header to test file and set cursor back to begin
-  StreamPos := aStream.Position;
+  StartPosition := aStream.Position;
   aStream.Read(Header, SizeOf(Header));
 
   // no colormapped files
-  if (Header.ColorMapType = 0) then begin
-    if Header.ImageType in [TGA_UNCOMPRESSED_RGB, TGA_UNCOMPRESSED_GRAY, TGA_COMPRESSED_RGB, TGA_COMPRESSED_GRAY] then begin
+  if (Header.ColorMapType = TGA_NONE_COLOR_TABLE) and (Header.ImageType in [
+    TGA_UNCOMPRESSED_RGB, TGA_UNCOMPRESSED_GRAY, TGA_COMPRESSED_RGB, TGA_COMPRESSED_GRAY]) then
+  begin
+    try
+      if Header.ImageID <> 0 then       // skip image ID
+        aStream.Position := aStream.Position + Header.ImageID;
+
       case Header.Bpp of
-        //TODO 8: Format := tfAlpha8;
-        16: Format := tfLuminance8Alpha8;
-        24: Format := tfBGR8;
-        32: Format := tfBGRA8;
-      else
-        raise EglBitmapException.Create('LoadTga - unsupported BitsPerPixel found.');
+         8: if IsGrayFormat then case (Header.ImageDesc and $F) of
+               0: tgaFormat := tfLuminance8;
+               8: tgaFormat := tfAlpha8;
+            end;
+
+        16: if IsGrayFormat then case (Header.ImageDesc and $F) of
+               0: tgaFormat := tfLuminance16;
+               8: tgaFormat := tfLuminance8Alpha8;
+            end else case (Header.ImageDesc and $F) of
+               0: tgaFormat := tfBGR5;
+               1: tgaFormat := tfBGR5A1;
+               4: tgaFormat := tfBGRA4;
+            end;
+
+        24: if not IsGrayFormat then case (Header.ImageDesc and $F) of
+               0: tgaFormat := tfBGR8;
+            end;
+
+        32: if not IsGrayFormat then case (Header.ImageDesc and $F) of
+               2: tgaFormat := tfBGR10A2;
+               8: tgaFormat := tfBGRA8;
+            end;
       end;
 
-      // skip image ID
-      if Header.ImageID <> 0 then
-        aStream.Position := aStream.Position + Header.ImageID;
+      if (tgaFormat = tfEmpty) then
+        raise EglBitmapException.Create('LoadTga - unsupported format');
 
-      PixelSize := TFormatDescriptor.Get(Format).GetSize(1, 1);
-      LineSize  := Trunc(Header.Width * PixelSize);
+      FormatDesc := TFormatDescriptor.Get(tgaFormat);
+      PixelSize  := FormatDesc.GetSize(1, 1);
+      LineSize   := FormatDesc.GetSize(Header.Width, 1);
 
-      GetMem(NewImage, LineSize * Header.Height);
+      GetMem(ImageData, LineSize * Header.Height);
       try
+        //column direction
+        if ((Header.ImageDesc and (1 shl 4)) > 0) then begin
+          Counter.X.low  := Header.Height-1;;
+          Counter.X.high := 0;
+          Counter.X.dir  := -1;
+        end else begin
+          Counter.X.low  := 0;
+          Counter.X.high := Header.Height-1;
+          Counter.X.dir  := 1;
+        end;
+
         // Row direction
-        if (Header.ImageDes and $20 > 0) then begin
-          YStart := 0;
-          YEnd := Header.Height -1;
-          YInc := 1;
+        if ((Header.ImageDesc and (1 shl 5)) > 0) then begin
+          Counter.Y.low  := 0;
+          Counter.Y.high := Header.Height-1;
+          Counter.Y.dir  := 1;
         end else begin
-          YStart := Header.Height -1;
-          YEnd := 0;
-          YInc := -1;
+          Counter.Y.low  := Header.Height-1;;
+          Counter.Y.high := 0;
+          Counter.Y.dir  := -1;
         end;
 
         // Read Image
@@ -6651,104 +6886,113 @@ begin
             ReadCompressed;
         end;
 
-        SetDataPointer(NewImage, Format, Header.Width, Header.Height);
+        SetDataPointer(ImageData, tgaFormat, Header.Width, Header.Height);
         result := true;
       except
-        FreeMem(NewImage);
+        FreeMem(ImageData);
         raise;
       end;
-    end
-      else aStream.Position := StreamPos;
+    finally
+      aStream.Position := StartPosition;
+    end;
   end
-    else aStream.Position := StreamPos;
+    else aStream.Position := StartPosition;
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 procedure TglBitmap.SaveTGA(const aStream: TStream);
 var
   Header: TTGAHeader;
-  Size: Integer;
-  pTemp: pByte;
+  LineSize, Size, x, y: Integer;
+  Pixel: TglBitmapPixelData;
+  LineBuf, SourceData, DestData: PByte;
+  SourceMD, DestMD: Pointer;
   FormatDesc: TFormatDescriptor;
-
-  procedure ConvertData(pTemp: pByte);
-  var
-    Idx, PixelSize: Integer;
-    Temp: byte;
-  begin
-    PixelSize := fPixelSize;
-    for Idx := 1 to Height * Width do begin
-      Temp := pByteArray(pTemp)^[2];
-      pByteArray(pTemp)^[2] := pByteArray(pTemp)^[0];
-      pByteArray(pTemp)^[0] := Temp;
-      Inc(pTemp, PixelSize);
-    end;
-  end;
-
+  Converter: TFormatDescriptor;
 begin
   if not (ftTGA in FormatGetSupportedFiles(Format)) then
     raise EglBitmapUnsupportedFormatFormat.Create('SaveTGA - ' + UNSUPPORTED_FORMAT);
 
+  //prepare header
   FillChar(Header, SizeOf(Header), 0);
-  case Format of
-    //TODO ifAlpha8, ifLuminance8, ifDepth8: begin
-    tfLuminance8: begin
-      Header.ImageType := TGA_UNCOMPRESSED_GRAY;
-      Header.Bpp := 8;
-    end;
-    tfLuminance8Alpha8: begin
-      Header.ImageType := TGA_UNCOMPRESSED_GRAY;
-      Header.Bpp := 16;
-    end;
-    tfRGB8, tfBGR8: begin
-      Header.ImageType := TGA_UNCOMPRESSED_RGB;
-      Header.Bpp := 24;
-    end;
-    tfRGBA8, tfBGRA8: begin
-      Header.ImageType := TGA_UNCOMPRESSED_RGB;
-      Header.Bpp := 32;
-    end;
-  else
-    raise EglBitmapUnsupportedFormatFormat.Create('SaveTGA - ' + UNSUPPORTED_FORMAT);
-  end;
 
-  Header.Width    := Width;
-  Header.Height   := Height;
-  Header.ImageDes := $20;
-  FormatDesc      := TFormatDescriptor.Get(Format);
+  //set ImageType
+  if (Format in [tfLuminance8, tfLuminance6Alpha2, tfLuminance4Alpha4, tfAlpha8,
+                 tfLuminance16, tfLuminance12Alpha4, tfLuminance8Alpha8]) then
+    Header.ImageType := TGA_UNCOMPRESSED_GRAY
+  else
+    Header.ImageType := TGA_UNCOMPRESSED_RGB;
+
+  //set BitsPerPixel
+  if (Format in [tfLuminance8, tfLuminance6Alpha2, tfLuminance4Alpha4, tfAlpha8]) then
+    Header.Bpp := 8
+  else if (Format in [tfLuminance16, tfLuminance12Alpha4, tfLuminance8Alpha8,
+                      tfRGB5, tfBGR5, tfRGB5A1, tfBGR5A1, tfRGBA4, tfBGRA4]) then
+    Header.Bpp := 16
+  else if (Format in [tfBGR8, tfRGB8]) then
+    Header.Bpp := 24
+  else
+    Header.Bpp := 32;
 
-  if FormatDesc.HasAlpha then
-    Header.ImageDes := Header.ImageDes or $08;
+  //set AlphaBitCount
+  case Format of
+    tfRGB5A1, tfBGR5A1:
+      Header.ImageDesc := 1 and $F;
+    tfRGB10A2, tfBGR10A2:
+      Header.ImageDesc := 2 and $F;
+    tfRGBA4, tfBGRA4:
+      Header.ImageDesc := 4 and $F;
+    tfAlpha8, tfLuminance8Alpha8, tfRGBA8, tfBGRA8:
+      Header.ImageDesc := 8 and $F;
+  end;
+
+  Header.Width     := Width;
+  Header.Height    := Height;
+  Header.ImageDesc := Header.ImageDesc or $20; //flip y
   aStream.Write(Header, SizeOf(Header));
 
   // convert RGB(A) to BGR(A)
-  Size := FormatDesc.GetSize(Dimension);
-  if Format in [tfRGB8, tfRGBA8] then begin
-    GetMem(pTemp, Size);
-  end else
-    pTemp := Data;
-
-  try
-    // convert data
-    if Format in [tfRGB8, tfRGBA8] then begin
-      Move(Data^, pTemp^, Size);
-      ConvertData(pTemp);
+  Converter  := nil;
+  FormatDesc := TFormatDescriptor.Get(Format);
+  Size       := FormatDesc.GetSize(Dimension);
+  if Format in [tfRGB5, tfRGB5A1, tfRGBA4, tfRGB8, tfRGB10A2, tfRGBA8] then begin
+    if (FormatDesc.RGBInverted = tfEmpty) then
+      raise EglBitmapException.Create('inverted RGB format is empty');
+    Converter := TFormatDescriptor.Get(FormatDesc.RGBInverted);
+    if not glBitmapColorRecCmp(Converter.Range, FormatDesc.Range) or
+       (Converter.PixelSize <> FormatDesc.PixelSize) then
+      raise EglBitmapException.Create('invalid inverted RGB format');
+  end;
+
+  if Assigned(Converter) then begin
+    LineSize := FormatDesc.GetSize(Width, 1);
+    LineBuf  := GetMem(LineSize);
+    SourceMD := FormatDesc.CreateMappingData;
+    DestMD   := Converter.CreateMappingData;
+    try
+      SourceData := Data;
+      for y := 0 to Height-1 do begin
+        DestData := LineBuf;
+        for x := 0 to Width-1 do begin
+          FormatDesc.Unmap(SourceData, Pixel, SourceMD);
+          Converter.Map(Pixel, DestData, DestMD);
+        end;
+        aStream.Write(LineBuf^, LineSize);
+      end;
+    finally
+      FreeMem(LineBuf);
+      FormatDesc.FreeMappingData(SourceMD);
+      FormatDesc.FreeMappingData(DestMD);
     end;
-
-    // write data
-    aStream.Write(pTemp^, Size);
-  finally
-    // free tempdata
-    if Format in [tfRGB8, tfRGBA8] then
-      FreeMem(pTemp);
-  end;
+  end else
+    aStream.Write(Data^, Size);
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //DDS/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 const
-  DDS_MAGIC                   = $20534444;
+  DDS_MAGIC: Cardinal         = $20534444;
 
   // DDS_header.dwFlags
   DDSD_CAPS                   = $00000001;
@@ -6762,9 +7006,11 @@ const
 
   // DDS_header.sPixelFormat.dwFlags
   DDPF_ALPHAPIXELS            = $00000001;
+  DDPF_ALPHA                  = $00000002;
   DDPF_FOURCC                 = $00000004;
   DDPF_INDEXED                = $00000020;
   DDPF_RGB                    = $00000040;
+  DDPF_LUMINANCE              = $00020000;
 
   // DDS_header.sCaps.dwCaps1
   DDSCAPS_COMPLEX             = $00000008;
@@ -6805,7 +7051,6 @@ type
   end;
 
   TDDSHeader = packed record
-    dwMagic: Cardinal;
     dwSize: Cardinal;
     dwFlags: Cardinal;
     dwHeight: Cardinal;
@@ -6823,128 +7068,176 @@ type
 function TglBitmap.LoadDDS(const aStream: TStream): Boolean;
 var
   Header: TDDSHeader;
-  StreamPos: Int64;
-  Y, LineSize: Cardinal;
-  RowSize: Cardinal;
-  NewImage, pData: pByte;
-  ddsFormat: TglBitmapFormat;
-
-  function RaiseEx : Exception;
-  begin
-    result := EglBitmapException.Create('LoadDDS - unsupported Pixelformat found.');
-  end;
+  Converter: TbmpBitfieldFormat;
 
   function GetDDSFormat: TglBitmapFormat;
+  var
+    fd: TFormatDescriptor;
+    i: Integer;
+    Range: TglBitmapColorRec;
+    match: Boolean;
   begin
+    result := tfEmpty;
     with Header.PixelFormat do begin
       // Compresses
-      if (dwFlags and DDPF_FOURCC) > 0 then begin
-        (* TODO
+      if ((dwFlags and DDPF_FOURCC) > 0) then begin
         case Header.PixelFormat.dwFourCC of
-          D3DFMT_DXT1: result := ifDXT1;
-          D3DFMT_DXT3: result := ifDXT3;
-          D3DFMT_DXT5: result := ifDXT5;
-        else
-          raise RaiseEx;
+          D3DFMT_DXT1: result := tfS3tcDtx1RGBA;
+          D3DFMT_DXT3: result := tfS3tcDtx3RGBA;
+          D3DFMT_DXT5: result := tfS3tcDtx5RGBA;
+        end;
+      end else if ((Header.PixelFormat.dwFlags and (DDPF_RGB or DDPF_ALPHAPIXELS or DDPF_LUMINANCE)) > 0) then begin
+
+        //find matching format
+        for result := High(TglBitmapFormat) downto Low(TglBitmapFormat) do begin
+          fd := TFormatDescriptor.Get(result);
+          if fd.MaskMatch(dwRBitMask, dwGBitMask, dwBBitMask, dwABitMask) and
+             (8 * fd.PixelSize = dwRGBBitCount) then
+            exit;
         end;
-        *)
-        raise RaiseEx;
-      end else
 
-      // RGB
-      if (dwFlags and (DDPF_RGB or DDPF_ALPHAPIXELS)) > 0 then begin
-        case dwRGBBitCount of
-          8: begin
-            (* TODO if dwFlags and DDPF_ALPHAPIXELS > 0 then
-              result := tfAlpha
-            else
-            *)
-              result := tfLuminance8;
-          end;
-          16: begin
-            if dwFlags and DDPF_ALPHAPIXELS > 0 then begin
-              // Alpha
-              case CountSetBits(dwRBitMask) of
-                5: result := tfRGB5A1;
-                //TODO 4: result := tfRGBA4;
-              else
-                result := tfLuminance8Alpha8;
-              end;
-            end else begin
-              // no Alpha
-              //TODO result := ifR5G6B5;
-              raise RaiseEx;
+        //find format with same Range
+        Range.r := dwRBitMask;
+        Range.g := dwGBitMask;
+        Range.b := dwBBitMask;
+        Range.a := dwABitMask;
+        for i := 0 to 3 do begin
+          while ((Range.arr[i] and 1) = 0) and (Range.arr[i] > 0) do
+            Range.arr[i] := Range.arr[i] shr 1;
+        end;
+        for result := High(TglBitmapFormat) downto Low(TglBitmapFormat) do begin
+          fd := TFormatDescriptor.Get(result);
+          match := true;
+          for i := 0 to 3 do
+            if (fd.Range.arr[i] <> Range.arr[i]) then begin
+              match := false;
+              break;
             end;
-          end;
-          24: begin
-            if dwRBitMask > dwBBitMask then
-              result := tfBGR8
-            else
-              result := tfRGB8;
-          end;
-        32: begin
-            if CountSetBits(dwRBitMask) = 10 then
-              //TODO result := tfRGB10A2
-              raise RaiseEx
-            else
+          if match then
+            break;
+        end;
 
-            if dwRBitMask > dwBBitMask then
-              result := tfBGRA8
-            else
-              result := tfRGBA8;
-          end;
-        else
-          raise RaiseEx;
+        //no format with same range found -> use default
+        if (result = tfEmpty) then begin
+          if (dwABitMask > 0) then
+            result := tfBGRA8
+          else
+            result := tfBGR8;
         end;
-      end else
-        raise RaiseEx;
+
+        Converter := TbmpBitfieldFormat.Create;
+        Converter.RedMask   := dwRBitMask;
+        Converter.GreenMask := dwGBitMask;
+        Converter.BlueMask  := dwBBitMask;
+        Converter.AlphaMask := dwABitMask;
+        Converter.PixelSize := dwRGBBitCount / 8;
+      end;
     end;
   end;
 
-begin
-  result := false;
+var
+  StreamPos: Int64;
+  x, y, j, LineSize, RowSize, Magic: Cardinal;
+  NewImage, TmpData, RowData, SrcData: PByte;
+  SourceMD, DestMD: Pointer;
+  Pixel: TglBitmapPixelData;
+  ddsFormat: TglBitmapFormat;
+  FormatDesc: TFormatDescriptor;
 
-  // Header
+begin
+  result    := false;
+  Converter := nil;
   StreamPos := aStream.Position;
-  aStream.Read(Header, sizeof(Header));
 
-  if ((Header.dwMagic <> DDS_MAGIC) or (Header.dwSize <> 124) or
-     ((Header.dwFlags and DDSD_PIXELFORMAT) = 0) or ((Header.dwFlags and DDSD_CAPS) = 0)) then begin
+  // Magic
+  aStream.Read(Magic, sizeof(Magic));
+  if (Magic <> DDS_MAGIC) then begin
+    aStream.Position := StreamPos;
+    exit;
+  end;
+
+  //Header
+  aStream.Read(Header, sizeof(Header));
+  if (Header.dwSize <> SizeOf(Header)) or
+     ((Header.dwFlags and (DDSD_PIXELFORMAT or DDSD_CAPS or DDSD_WIDTH or DDSD_HEIGHT)) <>
+        (DDSD_PIXELFORMAT or DDSD_CAPS or DDSD_WIDTH or DDSD_HEIGHT)) then
+  begin
     aStream.Position := StreamPos;
     exit;
   end;
 
+  if ((Header.Caps.dwCaps1 and DDSCAPS2_CUBEMAP) > 0) then
+    raise EglBitmapException.Create('LoadDDS - CubeMaps are not supported');
+
   ddsFormat := GetDDSFormat;
-  LineSize  := Trunc(Header.dwWidth * TFormatDescriptor.Get(ddsFormat).PixelSize);
-  GetMem(NewImage, Header.dwHeight * LineSize);
   try
-    pData := NewImage;
-
-    // Compressed
-    if (Header.PixelFormat.dwFlags and DDPF_FOURCC) > 0 then begin
-      RowSize := Header.dwPitchOrLinearSize div Header.dwWidth;
-      for Y := 0 to Header.dwHeight -1 do begin
-        aStream.Read(pData^, RowSize);
-        Inc(pData, LineSize);
-      end;
-    end else
+    if (ddsFormat = tfEmpty) then
+      raise EglBitmapException.Create('LoadDDS - unsupported Pixelformat found.');
 
-    // RGB(A)
-    if (Header.PixelFormat.dwFlags and (DDPF_RGB or DDPF_ALPHAPIXELS)) > 0 then begin
-      RowSize := Header.dwPitchOrLinearSize;
+    FormatDesc := TFormatDescriptor.Get(ddsFormat);
+    LineSize   := Trunc(Header.dwWidth * FormatDesc.PixelSize);
+    GetMem(NewImage, Header.dwHeight * LineSize);
+    try
+      TmpData := NewImage;
+
+      //Converter needed
+      if Assigned(Converter) then begin
+        RowSize := Round(Header.dwWidth * Header.PixelFormat.dwRGBBitCount / 8);
+        GetMem(RowData, RowSize);
+        SourceMD := Converter.CreateMappingData;
+        DestMD   := FormatDesc.CreateMappingData;
+        try
+          for y := 0 to Header.dwHeight-1 do begin
+            TmpData := NewImage + y * LineSize;
+            SrcData := RowData;
+            aStream.Read(SrcData^, RowSize);
+            for x := 0 to Header.dwWidth-1 do begin
+              Converter.Unmap(SrcData, Pixel, SourceMD);
+              //TODO use converter function
+              for j := 0 to 3 do
+                if (Converter.Range.arr[j] <> FormatDesc.Range.arr[j]) then begin
+                  if (Converter.Range.arr[j] > 0) then
+                    Pixel.Data.arr[j] := Round(Pixel.Data.arr[j] / Converter.Range.arr[j] * FormatDesc.Range.arr[j])
+                  else
+                    Pixel.Data.arr[j] := 0;
+                end;
+              FormatDesc.Map(Pixel, TmpData, DestMD);
+            end;
+          end;
+        finally
+          Converter.FreeMappingData(SourceMD);
+          FormatDesc.FreeMappingData(DestMD);
+          FreeMem(RowData);
+        end;
+      end else
 
-      for Y := 0 to Header.dwHeight -1 do begin
-        aStream.Read(pData^, RowSize);
-        Inc(pData, LineSize);
-      end;
-    end else
-      raise RaiseEx;
+      // Compressed
+      if ((Header.PixelFormat.dwFlags and DDPF_FOURCC) > 0) then begin
+        RowSize := Header.dwPitchOrLinearSize div Header.dwWidth;
+        for Y := 0 to Header.dwHeight-1 do begin
+          aStream.Read(TmpData^, RowSize);
+          Inc(TmpData, LineSize);
+        end;
+      end else
 
-    SetDataPointer(NewImage, ddsFormat, Header.dwWidth, Header.dwHeight);
-    result := true;
-  except
-    FreeMem(NewImage);
-    raise;
+      // Uncompressed
+      if (Header.PixelFormat.dwFlags and (DDPF_RGB or DDPF_ALPHAPIXELS or DDPF_LUMINANCE)) > 0 then begin
+        RowSize := (Header.PixelFormat.dwRGBBitCount * Header.dwWidth) shr 3;
+        for Y := 0 to Header.dwHeight-1 do begin
+          aStream.Read(TmpData^, RowSize);
+          Inc(TmpData, LineSize);
+        end;
+      end else
+        raise EglBitmapException.Create('LoadDDS - unsupported Pixelformat found.');
+
+      SetDataPointer(NewImage, ddsFormat, Header.dwWidth, Header.dwHeight);
+      result := true;
+    except
+      FreeMem(NewImage);
+      raise;
+    end;
+  finally
+    FreeAndNil(Converter);
   end;
 end;
 
@@ -6952,55 +7245,55 @@ end;
 procedure TglBitmap.SaveDDS(const aStream: TStream);
 var
   Header: TDDSHeader;
-  Pix: TglBitmapPixelData;
   FormatDesc: TFormatDescriptor;
 begin
-  //if not FormatIsUncompressed(InternalFormat) then
-  //  raise EglBitmapUnsupportedFormatFormat.Create('SaveDDS - ' + UNSUPPORTED_FORMAT);
+  if not (ftDDS in FormatGetSupportedFiles(Format)) then
+    raise EglBitmapUnsupportedFormatFormat.Create('SaveDDS - ' + UNSUPPORTED_FORMAT);
 
-  (* TODO if Format = tfAlpha8 then
-    FORMAT_DESCRIPTORS[tfLuminance8].PreparePixel(Pix);
-  else    *)
-    TFormatDescriptor.Get(Format).PreparePixel(Pix);
+  FormatDesc := TFormatDescriptor.Get(Format);
 
   // Generell
   FillChar(Header, SizeOf(Header), 0);
-  Header.dwMagic := DDS_MAGIC;
-  Header.dwSize  := 124;
-  Header.dwFlags := DDSD_PITCH or DDSD_CAPS or DDSD_PIXELFORMAT;
+  Header.dwSize  := SizeOf(Header);
+  Header.dwFlags := DDSD_WIDTH or DDSD_HEIGHT or DDSD_CAPS or DDSD_PIXELFORMAT;
 
-  if Width > 0 then begin
-    Header.dwWidth := Width;
-    Header.dwFlags := Header.dwFlags or DDSD_WIDTH;
-  end;
-
-  if Height > 0 then begin
-    Header.dwHeight := Height;
-    Header.dwFlags := Header.dwFlags or DDSD_HEIGHT;
-  end;
-
-  Header.dwPitchOrLinearSize := fRowSize;
-  Header.dwMipMapCount := 1;
+  Header.dwWidth  := Max(1, Width);
+  Header.dwHeight := Max(1, Height);
 
   // Caps
   Header.Caps.dwCaps1 := DDSCAPS_TEXTURE;
 
   // Pixelformat
-  Header.PixelFormat.dwSize  := Sizeof(Header.PixelFormat);
-  Header.PixelFormat.dwFlags := DDPF_RGB;
+  Header.PixelFormat.dwSize := sizeof(Header);
+  if (FormatDesc.IsCompressed) then begin
+    Header.PixelFormat.dwFlags := Header.PixelFormat.dwFlags or DDPF_FOURCC;
+    case Format of
+      tfS3tcDtx1RGBA: Header.PixelFormat.dwFourCC := D3DFMT_DXT1;
+      tfS3tcDtx3RGBA: Header.PixelFormat.dwFourCC := D3DFMT_DXT3;
+      tfS3tcDtx5RGBA: Header.PixelFormat.dwFourCC := D3DFMT_DXT5;
+    end;
+  end else if (Format in [tfAlpha8, tfAlpha16]) then begin
+    Header.PixelFormat.dwFlags       := Header.PixelFormat.dwFlags or DDPF_ALPHA;
+    Header.PixelFormat.dwRGBBitCount := Round(FormatDesc.PixelSize * 8);
+    Header.PixelFormat.dwABitMask    := FormatDesc.AlphaMask;
+  end else if (FormatDesc.RedMask = FormatDesc.GreenMask) and (FormatDesc.GreenMask = FormatDesc.BlueMask) then begin
+    Header.PixelFormat.dwFlags       := Header.PixelFormat.dwFlags or DDPF_LUMINANCE;
+    Header.PixelFormat.dwRGBBitCount := Round(FormatDesc.PixelSize * 8);
+    Header.PixelFormat.dwRBitMask    := FormatDesc.RedMask;
+    Header.PixelFormat.dwABitMask    := FormatDesc.AlphaMask;
+  end else begin
+    Header.PixelFormat.dwFlags := Header.PixelFormat.dwFlags or DDPF_RGB;
+    Header.PixelFormat.dwRGBBitCount := Round(FormatDesc.PixelSize * 8);
+    Header.PixelFormat.dwRBitMask    := FormatDesc.RedMask;
+    Header.PixelFormat.dwGBitMask    := FormatDesc.GreenMask;
+    Header.PixelFormat.dwBBitMask    := FormatDesc.BlueMask;
+    Header.PixelFormat.dwABitMask    := FormatDesc.AlphaMask;
+  end;
 
-  (* TODO tfAlpha8
-  if FORMAT_DESCRIPTORS[Format].HasAlpha and (Format <> tfAlpha8) then
+  if (FormatDesc.HasAlpha) then
     Header.PixelFormat.dwFlags := Header.PixelFormat.dwFlags or DDPF_ALPHAPIXELS;
-  *)
-
-  FormatDesc := TFormatDescriptor.Get(Format);
-  Header.PixelFormat.dwRGBBitCount  := Trunc(FormatDesc.PixelSize * 8);
-  Header.PixelFormat.dwRBitMask     := FormatDesc.RedMask;
-  Header.PixelFormat.dwGBitMask     := FormatDesc.GreenMask;
-  Header.PixelFormat.dwBBitMask     := FormatDesc.BlueMask;
-  Header.PixelFormat.dwABitMask := FormatDesc.AlphaMask;
 
+  aStream.Write(DDS_MAGIC, sizeof(DDS_MAGIC));
   aStream.Write(Header, SizeOf(Header));
   aStream.Write(Data^, FormatDesc.GetSize(Dimension));
 end;
@@ -7024,8 +7317,7 @@ var
 begin
   inherited SetDataPointer(aData, aFormat, aWidth, aHeight);
 
-  //TODO compression
-  if {FormatIsUncompressed(Format)} true then begin
+  if not TFormatDescriptor.Get(aFormat).IsCompressed then begin
     (* TODO PixelFuncs
     fGetPixelFunc := GetPixel2DUnmap;
     fSetPixelFunc := SetPixel2DUnmap;
@@ -7042,9 +7334,8 @@ begin
     end
       else SetLength(fLines, 0);
   end else begin
-    (*
     SetLength(fLines, 0);
-
+    (*
     fSetPixelFunc := nil;
 
     case Format of
@@ -7068,19 +7359,16 @@ var
 begin
   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
-  (* TODO compression
-  if Self.InternalFormat in [ifDXT1, ifDXT3, ifDXT5] then
-    glCompressedTexImage2D(Target, 0, InternalFormat, Width, Height, 0, Trunc(Width * Height * FormatGetSize(Self.InternalFormat)), Data)
-  else
-  *)
-
   FormatDesc := TFormatDescriptor.Get(Format);
-  if aBuildWithGlu then
+  if FormatDesc.IsCompressed then begin
+    glCompressedTexImage2D(Target, 0, FormatDesc.glInternalFormat, Width, Height, 0, FormatDesc.GetSize(fDimension), Data)
+  end else if aBuildWithGlu then begin
     gluBuild2DMipmaps(aTarget, FormatDesc.Components, Width, Height,
       FormatDesc.glFormat, FormatDesc.glDataFormat, Data)
-  else
+  end else begin
     glTexImage2D(aTarget, 0, FormatDesc.glInternalFormat, Width, Height, 0,
       FormatDesc.glFormat, FormatDesc.glDataFormat, Data);
+  end;
 
   // Freigeben
   if (FreeDataAfterGenTexture) then
@@ -7101,15 +7389,13 @@ var
   Size, w, h: Integer;
   FormatDesc: TFormatDescriptor;
 begin
-  (* TODO compression
-  if not FormatIsUncompressed(Format) then
+  FormatDesc := TFormatDescriptor.Get(Format);
+  if FormatDesc.IsCompressed then
     raise EglBitmapUnsupportedFormatFormat.Create('TglBitmap2D.GrabScreen - ' + UNSUPPORTED_FORMAT);
-  *)
 
-  w := aRight  - aLeft;
-  h := aBottom - aTop;
-  FormatDesc   := TFormatDescriptor.Get(Format);
-  Size         := FormatDesc.GetSize(w, h);
+  w    := aRight  - aLeft;
+  h    := aBottom - aTop;
+  Size := FormatDesc.GetSize(w, h);
   GetMem(Temp, Size);
   try
     glPixelStorei(GL_PACK_ALIGNMENT, 1);
@@ -7149,12 +7435,10 @@ begin
   FormatDesc := TFormatDescriptor.Get(IntFormat);
   GetMem(Temp, FormatDesc.GetSize(TempWidth, TempHeight));
   try
-    (* TODO Compression
-    if FormatIsCompressed(IntFormat) and (GL_VERSION_1_3 or GL_ARB_texture_compression) then
+    if FormatDesc.IsCompressed then
       glGetCompressedTexImage(Target, 0, Temp)
     else
-    *)
-    glGetTexImage(Target, 0, FormatDesc.glInternalFormat, FormatDesc.glDataFormat, Temp);
+     glGetTexImage(Target, 0, FormatDesc.glInternalFormat, FormatDesc.glDataFormat, Temp);
     SetDataPointer(Temp, IntFormat, TempWidth, TempHeight);
   except
     FreeMem(Temp);