* Format: implemented HasRed, HasGreen and HasBlue
[LazOpenGLCore.git] / glBitmap.pas
index b5e8f2e..b181705 100644 (file)
@@ -24,7 +24,7 @@ History
 - GetPixel isn't set if you are loading textures inside the constructor (Thanks Wilson)
 10-08-2008
 - AddAlphaFromglBitmap used the custom pointer instead the imagedatapointer (Thanks Wilson)
-- Additional Datapointer for functioninterface now has the name CustomData  
+- Additional Datapointer for functioninterface now has the name CustomData
 24-07-2008
 - AssigneAlphaToBitmap overwrites his own palette (Thanks Wilson)
 - If you load an texture from an file the property Filename will be set to the name of the file
@@ -53,7 +53,7 @@ History
 - Property DataPtr now has the name Data
 - Functions are more flexible between RGB(A) and BGR(A). RGB can be saved as Bitmap and will be saved as BGR
 - Unused Depth removed
-- Function FreeData to freeing image data added 
+- Function FreeData to freeing image data added
 24-10-2007
 - ImageID flag of TGAs was ignored. (Thanks Zwoetzen)
 15-11-2006
@@ -221,7 +221,7 @@ unit glBitmap;
 
 // Please uncomment the defines below to configure the glBitmap to your preferences.
 // If you have configured the unit you can uncomment the warning above.
-{$MESSAGE warn 'Hey. I''m the glBitmap.pas and i need to be configured. My master tell me your preferences! ;)'}
+{.$MESSAGE warn 'Hey. I''m the glBitmap.pas and i need to be configured. My master tell me your preferences! ;)'}
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 // Preferences ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -860,6 +860,7 @@ type
    EglBitmapSizeToLarge       = class(EglBitmap);
    EglBitmapNonPowerOfTwo     = class(EglBitmap);
    EglBitmapUnsupportedFormat = class(EglBitmap)
+   public
      constructor Create(const aFormat: TglBitmapFormat); overload;
      constructor Create(const aMsg: String; const aFormat: TglBitmapFormat); overload;
    end;
@@ -888,6 +889,9 @@ type
   TglBitmapFormatDescriptor = class(TObject)
   protected
     function GetIsCompressed: Boolean; virtual; abstract;
+    function GetHasRed:       Boolean; virtual; abstract;
+    function GetHasGreen:     Boolean; virtual; abstract;
+    function GetHasBlue:      Boolean; virtual; abstract;
     function GetHasAlpha:     Boolean; virtual; abstract;
 
     function GetglDataFormat:     GLenum;  virtual; abstract;
@@ -895,6 +899,9 @@ type
     function GetglInternalFormat: GLenum;  virtual; abstract;
   public
     property IsCompressed: Boolean read GetIsCompressed;
+    property HasRed:       Boolean read GetHasRed;
+    property HasGreen:     Boolean read GetHasGreen;
+    property HasBlue:      Boolean read GetHasBlue;
     property HasAlpha:     Boolean read GetHasAlpha;
 
     property glFormat:         GLenum  read GetglFormat;
@@ -923,9 +930,10 @@ type
     fTarget: GLuint;
     fAnisotropic: Integer;
     fDeleteTextureOnFree: Boolean;
+    fFreeDataOnDestroy: Boolean;
     fFreeDataAfterGenTexture: Boolean;
     fData: PByte;
-    fIsResident: Boolean;
+    fIsResident: GLboolean;
     fBorderColor: array[0..3] of Single;
 
     fDimension: TglBitmapPixelPosition;
@@ -965,6 +973,7 @@ type
     procedure SetCustomData(const aValue: Pointer);
     procedure SetCustomName(const aValue: String);
     procedure SetCustomNameW(const aValue: WideString);
+    procedure SetFreeDataOnDestroy(const aValue: Boolean);
     procedure SetDeleteTextureOnFree(const aValue: Boolean);
     procedure SetFormat(const aValue: TglBitmapFormat);
     procedure SetFreeDataAfterGenTexture(const aValue: Boolean);
@@ -1003,11 +1012,12 @@ type
     property CustomData:  Pointer    read fCustomData  write SetCustomData;
 
     property DeleteTextureOnFree:     Boolean read fDeleteTextureOnFree     write SetDeleteTextureOnFree;
+    property FreeDataOnDestroy:       Boolean read fFreeDataOnDestroy       write SetFreeDataOnDestroy;
     property FreeDataAfterGenTexture: Boolean read fFreeDataAfterGenTexture write SetFreeDataAfterGenTexture;
 
     property Dimension:  TglBitmapPixelPosition  read fDimension;
     property Data:       PByte                   read fData;
-    property IsResident: Boolean                 read fIsResident;
+    property IsResident: GLboolean               read fIsResident;
 
     procedure AfterConstruction; override;
     procedure BeforeDestruction; override;
@@ -1103,7 +1113,7 @@ type
     constructor Create; overload;
     constructor Create(const aFileName: String); overload;
     constructor Create(const aStream: TStream); overload;
-    constructor Create(const aSize: TglBitmapPixelPosition; const aFormat: TglBitmapFormat); overload;
+    constructor Create(const aSize: TglBitmapPixelPosition; const aFormat: TglBitmapFormat; aData: PByte = nil); overload;
     constructor Create(const aSize: TglBitmapPixelPosition; const aFormat: TglBitmapFormat; const aFunc: TglBitmapFunction; const aArgs: Pointer = nil); overload;
     constructor Create(const aInstance: Cardinal; const aResource: String; const aResType: PChar = nil); overload;
     constructor Create(const aInstance: Cardinal; const aResourceID: Integer; const aResType: PChar); overload;
@@ -1226,7 +1236,8 @@ implementation
 
 uses
   Math, syncobjs, typinfo
-  {$IFDEF GLB_DELPHI}, Types{$ENDIF};
+  {$IFDEF GLB_DELPHI}, Types{$ENDIF}
+  {$IF DEFINED(GLB_SUPPORT_JPEG_READ) AND DEFINED(GLB_LAZ_JPEG)}, FPReadJPEG{$IFEND};
 
 type
 {$IFNDEF fpc}
@@ -1267,6 +1278,9 @@ type
     fglDataFormat:     GLenum;
 
     function GetIsCompressed: Boolean; override;
+    function GetHasRed: Boolean; override;
+    function GetHasGreen: Boolean; override;
+    function GetHasBlue: Boolean; override;
     function GetHasAlpha: Boolean; override;
 
     function GetglFormat: GLenum; override;
@@ -2303,7 +2317,7 @@ begin
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//TglBitmapFormatDescriptor///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//TFormatDescriptor///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 function TFormatDescriptor.GetRedMask: QWord;
 begin
@@ -2335,6 +2349,24 @@ begin
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function TFormatDescriptor.GetHasRed: Boolean;
+begin
+  result := (fRange.r > 0);
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function TFormatDescriptor.GetHasGreen: Boolean;
+begin
+  result := (fRange.g > 0);
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+function TFormatDescriptor.GetHasBlue: Boolean;
+begin
+  result := (fRange.b > 0);
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 function TFormatDescriptor.GetHasAlpha: Boolean;
 begin
   result := (fRange.a > 0);
@@ -4175,6 +4207,14 @@ begin
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+procedure TglBitmap.SetFreeDataOnDestroy(const aValue: Boolean);
+begin
+  if fFreeDataOnDestroy = aValue then
+    exit;
+  fFreeDataOnDestroy := aValue;
+end;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 procedure TglBitmap.SetDeleteTextureOnFree(const aValue: Boolean);
 begin
   if fDeleteTextureOnFree = aValue then
@@ -4334,7 +4374,6 @@ begin
   fTarget     := 0;
   fIsResident := false;
 
-  fFormat                  := glBitmapGetDefaultFormat;
   fMipMap                  := glBitmapDefaultMipmap;
   fFreeDataAfterGenTexture := glBitmapGetDefaultFreeDataAfterGenTexture;
   fDeleteTextureOnFree     := glBitmapGetDefaultDeleteTextureOnFree;
@@ -4349,8 +4388,10 @@ procedure TglBitmap.BeforeDestruction;
 var
   NewData: PByte;
 begin
-  NewData := nil;
-  SetDataPointer(NewData, tfEmpty); //be careful, Data could be freed by this method
+  if fFreeDataOnDestroy then begin
+    NewData := nil;
+    SetDataPointer(NewData, tfEmpty); //be careful, Data could be freed by this method
+  end;
   if (fID > 0) and fDeleteTextureOnFree then
     glDeleteTextures(1, @fID);
   inherited BeforeDestruction;
@@ -4417,7 +4458,7 @@ begin
       FreeMem(tmpData);
     raise;
   end;
-  AddFunc(Self, aFunc, false, Format, aArgs);
+  AddFunc(Self, aFunc, false, aFormat, aArgs);
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -4955,6 +4996,42 @@ var
   FormatDesc: TFormatDescriptor;
   ImageData: PByte;
   ImageSize: Integer;
+  CanCopy: Boolean;
+
+  procedure CopyConvert;
+  var
+    bfFormat: TbmpBitfieldFormat;
+    pSourceLine, pDestLine: PByte;
+    pSourceMD, pDestMD: Pointer;
+    x, y: Integer;
+    pixel: TglBitmapPixelData;
+  begin
+    bfFormat  := TbmpBitfieldFormat.Create;
+    with aImage.DataDescription do begin
+      bfFormat.RedMask   := ((1 shl RedPrec)   - 1) shl RedShift;
+      bfFormat.GreenMask := ((1 shl GreenPrec) - 1) shl GreenShift;
+      bfFormat.BlueMask  := ((1 shl BluePrec)  - 1) shl BlueShift;
+      bfFormat.AlphaMask := ((1 shl AlphaPrec) - 1) shl AlphaShift;
+      bfFormat.PixelSize := BitsPerPixel / 8;
+    end;
+    pSourceMD := bfFormat.CreateMappingData;
+    pDestMD   := FormatDesc.CreateMappingData;
+    try
+      for y := 0 to aImage.Height-1 do begin
+        pSourceLine := aImage.PixelData + y * aImage.DataDescription.BytesPerLine;
+        pDestLine   := ImageData        + y * Round(FormatDesc.PixelSize * aImage.Width);
+        for x := 0 to aImage.Width-1 do begin
+          bfFormat.Unmap(pSourceLine, pixel, pSourceMD);
+          FormatDesc.Map(pixel, pDestLine, pDestMD);
+        end;
+      end;
+    finally
+      FormatDesc.FreeMappingData(pDestMD);
+      bfFormat.FreeMappingData(pSourceMD);
+      bfFormat.Free;
+    end;
+  end;
+
 begin
   result := false;
   if not Assigned(aImage) then
@@ -4973,10 +5050,17 @@ begin
   if (f = tfEmpty) then
     exit;
 
+  CanCopy :=
+    (Round(FormatDesc.PixelSize * 8)     = aImage.DataDescription.Depth) and
+    (aImage.DataDescription.BitsPerPixel = aImage.DataDescription.Depth);
+
   ImageSize := FormatDesc.GetSize(aImage.Width, aImage.Height);
   ImageData := GetMem(ImageSize);
   try
-    Move(aImage.PixelData^, ImageData^, (aImage.Width * aImage.Height * aImage.DataDescription.BitsPerPixel) shr 3);
+    if CanCopy then
+      Move(aImage.PixelData^, ImageData^, ImageSize)
+    else
+      CopyConvert;
     SetDataPointer(ImageData, f, aImage.Width, aImage.Height); //be careful, Data could be freed by this method
   except
     if Assigned(ImageData) then
@@ -5593,7 +5677,7 @@ begin
 
   if (ID > 0) then begin
     Bind(false);
-    glTexParameteriv(Target, GL_TEXTURE_SWIZZLE_RGBA, @fSwizzle[0]);
+    glTexParameteriv(Target, GL_TEXTURE_SWIZZLE_RGBA, PGLint(@fSwizzle[0]));
   end;
 end;
 
@@ -5623,6 +5707,8 @@ begin
   glbReadOpenGLExtensions;
 {$ENDIF}
   inherited Create;
+  fFormat            := glBitmapGetDefaultFormat;
+  fFreeDataOnDestroy := true;
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -5640,27 +5726,30 @@ begin
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-constructor TglBitmap.Create(const aSize: TglBitmapPixelPosition; const aFormat: TglBitmapFormat);
+constructor TglBitmap.Create(const aSize: TglBitmapPixelPosition; const aFormat: TglBitmapFormat; aData: PByte);
 var
-  Image: PByte;
   ImageSize: Integer;
 begin
   Create;
-  ImageSize := TFormatDescriptor.Get(aFormat).GetSize(aSize);
-  GetMem(Image, ImageSize);
-  try
-    FillChar(Image^, ImageSize, #$FF);
-    SetDataPointer(Image, aFormat, aSize.X, aSize.Y); //be careful, Data could be freed by this method
-  except
-    if Assigned(Image) then
-      FreeMem(Image);
-    raise;
+  if not Assigned(aData) then begin
+    ImageSize := TFormatDescriptor.Get(aFormat).GetSize(aSize);
+    GetMem(aData, ImageSize);
+    try
+      FillChar(aData^, ImageSize, #$FF);
+      SetDataPointer(aData, aFormat, aSize.X, aSize.Y); //be careful, Data could be freed by this method
+    except
+      if Assigned(aData) then
+        FreeMem(aData);
+      raise;
+    end;
+  end else begin
+    SetDataPointer(aData, aFormat, aSize.X, aSize.Y); //be careful, Data could be freed by this method
+    fFreeDataOnDestroy := false;
   end;
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-constructor TglBitmap.Create(const aSize: TglBitmapPixelPosition; const aFormat: TglBitmapFormat;
-  const aFunc: TglBitmapFunction; const aArgs: Pointer);
+constructor TglBitmap.Create(const aSize: TglBitmapPixelPosition; const aFormat: TglBitmapFormat; const aFunc: TglBitmapFunction; const aArgs: Pointer);
 begin
   Create;
   LoadFromFunc(aSize, aFunc, aFormat, aArgs);
@@ -5690,7 +5779,7 @@ const
   MAGIC_LEN = 8;
   PNG_MAGIC: String[MAGIC_LEN] = #$89#$50#$4E#$47#$0D#$0A#$1A#$0A;
 var
-  png: TPortableNetworkGraphic;
+  reader: TLazReaderPNG;
   intf: TLazIntfImage;
   StreamPos: Int64;
   magic: String[MAGIC_LEN];
@@ -5706,27 +5795,20 @@ begin
     exit;
   end;
 
-  png := TPortableNetworkGraphic.Create;
+  intf   := TLazIntfImage.Create(0, 0);
+  reader := TLazReaderPNG.Create;
   try try
-    png.LoadFromStream(aStream);
-    intf := png.CreateIntfImage;
-    try try
-      AssignFromLazIntfImage(intf);
-    except
-      result := false;
-      aStream.Position := StreamPos;
-      exit;
-    end;
-    finally
-      intf.Free;
-    end;
+    reader.UpdateDescription := true;
+    reader.ImageRead(aStream, intf);
+    AssignFromLazIntfImage(intf);
   except
     result := false;
     aStream.Position := StreamPos;
     exit;
   end;
   finally
-    png.Free;
+    reader.Free;
+    intf.Free;
   end;
 end;
 
@@ -6292,8 +6374,8 @@ const
   MAGIC_LEN = 2;
   JPEG_MAGIC: String[MAGIC_LEN] = #$FF#$D8;
 var
-  jpeg: TJPEGImage;
   intf: TLazIntfImage;
+  reader: TFPReaderJPEG;
   StreamPos: Int64;
   magic: String[MAGIC_LEN];
 begin
@@ -6308,28 +6390,20 @@ begin
     exit;
   end;
 
-  jpeg := TJPEGImage.Create;
+  reader := TFPReaderJPEG.Create;
+  intf := TLazIntfImage.Create(0, 0);
   try try
-    jpeg.LoadFromStream(aStream);
-    intf := TLazIntfImage.Create(0, 0);
-    try try
-      intf.LoadFromBitmap(jpeg.BitmapHandle, jpeg.MaskHandle);
-      AssignFromLazIntfImage(intf);
-    except
-      result := false;
-      aStream.Position := StreamPos;
-      exit;
-    end;
-    finally
-      intf.Free;
-    end;
+    intf.DataDescription := GetDescriptionFromDevice(0, 0, 0);
+    reader.ImageRead(aStream, intf);
+    AssignFromLazIntfImage(intf);
   except
     result := false;
     aStream.Position := StreamPos;
     exit;
   end;
   finally
-    jpeg.Free;
+    reader.Free;
+    intf.Free;
   end;
 end;
 
@@ -7980,7 +8054,7 @@ procedure TglBitmap2D.GetDataFromTexture;
 var
   Temp: PByte;
   TempWidth, TempHeight: Integer;
-  TempIntFormat: Cardinal;
+  TempIntFormat: GLint;
   IntFormat, f: TglBitmapFormat;
   FormatDesc: TFormatDescriptor;
 begin