* some fixes to support Delphi (thanks at Jens01)
[glBitmap.git] / glBitmap.pas
index 0221b4d..b5e8f2e 100644 (file)
@@ -242,7 +242,7 @@ unit glBitmap;
 {.$DEFINE GLB_DELPHI}
 
 // activate to enable the support for TLazIntfImage from Lazarus
-{$DEFINE GLB_LAZARUS}
+{.$DEFINE GLB_LAZARUS}
 
 
 
@@ -254,7 +254,7 @@ unit glBitmap;
 
 // activate to enable Lazarus TPortableNetworkGraphic support
 // if you enable this pngImage and libPNG will be ignored
-{$DEFINE GLB_LAZ_PNG}
+{.$DEFINE GLB_LAZ_PNG}
 
 // activate to enable png support with the unit pngimage -> http://pngdelphi.sourceforge.net/
 // if you enable pngimage the libPNG will be ignored
@@ -268,7 +268,7 @@ unit glBitmap;
 
 // activate to enable Lazarus TJPEGImage support
 // if you enable this delphi jpegs and libJPEG will be ignored
-{$DEFINE GLB_LAZ_JPEG}
+{.$DEFINE GLB_LAZ_JPEG}
 
 // if you enable delphi jpegs the libJPEG will be ignored
 {.$DEFINE GLB_DELPHI_JPEG}
@@ -443,11 +443,12 @@ interface
 uses
   {$IFNDEF GLB_NATIVE_OGL}      dglOpenGL,                          {$ENDIF}
   {$IF DEFINED(GLB_WIN) AND
-       DEFINED(GLB_NATIVE_OGL)} windows,                            {$IFEND}
+       (DEFINED(GLB_NATIVE_OGL) OR
+        DEFINED(GLB_DELPHI))}   windows,                            {$IFEND}
 
   {$IFDEF GLB_SDL}              SDL,                                {$ENDIF}
   {$IFDEF GLB_LAZARUS}          IntfGraphics, GraphType, Graphics,  {$ENDIF}
-  {$IFDEF GLB_DELPHI}           Dialogs, Graphics,                  {$ENDIF}
+  {$IFDEF GLB_DELPHI}           Dialogs, Graphics, Types,           {$ENDIF}
 
   {$IFDEF GLB_SDL_IMAGE}        SDL_image,                          {$ENDIF}
   {$IFDEF GLB_PNGIMAGE}         pngimage,                           {$ENDIF}
@@ -1224,7 +1225,8 @@ function CreateGrayPalette: HPALETTE;
 implementation
 
 uses
-  Math, syncobjs, typinfo;
+  Math, syncobjs, typinfo
+  {$IFDEF GLB_DELPHI}, Types{$ENDIF};
 
 type
 {$IFNDEF fpc}
@@ -1292,7 +1294,7 @@ type
     procedure Unmap(var aData: PByte; out aPixel: TglBitmapPixelData; var aMapData: Pointer); virtual; abstract;
 
     function GetSize(const aSize: TglBitmapPixelPosition): Integer; overload; virtual;
-    function GetSize(const aWidth, aHeight: Integer): Integer; overload; virtual; 
+    function GetSize(const aWidth, aHeight: Integer): Integer; overload; virtual;
 
     function CreateMappingData: Pointer; virtual;
     procedure FreeMappingData(var aMappingData: Pointer); virtual;
@@ -1944,7 +1946,7 @@ end;
 var
   GL_LibHandle: Pointer = nil;
 
-function glbGetProcAddress(aProcName: PChar; aLibHandle: Pointer = nil): Pointer;
+function glbGetProcAddress(aProcName: PAnsiChar; aLibHandle: Pointer = nil; const aRaiseOnErr: Boolean = true): Pointer;
 begin
   if not Assigned(aLibHandle) then
     aLibHandle := GL_LibHandle;
@@ -1971,7 +1973,7 @@ begin
 
   result := dlsym(aLibHandle, aProcName);
 {$IFEND}
-  if not Assigned(result) then
+  if not Assigned(result) and aRaiseOnErr then
     raise EglBitmap.Create('unable to load procedure form library: ' + aProcName);
 end;
 
@@ -2025,42 +2027,37 @@ begin
   if not Assigned(GLU_LibHandle) then
     raise EglBitmap.Create('unable to load library: ' + libglu);
 
-  try
-  {$IF DEFINED(GLB_WIN)}
-    wglGetProcAddress    := glbGetProcAddress('wglGetProcAddress');
-  {$ELSEIF DEFINED(GLB_LINUX)}
-    glXGetProcAddress    := glbGetProcAddress('glXGetProcAddress');
-    glXGetProcAddressARB := glbGetProcAddress('glXGetProcAddressARB');
-  {$IFEND}
-
-    glEnable := glbGetProcAddress('glEnable');
-    glDisable := glbGetProcAddress('glDisable');
-    glGetString := glbGetProcAddress('glGetString');
-    glGetIntegerv := glbGetProcAddress('glGetIntegerv');
-    glTexParameteri := glbGetProcAddress('glTexParameteri');
-    glTexParameteriv := glbGetProcAddress('glTexParameteriv');
-    glTexParameterfv := glbGetProcAddress('glTexParameterfv');
-    glGetTexParameteriv := glbGetProcAddress('glGetTexParameteriv');
-    glGetTexParameterfv := glbGetProcAddress('glGetTexParameterfv');
-    glGetTexLevelParameteriv := glbGetProcAddress('glGetTexLevelParameteriv');
-    glGetTexLevelParameterfv := glbGetProcAddress('glGetTexLevelParameterfv');
-    glTexGeni := glbGetProcAddress('glTexGeni');
-    glGenTextures := glbGetProcAddress('glGenTextures');
-    glBindTexture := glbGetProcAddress('glBindTexture');
-    glDeleteTextures := glbGetProcAddress('glDeleteTextures');
-    glAreTexturesResident := glbGetProcAddress('glAreTexturesResident');
-    glReadPixels := glbGetProcAddress('glReadPixels');
-    glPixelStorei := glbGetProcAddress('glPixelStorei');
-    glTexImage1D := glbGetProcAddress('glTexImage1D');
-    glTexImage2D := glbGetProcAddress('glTexImage2D');
-    glGetTexImage := glbGetProcAddress('glGetTexImage');
-
-    gluBuild1DMipmaps := glbGetProcAddress('gluBuild1DMipmaps', GLU_LibHandle);
-    gluBuild2DMipmaps := glbGetProcAddress('gluBuild2DMipmaps', GLU_LibHandle);
-  finally
-    glbFreeLibrary(GL_LibHandle);
-    glbFreeLibrary(GLU_LibHandle);
-  end;
+{$IF DEFINED(GLB_WIN)}
+  wglGetProcAddress    := glbGetProcAddress('wglGetProcAddress');
+{$ELSEIF DEFINED(GLB_LINUX)}
+  glXGetProcAddress    := glbGetProcAddress('glXGetProcAddress');
+  glXGetProcAddressARB := glbGetProcAddress('glXGetProcAddressARB');
+{$IFEND}
+
+  glEnable := glbGetProcAddress('glEnable');
+  glDisable := glbGetProcAddress('glDisable');
+  glGetString := glbGetProcAddress('glGetString');
+  glGetIntegerv := glbGetProcAddress('glGetIntegerv');
+  glTexParameteri := glbGetProcAddress('glTexParameteri');
+  glTexParameteriv := glbGetProcAddress('glTexParameteriv');
+  glTexParameterfv := glbGetProcAddress('glTexParameterfv');
+  glGetTexParameteriv := glbGetProcAddress('glGetTexParameteriv');
+  glGetTexParameterfv := glbGetProcAddress('glGetTexParameterfv');
+  glGetTexLevelParameteriv := glbGetProcAddress('glGetTexLevelParameteriv');
+  glGetTexLevelParameterfv := glbGetProcAddress('glGetTexLevelParameterfv');
+  glTexGeni := glbGetProcAddress('glTexGeni');
+  glGenTextures := glbGetProcAddress('glGenTextures');
+  glBindTexture := glbGetProcAddress('glBindTexture');
+  glDeleteTextures := glbGetProcAddress('glDeleteTextures');
+  glAreTexturesResident := glbGetProcAddress('glAreTexturesResident');
+  glReadPixels := glbGetProcAddress('glReadPixels');
+  glPixelStorei := glbGetProcAddress('glPixelStorei');
+  glTexImage1D := glbGetProcAddress('glTexImage1D');
+  glTexImage2D := glbGetProcAddress('glTexImage2D');
+  glGetTexImage := glbGetProcAddress('glGetTexImage');
+
+  gluBuild1DMipmaps := glbGetProcAddress('gluBuild1DMipmaps', GLU_LibHandle);
+  gluBuild2DMipmaps := glbGetProcAddress('gluBuild2DMipmaps', GLU_LibHandle);
 end;
 {$ENDIF}
 
@@ -2163,9 +2160,9 @@ begin
     glCompressedTexImage2D  := glbGetProcAddress('glCompressedTexImage2D');
     glGetCompressedTexImage := glbGetProcAddress('glGetCompressedTexImage');
   end else begin
-    glCompressedTexImage1D  := glbGetProcAddress('glCompressedTexImage1DARB');
-    glCompressedTexImage2D  := glbGetProcAddress('glCompressedTexImage2DARB');
-    glGetCompressedTexImage := glbGetProcAddress('glGetCompressedTexImageARB');
+    glCompressedTexImage1D  := glbGetProcAddress('glCompressedTexImage1DARB',  nil, false);
+    glCompressedTexImage2D  := glbGetProcAddress('glCompressedTexImage2DARB',  nil, false);
+    glGetCompressedTexImage := glbGetProcAddress('glGetCompressedTexImageARB', nil, false);
   end;
 end;
 {$ENDIF}
@@ -4292,12 +4289,11 @@ begin
     fData := aData;
   end;
 
-  FillChar(fDimension, SizeOf(fDimension), 0);
   if not Assigned(fData) then begin
-    fFormat    := tfEmpty;
     fPixelSize := 0;
     fRowSize   := 0;
   end else begin
+    FillChar(fDimension, SizeOf(fDimension), 0);
     if aWidth <> -1 then begin
       fDimension.Fields := fDimension.Fields + [ffX];
       fDimension.X := aWidth;
@@ -4777,7 +4773,7 @@ begin
         tfRGBA8, tfBGRA8:
           aBitmap.PixelFormat := pf32bit;
       else
-        raise EglBitmapException.Create('AssignToBitmap - Invalid Pixelformat.');
+        raise EglBitmap.Create('AssignToBitmap - Invalid Pixelformat.');
       end;
 
       pSource := Data;
@@ -4815,7 +4811,7 @@ begin
       pf32bit:
         IntFormat := tfBGRA8;
     else
-      raise EglBitmapException.Create('AssignFromBitmap - Invalid Pixelformat.');
+      raise EglBitmap.Create('AssignFromBitmap - Invalid Pixelformat.');
     end;
 
     TempWidth  := aBitmap.Width;
@@ -4879,7 +4875,7 @@ begin
               Inc(pSource);
             end;
           end;
-        end;   
+        end;
         result := true;
       end;
     end;
@@ -4926,7 +4922,7 @@ begin
 
   rid.Width        := Width;
   rid.Height       := Height;
-  rid.Depth        := CountSetBits(FormatDesc.Range.r or FormatDesc.Range.g or FormatDesc.Range.b or FormatDesc.Range.a);
+  rid.Depth        := CountSetBits(FormatDesc.RedMask or FormatDesc.GreenMask or FormatDesc.BlueMask or FormatDesc.AlphaMask);
   rid.BitOrder     := riboBitsInOrder;
   rid.ByteOrder    := riboLSBFirst;
   rid.LineOrder    := riloTopToBottom;
@@ -5414,8 +5410,8 @@ procedure TglBitmap.Invert(const aUseRGB: Boolean; const aUseAlpha: Boolean);
 begin
   if aUseRGB or aUseAlpha then
     AddFunc(glBitmapInvertFunc, false, {%H-}Pointer(
-      ((PtrInt(aUseAlpha) and 1) shl 1) or
-       (PtrInt(aUseRGB)   and 1)      ));
+      ((Byte(aUseAlpha) and 1) shl 1) or
+       (Byte(aUseRGB)   and 1)      ));
 end;
 
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -5690,13 +5686,26 @@ end;
 //PNG/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 function TglBitmap.LoadPNG(const aStream: TStream): Boolean;
+const
+  MAGIC_LEN = 8;
+  PNG_MAGIC: String[MAGIC_LEN] = #$89#$50#$4E#$47#$0D#$0A#$1A#$0A;
 var
   png: TPortableNetworkGraphic;
   intf: TLazIntfImage;
   StreamPos: Int64;
+  magic: String[MAGIC_LEN];
 begin
   result := true;
   StreamPos := aStream.Position;
+
+  SetLength(magic, MAGIC_LEN);
+  aStream.Read(magic[1], MAGIC_LEN);
+  aStream.Position := StreamPos;
+  if (magic <> PNG_MAGIC) then begin
+    result := false;
+    exit;
+  end;
+
   png := TPortableNetworkGraphic.Create;
   try try
     png.LoadFromStream(aStream);
@@ -5797,7 +5806,7 @@ begin
       // read informations
       png_read_info(png, png_info);
 
-      // size 
+      // size
       TempHeight := png_get_image_height(png, png_info);
       TempWidth := png_get_image_width(png, png_info);
 
@@ -5970,13 +5979,15 @@ procedure TglBitmap.SavePNG(const aStream: TStream);
 var
   png: TPortableNetworkGraphic;
   intf: TLazIntfImage;
+  raw: TRawImage;
 begin
   png  := TPortableNetworkGraphic.Create;
   intf := TLazIntfImage.Create(0, 0);
   try
     if not AssignToLazIntfImage(intf) then
       raise EglBitmap.Create('unable to create LazIntfImage from glBitmap');
-    png.LoadFromIntfImage(intf);
+    intf.GetRawImage(raw);
+    png.LoadFromRawImage(raw, false);
     png.SaveToStream(aStream);
   finally
     png.Free;
@@ -6277,13 +6288,26 @@ end;
 {$IF DEFINED(GLB_LAZ_JPEG)}
 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 function TglBitmap.LoadJPEG(const aStream: TStream): Boolean;
+const
+  MAGIC_LEN = 2;
+  JPEG_MAGIC: String[MAGIC_LEN] = #$FF#$D8;
 var
   jpeg: TJPEGImage;
   intf: TLazIntfImage;
   StreamPos: Int64;
+  magic: String[MAGIC_LEN];
 begin
   result := true;
   StreamPos := aStream.Position;
+
+  SetLength(magic, MAGIC_LEN);
+  aStream.Read(magic[1], MAGIC_LEN);
+  aStream.Position := StreamPos;
+  if (magic <> JPEG_MAGIC) then begin
+    result := false;
+    exit;
+  end;
+
   jpeg := TJPEGImage.Create;
   try try
     jpeg.LoadFromStream(aStream);
@@ -6493,13 +6517,15 @@ procedure TglBitmap.SaveJPEG(const aStream: TStream);
 var
   jpeg: TJPEGImage;
   intf: TLazIntfImage;
+  raw: TRawImage;
 begin
   jpeg := TJPEGImage.Create;
   intf := TLazIntfImage.Create(0, 0);
   try
     if not AssignToLazIntfImage(intf) then
       raise EglBitmap.Create('unable to create LazIntfImage from glBitmap');
-    jpeg.LoadFromIntfImage(intf);
+    intf.GetRawImage(raw);
+    jpeg.LoadFromRawImage(raw, false);
     jpeg.SaveToStream(aStream);
   finally
     intf.Free;
@@ -6886,7 +6912,7 @@ procedure TglBitmap.SaveBMP(const aStream: TStream);
 var
   Header: TBMPHeader;
   Info: TBMPInfo;
-  Converter: TbmpColorTableFormat;
+  Converter: TFormatDescriptor;
   FormatDesc: TFormatDescriptor;
   SourceFD, DestFD: Pointer;
   pData, srcData, dstData, ConvertBuffer: pByte;
@@ -6931,26 +6957,30 @@ begin
         Info.biBitCount  := 4;
         Header.bfSize    := Header.bfSize    + 16 * SizeOf(Cardinal);
         Header.bfOffBits := Header.bfOffBits + 16 * SizeOf(Cardinal); //16 ColorTable entries
-        Converter           := TbmpColorTableFormat.Create;
-        Converter.PixelSize := 0.5;
-        Converter.Format    := Format;
-        Converter.Range     := glBitmapColorRec($F, $F, $F, $0);
-        Converter.CreateColorTable;
+        Converter := TbmpColorTableFormat.Create;
+        with (Converter as TbmpColorTableFormat) do begin
+          PixelSize := 0.5;
+          Format    := Format;
+          Range     := glBitmapColorRec($F, $F, $F, $0);
+          CreateColorTable;
+        end;
       end;
 
       tfR3G3B2, tfLuminance8: begin
         Info.biBitCount  :=  8;
         Header.bfSize    := Header.bfSize    + 256 * SizeOf(Cardinal);
         Header.bfOffBits := Header.bfOffBits + 256 * SizeOf(Cardinal); //256 ColorTable entries
-        Converter           := TbmpColorTableFormat.Create;
-        Converter.PixelSize := 1;
-        Converter.Format    := Format;
-        if (Format = tfR3G3B2) then begin
-          Converter.Range := glBitmapColorRec($7, $7, $3, $0);
-          Converter.Shift := glBitmapShiftRec(0, 3, 6, 0);
-        end else
-          Converter.Range := glBitmapColorRec($FF, $FF, $FF, $0);
-        Converter.CreateColorTable;
+        Converter := TbmpColorTableFormat.Create;
+        with (Converter as TbmpColorTableFormat) do begin
+          PixelSize := 1;
+          Format    := Format;
+          if (Format = tfR3G3B2) then begin
+            Range := glBitmapColorRec($7, $7, $3, $0);
+            Shift := glBitmapShiftRec(0, 3, 6, 0);
+          end else
+            Range := glBitmapColorRec($FF, $FF, $FF, $0);
+          CreateColorTable;
+        end;
       end;
 
       tfRGB4, tfRGB5, tfR5G6B5, tfRGB5A1, tfRGBA4,
@@ -6961,6 +6991,8 @@ begin
 
       tfBGR8, tfRGB8: begin
         Info.biBitCount := 24;
+        if (Format = tfRGB8) then
+          Converter := TfdBGR8.Create; //use BGR8 Format Descriptor to Swap RGB Values
       end;
 
       tfRGB10, tfRGB10A2, tfRGBA8,
@@ -6990,9 +7022,10 @@ begin
     aStream.Write(Info, SizeOf(Info));
 
     // colortable
-    if Assigned(Converter) then
-      aStream.Write(Converter.ColorTable[0].b,
-        SizeOf(TbmpColorTableEnty) * Length(Converter.ColorTable));
+    if Assigned(Converter) and (Converter is TbmpColorTableFormat) then
+      with (Converter as TbmpColorTableFormat) do
+        aStream.Write(ColorTable[0].b,
+          SizeOf(TbmpColorTableEnty) * Length(ColorTable));
 
     // bitmasks
     if Info.biCompression = BMP_COMP_BITFIELDS then begin
@@ -7280,7 +7313,7 @@ begin
       if Header.ImageID <> 0 then       // skip image ID
         aStream.Position := aStream.Position + Header.ImageID;
 
-      tgaFormat := tfEmpty;        
+      tgaFormat := tfEmpty;
       case Header.Bpp of
          8: if IsGrayFormat then case (Header.ImageDesc and $F) of
                0: tgaFormat := tfLuminance8;
@@ -7799,9 +7832,11 @@ var
 begin
   // Upload data
   FormatDesc := TFormatDescriptor.Get(Format);
-  if FormatDesc.IsCompressed then
+  if FormatDesc.IsCompressed then begin
+    if not Assigned(glCompressedTexImage1D) then
+      raise EglBitmap.Create('compressed formats not supported by video adapter');
     glCompressedTexImage1D(Target, 0, FormatDesc.glInternalFormat, Width, 0, FormatDesc.GetSize(Width, 1), Data)
-  else if aBuildWithGlu then
+  end else if aBuildWithGlu then
     gluBuild1DMipmaps(Target, FormatDesc.glInternalFormat, Width, FormatDesc.glFormat, FormatDesc.glDataFormat, Data)
   else
     glTexImage1D(Target, 0, FormatDesc.glInternalFormat, Width, 0, FormatDesc.glFormat, FormatDesc.glDataFormat, Data);
@@ -7890,6 +7925,8 @@ begin
 
   FormatDesc := TFormatDescriptor.Get(Format);
   if FormatDesc.IsCompressed then begin
+    if not Assigned(glCompressedTexImage2D) then
+      raise EglBitmap.Create('compressed formats not supported by video adapter');
     glCompressedTexImage2D(aTarget, 0, FormatDesc.glInternalFormat, Width, Height, 0, FormatDesc.GetSize(fDimension), Data)
   end else if aBuildWithGlu then begin
     gluBuild2DMipmaps(aTarget, FormatDesc.Components, Width, Height,
@@ -7967,10 +8004,12 @@ begin
   FormatDesc := TFormatDescriptor.Get(IntFormat);
   GetMem(Temp, FormatDesc.GetSize(TempWidth, TempHeight));
   try
-    if FormatDesc.IsCompressed then
+    if FormatDesc.IsCompressed then begin
+      if not Assigned(glGetCompressedTexImage) then
+        raise EglBitmap.Create('compressed formats not supported by video adapter');
       glGetCompressedTexImage(Target, 0, Temp)
-    else
-     glGetTexImage(Target, 0, FormatDesc.glInternalFormat, FormatDesc.glDataFormat, Temp);
+    end else
+      glGetTexImage(Target, 0, FormatDesc.glFormat, FormatDesc.glDataFormat, Temp);
     SetDataPointer(Temp, IntFormat, TempWidth, TempHeight); //be careful, Data could be freed by this method
   except
     if Assigned(Temp) then
@@ -8522,9 +8561,15 @@ initialization
 finalization
   TFormatDescriptor.Finalize;
 
+{$IFDEF GLB_NATIVE_OGL}
+  if Assigned(GL_LibHandle) then
+    glbFreeLibrary(GL_LibHandle);
+
 {$IFDEF GLB_NATIVE_OGL_DYNAMIC}
+  if Assigned(GLU_LibHandle) then
+    glbFreeLibrary(GLU_LibHandle);
   FreeAndNil(InitOpenGLCS);
 {$ENDIF}
+{$ENDIF}  
 
 end.
-